From: Reed Kotler Date: Fri, 8 Feb 2013 03:57:41 +0000 (+0000) Subject: When Mips16 frames grow large, the immediate field may exceed the maximum X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=61b97b8c1721ba45e5c10ca307ceebe1efdf72a9;p=oota-llvm.git 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174696 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/Mips/Mips16InstrInfo.cpp b/lib/Target/Mips/Mips16InstrInfo.cpp index 117faea86ff..9f27ac35173 100644 --- a/lib/Target/Mips/Mips16InstrInfo.cpp +++ b/lib/Target/Mips/Mips16InstrInfo.cpp @@ -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; + + 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); - return 0; + 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 { diff --git a/lib/Target/Mips/Mips16InstrInfo.h b/lib/Target/Mips/Mips16InstrInfo.h index 3704e2573f4..26a5a5e5fb9 100644 --- a/lib/Target/Mips/Mips16InstrInfo.h +++ b/lib/Target/Mips/Mips16InstrInfo.h @@ -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; diff --git a/lib/Target/Mips/Mips16RegisterInfo.cpp b/lib/Target/Mips/Mips16RegisterInfo.cpp index c2e09a72063..a181a34cbd6 100644 --- a/lib/Target/Mips/Mips16RegisterInfo.cpp +++ b/lib/Target/Mips/Mips16RegisterInfo.cpp @@ -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); diff --git a/test/CodeGen/Mips/largefr1.ll b/test/CodeGen/Mips/largefr1.ll new file mode 100644 index 00000000000..0fe89f71d9f --- /dev/null +++ b/test/CodeGen/Mips/largefr1.ll @@ -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*, ...)