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


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@119977 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng
2010-11-22 18:12:04 +00:00
parent 4d5a299790
commit ab5c703fdb
9 changed files with 124 additions and 37 deletions

View File

@@ -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)