mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
When Mips16 frames grow large, the immediate field may exceed the maximum
allowed size for the instruction. This code uses RegScavenger to fix this. We sometimes need 2 registers for Mips16 so we must handle things differently than how register scavenger is normally used. llvm-svn: 174696
This commit is contained in:
parent
b8764716fa
commit
434681ac07
@ -19,6 +19,7 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
@ -306,11 +307,79 @@ void Mips16InstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
|
||||
/// This function generates the sequence of instructions needed to get the
|
||||
/// result of adding register REG and immediate IMM.
|
||||
unsigned
|
||||
Mips16InstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
|
||||
Mips16InstrInfo::loadImmediate(unsigned FrameReg,
|
||||
int64_t Imm, MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator II, DebugLoc DL,
|
||||
unsigned *NewImm) const {
|
||||
unsigned &NewImm) const {
|
||||
//
|
||||
// given original instruction is:
|
||||
// Instr rx, T[offset] where offset is too big.
|
||||
//
|
||||
// lo = offset & 0xFFFF
|
||||
// hi = ((offset >> 16) + (lo >> 15)) & 0xFFFF;
|
||||
//
|
||||
// let T = temporary register
|
||||
// li T, hi
|
||||
// shl T, 16
|
||||
// add T, Rx, T
|
||||
//
|
||||
RegScavenger rs;
|
||||
int32_t lo = Imm & 0xFFFF;
|
||||
int32_t hi = ((Imm >> 16) + (lo >> 15)) & 0xFFFF;
|
||||
NewImm = lo;
|
||||
unsigned Reg =0;
|
||||
unsigned SpReg = 0;
|
||||
rs.enterBasicBlock(&MBB);
|
||||
rs.forward(II);
|
||||
//
|
||||
// we use T0 for the first register, if we need to save something away.
|
||||
// we use T1 for the second register, if we need to save something away.
|
||||
//
|
||||
unsigned FirstRegSaved =0, SecondRegSaved=0;
|
||||
unsigned FirstRegSavedTo = 0, SecondRegSavedTo = 0;
|
||||
|
||||
return 0;
|
||||
Reg = rs.FindUnusedReg(&Mips::CPU16RegsRegClass);
|
||||
if (Reg == 0) {
|
||||
FirstRegSaved = Reg = Mips::V0;
|
||||
FirstRegSavedTo = Mips::T0;
|
||||
copyPhysReg(MBB, II, DL, FirstRegSavedTo, FirstRegSaved, true);
|
||||
}
|
||||
else
|
||||
rs.setUsed(Reg);
|
||||
BuildMI(MBB, II, DL, get(Mips::LiRxImmX16), Reg).addImm(hi);
|
||||
BuildMI(MBB, II, DL, get(Mips::SllX16), Reg).addReg(Reg).
|
||||
addImm(16);
|
||||
if (FrameReg == Mips::SP) {
|
||||
SpReg = rs.FindUnusedReg(&Mips::CPU16RegsRegClass);
|
||||
if (SpReg == 0) {
|
||||
if (Reg != Mips::V1) {
|
||||
SecondRegSaved = SpReg = Mips::V1;
|
||||
SecondRegSavedTo = Mips::T1;
|
||||
}
|
||||
else {
|
||||
SecondRegSaved = SpReg = Mips::V0;
|
||||
SecondRegSavedTo = Mips::T0;
|
||||
}
|
||||
copyPhysReg(MBB, II, DL, SecondRegSavedTo, SecondRegSaved, true);
|
||||
}
|
||||
else
|
||||
rs.setUsed(SpReg);
|
||||
|
||||
copyPhysReg(MBB, II, DL, SpReg, Mips::SP, false);
|
||||
BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(SpReg)
|
||||
.addReg(Reg);
|
||||
}
|
||||
else
|
||||
BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(FrameReg)
|
||||
.addReg(Reg, RegState::Kill);
|
||||
if (FirstRegSaved || SecondRegSaved) {
|
||||
II = llvm::next(II);
|
||||
if (FirstRegSaved)
|
||||
copyPhysReg(MBB, II, DL, FirstRegSaved, FirstRegSavedTo, true);
|
||||
if (SecondRegSaved)
|
||||
copyPhysReg(MBB, II, DL, SecondRegSaved, SecondRegSavedTo, true);
|
||||
}
|
||||
return Reg;
|
||||
}
|
||||
|
||||
unsigned Mips16InstrInfo::GetAnalyzableBrOpc(unsigned Opc) const {
|
||||
|
@ -77,12 +77,14 @@ public:
|
||||
void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I) const;
|
||||
|
||||
/// Emit a series of instructions to load an immediate. If NewImm is a
|
||||
/// non-NULL parameter, the last instruction is not emitted, but instead
|
||||
/// its immediate operand is returned in NewImm.
|
||||
unsigned loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
|
||||
/// Emit a series of instructions to load an immediate.
|
||||
// This is to adjust some FrameReg. We return the new register to be used
|
||||
// in place of FrameReg and the adjusted immediate field (&NewImm)
|
||||
//
|
||||
unsigned loadImmediate(unsigned FrameReg,
|
||||
int64_t Imm, MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator II, DebugLoc DL,
|
||||
unsigned *NewImm) const;
|
||||
unsigned &NewImm) const;
|
||||
|
||||
private:
|
||||
virtual unsigned GetAnalyzableBrOpc(unsigned Opc) const;
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
//===-- Mips16RegisterInfo.cpp - MIPS16 Register Information -== ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
@ -12,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Mips16RegisterInfo.h"
|
||||
#include "Mips16InstrInfo.h"
|
||||
#include "Mips.h"
|
||||
#include "Mips16InstrInfo.h"
|
||||
#include "MipsAnalyzeImmediate.h"
|
||||
@ -23,6 +25,7 @@
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/DebugInfo.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
@ -140,6 +143,7 @@ void Mips16RegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
|
||||
// by adding the size of the stack:
|
||||
// incoming argument, callee-saved register location or local variable.
|
||||
int64_t Offset;
|
||||
bool IsKill = false;
|
||||
Offset = SPOffset + (int64_t)StackSize;
|
||||
Offset += MI.getOperand(OpNo + 1).getImm();
|
||||
|
||||
@ -148,9 +152,14 @@ void Mips16RegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
|
||||
|
||||
if (!MI.isDebugValue() && ( ((FrameReg != Mips::SP) && !isInt<16>(Offset)) ||
|
||||
((FrameReg == Mips::SP) && !isInt<15>(Offset)) )) {
|
||||
llvm_unreachable("frame offset does not fit in instruction");
|
||||
MachineBasicBlock &MBB = *MI.getParent();
|
||||
DebugLoc DL = II->getDebugLoc();
|
||||
unsigned NewImm;
|
||||
FrameReg = TII.loadImmediate(FrameReg, Offset, MBB, II, DL, NewImm);
|
||||
Offset = SignExtend64<16>(NewImm);
|
||||
IsKill = true;
|
||||
}
|
||||
MI.getOperand(OpNo).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(OpNo).ChangeToRegister(FrameReg, false, false, IsKill);
|
||||
MI.getOperand(OpNo + 1).ChangeToImmediate(Offset);
|
||||
|
||||
|
||||
|
61
test/CodeGen/Mips/largefr1.ll
Normal file
61
test/CodeGen/Mips/largefr1.ll
Normal file
@ -0,0 +1,61 @@
|
||||
; RUN: llc -march=mipsel -mcpu=mips16 -mips16-hard-float -soft-float -relocation-model=static < %s | FileCheck %s -check-prefix=1
|
||||
|
||||
@i = common global i32 0, align 4
|
||||
@j = common global i32 0, align 4
|
||||
@.str = private unnamed_addr constant [8 x i8] c"%i %i \0A\00", align 1
|
||||
|
||||
define void @foo(i32* %p, i32 %i, i32 %j) nounwind {
|
||||
entry:
|
||||
%p.addr = alloca i32*, align 4
|
||||
%i.addr = alloca i32, align 4
|
||||
%j.addr = alloca i32, align 4
|
||||
store i32* %p, i32** %p.addr, align 4
|
||||
store i32 %i, i32* %i.addr, align 4
|
||||
store i32 %j, i32* %j.addr, align 4
|
||||
%0 = load i32* %j.addr, align 4
|
||||
%1 = load i32** %p.addr, align 4
|
||||
%2 = load i32* %i.addr, align 4
|
||||
%add.ptr = getelementptr inbounds i32* %1, i32 %2
|
||||
store i32 %0, i32* %add.ptr, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
; 1: main:
|
||||
; 1: 1: .word -797992
|
||||
; 1: li ${{[0-9]+}}, 12
|
||||
; 1: sll ${{[0-9]+}}, ${{[0-9]+}}, 16
|
||||
; 1: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
|
||||
; 2: move $sp, ${{[0-9]+}}
|
||||
; 2: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
|
||||
; 1: li ${{[0-9]+}}, 6
|
||||
; 1: sll ${{[0-9]+}}, ${{[0-9]+}}, 16
|
||||
; 1: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
|
||||
; 2: move $sp, ${{[0-9]+}}
|
||||
; 2: addu ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}}
|
||||
; 1: addiu ${{[0-9]+}}, ${{[0-9]+}}, 6800
|
||||
; 1: li ${{[0-9]+}}, 1
|
||||
; 1: sll ${{[0-9]+}}, ${{[0-9]+}}, 16
|
||||
; 2: li ${{[0-9]+}}, 34463
|
||||
%retval = alloca i32, align 4
|
||||
%one = alloca [100000 x i32], align 4
|
||||
%two = alloca [100000 x i32], align 4
|
||||
store i32 0, i32* %retval
|
||||
%arrayidx = getelementptr inbounds [100000 x i32]* %one, i32 0, i32 0
|
||||
call void @foo(i32* %arrayidx, i32 50, i32 9999)
|
||||
%arrayidx1 = getelementptr inbounds [100000 x i32]* %two, i32 0, i32 0
|
||||
call void @foo(i32* %arrayidx1, i32 99999, i32 5555)
|
||||
%arrayidx2 = getelementptr inbounds [100000 x i32]* %one, i32 0, i32 50
|
||||
%0 = load i32* %arrayidx2, align 4
|
||||
store i32 %0, i32* @i, align 4
|
||||
%arrayidx3 = getelementptr inbounds [100000 x i32]* %two, i32 0, i32 99999
|
||||
%1 = load i32* %arrayidx3, align 4
|
||||
store i32 %1, i32* @j, align 4
|
||||
%2 = load i32* @i, align 4
|
||||
%3 = load i32* @j, align 4
|
||||
%call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([8 x i8]* @.str, i32 0, i32 0), i32 %2, i32 %3)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare i32 @printf(i8*, ...)
|
Loading…
Reference in New Issue
Block a user