summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARM/Thumb1FrameLowering.cpp')
-rw-r--r--llvm/lib/Target/ARM/Thumb1FrameLowering.cpp106
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;
OpenPOWER on IntegriCloud