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

nativeGen PPC: fix > 16 bit offsets in stack handling

Implement access to spill slots at offsets larger than 16 bits.
Also allocation and deallocation of spill slots was restricted to
16 bit offsets. Now 32 bit offsets are supported on all PowerPC
platforms.

The implementation of 32 bit offsets requires more than one instruction
but the native code generator wants one instruction. So we implement
pseudo-instructions that are pretty printed into multiple assembly
instructions.

With pseudo-instructions for spill slot allocation and deallocation
we can also implement handling of the back chain pointer according
to the ELF ABIs.

Test Plan: validate (especially on powerpc (32 bit))

Reviewers: bgamari, austin, erikd

Reviewed By: erikd

Subscribers: thomie

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

GHC Trac Issues: #7830
parent 57e3742c
...@@ -74,19 +74,19 @@ instance Instruction Instr where ...@@ -74,19 +74,19 @@ instance Instruction Instr where
ppc_mkStackAllocInstr :: Platform -> Int -> Instr ppc_mkStackAllocInstr :: Platform -> Int -> Instr
ppc_mkStackAllocInstr platform amount ppc_mkStackAllocInstr platform amount
= case platformArch platform of = ppc_mkStackAllocInstr' platform (-amount)
ArchPPC -> -- SUB II32 (OpImm (ImmInt amount)) (OpReg esp)
ADD sp sp (RIImm (ImmInt (-amount)))
ArchPPC_64 _ -> STU II64 sp (AddrRegImm sp (ImmInt (-amount)))
arch -> panic $ "ppc_mkStackAllocInstr " ++ show arch
ppc_mkStackDeallocInstr :: Platform -> Int -> Instr ppc_mkStackDeallocInstr :: Platform -> Int -> Instr
ppc_mkStackDeallocInstr platform amount ppc_mkStackDeallocInstr platform amount
= ppc_mkStackAllocInstr' platform amount
ppc_mkStackAllocInstr' :: Platform -> Int -> Instr
ppc_mkStackAllocInstr' platform amount
= case platformArch platform of = case platformArch platform of
ArchPPC -> -- ADD II32 (OpImm (ImmInt amount)) (OpReg esp) ArchPPC -> UPDATE_SP II32 (ImmInt amount)
ADD sp sp (RIImm (ImmInt amount)) ArchPPC_64 _ -> UPDATE_SP II64 (ImmInt amount)
ArchPPC_64 _ -> ADD sp sp (RIImm (ImmInt amount)) _ -> panic $ "ppc_mkStackAllocInstr' "
arch -> panic $ "ppc_mkStackDeallocInstr " ++ show arch ++ show (platformArch platform)
-- --
-- See note [extra spill slots] in X86/Instr.hs -- See note [extra spill slots] in X86/Instr.hs
...@@ -186,8 +186,10 @@ data Instr ...@@ -186,8 +186,10 @@ data Instr
-- Loads and stores. -- Loads and stores.
| LD Format Reg AddrMode -- Load format, dst, src | LD Format Reg AddrMode -- Load format, dst, src
| LDFAR Format Reg AddrMode -- Load format, dst, src 32 bit offset
| LA Format Reg AddrMode -- Load arithmetic format, dst, src | LA Format Reg AddrMode -- Load arithmetic format, dst, src
| ST Format Reg AddrMode -- Store format, src, dst | ST Format Reg AddrMode -- Store format, src, dst
| STFAR Format Reg AddrMode -- Store format, src, dst 32 bit offset
| STU Format Reg AddrMode -- Store with Update format, src, dst | STU Format Reg AddrMode -- Store with Update format, src, dst
| LIS Reg Imm -- Load Immediate Shifted dst, src | LIS Reg Imm -- Load Immediate Shifted dst, src
| LI Reg Imm -- Load Immediate dst, src | LI Reg Imm -- Load Immediate dst, src
...@@ -277,6 +279,8 @@ data Instr ...@@ -277,6 +279,8 @@ data Instr
| NOP -- no operation, PowerPC 64 bit | NOP -- no operation, PowerPC 64 bit
-- needs this as place holder to -- needs this as place holder to
-- reload TOC pointer -- reload TOC pointer
| UPDATE_SP Format Imm -- expand/shrink spill area on C stack
-- pseudo-instruction
-- | Get the registers that are being used by this instruction. -- | Get the registers that are being used by this instruction.
-- regUsage doesn't need to do any trickery for jumps and such. -- regUsage doesn't need to do any trickery for jumps and such.
...@@ -288,8 +292,10 @@ ppc_regUsageOfInstr :: Platform -> Instr -> RegUsage ...@@ -288,8 +292,10 @@ ppc_regUsageOfInstr :: Platform -> Instr -> RegUsage
ppc_regUsageOfInstr platform instr ppc_regUsageOfInstr platform instr
= case instr of = case instr of
LD _ reg addr -> usage (regAddr addr, [reg]) LD _ reg addr -> usage (regAddr addr, [reg])
LDFAR _ reg addr -> usage (regAddr addr, [reg])
LA _ reg addr -> usage (regAddr addr, [reg]) LA _ reg addr -> usage (regAddr addr, [reg])
ST _ reg addr -> usage (reg : regAddr addr, []) ST _ reg addr -> usage (reg : regAddr addr, [])
STFAR _ reg addr -> usage (reg : regAddr addr, [])
STU _ reg addr -> usage (reg : regAddr addr, []) STU _ reg addr -> usage (reg : regAddr addr, [])
LIS reg _ -> usage ([], [reg]) LIS reg _ -> usage ([], [reg])
LI reg _ -> usage ([], [reg]) LI reg _ -> usage ([], [reg])
...@@ -349,6 +355,7 @@ ppc_regUsageOfInstr platform instr ...@@ -349,6 +355,7 @@ ppc_regUsageOfInstr platform instr
MFLR reg -> usage ([], [reg]) MFLR reg -> usage ([], [reg])
FETCHPC reg -> usage ([], [reg]) FETCHPC reg -> usage ([], [reg])
FETCHTOC reg _ -> usage ([], [reg]) FETCHTOC reg _ -> usage ([], [reg])
UPDATE_SP _ _ -> usage ([], [sp])
_ -> noUsage _ -> noUsage
where where
usage (src, dst) = RU (filter (interesting platform) src) usage (src, dst) = RU (filter (interesting platform) src)
...@@ -373,8 +380,10 @@ ppc_patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr ...@@ -373,8 +380,10 @@ ppc_patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr
ppc_patchRegsOfInstr instr env ppc_patchRegsOfInstr instr env
= case instr of = case instr of
LD fmt reg addr -> LD fmt (env reg) (fixAddr addr) LD fmt reg addr -> LD fmt (env reg) (fixAddr addr)
LDFAR fmt reg addr -> LDFAR fmt (env reg) (fixAddr addr)
LA fmt reg addr -> LA fmt (env reg) (fixAddr addr) LA fmt reg addr -> LA fmt (env reg) (fixAddr addr)
ST fmt reg addr -> ST fmt (env reg) (fixAddr addr) ST fmt reg addr -> ST fmt (env reg) (fixAddr addr)
STFAR fmt reg addr -> STFAR fmt (env reg) (fixAddr addr)
STU fmt reg addr -> STU fmt (env reg) (fixAddr addr) STU fmt reg addr -> STU fmt (env reg) (fixAddr addr)
LIS reg imm -> LIS (env reg) imm LIS reg imm -> LIS (env reg) imm
LI reg imm -> LI (env reg) imm LI reg imm -> LI (env reg) imm
...@@ -505,7 +514,11 @@ ppc_mkSpillInstr dflags reg delta slot ...@@ -505,7 +514,11 @@ ppc_mkSpillInstr dflags reg delta slot
_ -> II64 _ -> II64
RcDouble -> FF64 RcDouble -> FF64
_ -> panic "PPC.Instr.mkSpillInstr: no match" _ -> panic "PPC.Instr.mkSpillInstr: no match"
in ST fmt reg (AddrRegImm sp (ImmInt (off-delta))) instr = case makeImmediate W32 True (off-delta) of
Just _ -> ST
Nothing -> STFAR -- pseudo instruction: 32 bit offsets
in instr fmt reg (AddrRegImm sp (ImmInt (off-delta)))
ppc_mkLoadInstr ppc_mkLoadInstr
...@@ -526,7 +539,11 @@ ppc_mkLoadInstr dflags reg delta slot ...@@ -526,7 +539,11 @@ ppc_mkLoadInstr dflags reg delta slot
_ -> II64 _ -> II64
RcDouble -> FF64 RcDouble -> FF64
_ -> panic "PPC.Instr.mkLoadInstr: no match" _ -> panic "PPC.Instr.mkLoadInstr: no match"
in LD fmt reg (AddrRegImm sp (ImmInt (off-delta))) instr = case makeImmediate W32 True (off-delta) of
Just _ -> LD
Nothing -> LDFAR -- pseudo instruction: 32 bit offsets
in instr fmt reg (AddrRegImm sp (ImmInt (off-delta)))
-- | The maximum number of bytes required to spill a register. PPC32 -- | The maximum number of bytes required to spill a register. PPC32
......
...@@ -437,6 +437,15 @@ pprInstr (LD fmt reg addr) = hcat [ ...@@ -437,6 +437,15 @@ pprInstr (LD fmt reg addr) = hcat [
ptext (sLit ", "), ptext (sLit ", "),
pprAddr addr pprAddr addr
] ]
pprInstr (LDFAR fmt reg (AddrRegImm source off)) =
sdocWithPlatform $ \platform -> vcat [
pprInstr (ADDIS (tmpReg platform) source (HA off)),
pprInstr (LD fmt reg (AddrRegImm (tmpReg platform) (LO off)))
]
pprInstr (LDFAR _ _ _) =
panic "PPC.Ppr.pprInstr LDFAR: no match"
pprInstr (LA fmt reg addr) = hcat [ pprInstr (LA fmt reg addr) = hcat [
char '\t', char '\t',
ptext (sLit "l"), ptext (sLit "l"),
...@@ -467,6 +476,14 @@ pprInstr (ST fmt reg addr) = hcat [ ...@@ -467,6 +476,14 @@ pprInstr (ST fmt reg addr) = hcat [
ptext (sLit ", "), ptext (sLit ", "),
pprAddr addr pprAddr addr
] ]
pprInstr (STFAR fmt reg (AddrRegImm source off)) =
sdocWithPlatform $ \platform -> vcat [
pprInstr (ADDIS (tmpReg platform) source (HA off)),
pprInstr (ST fmt reg (AddrRegImm (tmpReg platform) (LO off)))
]
pprInstr (STFAR _ _ _) =
panic "PPC.Ppr.pprInstr STFAR: no match"
pprInstr (STU fmt reg addr) = hcat [ pprInstr (STU fmt reg addr) = hcat [
char '\t', char '\t',
ptext (sLit "st"), ptext (sLit "st"),
...@@ -799,6 +816,22 @@ pprInstr LWSYNC = ptext (sLit "\tlwsync") ...@@ -799,6 +816,22 @@ pprInstr LWSYNC = ptext (sLit "\tlwsync")
pprInstr NOP = ptext (sLit "\tnop") pprInstr NOP = ptext (sLit "\tnop")
pprInstr (UPDATE_SP fmt amount@(ImmInt offset))
| fits16Bits offset = vcat [
pprInstr (LD fmt r0 (AddrRegImm sp (ImmInt 0))),
pprInstr (STU fmt r0 (AddrRegImm sp amount))
]
pprInstr (UPDATE_SP fmt amount)
= sdocWithPlatform $ \platform ->
let tmp = tmpReg platform in
vcat [
pprInstr (LD fmt r0 (AddrRegImm sp (ImmInt 0))),
pprInstr (ADDIS tmp sp (HA amount)),
pprInstr (ADD tmp tmp (RIImm (LO amount))),
pprInstr (STU fmt r0 (AddrRegReg sp tmp))
]
-- pprInstr _ = panic "pprInstr (ppc)" -- pprInstr _ = panic "pprInstr (ppc)"
......
...@@ -37,7 +37,8 @@ module PPC.Regs ( ...@@ -37,7 +37,8 @@ module PPC.Regs (
fits16Bits, fits16Bits,
makeImmediate, makeImmediate,
fReg, fReg,
sp, toc, r3, r4, r11, r12, r27, r28, r30, r0, sp, toc, r3, r4, r11, r12, r27, r28, r30,
tmpReg,
f1, f20, f21, f1, f20, f21,
allocatableRegs allocatableRegs
...@@ -304,7 +305,8 @@ point registers. ...@@ -304,7 +305,8 @@ point registers.
fReg :: Int -> RegNo fReg :: Int -> RegNo
fReg x = (32 + x) fReg x = (32 + x)
sp, toc, r3, r4, r11, r12, r27, r28, r30, f1, f20, f21 :: Reg r0, sp, toc, r3, r4, r11, r12, r27, r28, r30, f1, f20, f21 :: Reg
r0 = regSingle 0
sp = regSingle 1 sp = regSingle 1
toc = regSingle 2 toc = regSingle 2
r3 = regSingle 3 r3 = regSingle 3
...@@ -325,3 +327,11 @@ allocatableRegs :: Platform -> [RealReg] ...@@ -325,3 +327,11 @@ allocatableRegs :: Platform -> [RealReg]
allocatableRegs platform allocatableRegs platform
= let isFree i = freeReg platform i = let isFree i = freeReg platform i
in map RealRegSingle $ filter isFree allMachRegNos in map RealRegSingle $ filter isFree allMachRegNos
-- temporary register for compiler use
tmpReg :: Platform -> Reg
tmpReg platform =
case platformArch platform of
ArchPPC -> regSingle 13
ArchPPC_64 _ -> regSingle 30
_ -> panic "PPC.Regs.tmpReg: unknowm arch"
...@@ -874,17 +874,25 @@ freeRegBase _ = True ...@@ -874,17 +874,25 @@ freeRegBase _ = True
#elif MACHREGS_powerpc #elif MACHREGS_powerpc
freeReg 0 = False -- Hack: r0 can't be used in all insns, freeReg 0 = False -- Used by code setting the back chain pointer
-- but it's actually free -- in stack reallocations on Linux
-- r0 is not usable in all insns so also reserved
-- on Darwin.
freeReg 1 = False -- The Stack Pointer freeReg 1 = False -- The Stack Pointer
# if !MACHREGS_darwin # if !MACHREGS_darwin
-- most non-darwin powerpc OSes use r2 as a TOC pointer or something like that -- most non-darwin powerpc OSes use r2 as a TOC pointer or something like that
freeReg 2 = False freeReg 2 = False
-- TODO: make this conditonal for ppc64 ELF freeReg 13 = False -- reserved for system thread ID on 64 bit
freeReg 13 = False -- reserved for system thread ID
-- TODO: do not reserve r30 in ppc64 ELF
-- at least linux in -fPIC relies on r30 in PLT stubs -- at least linux in -fPIC relies on r30 in PLT stubs
freeReg 30 = False freeReg 30 = False
{- TODO: reserve r13 on 64 bit systems only and r30 on 32 bit respectively.
For now we use r30 on 64 bit and r13 on 32 bit as a temporary register
in stack handling code. See compiler/nativeGen/PPC/Ppr.hs.
Later we might want to reserve r13 and r30 only where it is required.
Then use r12 as temporary register, which is also what the C ABI does.
-}
# endif # endif
# ifdef REG_Base # ifdef REG_Base
freeReg REG_Base = False freeReg REG_Base = False
......
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