summaryrefslogtreecommitdiff
path: root/compiler/GHC/CmmToAsm/Reg/Linear.hs
diff options
context:
space:
mode:
authorMoritz Angermann <moritz.angermann@gmail.com>2020-10-22 12:08:34 +0800
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-06-05 10:29:57 -0400
commit3b1aa7dba7c006b473855a6b199b15fa3a3d77a0 (patch)
tree631816f4aef8d28ee596b51b70a0a0ba2df12230 /compiler/GHC/CmmToAsm/Reg/Linear.hs
parent8c90e6c758769b068aea2891b26cc17577b6d36a (diff)
downloadhaskell-3b1aa7dba7c006b473855a6b199b15fa3a3d77a0.tar.gz
Adds AArch64 Native Code Generator
In which we add a new code generator to the Glasgow Haskell Compiler. This codegen supports ELF and Mach-O targets, thus covering Linux, macOS, and BSDs in principle. It was tested only on macOS and Linux. The NCG follows a similar structure as the other native code generators we already have, and should therfore be realtively easy to follow. It supports most of the features required for a proper native code generator, but does not claim to be perfect or fully optimised. There are still opportunities for optimisations. Metric Decrease: ManyAlternatives ManyConstructors MultiLayerModules PmSeriesG PmSeriesS PmSeriesT PmSeriesV T10421 T10421a T10858 T11195 T11276 T11303b T11374 T11822 T12227 T12545 T12707 T13035 T13253 T13253-spj T13379 T13701 T13719 T14683 T14697 T15164 T15630 T16577 T17096 T17516 T17836 T17836b T17977 T17977b T18140 T18282 T18304 T18478 T18698a T18698b T18923 T1969 T3064 T5030 T5321FD T5321Fun T5631 T5642 T5837 T783 T9198 T9233 T9630 T9872d T9961 WWRec Metric Increase: T4801
Diffstat (limited to 'compiler/GHC/CmmToAsm/Reg/Linear.hs')
-rw-r--r--compiler/GHC/CmmToAsm/Reg/Linear.hs100
1 files changed, 68 insertions, 32 deletions
diff --git a/compiler/GHC/CmmToAsm/Reg/Linear.hs b/compiler/GHC/CmmToAsm/Reg/Linear.hs
index 88fdcd6bce..a9a4545f62 100644
--- a/compiler/GHC/CmmToAsm/Reg/Linear.hs
+++ b/compiler/GHC/CmmToAsm/Reg/Linear.hs
@@ -110,10 +110,11 @@ import GHC.CmmToAsm.Reg.Linear.StackMap
import GHC.CmmToAsm.Reg.Linear.FreeRegs
import GHC.CmmToAsm.Reg.Linear.Stats
import GHC.CmmToAsm.Reg.Linear.JoinToTargets
-import qualified GHC.CmmToAsm.Reg.Linear.PPC as PPC
-import qualified GHC.CmmToAsm.Reg.Linear.SPARC as SPARC
-import qualified GHC.CmmToAsm.Reg.Linear.X86 as X86
-import qualified GHC.CmmToAsm.Reg.Linear.X86_64 as X86_64
+import qualified GHC.CmmToAsm.Reg.Linear.PPC as PPC
+import qualified GHC.CmmToAsm.Reg.Linear.SPARC as SPARC
+import qualified GHC.CmmToAsm.Reg.Linear.X86 as X86
+import qualified GHC.CmmToAsm.Reg.Linear.X86_64 as X86_64
+import qualified GHC.CmmToAsm.Reg.Linear.AArch64 as AArch64
import GHC.CmmToAsm.Reg.Target
import GHC.CmmToAsm.Reg.Liveness
import GHC.CmmToAsm.Reg.Utils
@@ -121,6 +122,7 @@ import GHC.CmmToAsm.Instr
import GHC.CmmToAsm.Config
import GHC.CmmToAsm.Types
import GHC.Platform.Reg
+import GHC.Platform.Reg.Class (RegClass(..))
import GHC.Cmm.BlockId
import GHC.Cmm.Dataflow.Collections
@@ -202,7 +204,7 @@ regAlloc _ (CmmProc _ _ _ _)
-- an entry in the block map or it is the first block.
--
linearRegAlloc
- :: forall instr. Instruction instr
+ :: forall instr. (Instruction instr)
=> NCGConfig
-> [BlockId] -- ^ entry points
-> BlockMap RegSet
@@ -220,7 +222,7 @@ linearRegAlloc config entry_ids block_live sccs
ArchSPARC64 -> panic "linearRegAlloc ArchSPARC64"
ArchPPC -> go $ (frInitFreeRegs platform :: PPC.FreeRegs)
ArchARM _ _ _ -> panic "linearRegAlloc ArchARM"
- ArchAArch64 -> panic "linearRegAlloc ArchAArch64"
+ ArchAArch64 -> go $ (frInitFreeRegs platform :: AArch64.FreeRegs)
ArchPPC_64 _ -> go $ (frInitFreeRegs platform :: PPC.FreeRegs)
ArchAlpha -> panic "linearRegAlloc ArchAlpha"
ArchMipseb -> panic "linearRegAlloc ArchMipseb"
@@ -487,7 +489,7 @@ isInReg src assig | Just (InReg _) <- lookupUFM assig src = True
genRaInsn :: forall freeRegs instr.
- OutputableRegConstraint freeRegs instr
+ (OutputableRegConstraint freeRegs instr)
=> BlockMap RegSet
-> [instr]
-> BlockId
@@ -497,7 +499,7 @@ genRaInsn :: forall freeRegs instr.
-> RegM freeRegs ([instr], [NatBasicBlock instr])
genRaInsn block_live new_instrs block_id instr r_dying w_dying = do
--- pprTraceM "genRaInsn" $ ppr (block_id, instr)
+-- pprTraceM "genRaInsn" $ ppr (block_id, instr)
platform <- getPlatform
case regUsageOfInstr platform instr of { RU read written ->
do
@@ -509,19 +511,20 @@ genRaInsn block_live new_instrs block_id instr r_dying w_dying = do
-- so using nub isn't a problem).
let virt_read = nub [ vr | (RegVirtual vr) <- read ] :: [VirtualReg]
- -- debugging
-{- freeregs <- getFreeRegsR
- assig <- getAssigR
- pprDebugAndThen (defaultDynFlags Settings{ sTargetPlatform=platform } undefined) trace "genRaInsn"
- (ppr instr
- $$ text "r_dying = " <+> ppr r_dying
- $$ text "w_dying = " <+> ppr w_dying
- $$ text "virt_read = " <+> ppr virt_read
- $$ text "virt_written = " <+> ppr virt_written
- $$ text "freeregs = " <+> text (show freeregs)
- $$ text "assig = " <+> ppr assig)
- $ do
--}
+-- do
+-- let real_read = nub [ rr | (RegReal rr) <- read]
+-- freeregs <- getFreeRegsR
+-- assig <- getAssigR
+
+-- pprTraceM "genRaInsn"
+-- ( text "block = " <+> ppr block_id
+-- $$ text "instruction = " <+> ppr instr
+-- $$ text "r_dying = " <+> ppr r_dying
+-- $$ text "w_dying = " <+> ppr w_dying
+-- $$ text "read = " <+> ppr real_read <+> ppr virt_read
+-- $$ text "written = " <+> ppr real_written <+> ppr virt_written
+-- $$ text "freeregs = " <+> ppr freeregs
+-- $$ text "assign = " <+> ppr assig)
-- (a), (b) allocate real regs for all regs read by this instruction.
(r_spills, r_allocd) <-
@@ -580,7 +583,6 @@ genRaInsn block_live new_instrs block_id instr r_dying w_dying = do
Nothing -> x
Just y -> y
-
-- (j) free up stack slots for dead spilled regs
-- TODO (can't be bothered right now)
@@ -592,7 +594,32 @@ genRaInsn block_live new_instrs block_id instr r_dying w_dying = do
| src == dst -> []
_ -> [patched_instr]
- let code = concat [ squashed_instr, w_spills, reverse r_spills, clobber_saves, new_instrs ]
+ -- On the use of @reverse@ below.
+ -- Since we can have spills and reloads produce multiple instructions
+ -- we need to ensure they are emitted in the correct order. We used to only
+ -- emit single instructions in mkSpill/mkReload/mkRegRegMove.
+ -- As such order of spills and reloads didn't matter. However, with
+ -- mutliple instructions potentially issued by those functions we need to be
+ -- careful to not break execution order. Reversing the spills (clobber will
+ -- also spill), will ensure they are emitted in the right order.
+ --
+ -- See also Ticket 19910 for changing the return type from [] to OrdList.
+
+ -- For debugging, uncomment the follow line and the mkComment lines.
+ -- u <- getUniqueR
+ let code = concat [ -- mkComment (text "<genRaInsn(" <> ppr u <> text ")>")
+ -- ,mkComment (text "<genRaInsn(" <> ppr u <> text "):squashed>")]
+ squashed_instr
+ -- ,mkComment (text "<genRaInsn(" <> ppr u <> text "):w_spills>")
+ , reverse w_spills
+ -- ,mkComment (text "<genRaInsn(" <> ppr u <> text "):r_spills>")
+ , reverse r_spills
+ -- ,mkComment (text "<genRaInsn(" <> ppr u <> text "):clobber_saves>")
+ , reverse clobber_saves
+ -- ,mkComment (text "<genRaInsn(" <> ppr u <> text "):new_instrs>")
+ , new_instrs
+ -- ,mkComment (text "</genRaInsn(" <> ppr u <> text ")>")
+ ]
-- pprTrace "patched-code" ((vcat $ map (docToSDoc . pprInstr) code)) $ do
-- pprTrace "pached-fixup" ((ppr fixup_blocks)) $ do
@@ -609,6 +636,7 @@ releaseRegs regs = do
platform <- getPlatform
assig <- getAssigR
free <- getFreeRegsR
+
let loop assig !free [] = do setAssigR assig; setFreeRegsR free; return ()
loop assig !free (RegReal rr : rs) = loop assig (frReleaseReg platform rr free) rs
loop assig !free (r:rs) =
@@ -662,8 +690,9 @@ saveClobberedTemps clobbered dying
(instrs,assig') <- clobber assig [] to_spill
setAssigR assig'
- return instrs
-
+ return $ -- mkComment (text "<saveClobberedTemps>") ++
+ instrs
+-- ++ mkComment (text "</saveClobberedTemps>")
where
-- See Note [UniqFM and the register allocator]
clobber :: RegMap Loc -> [instr] -> [(Unique,RealReg)] -> RegM freeRegs ([instr], RegMap Loc)
@@ -700,7 +729,7 @@ saveClobberedTemps clobbered dying
let new_assign = addToUFM_Directly assig temp (InBoth reg slot)
- clobber new_assign (spill : instrs) rest
+ clobber new_assign (spill ++ instrs) rest
@@ -714,7 +743,17 @@ clobberRegs []
clobberRegs clobbered
= do platform <- getPlatform
freeregs <- getFreeRegsR
- setFreeRegsR $! foldl' (flip $ frAllocateReg platform) freeregs clobbered
+
+ let gpRegs = frGetFreeRegs platform RcInteger freeregs :: [RealReg]
+ fltRegs = frGetFreeRegs platform RcFloat freeregs :: [RealReg]
+ dblRegs = frGetFreeRegs platform RcDouble freeregs :: [RealReg]
+
+ let extra_clobbered = [ r | r <- clobbered
+ , r `elem` (gpRegs ++ fltRegs ++ dblRegs) ]
+
+ setFreeRegsR $! foldl' (flip $ frAllocateReg platform) freeregs extra_clobbered
+
+ -- setFreeRegsR $! foldl' (flip $ frAllocateReg platform) freeregs clobbered
assig <- getAssigR
setAssigR $! clobber assig (nonDetUFMToList assig)
@@ -909,10 +948,7 @@ allocRegsAndSpill_spill reading keep spills alloc r rs assig spill_loc
| (temp_to_push_out, (my_reg :: RealReg)) : _
<- candidates_inReg
= do
- (spill_insn, slot) <- spillR (RegReal my_reg) temp_to_push_out
- let spill_store = (if reading then id else reverse)
- [ -- COMMENT (fsLit "spill alloc")
- spill_insn ]
+ (spill_store, slot) <- spillR (RegReal my_reg) temp_to_push_out
-- record that this temp was spilled
recordSpill (SpillAlloc temp_to_push_out)
@@ -962,7 +998,7 @@ loadTemp vreg (ReadMem slot) hreg spills
= do
insn <- loadR (RegReal hreg) slot
recordSpill (SpillLoad $ getUnique vreg)
- return $ {- COMMENT (fsLit "spill load") : -} insn : spills
+ return $ {- mkComment (text "spill load") : -} insn ++ spills
loadTemp _ _ _ spills =
return spills