[llvm] r300639 - ARMFrameLowering: Reserve emergency spill slot for large arguments

Matthias Braun via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 18 18:16:07 PDT 2017


Author: matze
Date: Tue Apr 18 20:16:07 2017
New Revision: 300639

URL: http://llvm.org/viewvc/llvm-project?rev=300639&view=rev
Log:
ARMFrameLowering: Reserve emergency spill slot for large arguments

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

Added:
    llvm/trunk/test/CodeGen/ARM/fpoffset_overflow.mir
Modified:
    llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp

Modified: llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp?rev=300639&r1=300638&r2=300639&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp Tue Apr 18 20:16:07 2017
@@ -322,6 +322,24 @@ static void emitAligningInstructions(Mac
   }
 }
 
+/// 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();
@@ -432,8 +450,10 @@ void ARMFrameLowering::emitPrologue(Mach
   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);
   }
@@ -1700,6 +1720,14 @@ void ARMFrameLowering::determineCalleeSa
   //        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())
@@ -1707,15 +1735,20 @@ void ARMFrameLowering::determineCalleeSa
   } 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) {
@@ -1899,7 +1932,7 @@ void ARMFrameLowering::determineCalleeSa
     // 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;

Added: llvm/trunk/test/CodeGen/ARM/fpoffset_overflow.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/fpoffset_overflow.mir?rev=300639&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/fpoffset_overflow.mir (added)
+++ llvm/trunk/test/CodeGen/ARM/fpoffset_overflow.mir Tue Apr 18 20:16:07 2017
@@ -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
+...




More information about the llvm-commits mailing list