diff options
author | Evan Cheng <evan.cheng@apple.com> | 2010-11-22 18:12:04 +0000 |
---|---|---|
committer | Evan Cheng <evan.cheng@apple.com> | 2010-11-22 18:12:04 +0000 |
commit | eb56dca4fd5a0d08dbb869478f4d78dd2e2c1979 (patch) | |
tree | 9b8fd8127ec14fc207515c8798ec1467da9a1d2e /llvm/lib/Target/ARM/ARMFrameInfo.cpp | |
parent | abc0204bf65f5d9cd7b6ffb943b08c83182af51d (diff) | |
download | bcm5719-llvm-eb56dca4fd5a0d08dbb869478f4d78dd2e2c1979.tar.gz bcm5719-llvm-eb56dca4fd5a0d08dbb869478f4d78dd2e2c1979.zip |
Fix epilogue codegen to avoid leaving the stack pointer in an invalid
state. Previously Thumb2 would restore sp from fp like this:
mov sp, r7
sub, sp, #4
If an interrupt is taken after the 'mov' but before the 'sub', callee-saved
registers might be clobbered by the interrupt handler. Instead, try
restoring directly from sp:
add sp, #4
Or, if necessary (with VLA, etc.) use a scratch register to compute sp and
then restore it:
sub.w r4, r7, #8
mov sp, r7
rdar://8465407
llvm-svn: 119977
Diffstat (limited to 'llvm/lib/Target/ARM/ARMFrameInfo.cpp')
-rw-r--r-- | llvm/lib/Target/ARM/ARMFrameInfo.cpp | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/llvm/lib/Target/ARM/ARMFrameInfo.cpp b/llvm/lib/Target/ARM/ARMFrameInfo.cpp index 7766b1f4881..62f3f986b27 100644 --- a/llvm/lib/Target/ARM/ARMFrameInfo.cpp +++ b/llvm/lib/Target/ARM/ARMFrameInfo.cpp @@ -17,6 +17,7 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; @@ -212,15 +213,21 @@ void ARMFrameInfo::emitPrologue(MachineFunction &MF) const { if (NumBytes) { // Adjust SP after all the callee-save spills. emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes); - if (HasFP) + if (HasFP && isARM) + // Restore from fp only in ARM mode: e.g. sub sp, r7, #24 + // Note it's not safe to do this in Thumb2 mode because it would have + // taken two instructions: + // mov sp, r7 + // sub sp, #24 + // If an interrupt is taken between the two instructions, then sp is in + // an inconsistent state (pointing to the middle of callee-saved area). + // The interrupt handler can end up clobbering the registers. AFI->setShouldRestoreSPFromFP(true); } - if (STI.isTargetELF() && hasFP(MF)) { + if (STI.isTargetELF() && hasFP(MF)) MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() - AFI->getFramePtrSpillOffset()); - AFI->setShouldRestoreSPFromFP(true); - } AFI->setGPRCalleeSavedArea1Size(GPRCS1Size); AFI->setGPRCalleeSavedArea2Size(GPRCS2Size); @@ -275,7 +282,7 @@ void ARMFrameInfo::emitPrologue(MachineFunction &MF) const { // If the frame has variable sized objects then the epilogue must restore // the sp from fp. - if (!AFI->shouldRestoreSPFromFP() && MFI->hasVarSizedObjects()) + if (MFI->hasVarSizedObjects()) AFI->setShouldRestoreSPFromFP(true); } @@ -326,9 +333,21 @@ void ARMFrameInfo::emitEpilogue(MachineFunction &MF, if (isARM) emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, ARMCC::AL, 0, TII); - else - emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, + else { + // It's not possible to restore SP from FP in a single instruction. + // For Darwin, this looks like: + // mov sp, r7 + // sub sp, #24 + // This is bad, if an interrupt is taken after the mov, sp is in an + // inconsistent state. + // Use the first callee-saved register as a scratch register. + assert(MF.getRegInfo().isPhysRegUsed(ARM::R4) && + "No scratch register to restore SP from FP!"); + emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes, ARMCC::AL, 0, TII); + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) + .addReg(ARM::R4); + } } else { // Thumb2 or ARM. if (isARM) |