Commit f4b0488d authored by Peter Trommler's avatar Peter Trommler 🥁 Committed by Ben Gamari
Browse files

PPC NCG: Fix and refactor TOC handling.

In a call to a fixed function the TOC does not need to be saved.
The linker handles TOC saving.

Refactor TOC handling by folding the two functions toc_before and
toc_after into the code generating the call sequence. This saves
repeating the case distinction in those two functions.

Test Plan: validate on PowerPC 32-bit Linux and AIX

Reviewers: hvr, simonmar, austin, erikd, bgamari

Reviewed By: bgamari

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D2328
parent 2897be77
...@@ -1150,7 +1150,13 @@ genCCall' ...@@ -1150,7 +1150,13 @@ genCCall'
PowerPC 64 Linux uses the System V Release 4 Calling Convention for PowerPC 64 Linux uses the System V Release 4 Calling Convention for
64-bit PowerPC. It is specified in 64-bit PowerPC. It is specified in
"64-bit PowerPC ELF Application Binary Interface Supplement 1.9". "64-bit PowerPC ELF Application Binary Interface Supplement 1.9"
(PPC64 ELF v1.9).
PowerPC 64 Linux in little endian mode uses the "Power Architecture 64-Bit
ELF V2 ABI Specification -- OpenPOWER ABI for Linux Supplement"
(PPC64 ELF v2).
AIX follows the "PowerOpen ABI: Application Binary Interface Big-Endian
32-Bit Hardware Implementation"
According to all conventions, the parameter area should be part of the According to all conventions, the parameter area should be part of the
caller's stack frame, allocated in the caller's prologue code (large enough caller's stack frame, allocated in the caller's prologue code (large enough
...@@ -1191,41 +1197,46 @@ genCCall' dflags gcp target dest_regs args ...@@ -1191,41 +1197,46 @@ genCCall' dflags gcp target dest_regs args
PrimTarget mop -> outOfLineMachOp mop PrimTarget mop -> outOfLineMachOp mop
let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode
`appOL` toc_before codeAfter = move_sp_up finalStack `appOL` moveResult reduceToFF32
codeAfter = toc_after labelOrExpr `appOL` move_sp_up finalStack
`appOL` moveResult reduceToFF32
case labelOrExpr of case labelOrExpr of
Left lbl -> do -- the linker does all the work for us Left lbl -> do -- the linker does all the work for us
return ( codeBefore return ( codeBefore
`snocOL` BL lbl usedRegs `snocOL` BL lbl usedRegs
`appOL` maybeNOP -- some ABI require a NOP after BL
`appOL` codeAfter) `appOL` codeAfter)
Right dyn -> do -- implement call through function pointer Right dyn -> do -- implement call through function pointer
(dynReg, dynCode) <- getSomeReg dyn (dynReg, dynCode) <- getSomeReg dyn
case gcp of case gcp of
GCPLinux64ELF 1 -> return ( dynCode GCPLinux64ELF 1 -> return ( dynCode
`appOL` codeBefore `appOL` codeBefore
`snocOL` ST spFormat toc (AddrRegImm sp (ImmInt 40))
`snocOL` LD II64 r11 (AddrRegImm dynReg (ImmInt 0)) `snocOL` LD II64 r11 (AddrRegImm dynReg (ImmInt 0))
`snocOL` LD II64 toc (AddrRegImm dynReg (ImmInt 8)) `snocOL` LD II64 toc (AddrRegImm dynReg (ImmInt 8))
`snocOL` MTCTR r11 `snocOL` MTCTR r11
`snocOL` LD II64 r11 (AddrRegImm dynReg (ImmInt 16)) `snocOL` LD II64 r11 (AddrRegImm dynReg (ImmInt 16))
`snocOL` BCTRL usedRegs `snocOL` BCTRL usedRegs
`snocOL` LD spFormat toc (AddrRegImm sp (ImmInt 40))
`appOL` codeAfter) `appOL` codeAfter)
GCPLinux64ELF 2 -> return ( dynCode GCPLinux64ELF 2 -> return ( dynCode
`appOL` codeBefore `appOL` codeBefore
`snocOL` ST spFormat toc (AddrRegImm sp (ImmInt 24))
`snocOL` MR r12 dynReg `snocOL` MR r12 dynReg
`snocOL` MTCTR r12 `snocOL` MTCTR r12
`snocOL` BCTRL usedRegs `snocOL` BCTRL usedRegs
`snocOL` LD spFormat toc (AddrRegImm sp (ImmInt 24))
`appOL` codeAfter) `appOL` codeAfter)
GCPAIX -> return ( dynCode GCPAIX -> return ( dynCode
-- AIX/XCOFF follows the PowerOPEN ABI -- AIX/XCOFF follows the PowerOPEN ABI
-- which is quite similiar to LinuxPPC64/ELFv1 -- which is quite similiar to LinuxPPC64/ELFv1
`appOL` codeBefore `appOL` codeBefore
`snocOL` ST spFormat toc (AddrRegImm sp (ImmInt 20))
`snocOL` LD II32 r11 (AddrRegImm dynReg (ImmInt 0)) `snocOL` LD II32 r11 (AddrRegImm dynReg (ImmInt 0))
`snocOL` LD II32 toc (AddrRegImm dynReg (ImmInt 4)) `snocOL` LD II32 toc (AddrRegImm dynReg (ImmInt 4))
`snocOL` MTCTR r11 `snocOL` MTCTR r11
`snocOL` LD II32 r11 (AddrRegImm dynReg (ImmInt 8)) `snocOL` LD II32 r11 (AddrRegImm dynReg (ImmInt 8))
`snocOL` BCTRL usedRegs `snocOL` BCTRL usedRegs
`snocOL` LD spFormat toc (AddrRegImm sp (ImmInt 20))
`appOL` codeAfter) `appOL` codeAfter)
_ -> return ( dynCode _ -> return ( dynCode
`snocOL` MTCTR dynReg `snocOL` MTCTR dynReg
...@@ -1281,30 +1292,6 @@ genCCall' dflags gcp target dest_regs args ...@@ -1281,30 +1292,6 @@ genCCall' dflags gcp target dest_regs args
DELTA (-delta)] DELTA (-delta)]
| otherwise = nilOL | otherwise = nilOL
where delta = stackDelta finalStack where delta = stackDelta finalStack
toc_before = case gcp of
GCPLinux64ELF 1 -> unitOL $ ST spFormat toc (AddrRegImm sp (ImmInt 40))
GCPLinux64ELF 2 -> unitOL $ ST spFormat toc (AddrRegImm sp (ImmInt 24))
GCPAIX -> unitOL $ ST spFormat toc (AddrRegImm sp (ImmInt 20))
_ -> nilOL
toc_after labelOrExpr = case gcp of
GCPLinux64ELF 1 -> case labelOrExpr of
Left _ -> toOL [ NOP ]
Right _ -> toOL [ LD spFormat toc
(AddrRegImm sp
(ImmInt 40))
]
GCPLinux64ELF 2 -> case labelOrExpr of
Left _ -> toOL [ NOP ]
Right _ -> toOL [ LD spFormat toc
(AddrRegImm sp
(ImmInt 24))
]
GCPAIX -> case labelOrExpr of
Left _ -> unitOL NOP
Right _ -> unitOL (LD spFormat toc
(AddrRegImm sp
(ImmInt 20)))
_ -> nilOL
move_sp_up finalStack move_sp_up finalStack
| delta > 64 = -- TODO: fix-up stack back-chain | delta > 64 = -- TODO: fix-up stack back-chain
toOL [ADD sp sp (RIImm (ImmInt delta)), toOL [ADD sp sp (RIImm (ImmInt delta)),
...@@ -1312,6 +1299,19 @@ genCCall' dflags gcp target dest_regs args ...@@ -1312,6 +1299,19 @@ genCCall' dflags gcp target dest_regs args
| otherwise = nilOL | otherwise = nilOL
where delta = stackDelta finalStack where delta = stackDelta finalStack
-- A NOP instruction is required after a call (bl instruction)
-- on AIX and 64-Bit Linux.
-- If the call is to a function with a different TOC (r2) the
-- link editor replaces the NOP instruction with a load of the TOC
-- from the stack to restore the TOC.
maybeNOP = case gcp of
-- See Section 3.9.4 of OpenPower ABI
GCPAIX -> unitOL NOP
-- See Section 3.5.11 of PPC64 ELF v1.9
GCPLinux64ELF 1 -> unitOL NOP
-- See Section 2.3.6 of PPC64 ELF v2
GCPLinux64ELF 2 -> unitOL NOP
_ -> nilOL
passArguments [] _ _ stackOffset accumCode accumUsed = return (stackOffset, accumCode, accumUsed) passArguments [] _ _ stackOffset accumCode accumUsed = return (stackOffset, accumCode, accumUsed)
passArguments ((arg,arg_ty):args) gprs fprs stackOffset passArguments ((arg,arg_ty):args) gprs fprs stackOffset
......
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