[PATCH] Fix return sequence on armv4 thumb
Jonathan Roelofs
jonathan at codesourcery.com
Thu Jul 31 13:24:23 PDT 2014
Tim,
Currently the return sequence we generate for thumb functions without varargs is
something like this:
pop {r7, pc}
which works on v5t and later processors. Unfortunately, this doesn't work on
armv4t. According to
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204j/Cihfddaf.html,
pop does not change the arm/thumb state on armv4. This means that we can't use
it to return from functions that we expect to be interworking-safe.
> POP, with reglist including the pc
> This instruction causes a branch to the address popped off the stack into the
> pc. This is usually a return from a subroutine, where the lr was pushed onto
> the stack at the start of the subroutine.
> In ARMv4, bits[1:0] of the address loaded must be 0b00. POP cannot be used to
> change state.
> The following restrictions apply to the 16-bit instructions:
> For POP, reglist can only include the Lo registers and the pc
Therefore, the return sequence needs to be:
pop { ... }
pop {r3}
bx r3
Attached is a patch that fixes this behavior.
Regards,
Jon
--
Jon Roelofs
jonathan at codesourcery.com
CodeSourcery / Mentor Embedded
-------------- next part --------------
commit f55a03262695edbd045e6d8bef0abecddbd5f906
Author: Jonathan Roelofs <jonathan at codesourcery.com>
Date: Thu Jul 31 14:11:18 2014 -0600
[llvm] 'pop {pc}' does not set the arm/thumb bit on armv4, so use a different return sequence
diff --git a/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp b/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
index baa97a7..a30dfdd 100644
--- a/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
+++ b/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
@@ -463,6 +463,7 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineInstrBuilder MIB = BuildMI(MF, DL, TII.get(ARM::tPOP));
AddDefaultPred(MIB);
+ bool IsReturn = false;
bool NumRegs = false;
for (unsigned i = CSI.size(); i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
@@ -470,6 +471,9 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
// Special epilogue for vararg functions. See emitEpilogue
if (isVarArg)
continue;
+ IsReturn = true;
+ if (STI.hasV4TOps() && !STI.hasV5TOps())
+ continue;
Reg = ARM::PC;
(*MIB).setDesc(TII.get(ARM::tPOP_RET));
MIB.copyImplicitOps(&*MI);
@@ -485,5 +489,27 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
else
MF.DeleteMachineInstr(MIB);
+ // On armv4, popping into PC will not change arm/thumb state,
+ // so instead we have to emit that as:
+ // POP {r3}
+ // BX r3
+ if (IsReturn && STI.hasV4TOps() && !STI.hasV5TOps()) {
+ // Get the last instruction, tBX_RET
+ MI = MBB.getLastNonDebugInstr();
+ assert (MI->getOpcode() == ARM::tBX_RET);
+ DebugLoc dl = MI->getDebugLoc();
+ // Epilogue: pop LR to R3 and branch off it.
+ AddDefaultPred(BuildMI(MBB, MI, dl, TII.get(ARM::tPOP)))
+ .addReg(ARM::R3, RegState::Define);
+
+ MachineInstrBuilder MIB =
+ BuildMI(MBB, MI, dl, TII.get(ARM::tBX))
+ .addReg(ARM::R3, RegState::Kill);
+ AddDefaultPred(MIB);
+ MIB.copyImplicitOps(&*MI);
+ // erase the old tBX_RET instruction
+ MBB.erase(MI);
+ }
+
return true;
}
More information about the llvm-commits
mailing list