Skip to content

Commit

Permalink
ARMFrameLowering: Reserve emergency spill slot for large arguments
Browse files Browse the repository at this point in the history
Re-commit after revert in r300668. Changed getMaxFPOffset() to a
more conservative heuristic instead of trying to be clever and missing
for some exotic calling conventions.

We need to reserve an emergency spill slot in cases with large argument
types that could overflow immediate offsets for FP relative address
calculations.

rdar://31317893

Differential Revision: https://reviews.llvm.org/D31643

llvm-svn: 300761
  • Loading branch information
MatzeB committed Apr 19, 2017
1 parent 9be010f commit 8aaa368
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 8 deletions.
43 changes: 35 additions & 8 deletions llvm/lib/Target/ARM/ARMFrameLowering.cpp
Expand Up @@ -322,6 +322,18 @@ static void emitAligningInstructions(MachineFunction &MF, ARMFunctionInfo *AFI,
}
}

/// 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) {
// This is a conservative estimation: Assume the frame pointer being r7 and
// pc("r15") up to r8 getting spilled before (= 8 registers).
return -AFI.getArgRegsSaveSize() - (8 * 4);
}

void ARMFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
Expand Down Expand Up @@ -432,8 +444,10 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
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);
}
Expand Down Expand Up @@ -1700,22 +1714,35 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// 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())
EstimatedStackSize += 4;
} 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) {
Expand Down Expand Up @@ -1899,7 +1926,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// 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;
Expand Down
94 changes: 94 additions & 0 deletions llvm/test/CodeGen/ARM/fpoffset_overflow.mir
@@ -0,0 +1,94 @@
# 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
...

0 comments on commit 8aaa368

Please sign in to comment.