module GHC.CmmToAsm.Reg.Graph (
regAlloc
) where
import GHC.Prelude
import qualified GHC.Data.Graph.Color as Color
import GHC.CmmToAsm.Reg.Liveness
import GHC.CmmToAsm.Reg.Graph.Spill
import GHC.CmmToAsm.Reg.Graph.SpillClean
import GHC.CmmToAsm.Reg.Graph.SpillCost
import GHC.CmmToAsm.Reg.Graph.Stats
import GHC.CmmToAsm.Reg.Graph.TrivColorable
import GHC.CmmToAsm.Instr
import GHC.CmmToAsm.Reg.Target
import GHC.CmmToAsm.Config
import GHC.CmmToAsm.Types
import GHC.Platform.Reg.Class
import GHC.Platform.Reg
import GHC.Data.Bag
import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Platform
import GHC.Types.Unique.FM
import GHC.Types.Unique.Set
import GHC.Types.Unique.Supply
import GHC.Utils.Misc (seqList)
import GHC.CmmToAsm.CFG
import Data.Maybe
import Control.Monad
maxSpinCount :: Int
maxSpinCount = 10
regAlloc
:: (OutputableP Platform statics, Instruction instr)
=> NCGConfig
-> UniqFM RegClass (UniqSet RealReg)
-> UniqSet Int
-> Int
-> [LiveCmmDecl statics instr]
-> Maybe CFG
-> UniqSM ( [NatCmmDecl statics instr]
, Maybe Int, [RegAllocStats statics instr] )
regAlloc config regsFree slotsFree slotsCount code cfg
= do
let platform = ncgPlatform config
triv = trivColorable platform
(targetVirtualRegSqueeze platform)
(targetRealRegSqueeze platform)
(code_final, debug_codeGraphs, slotsCount', _)
<- regAlloc_spin config 0
triv
regsFree slotsFree slotsCount [] code cfg
let needStack
| slotsCount == slotsCount'
= Nothing
| otherwise
= Just slotsCount'
return ( code_final
, needStack
, reverse debug_codeGraphs )
regAlloc_spin
:: forall instr statics.
(Instruction instr,
OutputableP Platform statics)
=> NCGConfig
-> Int
-> Color.Triv VirtualReg RegClass RealReg
-> UniqFM RegClass (UniqSet RealReg)
-> UniqSet Int
-> Int
-> [RegAllocStats statics instr]
-> [LiveCmmDecl statics instr]
-> Maybe CFG
-> UniqSM ( [NatCmmDecl statics instr]
, [RegAllocStats statics instr]
, Int
, Color.Graph VirtualReg RegClass RealReg)
regAlloc_spin config spinCount triv regsFree slotsFree slotsCount debug_codeGraphs code cfg
= do
let platform = ncgPlatform config
let dump = or
[ ncgDumpRegAllocStages config
, ncgDumpAsmStats config
, ncgDumpAsmConflicts config
]
when (spinCount > maxSpinCount)
$ pprPanic "regAlloc_spin: max build/spill cycle count exceeded."
( text "It looks like the register allocator is stuck in an infinite loop."
$$ text "max cycles = " <> int maxSpinCount
$$ text "regsFree = " <> (hcat $ punctuate space $ map ppr
$ nonDetEltsUniqSet $ unionManyUniqSets
$ nonDetEltsUFM regsFree)
$$ text "slotsFree = " <> ppr (sizeUniqSet slotsFree))
(graph :: Color.Graph VirtualReg RegClass RealReg)
<- buildGraph code
seqGraph graph `seq` return ()
let spillCosts = foldl' plusSpillCostInfo zeroSpillCostInfo
$ map (slurpSpillCostInfo platform cfg) code
let spill = chooseSpill spillCosts
let stat1
= if spinCount == 0
then Just $ RegAllocStatsStart
{ raLiveCmm = code
, raGraph = graph
, raSpillCosts = spillCosts
, raPlatform = platform
}
else Nothing
let (graph_colored, rsSpill, rmCoalesce)
=
Color.colorGraph
(ncgRegsIterative config)
spinCount
regsFree triv spill graph
let patchF reg
| RegVirtual vr <- reg
= case lookupUFM rmCoalesce vr of
Just vr' -> patchF (RegVirtual vr')
Nothing -> reg
| otherwise
= reg
let (code_coalesced :: [LiveCmmDecl statics instr])
= map (patchEraseLive patchF) code
if isEmptyUniqSet rsSpill
then do
let graph_colored_lint =
if ncgAsmLinting config
then Color.validateGraph (text "")
True
graph_colored
else graph_colored
let code_patched
= map (patchRegsFromGraph platform graph_colored_lint)
code_coalesced
let code_spillclean
= map (cleanSpills platform) code_patched
let code_final
= map (stripLive config) code_spillclean
let stat
= RegAllocStatsColored
{ raCode = code
, raGraph = graph
, raGraphColored = graph_colored_lint
, raCoalesced = rmCoalesce
, raCodeCoalesced = code_coalesced
, raPatched = code_patched
, raSpillClean = code_spillclean
, raFinal = code_final
, raSRMs = foldl' addSRM (0, 0, 0)
$ map countSRMs code_spillclean
, raPlatform = platform
}
let statList =
if dump then [stat] ++ maybeToList stat1 ++ debug_codeGraphs
else []
seqList statList (return ())
return ( code_final
, statList
, slotsCount
, graph_colored_lint)
else do
let graph_colored_lint =
if ncgAsmLinting config
then Color.validateGraph (text "")
False
graph_colored
else graph_colored
(code_spilled, slotsFree', slotsCount', spillStats)
<- regSpill platform code_coalesced slotsFree slotsCount rsSpill
code_relive <- mapM (regLiveness platform . reverseBlocksInTops)
code_spilled
let stat =
RegAllocStatsSpill
{ raCode = code
, raGraph = graph_colored_lint
, raCoalesced = rmCoalesce
, raSpillStats = spillStats
, raSpillCosts = spillCosts
, raSpilled = code_spilled
, raPlatform = platform }
let statList =
if dump
then [stat] ++ maybeToList stat1 ++ debug_codeGraphs
else []
seqList statList (return ())
regAlloc_spin config (spinCount + 1) triv regsFree slotsFree'
slotsCount' statList code_relive cfg
buildGraph
:: Instruction instr
=> [LiveCmmDecl statics instr]
-> UniqSM (Color.Graph VirtualReg RegClass RealReg)
buildGraph code
= do
let (conflictList, moveList) =
unzip $ map slurpConflicts code
let moveList2 = map slurpReloadCoalesce code
let conflictBag = unionManyBags conflictList
let graph_conflict
= foldr graphAddConflictSet Color.initGraph conflictBag
let moveBag
= unionBags (unionManyBags moveList2)
(unionManyBags moveList)
let graph_coalesce
= foldr graphAddCoalesce graph_conflict moveBag
return graph_coalesce
graphAddConflictSet
:: UniqSet Reg
-> Color.Graph VirtualReg RegClass RealReg
-> Color.Graph VirtualReg RegClass RealReg
graphAddConflictSet set graph
= let virtuals = mkUniqSet
[ vr | RegVirtual vr <- nonDetEltsUniqSet set ]
graph1 = Color.addConflicts virtuals classOfVirtualReg graph
graph2 = foldr (\(r1, r2) -> Color.addExclusion r1 classOfVirtualReg r2)
graph1
[ (vr, rr)
| RegVirtual vr <- nonDetEltsUniqSet set
, RegReal rr <- nonDetEltsUniqSet set]
in graph2
graphAddCoalesce
:: (Reg, Reg)
-> Color.Graph VirtualReg RegClass RealReg
-> Color.Graph VirtualReg RegClass RealReg
graphAddCoalesce (r1, r2) graph
| RegReal rr <- r1
, RegVirtual vr <- r2
= Color.addPreference (vr, classOfVirtualReg vr) rr graph
| RegReal rr <- r2
, RegVirtual vr <- r1
= Color.addPreference (vr, classOfVirtualReg vr) rr graph
| RegVirtual vr1 <- r1
, RegVirtual vr2 <- r2
= Color.addCoalesce
(vr1, classOfVirtualReg vr1)
(vr2, classOfVirtualReg vr2)
graph
| RegReal _ <- r1
, RegReal _ <- r2
= graph
#if __GLASGOW_HASKELL__ <= 810
| otherwise
= panic "graphAddCoalesce"
#endif
patchRegsFromGraph
:: (OutputableP Platform statics, Instruction instr)
=> Platform -> Color.Graph VirtualReg RegClass RealReg
-> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
patchRegsFromGraph platform graph code
= patchEraseLive patchF code
where
patchF reg
| RegReal{} <- reg
= reg
| RegVirtual vr <- reg
, Just node <- Color.lookupNode graph vr
= case Color.nodeColor node of
Just color -> RegReal color
Nothing -> RegVirtual vr
| otherwise
= pprPanic "patchRegsFromGraph: register mapping failed."
( text "There is no node in the graph for register "
<> ppr reg
$$ pprLiveCmmDecl platform code
$$ Color.dotGraph
(\_ -> text "white")
(trivColorable platform
(targetVirtualRegSqueeze platform)
(targetRealRegSqueeze platform))
graph)
seqGraph :: Color.Graph VirtualReg RegClass RealReg -> ()
seqGraph graph = seqNodes (nonDetEltsUFM (Color.graphMap graph))
seqNodes :: [Color.Node VirtualReg RegClass RealReg] -> ()
seqNodes ns
= case ns of
[] -> ()
(n : ns) -> seqNode n `seq` seqNodes ns
seqNode :: Color.Node VirtualReg RegClass RealReg -> ()
seqNode node
= seqVirtualReg (Color.nodeId node)
`seq` seqRegClass (Color.nodeClass node)
`seq` seqMaybeRealReg (Color.nodeColor node)
`seq` (seqVirtualRegList (nonDetEltsUniqSet (Color.nodeConflicts node)))
`seq` (seqRealRegList (nonDetEltsUniqSet (Color.nodeExclusions node)))
`seq` (seqRealRegList (Color.nodePreference node))
`seq` (seqVirtualRegList (nonDetEltsUniqSet (Color.nodeCoalesce node)))
seqVirtualReg :: VirtualReg -> ()
seqVirtualReg reg = reg `seq` ()
seqRealReg :: RealReg -> ()
seqRealReg reg = reg `seq` ()
seqRegClass :: RegClass -> ()
seqRegClass c = c `seq` ()
seqMaybeRealReg :: Maybe RealReg -> ()
seqMaybeRealReg mr
= case mr of
Nothing -> ()
Just r -> seqRealReg r
seqVirtualRegList :: [VirtualReg] -> ()
seqVirtualRegList rs
= case rs of
[] -> ()
(r : rs) -> seqVirtualReg r `seq` seqVirtualRegList rs
seqRealRegList :: [RealReg] -> ()
seqRealRegList rs
= case rs of
[] -> ()
(r : rs) -> seqRealReg r `seq` seqRealRegList rs