Compute correct frame sizes for SPARC v9 64-bit frames.
authorJakob Stoklund Olesen <stoklund@2pi.dk>
Tue, 9 Apr 2013 04:37:47 +0000 (04:37 +0000)
committerJakob Stoklund Olesen <stoklund@2pi.dk>
Tue, 9 Apr 2013 04:37:47 +0000 (04:37 +0000)
The save area is twice as big and there is no struct return slot. The
stack pointer is always 16-byte aligned (after adding the bias).

Also eliminate the stack adjustment instructions around calls when the
function has a reserved stack frame.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@179083 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/Sparc/SparcFrameLowering.cpp
lib/Target/Sparc/SparcFrameLowering.h
lib/Target/Sparc/SparcISelLowering.cpp
test/CodeGen/SPARC/64abi.ll

index a0dae6e9480ccfd2aed83a02f372f29abe6b3f69..7874240f5983e7c5a0c03741360e45e17713bb7f 100644 (file)
@@ -37,18 +37,27 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF) const {
   // Get the number of bytes to allocate from the FrameInfo
   int NumBytes = (int) MFI->getStackSize();
 
-  // Emit the correct save instruction based on the number of bytes in
-  // the frame. Minimum stack frame size according to V8 ABI is:
-  //   16 words for register window spill
-  //    1 word for address of returned aggregate-value
-  // +  6 words for passing parameters on the stack
-  // ----------
-  //   23 words * 4 bytes per word = 92 bytes
-  NumBytes += 92;
+  if (SubTarget.is64Bit()) {
+    // All 64-bit stack frames must be 16-byte aligned, and must reserve space
+    // for spilling the 16 window registers at %sp+BIAS..%sp+BIAS+128.
+    NumBytes += 128;
+    // Frames with calls must also reserve space for 6 outgoing arguments
+    // whether they are used or not. LowerCall_64 takes care of that.
+    assert(NumBytes % 16 == 0 && "Stack size not 16-byte aligned");
+  } else {
+    // Emit the correct save instruction based on the number of bytes in
+    // the frame. Minimum stack frame size according to V8 ABI is:
+    //   16 words for register window spill
+    //    1 word for address of returned aggregate-value
+    // +  6 words for passing parameters on the stack
+    // ----------
+    //   23 words * 4 bytes per word = 92 bytes
+    NumBytes += 92;
 
-  // Round up to next doubleword boundary -- a double-word boundary
-  // is required by the ABI.
-  NumBytes = (NumBytes + 7) & ~7;
+    // Round up to next doubleword boundary -- a double-word boundary
+    // is required by the ABI.
+    NumBytes = RoundUpToAlignment(NumBytes, 8);
+  }
   NumBytes = -NumBytes;
 
   if (NumBytes >= -4096) {
@@ -70,15 +79,18 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF) const {
 void SparcFrameLowering::
 eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                               MachineBasicBlock::iterator I) const {
-  MachineInstr &MI = *I;
-  DebugLoc dl = MI.getDebugLoc();
-  int Size = MI.getOperand(0).getImm();
-  if (MI.getOpcode() == SP::ADJCALLSTACKDOWN)
-    Size = -Size;
-  const SparcInstrInfo &TII =
-    *static_cast<const SparcInstrInfo*>(MF.getTarget().getInstrInfo());
-  if (Size)
-    BuildMI(MBB, I, dl, TII.get(SP::ADDri), SP::O6).addReg(SP::O6).addImm(Size);
+  if (!hasReservedCallFrame(MF)) {
+    MachineInstr &MI = *I;
+    DebugLoc DL = MI.getDebugLoc();
+    int Size = MI.getOperand(0).getImm();
+    if (MI.getOpcode() == SP::ADJCALLSTACKDOWN)
+      Size = -Size;
+    const SparcInstrInfo &TII =
+      *static_cast<const SparcInstrInfo*>(MF.getTarget().getInstrInfo());
+    if (Size)
+      BuildMI(MBB, I, DL, TII.get(SP::ADDri), SP::O6).addReg(SP::O6)
+        .addImm(Size);
+  }
   MBB.erase(I);
 }
 
index 464233e7da35c1bec9f863858271bd1c5e3e235f..c375662016131ffee12f42833979f3df3c382ebb 100644 (file)
@@ -22,10 +22,12 @@ namespace llvm {
   class SparcSubtarget;
 
 class SparcFrameLowering : public TargetFrameLowering {
+  const SparcSubtarget &SubTarget;
 public:
-  explicit SparcFrameLowering(const SparcSubtarget &/*sti*/)
-    : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 8, 0) {
-  }
+  explicit SparcFrameLowering(const SparcSubtarget &ST)
+    : TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
+                          ST.is64Bit() ? 16 : 8, 0, ST.is64Bit() ? 16 : 8),
+      SubTarget(ST) {}
 
   /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
   /// the function.
index eb01c5ef318169f1f62b2e99c98d8d8ffb404dbf..9dc5c1ffffdc7980505c13006e189106bc08f4fd 100644 (file)
@@ -912,8 +912,9 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
 
   // Get the size of the outgoing arguments stack space requirement.
   // The stack offset computed by CC_Sparc64 includes all arguments.
-  // We always allocate space for 6 arguments in the prolog.
-  unsigned ArgsSize = std::max(6*8u, CCInfo.getNextStackOffset()) - 6*8u;
+  // Called functions expect 6 argument words to exist in the stack frame, used
+  // or not.
+  unsigned ArgsSize = std::max(6*8u, CCInfo.getNextStackOffset());
 
   // Keep stack frames 16-byte aligned.
   ArgsSize = RoundUpToAlignment(ArgsSize, 16);
index 10d8ff7c9aee93cc8ed2e0bf8bd9b7684e08ca68..ec9713572141306769574dd970a33705cb445cc4 100644 (file)
@@ -1,6 +1,9 @@
 ; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler | FileCheck %s
 
 ; CHECK: intarg
+; The save/restore frame is not strictly necessary here, but we would need to
+; refer to %o registers instead.
+; CHECK: save %sp, -128, %sp
 ; CHECK: stb %i0, [%i4]
 ; CHECK: stb %i1, [%i4]
 ; CHECK: sth %i2, [%i4]
@@ -11,6 +14,7 @@
 ; CHECK: st  [[R]], [%i4]
 ; CHECK: ldx [%fp+2231], [[R:%[gilo][0-7]]]
 ; CHECK: stx [[R]], [%i4]
+; CHECK: restore
 define void @intarg(i8  %a0,   ; %i0
                     i8  %a1,   ; %i1
                     i16 %a2,   ; %i2
@@ -34,18 +38,23 @@ define void @intarg(i8  %a0,   ; %i0
 }
 
 ; CHECK: call_intarg
+; 16 saved + 8 args.
+; CHECK: save %sp, -192, %sp
 ; Sign-extend and store the full 64 bits.
 ; CHECK: sra %i0, 0, [[R:%[gilo][0-7]]]
 ; CHECK: stx [[R]], [%sp+2223]
 ; Use %o0-%o5 for outgoing arguments
 ; CHECK: or %g0, 5, %o5
 ; CHECK: call intarg
+; CHECK-NOT: add %sp
+; CHECK: restore
 define void @call_intarg(i32 %i0, i8* %i1) {
   call void @intarg(i8 0, i8 1, i16 2, i32 3, i8* undef, i32 5, i32 %i0, i8* %i1)
   ret void
 }
 
 ; CHECK: floatarg
+; CHECK: save %sp, -128, %sp
 ; CHECK: fstod %f1,
 ; CHECK: faddd %f2,
 ; CHECK: faddd %f4,
@@ -81,12 +90,15 @@ define double @floatarg(float %a0,    ; %f1
 }
 
 ; CHECK: call_floatarg
+; CHECK: save %sp, -272, %sp
 ; Store 4 bytes, right-aligned in slot.
 ; CHECK: st %f1, [%sp+2307]
 ; Store 8 bytes in full slot.
 ; CHECK: std %f2, [%sp+2311]
 ; CHECK: fmovd %f2, %f4
 ; CHECK: call floatarg
+; CHECK-NOT: add %sp
+; CHECK: restore
 define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) {
   %r = call double @floatarg(float %f5, double %d2, double %d2, double %d2,
                              float %f5, float %f5,  float %f5,  float %f5,
@@ -127,6 +139,8 @@ define void @mixedarg(i8 %a0,      ; %i0
 ; CHECK: fmovd %f2, %f6
 ; CHECK: fmovd %f2, %f16
 ; CHECK: call mixedarg
+; CHECK-NOT: add %sp
+; CHECK: restore
 define void @call_mixedarg(i64 %i0, double %f2, i16* %i2) {
   call void @mixedarg(i8 undef,
                       float undef,
@@ -155,6 +169,8 @@ define i32 @inreg_fi(i32 inreg %a0,     ; high bits of %i0
 }
 
 ; CHECK: call_inreg_fi
+; Allocate space for 6 arguments, even when only 2 are used.
+; CHECK: save %sp, -176, %sp
 ; CHECK: sllx %i1, 32, %o0
 ; CHECK: fmovs %f5, %f1
 ; CHECK: call inreg_fi