}
}
+/// We need the offset of the frame pointer relative to other MachineFrameInfo
+/// offsets which are encoded relative to SP at function begin.
+/// See also emitPrologue() for how the FP is set up.
+/// Unfortunately we cannot determine this value in determineCalleeSaves() yet
+/// as assignCalleeSavedSpillSlots() hasn't run at this point. Instead we use
+/// this to produce a conservative estimate that we check in an assert() later.
+static int getMaxFPOffset(const Function &F, const ARMFunctionInfo &AFI) {
+ // We may end up saving a lot of registers that are higher numbered than the
+ // r7 used for FP in thumb.
+ if (F.hasFnAttribute("interrupt") ||
+ F.getCallingConv() == CallingConv::CXX_FAST_TLS)
+ return -AFI.getArgRegsSaveSize() - (8 * 4);
+
+ // Usually it is just the link register and the FP itself (and in rare cases
+ // r12?) saved to reach FP.
+ return -AFI.getArgRegsSaveSize() - 12;
+}
+
void ARMFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
unsigned DPRCSOffset = GPRCS2Offset - DPRGapSize - DPRCSSize;
int FramePtrOffsetInPush = 0;
if (HasFP) {
- FramePtrOffsetInPush =
- MFI.getObjectOffset(FramePtrSpillFI) + ArgRegsSaveSize;
+ int FPOffset = MFI.getObjectOffset(FramePtrSpillFI);
+ assert(getMaxFPOffset(*MF.getFunction(), *AFI) <= FPOffset &&
+ "Max FP estimation is wrong");
+ FramePtrOffsetInPush = FPOffset + ArgRegsSaveSize;
AFI->setFramePtrSpillOffset(MFI.getObjectOffset(FramePtrSpillFI) +
NumBytes);
}
// worth the effort and added fragility?
unsigned EstimatedStackSize =
MFI.estimateStackSize(MF) + 4 * (NumGPRSpills + NumFPRSpills);
+
+ // Determine biggest (positive) SP offset in MachineFrameInfo.
+ int MaxFixedOffset = 0;
+ for (int I = MFI.getObjectIndexBegin(); I < 0; ++I) {
+ int MaxObjectOffset = MFI.getObjectOffset(I) + MFI.getObjectSize(I);
+ MaxFixedOffset = std::max(MaxFixedOffset, MaxObjectOffset);
+ }
+
bool HasFP = hasFP(MF);
if (HasFP) {
if (AFI->hasStackFrame())
} else {
// If FP is not used, SP will be used to access arguments, so count the
// size of arguments into the estimation.
- EstimatedStackSize += AFI->getArgumentStackSize();
+ EstimatedStackSize += MaxFixedOffset;
}
EstimatedStackSize += 16; // For possible paddings.
- bool BigStack = EstimatedStackSize >= estimateRSStackSizeLimit(MF, this) ||
- MFI.hasVarSizedObjects() ||
- (MFI.adjustsStack() && !canSimplifyCallFramePseudos(MF));
+ unsigned EstimatedRSStackSizeLimit = estimateRSStackSizeLimit(MF, this);
+ int MaxFPOffset = getMaxFPOffset(*MF.getFunction(), *AFI);
+ bool BigFrameOffsets = EstimatedStackSize >= EstimatedRSStackSizeLimit ||
+ MFI.hasVarSizedObjects() ||
+ (MFI.adjustsStack() && !canSimplifyCallFramePseudos(MF)) ||
+ // For large argument stacks fp relative addressed may overflow.
+ (HasFP && (MaxFixedOffset - MaxFPOffset) >= (int)EstimatedRSStackSizeLimit);
bool ExtraCSSpill = false;
- if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF)) {
+ if (BigFrameOffsets ||
+ !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF)) {
AFI->setHasStackFrame(true);
if (HasFP) {
// callee-saved register or reserve a special spill slot to facilitate
// register scavenging. Thumb1 needs a spill slot for stack pointer
// adjustments also, even when the frame itself is small.
- if (BigStack && !ExtraCSSpill) {
+ if (BigFrameOffsets && !ExtraCSSpill) {
// If any non-reserved CS register isn't spilled, just spill one or two
// extra. That should take care of it!
unsigned NumExtras = TargetAlign / 4;
--- /dev/null
+# RUN: llc -o - %s -mtriple=thumbv7-- -run-pass=stack-protector -run-pass=prologepilog | FileCheck %s
+---
+# This should trigger an emergency spill in the register scavenger because the
+# frame offset into the large argument is too large.
+# CHECK-LABEL: name: func0
+# CHECK: t2STRi12 killed %r7, %sp, 0, 14, _ :: (store 4 into %stack.0)
+# CHECK: %r7 = t2ADDri killed %sp, 4096, 14, _, _
+# CHECK: %r11 = t2LDRi12 killed %r7, 36, 14, _ :: (load 4)
+# CHECK: %r7 = t2LDRi12 %sp, 0, 14, _ :: (load 4 from %stack.0)
+name: func0
+tracksRegLiveness: true
+fixedStack:
+ - { id: 0, offset: 4084, size: 4, alignment: 4, isImmutable: true,
+ isAliased: false }
+ - { id: 1, offset: -12, size: 4096, alignment: 4, isImmutable: false,
+ isAliased: false }
+body: |
+ bb.0:
+ %r0 = IMPLICIT_DEF
+ %r1 = IMPLICIT_DEF
+ %r2 = IMPLICIT_DEF
+ %r3 = IMPLICIT_DEF
+ %r4 = IMPLICIT_DEF
+ %r5 = IMPLICIT_DEF
+ %r6 = IMPLICIT_DEF
+ %r8 = IMPLICIT_DEF
+ %r9 = IMPLICIT_DEF
+ %r10 = IMPLICIT_DEF
+ %r11 = IMPLICIT_DEF
+ %r12 = IMPLICIT_DEF
+ %lr = IMPLICIT_DEF
+
+ %r11 = t2LDRi12 %fixed-stack.0, 0, 14, _ :: (load 4)
+
+ KILL %r0
+ KILL %r1
+ KILL %r2
+ KILL %r3
+ KILL %r4
+ KILL %r5
+ KILL %r6
+ KILL %r8
+ KILL %r9
+ KILL %r10
+ KILL %r11
+ KILL %r12
+ KILL %lr
+...
+---
+# This should not trigger an emergency spill yet.
+# CHECK-LABEL: name: func1
+# CHECK-NOT: t2STRi12
+# CHECK-NOT: t2ADDri
+# CHECK: %r11 = t2LDRi12 %sp, 4092, 14, _ :: (load 4)
+# CHECK-NOT: t2LDRi12
+name: func1
+tracksRegLiveness: true
+fixedStack:
+ - { id: 0, offset: 4044, size: 4, alignment: 4, isImmutable: true,
+ isAliased: false }
+ - { id: 1, offset: -12, size: 4056, alignment: 4, isImmutable: false,
+ isAliased: false }
+body: |
+ bb.0:
+ %r0 = IMPLICIT_DEF
+ %r1 = IMPLICIT_DEF
+ %r2 = IMPLICIT_DEF
+ %r3 = IMPLICIT_DEF
+ %r4 = IMPLICIT_DEF
+ %r5 = IMPLICIT_DEF
+ %r6 = IMPLICIT_DEF
+ %r8 = IMPLICIT_DEF
+ %r9 = IMPLICIT_DEF
+ %r10 = IMPLICIT_DEF
+ %r11 = IMPLICIT_DEF
+ %r12 = IMPLICIT_DEF
+ %lr = IMPLICIT_DEF
+
+ %r11 = t2LDRi12 %fixed-stack.0, 0, 14, _ :: (load 4)
+
+ KILL %r0
+ KILL %r1
+ KILL %r2
+ KILL %r3
+ KILL %r4
+ KILL %r5
+ KILL %r6
+ KILL %r8
+ KILL %r9
+ KILL %r10
+ KILL %r11
+ KILL %r12
+ KILL %lr
+...