diff options
Diffstat (limited to 'llvm/lib/Target/ARM/Thumb1FrameLowering.cpp')
-rw-r--r-- | llvm/lib/Target/ARM/Thumb1FrameLowering.cpp | 106 |
1 files changed, 72 insertions, 34 deletions
diff --git a/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp b/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp index f6996f098c0..31aae92ec59 100644 --- a/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp +++ b/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp @@ -512,6 +512,26 @@ bool Thumb1FrameLowering::needPopSpecialFixUp(const MachineFunction &MF) const { return false; } +static void findTemporariesForLR(const BitVector &GPRsNoLRSP, + const BitVector &PopFriendly, + const LivePhysRegs &UsedRegs, unsigned &PopReg, + unsigned &TmpReg) { + PopReg = TmpReg = 0; + for (auto Reg : GPRsNoLRSP.set_bits()) { + if (!UsedRegs.contains(Reg)) { + // Remember the first pop-friendly register and exit. + if (PopFriendly.test(Reg)) { + PopReg = Reg; + TmpReg = 0; + break; + } + // Otherwise, remember that the register will be available to + // save a pop-friendly register. + TmpReg = Reg; + } + } +} + bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB, bool DoIt) const { MachineFunction &MF = *MBB.getParent(); @@ -600,17 +620,19 @@ bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB, GPRsNoLRSP.reset(ARM::LR); GPRsNoLRSP.reset(ARM::SP); GPRsNoLRSP.reset(ARM::PC); - for (unsigned Register : GPRsNoLRSP.set_bits()) { - if (!UsedRegs.contains(Register)) { - // Remember the first pop-friendly register and exit. - if (PopFriendly.test(Register)) { - PopReg = Register; - TemporaryReg = 0; - break; - } - // Otherwise, remember that the register will be available to - // save a pop-friendly register. - TemporaryReg = Register; + findTemporariesForLR(GPRsNoLRSP, PopFriendly, UsedRegs, PopReg, TemporaryReg); + + // If we couldn't find a pop-friendly register, restore LR before popping the + // other callee-saved registers, so we can use one of them as a temporary. + bool UseLDRSP = false; + if (!PopReg && MBBI != MBB.begin()) { + auto PrevMBBI = MBBI; + PrevMBBI--; + if (PrevMBBI->getOpcode() == ARM::tPOP) { + MBBI = PrevMBBI; + UsedRegs.stepBackward(*MBBI); + findTemporariesForLR(GPRsNoLRSP, PopFriendly, UsedRegs, PopReg, TemporaryReg); + UseLDRSP = true; } } @@ -619,6 +641,26 @@ bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB, assert((PopReg || TemporaryReg) && "Cannot get LR"); + if (UseLDRSP) { + assert(PopReg && "Do not know how to get LR"); + // Load the LR via LDR tmp, [SP, #off] + BuildMI(MBB, MBBI, dl, TII.get(ARM::tLDRspi)) + .addReg(PopReg, RegState::Define) + .addReg(ARM::SP) + .addImm(MBBI->getNumOperands() - 3) + .add(predOps(ARMCC::AL)); + // Move from the temporary register to the LR. + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr)) + .addReg(ARM::LR, RegState::Define) + .addReg(PopReg, RegState::Kill) + .add(predOps(ARMCC::AL)); + // Advance past the pop instruction. + MBBI++; + // Increment the SP. + emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, ArgRegsSaveSize + 4); + return true; + } + if (TemporaryReg) { assert(!PopReg && "Unnecessary MOV is about to be inserted"); PopReg = PopFriendly.find_first(); @@ -911,33 +953,29 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB, if (Reg == ARM::LR) { Info.setRestored(false); - if (MBB.succ_empty()) { - // Special epilogue for vararg functions. See emitEpilogue - if (isVarArg) - continue; - // ARMv4T requires BX, see emitEpilogue - if (!STI.hasV5TOps()) - continue; - // Tailcall optimization failed; change TCRETURN to a tBL - if (MI->getOpcode() == ARM::TCRETURNdi || - MI->getOpcode() == ARM::TCRETURNri) { - unsigned Opcode = MI->getOpcode() == ARM::TCRETURNdi - ? ARM::tBL : ARM::tBLXr; - MachineInstrBuilder BL = BuildMI(MF, DL, TII.get(Opcode)); - BL.add(predOps(ARMCC::AL)); - BL.add(MI->getOperand(0)); - MBB.insert(MI, &*BL); - } - Reg = ARM::PC; - (*MIB).setDesc(TII.get(ARM::tPOP_RET)); - if (MI != MBB.end()) - MIB.copyImplicitOps(*MI); - MI = MBB.erase(MI); - } else + if (!MBB.succ_empty() || + MI->getOpcode() == ARM::TCRETURNdi || + MI->getOpcode() == ARM::TCRETURNri) // LR may only be popped into PC, as part of return sequence. // If this isn't the return sequence, we'll need emitPopSpecialFixUp // to restore LR the hard way. + // FIXME: if we don't pass any stack arguments it would be actually + // advantageous *and* correct to do the conversion to an ordinary call + // instruction here. continue; + // Special epilogue for vararg functions. See emitEpilogue + if (isVarArg) + continue; + // ARMv4T requires BX, see emitEpilogue + if (!STI.hasV5TOps()) + continue; + + // Pop LR into PC. + Reg = ARM::PC; + (*MIB).setDesc(TII.get(ARM::tPOP_RET)); + if (MI != MBB.end()) + MIB.copyImplicitOps(*MI); + MI = MBB.erase(MI); } MIB.addReg(Reg, getDefRegState(true)); NeedsPop = true; |