diff options
author | Momchil Velikov <momchil.velikov@arm.com> | 2017-11-14 10:36:52 +0000 |
---|---|---|
committer | Momchil Velikov <momchil.velikov@arm.com> | 2017-11-14 10:36:52 +0000 |
commit | dc86e1444d4291ba414b5a2bf5dee25c3aa1efd8 (patch) | |
tree | d31b83df92bf0fabae72c931b88d7bb145f74a58 /llvm/lib/Target/ARM/Thumb1FrameLowering.cpp | |
parent | 3cc3911cc0b53579b52e34f828155db38fce8d17 (diff) | |
download | bcm5719-llvm-dc86e1444d4291ba414b5a2bf5dee25c3aa1efd8.tar.gz bcm5719-llvm-dc86e1444d4291ba414b5a2bf5dee25c3aa1efd8.zip |
[ARM] Fix incorrect conversion of a tail call to an ordinary call
When we emit a tail call for Armv8-M, but then discover that the caller needs to
save/restore `LR`, we convert the tail call to an ordinary one, since restoring
`LR` takes extra instructions, which may negate the benefits of the tail
call. If the callee, however, takes stack arguments, this conversion is
incorrect, since nothing has been done to pass the stack arguments.
Thus the patch reverts https://reviews.llvm.org/rL294000
Also, we improve the instruction sequence for popping `LR` in the case when we
couldn't immediately find a scratch low register, but we can use as a temporary
one of the callee-saved low registers and restore `LR` before popping other
callee-saves.
Differential Revision: https://reviews.llvm.org/D39599
llvm-svn: 318143
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; |