Index: llvm/lib/Target/ARM/Thumb1FrameLowering.cpp =================================================================== --- llvm/lib/Target/ARM/Thumb1FrameLowering.cpp +++ llvm/lib/Target/ARM/Thumb1FrameLowering.cpp @@ -463,6 +463,7 @@ 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 @@ // 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 @@ 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; }