diff options
| author | Peter Trommler <ptrommler@acm.org> | 2015-07-03 19:09:06 +0200 |
|---|---|---|
| committer | Ben Gamari <ben@smart-cactus.org> | 2015-07-03 19:09:06 +0200 |
| commit | d3c1dda60d0ec07fc7f593bfd83ec9457dfa7984 (patch) | |
| tree | 6d18388d249d0186c851c2f50f345020001fef7f /compiler/nativeGen/PIC.hs | |
| parent | bdf7f133d1d4bcc7ca3c0bbadda51ef542cccfb0 (diff) | |
| download | haskell-d3c1dda60d0ec07fc7f593bfd83ec9457dfa7984.tar.gz | |
Implement PowerPC 64-bit native code backend for Linux
Extend the PowerPC 32-bit native code generator for "64-bit
PowerPC ELF Application Binary Interface Supplement 1.9" by
Ian Lance Taylor and "Power Architecture 64-Bit ELF V2 ABI Specification --
OpenPOWER ABI for Linux Supplement" by IBM.
The latter ABI is mainly used on POWER7/7+ and POWER8
Linux systems running in little-endian mode. The code generator
supports both static and dynamic linking. PowerPC 64-bit
code for ELF ABI 1.9 and 2 is mostly position independent
anyway, and thus so is all the code emitted by the code
generator. In other words, -fPIC does not make a difference.
rts/stg/SMP.h support is implemented.
Following the spirit of the introductory comment in
PPC/CodeGen.hs, the rest of the code is a straightforward
extension of the 32-bit implementation.
Limitations:
* Code is generated only in the medium code model, which
is also gcc's default
* Local symbols are not accessed directly, which seems to
also be the case for 32-bit
* LLVM does not work, but this does not work on 32-bit either
* Must use the system runtime linker in GHCi, because the
GHC linker for "static" object files (rts/Linker.c) for
PPC 64-bit is not implemented. The system runtime
(dynamic) linker works.
* The handling of the system stack (register 1) is not ELF-
compliant so stack traces break. Instead of allocating a new
stack frame, spill code should use the "official" spill area
in the current stack frame and deallocation code should restore
the back chain
* DWARF support is missing
Fixes #9863
Test Plan: validate (on powerpc, too)
Reviewers: simonmar, trofi, erikd, austin
Reviewed By: trofi
Subscribers: bgamari, arnons1, kgardas, thomie
Differential Revision: https://phabricator.haskell.org/D629
GHC Trac Issues: #9863
Diffstat (limited to 'compiler/nativeGen/PIC.hs')
| -rw-r--r-- | compiler/nativeGen/PIC.hs | 83 |
1 files changed, 71 insertions, 12 deletions
diff --git a/compiler/nativeGen/PIC.hs b/compiler/nativeGen/PIC.hs index d4739cb7d9..ca556759ed 100644 --- a/compiler/nativeGen/PIC.hs +++ b/compiler/nativeGen/PIC.hs @@ -158,7 +158,14 @@ cmmMakePicReference dflags lbl -- everything gets relocated at runtime | OSMinGW32 <- platformOS $ targetPlatform dflags = CmmLit $ CmmLabel lbl - + -- both ABI versions default to medium code model + | ArchPPC_64 _ <- platformArch $ targetPlatform dflags + = CmmMachOp (MO_Add W32) -- code model medium + [ CmmReg (CmmGlobal PicBaseReg) + , CmmLit $ picRelative + (platformArch $ targetPlatform dflags) + (platformOS $ targetPlatform dflags) + lbl ] | (gopt Opt_PIC dflags || not (gopt Opt_Static dflags)) && absoluteLabel lbl = CmmMachOp (MO_Add (wordWidth dflags)) @@ -293,13 +300,17 @@ howToAccessLabel dflags arch OSDarwin this_mod _ lbl -- from position independent code. It is also required from the main program -- when dynamic libraries containing Haskell code are used. -howToAccessLabel _ ArchPPC_64 os _ kind _ +howToAccessLabel _ (ArchPPC_64 _) os _ kind _ | osElfTarget os - = if kind == DataReference - -- ELF PPC64 (powerpc64-linux), AIX, MacOS 9, BeOS/PPC - then AccessViaSymbolPtr - -- actually, .label instead of label - else AccessDirectly + = case kind of + -- ELF PPC64 (powerpc64-linux), AIX, MacOS 9, BeOS/PPC + DataReference -> AccessViaSymbolPtr + -- RTLD does not generate stubs for function descriptors + -- in tail calls. Create a symbol pointer and generate + -- the code to load the function descriptor at the call site. + JumpReference -> AccessViaSymbolPtr + -- regular calls are handled by the runtime linker + _ -> AccessDirectly howToAccessLabel dflags _ os _ _ _ -- no PIC -> the dynamic linker does everything for us; @@ -430,9 +441,14 @@ needImportedSymbols dflags arch os , arch == ArchPPC = gopt Opt_PIC dflags || not (gopt Opt_Static dflags) + -- PowerPC 64 Linux: always + | osElfTarget os + , arch == ArchPPC_64 ELF_V1 || arch == ArchPPC_64 ELF_V2 + = True + -- i386 (and others?): -dynamic but not -fPIC | osElfTarget os - , arch /= ArchPPC_64 + , arch /= ArchPPC_64 ELF_V1 && arch /= ArchPPC_64 ELF_V2 = not (gopt Opt_Static dflags) && not (gopt Opt_PIC dflags) | otherwise @@ -467,16 +483,30 @@ pprGotDeclaration dflags ArchX86 OSDarwin pprGotDeclaration _ _ OSDarwin = empty +-- PPC 64 ELF v1needs a Table Of Contents (TOC) on Linux +pprGotDeclaration _ (ArchPPC_64 ELF_V1) OSLinux + = ptext (sLit ".section \".toc\",\"aw\"") +-- In ELF v2 we also need to tell the assembler that we want ABI +-- version 2. This would normally be done at the top of the file +-- right after a file directive, but I could not figure out how +-- to do that. +pprGotDeclaration _ (ArchPPC_64 ELF_V2) OSLinux + = vcat [ ptext (sLit ".abiversion 2"), + ptext (sLit ".section \".toc\",\"aw\"") + ] +pprGotDeclaration _ (ArchPPC_64 _) _ + = panic "pprGotDeclaration: ArchPPC_64 only Linux supported" + -- Emit GOT declaration -- Output whatever needs to be output once per .s file. pprGotDeclaration dflags arch os | osElfTarget os - , arch /= ArchPPC_64 + , arch /= ArchPPC_64 ELF_V1 && arch /= ArchPPC_64 ELF_V2 , not (gopt Opt_PIC dflags) = empty | osElfTarget os - , arch /= ArchPPC_64 + , arch /= ArchPPC_64 ELF_V1 && arch /= ArchPPC_64 ELF_V2 = vcat [ -- See Note [.LCTOC1 in PPC PIC code] ptext (sLit ".section \".got2\",\"aw\""), @@ -635,9 +665,16 @@ pprImportedSymbol _ (Platform { platformOS = OSDarwin }) _ -- the NCG will keep track of all DynamicLinkerLabels it uses -- and output each of them using pprImportedSymbol. -pprImportedSymbol _ platform@(Platform { platformArch = ArchPPC_64 }) _ +pprImportedSymbol _ platform@(Platform { platformArch = ArchPPC_64 _ }) + importedLbl | osElfTarget (platformOS platform) - = empty + = case dynamicLinkerLabelInfo importedLbl of + Just (SymbolPtr, lbl) + -> vcat [ + ptext (sLit ".section \".toc\", \"aw\""), + ptext (sLit ".LC_") <> pprCLabel platform lbl <> char ':', + ptext (sLit "\t.quad") <+> pprCLabel platform lbl ] + _ -> empty pprImportedSymbol dflags platform importedLbl | osElfTarget (platformOS platform) @@ -735,6 +772,28 @@ initializePicBase_ppc ArchPPC OSDarwin picReg where BasicBlock bID insns = entry b' = BasicBlock bID (PPC.FETCHPC picReg : insns) +------------------------------------------------------------------------- +-- Load TOC into register 2 +-- PowerPC 64-bit ELF ABI 2.0 requires the address of the callee +-- in register 12. +-- We pass the label to FETCHTOC and create a .localentry too. +-- TODO: Explain this better and refer to ABI spec! +{- +We would like to do approximately this, but spill slot allocation +might be added before the first BasicBlock. That violates the ABI. + +For now we will emit the prologue code in the pretty printer, +which is also what we do for ELF v1. +initializePicBase_ppc (ArchPPC_64 ELF_V2) OSLinux picReg + (CmmProc info lab live (ListGraph (entry:blocks)) : statics) + = do + bID <-getUniqueM + return (CmmProc info lab live (ListGraph (b':entry:blocks)) + : statics) + where BasicBlock entryID _ = entry + b' = BasicBlock bID [PPC.FETCHTOC picReg lab, + PPC.BCC PPC.ALWAYS entryID] +-} initializePicBase_ppc _ _ _ _ = panic "initializePicBase_ppc: not needed" |
