PPC NCG: Implement minimal stack frame header.
authorPeter Trommler <ptrommler@acm.org>
Wed, 31 Aug 2016 19:18:06 +0000 (15:18 -0400)
committerBen Gamari <ben@smart-cactus.org>
Wed, 31 Aug 2016 19:18:39 +0000 (15:18 -0400)
According to the ABI specifications a minimal stack frame consists
of a header and a minimum size parameter save area. We reserve the
minimal size for each ABI.

On PowerPC 64-bil Linux and AIX the parameter save area can accomodate
up to eight parameters. So calls with eight parameters and fewer
can be done without allocating a new stack frame and deallocating
that stack frame after the call. On AIX one additional spill slot
is available on the stack.

Code size for all nofib benchmarks is 0.3 % smaller on powerpc64.

Test Plan: validate on AIX

Reviewers: hvr!, erikd, austin, simonmar, bgamari

Reviewed By: bgamari

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D2445

compiler/nativeGen/PPC/CodeGen.hs
compiler/nativeGen/PPC/Instr.hs

index 1b719fc..d03a6e5 100644 (file)
@@ -1286,14 +1286,15 @@ genCCall' dflags gcp target dest_regs args
 
         spFormat = if target32Bit platform then II32 else II64
 
+        -- TODO: Do not create a new stack frame if delta is too large.
         move_sp_down finalStack
-               | delta > 64 =
+               | delta > stackFrameHeaderSize dflags =
                         toOL [STU spFormat sp (AddrRegImm sp (ImmInt (-delta))),
                               DELTA (-delta)]
                | otherwise = nilOL
                where delta = stackDelta finalStack
         move_sp_up finalStack
-               | delta > 64 =  -- TODO: fix-up stack back-chain
+               | delta > stackFrameHeaderSize dflags =
                         toOL [ADD sp sp (RIImm (ImmInt delta)),
                               DELTA 0]
                | otherwise = nilOL
index 23d8b6b..5dc0325 100644 (file)
@@ -15,6 +15,7 @@ module PPC.Instr (
     archWordFormat,
     RI(..),
     Instr(..),
+    stackFrameHeaderSize,
     maxSpillSlots,
     allocMoreStack,
     makeFarBranches
@@ -508,7 +509,7 @@ ppc_mkSpillInstr
 
 ppc_mkSpillInstr dflags reg delta slot
   = let platform = targetPlatform dflags
-        off      = spillSlotToOffset slot
+        off      = spillSlotToOffset dflags slot
         arch     = platformArch platform
     in
     let fmt = case targetClassOfReg platform reg of
@@ -533,7 +534,7 @@ ppc_mkLoadInstr
 
 ppc_mkLoadInstr dflags reg delta slot
   = let platform = targetPlatform dflags
-        off     = spillSlotToOffset slot
+        off      = spillSlotToOffset dflags slot
         arch     = platformArch platform
     in
     let fmt = case targetClassOfReg platform reg of
@@ -549,6 +550,22 @@ ppc_mkLoadInstr dflags reg delta slot
     in instr fmt reg (AddrRegImm sp (ImmInt (off-delta)))
 
 
+-- | The size of a minimal stackframe header including minimal
+-- parameter save area.
+stackFrameHeaderSize :: DynFlags -> Int
+stackFrameHeaderSize dflags
+  = case platformOS platform of
+      OSLinux  -> case platformArch platform of
+                             -- header + parameter save area
+        ArchPPC           -> 64 -- TODO: check ABI spec
+        ArchPPC_64 ELF_V1 -> 48 + 8 * 8
+        ArchPPC_64 ELF_V2 -> 32 + 8 * 8
+        _ -> panic "PPC.stackFrameHeaderSize: Unknown Linux"
+      OSAIX    -> 24 + 8 * 4
+      OSDarwin -> 64 -- TODO: check ABI spec
+      _ -> panic "PPC.stackFrameHeaderSize: not defined for this OS"
+     where platform = targetPlatform dflags
+
 -- | The maximum number of bytes required to spill a register. PPC32
 -- has 32-bit GPRs and 64-bit FPRs, while PPC64 has 64-bit GPRs and
 -- 64-bit FPRs. So the maximum is 8 regardless of platforms unlike
@@ -560,7 +577,8 @@ spillSlotSize = 8
 -- | The number of spill slots available without allocating more.
 maxSpillSlots :: DynFlags -> Int
 maxSpillSlots dflags
-    = ((rESERVED_C_STACK_BYTES dflags - 64) `div` spillSlotSize) - 1
+    = ((rESERVED_C_STACK_BYTES dflags - stackFrameHeaderSize dflags)
+       `div` spillSlotSize) - 1
 --     = 0 -- useful for testing allocMoreStack
 
 -- | The number of bytes that the stack pointer should be aligned
@@ -570,9 +588,9 @@ stackAlign :: Int
 stackAlign = 16
 
 -- | Convert a spill slot number to a *byte* offset, with no sign.
-spillSlotToOffset :: Int -> Int
-spillSlotToOffset slot
-   = 64 + spillSlotSize * slot
+spillSlotToOffset :: DynFlags -> Int -> Int
+spillSlotToOffset dflags slot
+   = stackFrameHeaderSize dflags + spillSlotSize * slot
 
 
 --------------------------------------------------------------------------------