diff options
author | Moritz Angermann <moritz.angermann@gmail.com> | 2020-10-22 12:08:34 +0800 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-06-05 10:29:57 -0400 |
commit | 3b1aa7dba7c006b473855a6b199b15fa3a3d77a0 (patch) | |
tree | 631816f4aef8d28ee596b51b70a0a0ba2df12230 /compiler/GHC/CmmToAsm/Reg/Linear.hs | |
parent | 8c90e6c758769b068aea2891b26cc17577b6d36a (diff) | |
download | haskell-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.hs | 100 |
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 |