Commit 010b07aa authored by Peter Trommler's avatar Peter Trommler 🥁 Committed by Ben Gamari

PPC NCG: Implement minimal stack frame header.

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
parent 1ad770f5
...@@ -1286,14 +1286,15 @@ genCCall' dflags gcp target dest_regs args ...@@ -1286,14 +1286,15 @@ genCCall' dflags gcp target dest_regs args
spFormat = if target32Bit platform then II32 else II64 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 move_sp_down finalStack
| delta > 64 = | delta > stackFrameHeaderSize dflags =
toOL [STU spFormat sp (AddrRegImm sp (ImmInt (-delta))), toOL [STU spFormat sp (AddrRegImm sp (ImmInt (-delta))),
DELTA (-delta)] DELTA (-delta)]
| otherwise = nilOL | otherwise = nilOL
where delta = stackDelta finalStack where delta = stackDelta finalStack
move_sp_up finalStack move_sp_up finalStack
| delta > 64 = -- TODO: fix-up stack back-chain | delta > stackFrameHeaderSize dflags =
toOL [ADD sp sp (RIImm (ImmInt delta)), toOL [ADD sp sp (RIImm (ImmInt delta)),
DELTA 0] DELTA 0]
| otherwise = nilOL | otherwise = nilOL
......
...@@ -15,6 +15,7 @@ module PPC.Instr ( ...@@ -15,6 +15,7 @@ module PPC.Instr (
archWordFormat, archWordFormat,
RI(..), RI(..),
Instr(..), Instr(..),
stackFrameHeaderSize,
maxSpillSlots, maxSpillSlots,
allocMoreStack, allocMoreStack,
makeFarBranches makeFarBranches
...@@ -508,7 +509,7 @@ ppc_mkSpillInstr ...@@ -508,7 +509,7 @@ ppc_mkSpillInstr
ppc_mkSpillInstr dflags reg delta slot ppc_mkSpillInstr dflags reg delta slot
= let platform = targetPlatform dflags = let platform = targetPlatform dflags
off = spillSlotToOffset slot off = spillSlotToOffset dflags slot
arch = platformArch platform arch = platformArch platform
in in
let fmt = case targetClassOfReg platform reg of let fmt = case targetClassOfReg platform reg of
...@@ -533,7 +534,7 @@ ppc_mkLoadInstr ...@@ -533,7 +534,7 @@ ppc_mkLoadInstr
ppc_mkLoadInstr dflags reg delta slot ppc_mkLoadInstr dflags reg delta slot
= let platform = targetPlatform dflags = let platform = targetPlatform dflags
off = spillSlotToOffset slot off = spillSlotToOffset dflags slot
arch = platformArch platform arch = platformArch platform
in in
let fmt = case targetClassOfReg platform reg of let fmt = case targetClassOfReg platform reg of
...@@ -549,6 +550,22 @@ ppc_mkLoadInstr dflags reg delta slot ...@@ -549,6 +550,22 @@ ppc_mkLoadInstr dflags reg delta slot
in instr fmt reg (AddrRegImm sp (ImmInt (off-delta))) 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 -- | 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 -- 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 -- 64-bit FPRs. So the maximum is 8 regardless of platforms unlike
...@@ -560,7 +577,8 @@ spillSlotSize = 8 ...@@ -560,7 +577,8 @@ spillSlotSize = 8
-- | The number of spill slots available without allocating more. -- | The number of spill slots available without allocating more.
maxSpillSlots :: DynFlags -> Int maxSpillSlots :: DynFlags -> Int
maxSpillSlots dflags 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 -- = 0 -- useful for testing allocMoreStack
-- | The number of bytes that the stack pointer should be aligned -- | The number of bytes that the stack pointer should be aligned
...@@ -570,9 +588,9 @@ stackAlign :: Int ...@@ -570,9 +588,9 @@ stackAlign :: Int
stackAlign = 16 stackAlign = 16
-- | Convert a spill slot number to a *byte* offset, with no sign. -- | Convert a spill slot number to a *byte* offset, with no sign.
spillSlotToOffset :: Int -> Int spillSlotToOffset :: DynFlags -> Int -> Int
spillSlotToOffset slot spillSlotToOffset dflags slot
= 64 + spillSlotSize * slot = stackFrameHeaderSize dflags + spillSlotSize * slot
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment