diff --git a/lib/Target/Mips/Mips16FrameLowering.cpp b/lib/Target/Mips/Mips16FrameLowering.cpp index d17c1259e57..e0c51ed5873 100644 --- a/lib/Target/Mips/Mips16FrameLowering.cpp +++ b/lib/Target/Mips/Mips16FrameLowering.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Mips16FrameLowering.h" +#include "Mips16InstrInfo.h" #include "MCTargetDesc/MipsBaseInfo.h" #include "MipsInstrInfo.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -29,8 +30,8 @@ using namespace llvm; void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { MachineBasicBlock &MBB = MF.front(); MachineFrameInfo *MFI = MF.getFrameInfo(); - const MipsInstrInfo &TII = - *static_cast(MF.getTarget().getInstrInfo()); + const Mips16InstrInfo &TII = + *static_cast(MF.getTarget().getInstrInfo()); MachineBasicBlock::iterator MBBI = MBB.begin(); DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); uint64_t StackSize = MFI->getStackSize(); @@ -39,8 +40,7 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { if (StackSize == 0 && !MFI->adjustsStack()) return; // Adjust stack. - if (isInt<16>(-StackSize)) - BuildMI(MBB, MBBI, dl, TII.get(Mips::SaveRaF16)).addImm(StackSize); + TII.makeFrame(Mips::SP, StackSize, MBB, MBBI); if (hasFP(MF)) BuildMI(MBB, MBBI, dl, TII.get(Mips::MoveR3216), Mips::S0) @@ -52,8 +52,8 @@ void Mips16FrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); MachineFrameInfo *MFI = MF.getFrameInfo(); - const MipsInstrInfo &TII = - *static_cast(MF.getTarget().getInstrInfo()); + const Mips16InstrInfo &TII = + *static_cast(MF.getTarget().getInstrInfo()); DebugLoc dl = MBBI->getDebugLoc(); uint64_t StackSize = MFI->getStackSize(); @@ -65,9 +65,8 @@ void Mips16FrameLowering::emitEpilogue(MachineFunction &MF, .addReg(Mips::S0); // Adjust stack. - if (isInt<16>(StackSize)) - // assumes stacksize multiple of 8 - BuildMI(MBB, MBBI, dl, TII.get(Mips::RestoreRaF16)).addImm(StackSize); + // assumes stacksize multiple of 8 + TII.restoreFrame(Mips::SP, StackSize, MBB, MBBI); } bool Mips16FrameLowering:: diff --git a/lib/Target/Mips/Mips16InstrInfo.cpp b/lib/Target/Mips/Mips16InstrInfo.cpp index 10b696fe876..91b5ba0800d 100644 --- a/lib/Target/Mips/Mips16InstrInfo.cpp +++ b/lib/Target/Mips/Mips16InstrInfo.cpp @@ -19,11 +19,19 @@ #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; +static cl::opt NeverUseSaveRestore( + "mips16-never-use-save-restore", + cl::init(false), + cl::desc("For testing ability to adjust stack pointer without save/restore instruction"), + cl::Hidden); + + Mips16InstrInfo::Mips16InstrInfo(MipsTargetMachine &tm) : MipsInstrInfo(tm, Mips::BimmX16), RI(*tm.getSubtargetImpl(), *this) {} @@ -160,20 +168,135 @@ unsigned Mips16InstrInfo::GetOppositeBranchOpc(unsigned Opc) const { return 0; } +// Adjust SP by FrameSize bytes. Save RA, S0, S1 +void Mips16InstrInfo::makeFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + if (!NeverUseSaveRestore) { + if (isUInt<11>(FrameSize)) + BuildMI(MBB, I, DL, get(Mips::SaveRaF16)).addImm(FrameSize); + else { + int Base = 2040; // should create template function like isUInt that returns largest + // possible n bit unsigned integer + int64_t Remainder = FrameSize - Base; + BuildMI(MBB, I, DL, get(Mips::SaveRaF16)). addImm(Base); + if (isInt<16>(-Remainder)) + BuildMI(MBB, I, DL, get(Mips::AddiuSpImmX16)). addImm(-Remainder); + else + adjustStackPtrBig(SP, -Remainder, MBB, I, Mips::V0, Mips::V1); + } + + } + else { + // + // sw ra, -4[sp] + // sw s1, -8[sp] + // sw s0, -12[sp] + + MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::SwRxSpImmX16), Mips::RA); + MIB1.addReg(Mips::SP); + MIB1.addImm(-4); + MachineInstrBuilder MIB2 = BuildMI(MBB, I, DL, get(Mips::SwRxSpImmX16), Mips::S1); + MIB2.addReg(Mips::SP); + MIB2.addImm(-8); + MachineInstrBuilder MIB3 = BuildMI(MBB, I, DL, get(Mips::SwRxSpImmX16), Mips::S0); + MIB3.addReg(Mips::SP); + MIB3.addImm(-12); + adjustStackPtrBig(SP, -FrameSize, MBB, I, Mips::V0, Mips::V1); + } +} + +// Adjust SP by FrameSize bytes. Restore RA, S0, S1 +void Mips16InstrInfo::restoreFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + if (!NeverUseSaveRestore) { + if (isUInt<11>(FrameSize)) + BuildMI(MBB, I, DL, get(Mips::RestoreRaF16)).addImm(FrameSize); + else { + int Base = 2040; // should create template function like isUInt that returns largest + // possible n bit unsigned integer + int64_t Remainder = FrameSize - Base; + if (isInt<16>(Remainder)) + BuildMI(MBB, I, DL, get(Mips::AddiuSpImmX16)). addImm(Remainder); + else + adjustStackPtrBig(SP, Remainder, MBB, I, Mips::A0, Mips::A1); + BuildMI(MBB, I, DL, get(Mips::RestoreRaF16)). addImm(Base); + } + } + else { + adjustStackPtrBig(SP, FrameSize, MBB, I, Mips::A0, Mips::A1); + // lw ra, -4[sp] + // lw s1, -8[sp] + // lw s0, -12[sp] + MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::LwRxSpImmX16), Mips::A0); + MIB1.addReg(Mips::SP); + MIB1.addImm(-4); + MachineInstrBuilder MIB0 = BuildMI(MBB, I, DL, get(Mips::Move32R16), Mips::RA); + MIB0.addReg(Mips::A0); + MachineInstrBuilder MIB2 = BuildMI(MBB, I, DL, get(Mips::LwRxSpImmX16), Mips::S1); + MIB2.addReg(Mips::SP); + MIB2.addImm(-8); + MachineInstrBuilder MIB3 = BuildMI(MBB, I, DL, get(Mips::LwRxSpImmX16), Mips::S0); + MIB3.addReg(Mips::SP); + MIB3.addImm(-12); + } + +} + +// Adjust SP by Amount bytes where bytes can be up to 32bit number. +// This can only be called at times that we know that there is at least one free register. +// This is clearly safe at prologue and epilogue. +// +void Mips16InstrInfo::adjustStackPtrBig(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Reg1, unsigned Reg2) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); +// MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); +// unsigned Reg1 = RegInfo.createVirtualRegister(&Mips::CPU16RegsRegClass); +// unsigned Reg2 = RegInfo.createVirtualRegister(&Mips::CPU16RegsRegClass); + // + // li reg1, constant + // move reg2, sp + // add reg1, reg1, reg2 + // move sp, reg1 + // + // + MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::LwConstant32), Reg1); + MIB1.addImm(Amount); + MachineInstrBuilder MIB2 = BuildMI(MBB, I, DL, get(Mips::MoveR3216), Reg2); + MIB2.addReg(Mips::SP, RegState::Kill); + MachineInstrBuilder MIB3 = BuildMI(MBB, I, DL, get(Mips::AdduRxRyRz16), Reg1); + MIB3.addReg(Reg1); + MIB3.addReg(Reg2, RegState::Kill); + MachineInstrBuilder MIB4 = BuildMI(MBB, I, DL, get(Mips::Move32R16), Mips::SP); + MIB4.addReg(Reg1, RegState::Kill); +} + +void Mips16InstrInfo::adjustStackPtrBigUnrestricted(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + assert(false && "adjust stack pointer amount exceeded"); +} + /// Adjust SP by Amount bytes. void Mips16InstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); - if (isInt<16>(Amount)) { - if (Amount < 0) - BuildMI(MBB, I, DL, get(Mips::SaveDecSpF16)). addImm(-Amount); - else if (Amount > 0) - BuildMI(MBB, I, DL, get(Mips::RestoreIncSpF16)).addImm(Amount); - } + if (isInt<16>(Amount)) // need to change to addiu sp, ....and isInt<16> + BuildMI(MBB, I, DL, get(Mips::AddiuSpImmX16)). addImm(Amount); else - // not implemented for large values yet - assert(false && "adjust stack pointer amount exceeded"); + adjustStackPtrBigUnrestricted(SP, Amount, MBB, I); +} + +/// 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, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned *NewImm) const { + + return 0; } unsigned Mips16InstrInfo::GetAnalyzableBrOpc(unsigned Opc) const { diff --git a/lib/Target/Mips/Mips16InstrInfo.h b/lib/Target/Mips/Mips16InstrInfo.h index d6ef8d2bf18..16487e7937e 100644 --- a/lib/Target/Mips/Mips16InstrInfo.h +++ b/lib/Target/Mips/Mips16InstrInfo.h @@ -64,15 +64,42 @@ public: virtual unsigned GetOppositeBranchOpc(unsigned Opc) const; + // Adjust SP by FrameSize bytes. Save RA, S0, S1 + void makeFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + // Adjust SP by FrameSize bytes. Restore RA, S0, S1 + void restoreFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + /// Adjust SP by Amount bytes. 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, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned *NewImm) const; + private: virtual unsigned GetAnalyzableBrOpc(unsigned Opc) const; void ExpandRetRA16(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned Opc) const; + + // Adjust SP by Amount bytes where bytes can be up to 32bit number. + void adjustStackPtrBig(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Reg1, unsigned Reg2) const; + + // Adjust SP by Amount bytes where bytes can be up to 32bit number. + void adjustStackPtrBigUnrestricted(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + }; } diff --git a/lib/Target/Mips/Mips16InstrInfo.td b/lib/Target/Mips/Mips16InstrInfo.td index ebbd21409dc..e8e2f3ce41c 100644 --- a/lib/Target/Mips/Mips16InstrInfo.td +++ b/lib/Target/Mips/Mips16InstrInfo.td @@ -57,13 +57,17 @@ class FEXT_I16_ins eop, string asmstr, InstrItinClass itin> : class FEXT_I816_ins_base _func, string asmstr, string asmstr2, InstrItinClass itin>: - FEXT_I816<_func, (outs), (ins uimm16:$imm), !strconcat(asmstr, asmstr2), + FEXT_I816<_func, (outs), (ins simm16:$imm), !strconcat(asmstr, asmstr2), [], itin>; class FEXT_I816_ins _func, string asmstr, InstrItinClass itin>: FEXT_I816_ins_base<_func, asmstr, "\t$imm", itin>; +class FEXT_I816_SP_ins _func, string asmstr, + InstrItinClass itin>: + FEXT_I816_ins_base<_func, asmstr, "\t$$sp, $imm", itin>; + // // Assembler formats in alphabetical order. // Natural and pseudos are mixed together. @@ -352,6 +356,18 @@ class SelT f1, string op1, bits<5> f2, string op2, let Constraints = "$rd = $rd_"; } +// +// 32 bit constant +// +def imm32: Operand; + +def Constant32: + MipsPseudo16<(outs), (ins imm32:$imm), "\t.word $imm", []>; + +def LwConstant32: + MipsPseudo16<(outs), (ins CPU16Regs:$rx, imm32:$imm), + "lw\t$rx, 1f\n\tb\t2f\n\t.align\t2\n1: \t.word\t$imm\n2:", []>; + // // Some general instruction class info @@ -404,6 +420,18 @@ def AddiuRxRyOffMemX16: // To add a constant to the program counter. // def AddiuRxPcImmX16: FEXT_RI16_PC_ins<0b00001, "addiu", IIAlu>; + +// +// Format: ADDIU sp, immediate MIPS16e +// Purpose: Add Immediate Unsigned Word (2-Operand, SP-Relative, Extended) +// To add a constant to the stack pointer. +// +def AddiuSpImmX16 + : FEXT_I816_SP_ins<0b011, "addiu", IIAlu> { + let Defs = [SP]; + let Uses = [SP]; +} + // // Format: ADDU rz, rx, ry MIPS16e // Purpose: Add Unsigned Word (3-Operand) diff --git a/test/CodeGen/Mips/alloca16.ll b/test/CodeGen/Mips/alloca16.ll index 731edae43cb..5ae9a847917 100644 --- a/test/CodeGen/Mips/alloca16.ll +++ b/test/CodeGen/Mips/alloca16.ll @@ -68,8 +68,8 @@ entry: %21 = load i32** %ip, align 4 %arrayidx6 = getelementptr inbounds i32* %21, i32 %20 %22 = load i32* %arrayidx6, align 4 -; 16: save 16 +; 16: addiu $sp, -16 call void @temp(i32 %22) -; 16: restore 16 +; 16: addiu $sp, 16 ret void }