{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}


-- | Graph coloring register allocator.
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


-- | The maximum number of build\/spill cycles we'll allow.
--
--   It should only take 3 or 4 cycles for the allocator to converge.
--   If it takes any longer than this it's probably in an infinite loop,
--   so it's better just to bail out and report a bug.
maxSpinCount    :: Int
maxSpinCount :: Int
maxSpinCount    = Int
10


-- | The top level of the graph coloring register allocator.
regAlloc
        :: (OutputableP Platform statics, Instruction instr)
        => NCGConfig
        -> UniqFM RegClass (UniqSet RealReg)     -- ^ registers we can use for allocation
        -> UniqSet Int                  -- ^ set of available spill slots.
        -> Int                          -- ^ current number of spill slots
        -> [LiveCmmDecl statics instr]  -- ^ code annotated with liveness information.
        -> Maybe CFG                    -- ^ CFG of basic blocks if available
        -> UniqSM ( [NatCmmDecl statics instr]
                  , Maybe Int, [RegAllocStats statics instr] )
           -- ^ code with registers allocated, additional stacks required
           -- and stats for each stage of allocation

regAlloc :: forall statics instr.
(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 NCGConfig
config UniqFM RegClass (UniqSet RealReg)
regsFree UniqSet Int
slotsFree Int
slotsCount [LiveCmmDecl statics instr]
code Maybe CFG
cfg
 = do
        let platform :: Platform
platform = NCGConfig -> Platform
ncgPlatform NCGConfig
config
            triv :: Triv VirtualReg RegClass RealReg
triv = Platform
-> (RegClass -> VirtualReg -> Int)
-> (RegClass -> RealReg -> Int)
-> Triv VirtualReg RegClass RealReg
trivColorable Platform
platform
                        (Platform -> RegClass -> VirtualReg -> Int
targetVirtualRegSqueeze Platform
platform)
                        (Platform -> RegClass -> RealReg -> Int
targetRealRegSqueeze Platform
platform)

        (code_final, debug_codeGraphs, slotsCount', _)
                <- NCGConfig
-> Int
-> 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,
      Graph VirtualReg RegClass RealReg)
forall instr statics.
(Instruction instr, OutputableP Platform statics) =>
NCGConfig
-> Int
-> 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,
      Graph VirtualReg RegClass RealReg)
regAlloc_spin NCGConfig
config Int
0
                        Triv VirtualReg RegClass RealReg
triv
                        UniqFM RegClass (UniqSet RealReg)
regsFree UniqSet Int
slotsFree Int
slotsCount [] [LiveCmmDecl statics instr]
code Maybe CFG
cfg

        let needStack
                | Int
slotsCount Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
slotsCount'
                = Maybe Int
forall a. Maybe a
Nothing
                | Bool
otherwise
                = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
slotsCount'

        return  ( code_final
                , needStack
                , reverse debug_codeGraphs )


-- | Perform solver iterations for the graph coloring allocator.
--
--   We extract a register conflict graph from the provided cmm code,
--   and try to colour it. If that works then we use the solution rewrite
--   the code with real hregs. If coloring doesn't work we add spill code
--   and try to colour it again. After `maxSpinCount` iterations we give up.
--
regAlloc_spin
        :: forall instr statics.
           (Instruction instr,
            OutputableP Platform statics)
        => NCGConfig
        -> Int  -- ^ Number of solver iterations we've already performed.
        -> Color.Triv VirtualReg RegClass RealReg
                -- ^ Function for calculating whether a register is trivially
                --   colourable.
        -> UniqFM RegClass (UniqSet RealReg)      -- ^ Free registers that we can allocate.
        -> UniqSet Int                   -- ^ Free stack slots that we can use.
        -> Int                           -- ^ Number of spill slots in use
        -> [RegAllocStats statics instr] -- ^ Current regalloc stats to add to.
        -> [LiveCmmDecl statics instr]   -- ^ Liveness annotated code to allocate.
        -> Maybe CFG
        -> UniqSM ( [NatCmmDecl statics instr]
                  , [RegAllocStats statics instr]
                  , Int                  -- Slots in use
                  , Color.Graph VirtualReg RegClass RealReg)

regAlloc_spin :: forall instr statics.
(Instruction instr, OutputableP Platform statics) =>
NCGConfig
-> Int
-> 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,
      Graph VirtualReg RegClass RealReg)
regAlloc_spin NCGConfig
config Int
spinCount Triv VirtualReg RegClass RealReg
triv UniqFM RegClass (UniqSet RealReg)
regsFree UniqSet Int
slotsFree Int
slotsCount [RegAllocStats statics instr]
debug_codeGraphs [LiveCmmDecl statics instr]
code Maybe CFG
cfg
 = do
        let platform :: Platform
platform = NCGConfig -> Platform
ncgPlatform NCGConfig
config

        -- If any of these dump flags are turned on we want to hang on to
        -- intermediate structures in the allocator - otherwise tell the
        -- allocator to ditch them early so we don't end up creating space leaks.
        let dump :: Bool
dump = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or
                [ NCGConfig -> Bool
ncgDumpRegAllocStages NCGConfig
config
                , NCGConfig -> Bool
ncgDumpAsmStats       NCGConfig
config
                , NCGConfig -> Bool
ncgDumpAsmConflicts   NCGConfig
config
                ]

        -- Check that we're not running off down the garden path.
        Bool -> UniqSM () -> UniqSM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
spinCount Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxSpinCount)
         (UniqSM () -> UniqSM ()) -> UniqSM () -> UniqSM ()
forall a b. (a -> b) -> a -> b
$ String -> SDoc -> UniqSM ()
forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"regAlloc_spin: max build/spill cycle count exceeded."
           (  String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"It looks like the register allocator is stuck in an infinite loop."
           SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"max cycles  = " SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> Int -> SDoc
forall doc. IsLine doc => Int -> doc
int Int
maxSpinCount
           SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"regsFree    = " SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> ([SDoc] -> SDoc
forall doc. IsLine doc => [doc] -> doc
hcat ([SDoc] -> SDoc) -> [SDoc] -> SDoc
forall a b. (a -> b) -> a -> b
$ SDoc -> [SDoc] -> [SDoc]
forall doc. IsLine doc => doc -> [doc] -> [doc]
punctuate SDoc
forall doc. IsLine doc => doc
space ([SDoc] -> [SDoc]) -> [SDoc] -> [SDoc]
forall a b. (a -> b) -> a -> b
$ (RealReg -> SDoc) -> [RealReg] -> [SDoc]
forall a b. (a -> b) -> [a] -> [b]
map RealReg -> SDoc
forall a. Outputable a => a -> SDoc
ppr
                                             ([RealReg] -> [SDoc]) -> [RealReg] -> [SDoc]
forall a b. (a -> b) -> a -> b
$ UniqSet RealReg -> [RealReg]
forall elt. UniqSet elt -> [elt]
nonDetEltsUniqSet (UniqSet RealReg -> [RealReg]) -> UniqSet RealReg -> [RealReg]
forall a b. (a -> b) -> a -> b
$ [UniqSet RealReg] -> UniqSet RealReg
forall a. [UniqSet a] -> UniqSet a
unionManyUniqSets
                                             ([UniqSet RealReg] -> UniqSet RealReg)
-> [UniqSet RealReg] -> UniqSet RealReg
forall a b. (a -> b) -> a -> b
$ UniqFM RegClass (UniqSet RealReg) -> [UniqSet RealReg]
forall {k} (key :: k) elt. UniqFM key elt -> [elt]
nonDetEltsUFM UniqFM RegClass (UniqSet RealReg)
regsFree)
              -- This is non-deterministic but we do not
              -- currently support deterministic code-generation.
              -- See Note [Unique Determinism and code generation]
           SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"slotsFree   = " SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr (UniqSet Int -> Int
forall a. UniqSet a -> Int
sizeUniqSet UniqSet Int
slotsFree))

        -- Build the register conflict graph from the cmm code.
        (graph  :: Color.Graph VirtualReg RegClass RealReg)
                <- {-# SCC "BuildGraph" #-} [LiveCmmDecl statics instr]
-> UniqSM (Graph VirtualReg RegClass RealReg)
forall instr statics.
Instruction instr =>
[LiveCmmDecl statics instr]
-> UniqSM (Graph VirtualReg RegClass RealReg)
buildGraph [LiveCmmDecl statics instr]
code

        -- VERY IMPORTANT:
        --   We really do want the graph to be fully evaluated _before_ we
        --   start coloring. If we don't do this now then when the call to
        --   Color.colorGraph forces bits of it, the heap will be filled with
        --   half evaluated pieces of graph and zillions of apply thunks.
        seqGraph graph `seq` return ()

        -- Build a map of the cost of spilling each instruction.
        -- This is a lazy binding, so the map will only be computed if we
        -- actually have to spill to the stack.
        let spillCosts  = (SpillCostInfo -> SpillCostInfo -> SpillCostInfo)
-> SpillCostInfo -> [SpillCostInfo] -> SpillCostInfo
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' SpillCostInfo -> SpillCostInfo -> SpillCostInfo
plusSpillCostInfo SpillCostInfo
zeroSpillCostInfo
                        ([SpillCostInfo] -> SpillCostInfo)
-> [SpillCostInfo] -> SpillCostInfo
forall a b. (a -> b) -> a -> b
$ (LiveCmmDecl statics instr -> SpillCostInfo)
-> [LiveCmmDecl statics instr] -> [SpillCostInfo]
forall a b. (a -> b) -> [a] -> [b]
map (Platform -> Maybe CFG -> LiveCmmDecl statics instr -> SpillCostInfo
forall instr statics.
Instruction instr =>
Platform -> Maybe CFG -> LiveCmmDecl statics instr -> SpillCostInfo
slurpSpillCostInfo Platform
platform Maybe CFG
cfg) [LiveCmmDecl statics instr]
code

        -- The function to choose regs to leave uncolored.
        let spill       = SpillCostInfo -> Graph VirtualReg RegClass RealReg -> VirtualReg
chooseSpill SpillCostInfo
spillCosts

        -- Record startup state in our log.
        let stat1
             = if Int
spinCount Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
                 then   RegAllocStats statics instr -> Maybe (RegAllocStats statics instr)
forall a. a -> Maybe a
Just (RegAllocStats statics instr
 -> Maybe (RegAllocStats statics instr))
-> RegAllocStats statics instr
-> Maybe (RegAllocStats statics instr)
forall a b. (a -> b) -> a -> b
$ RegAllocStatsStart
                        { raLiveCmm :: [LiveCmmDecl statics instr]
raLiveCmm     = [LiveCmmDecl statics instr]
code
                        , raGraph :: Graph VirtualReg RegClass RealReg
raGraph       = Graph VirtualReg RegClass RealReg
graph
                        , raSpillCosts :: SpillCostInfo
raSpillCosts  = SpillCostInfo
spillCosts
                        , raPlatform :: Platform
raPlatform    = Platform
platform
                        }
                 else   Maybe (RegAllocStats statics instr)
forall a. Maybe a
Nothing

        -- Try and color the graph.
        let (graph_colored, rsSpill, rmCoalesce)
                = {-# SCC "ColorGraph" #-}
                  Color.colorGraph
                       (ncgRegsIterative config)
                       spinCount
                       regsFree triv spill graph

        -- Rewrite registers in the code that have been coalesced.
        let patchF Reg
reg
                | RegVirtual VirtualReg
vr <- Reg
reg
                = case UniqFM VirtualReg VirtualReg -> VirtualReg -> Maybe VirtualReg
forall key elt. Uniquable key => UniqFM key elt -> key -> Maybe elt
lookupUFM UniqFM VirtualReg VirtualReg
rmCoalesce VirtualReg
vr of
                        Just VirtualReg
vr'        -> Reg -> Reg
patchF (VirtualReg -> Reg
RegVirtual VirtualReg
vr')
                        Maybe VirtualReg
Nothing         -> Reg
reg

                | Bool
otherwise
                = Reg
reg

        let (code_coalesced :: [LiveCmmDecl statics instr])
                = map (patchEraseLive patchF) code

        -- Check whether we've found a coloring.
        if isEmptyUniqSet rsSpill

         -- Coloring was successful because no registers needed to be spilled.
         then do
                -- if -fasm-lint is turned on then validate the graph.
                -- This checks for bugs in the graph allocator itself.
                let graph_colored_lint  =
                        if NCGConfig -> Bool
ncgAsmLinting NCGConfig
config
                                then SDoc
-> Bool
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
forall k color cls.
(Uniquable k, Outputable k, Eq color) =>
SDoc -> Bool -> Graph k cls color -> Graph k cls color
Color.validateGraph (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"")
                                        Bool
True    -- Require all nodes to be colored.
                                        Graph VirtualReg RegClass RealReg
graph_colored
                                else Graph VirtualReg RegClass RealReg
graph_colored

                -- Rewrite the code to use real hregs, using the colored graph.
                let code_patched
                        = (LiveCmmDecl statics instr -> LiveCmmDecl statics instr)
-> [LiveCmmDecl statics instr] -> [LiveCmmDecl statics instr]
forall a b. (a -> b) -> [a] -> [b]
map (Platform
-> Graph VirtualReg RegClass RealReg
-> LiveCmmDecl statics instr
-> LiveCmmDecl statics instr
forall statics instr.
(OutputableP Platform statics, Instruction instr) =>
Platform
-> Graph VirtualReg RegClass RealReg
-> LiveCmmDecl statics instr
-> LiveCmmDecl statics instr
patchRegsFromGraph Platform
platform Graph VirtualReg RegClass RealReg
graph_colored_lint)
                              [LiveCmmDecl statics instr]
code_coalesced

                -- Clean out unneeded SPILL/RELOAD meta instructions.
                --   The spill code generator just spills the entire live range
                --   of a vreg, but it might not need to be on the stack for
                --   its entire lifetime.
                let code_spillclean
                        = (LiveCmmDecl statics instr -> LiveCmmDecl statics instr)
-> [LiveCmmDecl statics instr] -> [LiveCmmDecl statics instr]
forall a b. (a -> b) -> [a] -> [b]
map (Platform -> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
forall instr statics.
Instruction instr =>
Platform -> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
cleanSpills Platform
platform) [LiveCmmDecl statics instr]
code_patched

                -- Strip off liveness information from the allocated code.
                -- Also rewrite SPILL/RELOAD meta instructions into real machine
                -- instructions along the way
                let code_final
                        = (LiveCmmDecl statics instr -> NatCmmDecl statics instr)
-> [LiveCmmDecl statics instr] -> [NatCmmDecl statics instr]
forall a b. (a -> b) -> [a] -> [b]
map (NCGConfig -> LiveCmmDecl statics instr -> NatCmmDecl statics instr
forall statics instr.
(OutputableP Platform statics, Instruction instr) =>
NCGConfig -> LiveCmmDecl statics instr -> NatCmmDecl statics instr
stripLive NCGConfig
config) [LiveCmmDecl statics instr]
code_spillclean

                -- Record what happened in this stage for debugging
                let stat
                     =  RegAllocStatsColored
                        { raCode :: [LiveCmmDecl statics instr]
raCode                = [LiveCmmDecl statics instr]
code
                        , raGraph :: Graph VirtualReg RegClass RealReg
raGraph               = Graph VirtualReg RegClass RealReg
graph
                        , raGraphColored :: Graph VirtualReg RegClass RealReg
raGraphColored        = Graph VirtualReg RegClass RealReg
graph_colored_lint
                        , raCoalesced :: UniqFM VirtualReg VirtualReg
raCoalesced           = UniqFM VirtualReg VirtualReg
rmCoalesce
                        , raCodeCoalesced :: [LiveCmmDecl statics instr]
raCodeCoalesced       = [LiveCmmDecl statics instr]
code_coalesced
                        , raPatched :: [LiveCmmDecl statics instr]
raPatched             = [LiveCmmDecl statics instr]
code_patched
                        , raSpillClean :: [LiveCmmDecl statics instr]
raSpillClean          = [LiveCmmDecl statics instr]
code_spillclean
                        , raFinal :: [NatCmmDecl statics instr]
raFinal               = [NatCmmDecl statics instr]
code_final
                        , raSRMs :: (Int, Int, Int)
raSRMs                = ((Int, Int, Int) -> (Int, Int, Int) -> (Int, Int, Int))
-> (Int, Int, Int) -> [(Int, Int, Int)] -> (Int, Int, Int)
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (Int, Int, Int) -> (Int, Int, Int) -> (Int, Int, Int)
addSRM (Int
0, Int
0, Int
0)
                                                ([(Int, Int, Int)] -> (Int, Int, Int))
-> [(Int, Int, Int)] -> (Int, Int, Int)
forall a b. (a -> b) -> a -> b
$ (LiveCmmDecl statics instr -> (Int, Int, Int))
-> [LiveCmmDecl statics instr] -> [(Int, Int, Int)]
forall a b. (a -> b) -> [a] -> [b]
map LiveCmmDecl statics instr -> (Int, Int, Int)
forall instr statics.
Instruction instr =>
LiveCmmDecl statics instr -> (Int, Int, Int)
countSRMs [LiveCmmDecl statics instr]
code_spillclean
                        , raPlatform :: Platform
raPlatform    = Platform
platform
                     }

                -- Bundle up all the register allocator statistics.
                --   .. but make sure to drop them on the floor if they're not
                --      needed, otherwise we'll get a space leak.
                let statList =
                        if Bool
dump then [RegAllocStats statics instr
stat] [RegAllocStats statics instr]
-> [RegAllocStats statics instr] -> [RegAllocStats statics instr]
forall a. [a] -> [a] -> [a]
++ Maybe (RegAllocStats statics instr)
-> [RegAllocStats statics instr]
forall a. Maybe a -> [a]
maybeToList Maybe (RegAllocStats statics instr)
stat1 [RegAllocStats statics instr]
-> [RegAllocStats statics instr] -> [RegAllocStats statics instr]
forall a. [a] -> [a] -> [a]
++ [RegAllocStats statics instr]
debug_codeGraphs
                                else []

                -- Ensure all the statistics are evaluated, to avoid space leaks.
                seqList statList (return ())

                return  ( code_final
                        , statList
                        , slotsCount
                        , graph_colored_lint)

         -- Coloring was unsuccessful. We need to spill some register to the
         -- stack, make a new graph, and try to color it again.
         else do
                -- if -fasm-lint is turned on then validate the graph
                let graph_colored_lint  =
                        if NCGConfig -> Bool
ncgAsmLinting NCGConfig
config
                                then SDoc
-> Bool
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
forall k color cls.
(Uniquable k, Outputable k, Eq color) =>
SDoc -> Bool -> Graph k cls color -> Graph k cls color
Color.validateGraph (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"")
                                        Bool
False   -- don't require nodes to be colored
                                        Graph VirtualReg RegClass RealReg
graph_colored
                                else Graph VirtualReg RegClass RealReg
graph_colored

                -- Spill uncolored regs to the stack.
                (code_spilled, slotsFree', slotsCount', spillStats)
                        <- regSpill platform code_coalesced slotsFree slotsCount rsSpill

                -- Recalculate liveness information.
                -- NOTE: we have to reverse the SCCs here to get them back into
                --       the reverse-dependency order required by computeLiveness.
                --       If they're not in the correct order that function will panic.
                code_relive     <- mapM (regLiveness platform . reverseBlocksInTops)
                                        code_spilled

                -- Record what happened in this stage for debugging.
                let stat        =
                        RegAllocStatsSpill
                        { raCode :: [LiveCmmDecl statics instr]
raCode        = [LiveCmmDecl statics instr]
code
                        , raGraph :: Graph VirtualReg RegClass RealReg
raGraph       = Graph VirtualReg RegClass RealReg
graph_colored_lint
                        , raCoalesced :: UniqFM VirtualReg VirtualReg
raCoalesced   = UniqFM VirtualReg VirtualReg
rmCoalesce
                        , raSpillStats :: SpillStats
raSpillStats  = SpillStats
spillStats
                        , raSpillCosts :: SpillCostInfo
raSpillCosts  = SpillCostInfo
spillCosts
                        , raSpilled :: [LiveCmmDecl statics instr]
raSpilled     = [LiveCmmDecl statics instr]
code_spilled
                        , raPlatform :: Platform
raPlatform    = Platform
platform }

                -- Bundle up all the register allocator statistics.
                --   .. but make sure to drop them on the floor if they're not
                --      needed, otherwise we'll get a space leak.
                let statList =
                        if Bool
dump
                                then [RegAllocStats statics instr
stat] [RegAllocStats statics instr]
-> [RegAllocStats statics instr] -> [RegAllocStats statics instr]
forall a. [a] -> [a] -> [a]
++ Maybe (RegAllocStats statics instr)
-> [RegAllocStats statics instr]
forall a. Maybe a -> [a]
maybeToList Maybe (RegAllocStats statics instr)
stat1 [RegAllocStats statics instr]
-> [RegAllocStats statics instr] -> [RegAllocStats statics instr]
forall a. [a] -> [a] -> [a]
++ [RegAllocStats statics instr]
debug_codeGraphs
                                else []

                -- Ensure all the statistics are evaluated, to avoid space leaks.
                seqList statList (return ())

                regAlloc_spin config (spinCount + 1) triv regsFree slotsFree'
                              slotsCount' statList code_relive cfg


-- | Build a graph from the liveness and coalesce information in this code.
buildGraph
        :: Instruction instr
        => [LiveCmmDecl statics instr]
        -> UniqSM (Color.Graph VirtualReg RegClass RealReg)

buildGraph :: forall instr statics.
Instruction instr =>
[LiveCmmDecl statics instr]
-> UniqSM (Graph VirtualReg RegClass RealReg)
buildGraph [LiveCmmDecl statics instr]
code
 = do
        -- Slurp out the conflicts and reg->reg moves from this code.
        let ([Bag (UniqSet Reg)]
conflictList, [Bag (Reg, Reg)]
moveList) =
                [(Bag (UniqSet Reg), Bag (Reg, Reg))]
-> ([Bag (UniqSet Reg)], [Bag (Reg, Reg)])
forall a b. [(a, b)] -> ([a], [b])
unzip ([(Bag (UniqSet Reg), Bag (Reg, Reg))]
 -> ([Bag (UniqSet Reg)], [Bag (Reg, Reg)]))
-> [(Bag (UniqSet Reg), Bag (Reg, Reg))]
-> ([Bag (UniqSet Reg)], [Bag (Reg, Reg)])
forall a b. (a -> b) -> a -> b
$ (LiveCmmDecl statics instr -> (Bag (UniqSet Reg), Bag (Reg, Reg)))
-> [LiveCmmDecl statics instr]
-> [(Bag (UniqSet Reg), Bag (Reg, Reg))]
forall a b. (a -> b) -> [a] -> [b]
map LiveCmmDecl statics instr -> (Bag (UniqSet Reg), Bag (Reg, Reg))
forall instr statics.
Instruction instr =>
LiveCmmDecl statics instr -> (Bag (UniqSet Reg), Bag (Reg, Reg))
slurpConflicts [LiveCmmDecl statics instr]
code

        -- Slurp out the spill/reload coalesces.
        let moveList2 :: [Bag (Reg, Reg)]
moveList2           = (LiveCmmDecl statics instr -> Bag (Reg, Reg))
-> [LiveCmmDecl statics instr] -> [Bag (Reg, Reg)]
forall a b. (a -> b) -> [a] -> [b]
map LiveCmmDecl statics instr -> Bag (Reg, Reg)
forall statics instr.
Instruction instr =>
LiveCmmDecl statics instr -> Bag (Reg, Reg)
slurpReloadCoalesce [LiveCmmDecl statics instr]
code

        -- Add the reg-reg conflicts to the graph.
        let conflictBag :: Bag (UniqSet Reg)
conflictBag         = [Bag (UniqSet Reg)] -> Bag (UniqSet Reg)
forall a. [Bag a] -> Bag a
unionManyBags [Bag (UniqSet Reg)]
conflictList
        let graph_conflict :: Graph VirtualReg RegClass RealReg
graph_conflict
                = (UniqSet Reg
 -> Graph VirtualReg RegClass RealReg
 -> Graph VirtualReg RegClass RealReg)
-> Graph VirtualReg RegClass RealReg
-> Bag (UniqSet Reg)
-> Graph VirtualReg RegClass RealReg
forall a b. (a -> b -> b) -> b -> Bag a -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr UniqSet Reg
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
graphAddConflictSet Graph VirtualReg RegClass RealReg
forall k cls color. Graph k cls color
Color.initGraph Bag (UniqSet Reg)
conflictBag

        -- Add the coalescences edges to the graph.
        let moveBag :: Bag (Reg, Reg)
moveBag
                = Bag (Reg, Reg) -> Bag (Reg, Reg) -> Bag (Reg, Reg)
forall a. Bag a -> Bag a -> Bag a
unionBags ([Bag (Reg, Reg)] -> Bag (Reg, Reg)
forall a. [Bag a] -> Bag a
unionManyBags [Bag (Reg, Reg)]
moveList2)
                            ([Bag (Reg, Reg)] -> Bag (Reg, Reg)
forall a. [Bag a] -> Bag a
unionManyBags [Bag (Reg, Reg)]
moveList)

        let graph_coalesce :: Graph VirtualReg RegClass RealReg
graph_coalesce
                = ((Reg, Reg)
 -> Graph VirtualReg RegClass RealReg
 -> Graph VirtualReg RegClass RealReg)
-> Graph VirtualReg RegClass RealReg
-> Bag (Reg, Reg)
-> Graph VirtualReg RegClass RealReg
forall a b. (a -> b -> b) -> b -> Bag a -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (Reg, Reg)
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
graphAddCoalesce Graph VirtualReg RegClass RealReg
graph_conflict Bag (Reg, Reg)
moveBag

        Graph VirtualReg RegClass RealReg
-> UniqSM (Graph VirtualReg RegClass RealReg)
forall a. a -> UniqSM a
forall (m :: * -> *) a. Monad m => a -> m a
return  Graph VirtualReg RegClass RealReg
graph_coalesce


-- | Add some conflict edges to the graph.
--   Conflicts between virtual and real regs are recorded as exclusions.
graphAddConflictSet
        :: UniqSet Reg
        -> Color.Graph VirtualReg RegClass RealReg
        -> Color.Graph VirtualReg RegClass RealReg

graphAddConflictSet :: UniqSet Reg
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
graphAddConflictSet UniqSet Reg
set Graph VirtualReg RegClass RealReg
graph
 = let  virtuals :: UniqSet VirtualReg
virtuals        = [VirtualReg] -> UniqSet VirtualReg
forall a. Uniquable a => [a] -> UniqSet a
mkUniqSet
                        [ VirtualReg
vr | RegVirtual VirtualReg
vr <- UniqSet Reg -> [Reg]
forall elt. UniqSet elt -> [elt]
nonDetEltsUniqSet UniqSet Reg
set ]

        graph1 :: Graph VirtualReg RegClass RealReg
graph1  = UniqSet VirtualReg
-> (VirtualReg -> RegClass)
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
forall k cls color.
Uniquable k =>
UniqSet k -> (k -> cls) -> Graph k cls color -> Graph k cls color
Color.addConflicts UniqSet VirtualReg
virtuals VirtualReg -> RegClass
classOfVirtualReg Graph VirtualReg RegClass RealReg
graph

        graph2 :: Graph VirtualReg RegClass RealReg
graph2  = ((VirtualReg, RealReg)
 -> Graph VirtualReg RegClass RealReg
 -> Graph VirtualReg RegClass RealReg)
-> Graph VirtualReg RegClass RealReg
-> [(VirtualReg, RealReg)]
-> Graph VirtualReg RegClass RealReg
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(VirtualReg
r1, RealReg
r2) -> VirtualReg
-> (VirtualReg -> RegClass)
-> RealReg
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
forall k color cls.
(Uniquable k, Uniquable color) =>
k -> (k -> cls) -> color -> Graph k cls color -> Graph k cls color
Color.addExclusion VirtualReg
r1 VirtualReg -> RegClass
classOfVirtualReg RealReg
r2)
                        Graph VirtualReg RegClass RealReg
graph1
                        [ (VirtualReg
vr, RealReg
rr)
                                | RegVirtual VirtualReg
vr <- UniqSet Reg -> [Reg]
forall elt. UniqSet elt -> [elt]
nonDetEltsUniqSet UniqSet Reg
set
                                , RegReal    RealReg
rr <- UniqSet Reg -> [Reg]
forall elt. UniqSet elt -> [elt]
nonDetEltsUniqSet UniqSet Reg
set]
                          -- See Note [Unique Determinism and code generation]

   in   Graph VirtualReg RegClass RealReg
graph2


-- | Add some coalescence edges to the graph
--   Coalescences between virtual and real regs are recorded as preferences.
graphAddCoalesce
        :: (Reg, Reg)
        -> Color.Graph VirtualReg RegClass RealReg
        -> Color.Graph VirtualReg RegClass RealReg

graphAddCoalesce :: (Reg, Reg)
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
graphAddCoalesce (Reg
r1, Reg
r2) Graph VirtualReg RegClass RealReg
graph
        | RegReal RealReg
rr            <- Reg
r1
        , RegVirtual VirtualReg
vr         <- Reg
r2
        = (VirtualReg, RegClass)
-> RealReg
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
forall k cls color.
Uniquable k =>
(k, cls) -> color -> Graph k cls color -> Graph k cls color
Color.addPreference (VirtualReg
vr, VirtualReg -> RegClass
classOfVirtualReg VirtualReg
vr) RealReg
rr Graph VirtualReg RegClass RealReg
graph

        | RegReal RealReg
rr            <- Reg
r2
        , RegVirtual VirtualReg
vr         <- Reg
r1
        = (VirtualReg, RegClass)
-> RealReg
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
forall k cls color.
Uniquable k =>
(k, cls) -> color -> Graph k cls color -> Graph k cls color
Color.addPreference (VirtualReg
vr, VirtualReg -> RegClass
classOfVirtualReg VirtualReg
vr) RealReg
rr Graph VirtualReg RegClass RealReg
graph

        | RegVirtual VirtualReg
vr1        <- Reg
r1
        , RegVirtual VirtualReg
vr2        <- Reg
r2
        = (VirtualReg, RegClass)
-> (VirtualReg, RegClass)
-> Graph VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
forall k cls color.
Uniquable k =>
(k, cls) -> (k, cls) -> Graph k cls color -> Graph k cls color
Color.addCoalesce
                (VirtualReg
vr1, VirtualReg -> RegClass
classOfVirtualReg VirtualReg
vr1)
                (VirtualReg
vr2, VirtualReg -> RegClass
classOfVirtualReg VirtualReg
vr2)
                Graph VirtualReg RegClass RealReg
graph

        -- We can't coalesce two real regs, but there could well be existing
        --      hreg,hreg moves in the input code. We'll just ignore these
        --      for coalescing purposes.
        | RegReal RealReg
_             <- Reg
r1
        , RegReal RealReg
_             <- Reg
r2
        = Graph VirtualReg RegClass RealReg
graph


-- | Patch registers in code using the reg -> reg mapping in this graph.
patchRegsFromGraph
        :: (OutputableP Platform statics, Instruction instr)
        => Platform -> Color.Graph VirtualReg RegClass RealReg
        -> LiveCmmDecl statics instr -> LiveCmmDecl statics instr

patchRegsFromGraph :: forall statics instr.
(OutputableP Platform statics, Instruction instr) =>
Platform
-> Graph VirtualReg RegClass RealReg
-> LiveCmmDecl statics instr
-> LiveCmmDecl statics instr
patchRegsFromGraph Platform
platform Graph VirtualReg RegClass RealReg
graph LiveCmmDecl statics instr
code
 = (Reg -> Reg)
-> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
forall instr statics.
Instruction instr =>
(Reg -> Reg)
-> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
patchEraseLive Reg -> Reg
patchF LiveCmmDecl statics instr
code
 where
        -- Function to lookup the hardreg for a virtual reg from the graph.
        patchF :: Reg -> Reg
patchF Reg
reg
                -- leave real regs alone.
                | RegReal{}     <- Reg
reg
                = Reg
reg

                -- this virtual has a regular node in the graph.
                | RegVirtual VirtualReg
vr <- Reg
reg
                , Just Node VirtualReg RegClass RealReg
node     <- Graph VirtualReg RegClass RealReg
-> VirtualReg -> Maybe (Node VirtualReg RegClass RealReg)
forall k cls color.
Uniquable k =>
Graph k cls color -> k -> Maybe (Node k cls color)
Color.lookupNode Graph VirtualReg RegClass RealReg
graph VirtualReg
vr
                = case Node VirtualReg RegClass RealReg -> Maybe RealReg
forall k cls color. Node k cls color -> Maybe color
Color.nodeColor Node VirtualReg RegClass RealReg
node of
                        Just RealReg
color      -> RealReg -> Reg
RegReal    RealReg
color
                        Maybe RealReg
Nothing         -> VirtualReg -> Reg
RegVirtual VirtualReg
vr

                -- no node in the graph for this virtual, bad news.
                | Bool
otherwise
                = String -> SDoc -> Reg
forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"patchRegsFromGraph: register mapping failed."
                        (  String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"There is no node in the graph for register "
                                SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> Reg -> SDoc
forall a. Outputable a => a -> SDoc
ppr Reg
reg
                        SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ Platform -> LiveCmmDecl statics instr -> SDoc
forall statics instr.
(OutputableP Platform statics, Instruction instr) =>
Platform -> LiveCmmDecl statics instr -> SDoc
pprLiveCmmDecl Platform
platform LiveCmmDecl statics instr
code
                        SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ (RealReg -> SDoc)
-> Triv VirtualReg RegClass RealReg
-> Graph VirtualReg RegClass RealReg
-> SDoc
forall k cls color.
(Uniquable k, Outputable k, Outputable cls, Outputable color) =>
(color -> SDoc) -> Triv k cls color -> Graph k cls color -> SDoc
Color.dotGraph
                                (\RealReg
_ -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"white")
                                (Platform
-> (RegClass -> VirtualReg -> Int)
-> (RegClass -> RealReg -> Int)
-> Triv VirtualReg RegClass RealReg
trivColorable Platform
platform
                                        (Platform -> RegClass -> VirtualReg -> Int
targetVirtualRegSqueeze Platform
platform)
                                        (Platform -> RegClass -> RealReg -> Int
targetRealRegSqueeze Platform
platform))
                                Graph VirtualReg RegClass RealReg
graph)


-----
-- for when laziness just isn't what you wanted...
--  We need to deepSeq the whole graph before trying to colour it to avoid
--  space leaks.
seqGraph :: Color.Graph VirtualReg RegClass RealReg -> ()
seqGraph :: Graph VirtualReg RegClass RealReg -> ()
seqGraph Graph VirtualReg RegClass RealReg
graph          = [Node VirtualReg RegClass RealReg] -> ()
seqNodes (UniqFM VirtualReg (Node VirtualReg RegClass RealReg)
-> [Node VirtualReg RegClass RealReg]
forall {k} (key :: k) elt. UniqFM key elt -> [elt]
nonDetEltsUFM (Graph VirtualReg RegClass RealReg
-> UniqFM VirtualReg (Node VirtualReg RegClass RealReg)
forall k cls color.
Graph k cls color -> UniqFM k (Node k cls color)
Color.graphMap Graph VirtualReg RegClass RealReg
graph))
   -- See Note [Unique Determinism and code generation]

seqNodes :: [Color.Node VirtualReg RegClass RealReg] -> ()
seqNodes :: [Node VirtualReg RegClass RealReg] -> ()
seqNodes [Node VirtualReg RegClass RealReg]
ns
 = case [Node VirtualReg RegClass RealReg]
ns of
        []              -> ()
        (Node VirtualReg RegClass RealReg
n : [Node VirtualReg RegClass RealReg]
ns)        -> Node VirtualReg RegClass RealReg -> ()
seqNode Node VirtualReg RegClass RealReg
n () -> () -> ()
forall a b. a -> b -> b
`seq` [Node VirtualReg RegClass RealReg] -> ()
seqNodes [Node VirtualReg RegClass RealReg]
ns

seqNode :: Color.Node VirtualReg RegClass RealReg -> ()
seqNode :: Node VirtualReg RegClass RealReg -> ()
seqNode Node VirtualReg RegClass RealReg
node
        =     VirtualReg -> ()
seqVirtualReg     (Node VirtualReg RegClass RealReg -> VirtualReg
forall k cls color. Node k cls color -> k
Color.nodeId Node VirtualReg RegClass RealReg
node)
        () -> () -> ()
forall a b. a -> b -> b
`seq` RegClass -> ()
seqRegClass       (Node VirtualReg RegClass RealReg -> RegClass
forall k cls color. Node k cls color -> cls
Color.nodeClass Node VirtualReg RegClass RealReg
node)
        () -> () -> ()
forall a b. a -> b -> b
`seq` Maybe RealReg -> ()
seqMaybeRealReg   (Node VirtualReg RegClass RealReg -> Maybe RealReg
forall k cls color. Node k cls color -> Maybe color
Color.nodeColor Node VirtualReg RegClass RealReg
node)
        () -> () -> ()
forall a b. a -> b -> b
`seq` ([VirtualReg] -> ()
seqVirtualRegList (UniqSet VirtualReg -> [VirtualReg]
forall elt. UniqSet elt -> [elt]
nonDetEltsUniqSet (Node VirtualReg RegClass RealReg -> UniqSet VirtualReg
forall k cls color. Node k cls color -> UniqSet k
Color.nodeConflicts Node VirtualReg RegClass RealReg
node)))
        () -> () -> ()
forall a b. a -> b -> b
`seq` ([RealReg] -> ()
seqRealRegList    (UniqSet RealReg -> [RealReg]
forall elt. UniqSet elt -> [elt]
nonDetEltsUniqSet (Node VirtualReg RegClass RealReg -> UniqSet RealReg
forall k cls color. Node k cls color -> UniqSet color
Color.nodeExclusions Node VirtualReg RegClass RealReg
node)))
        () -> () -> ()
forall a b. a -> b -> b
`seq` ([RealReg] -> ()
seqRealRegList (Node VirtualReg RegClass RealReg -> [RealReg]
forall k cls color. Node k cls color -> [color]
Color.nodePreference Node VirtualReg RegClass RealReg
node))
        () -> () -> ()
forall a b. a -> b -> b
`seq` ([VirtualReg] -> ()
seqVirtualRegList (UniqSet VirtualReg -> [VirtualReg]
forall elt. UniqSet elt -> [elt]
nonDetEltsUniqSet (Node VirtualReg RegClass RealReg -> UniqSet VirtualReg
forall k cls color. Node k cls color -> UniqSet k
Color.nodeCoalesce Node VirtualReg RegClass RealReg
node)))
              -- It's OK to use nonDetEltsUniqSet for seq

seqVirtualReg :: VirtualReg -> ()
seqVirtualReg :: VirtualReg -> ()
seqVirtualReg VirtualReg
reg = VirtualReg
reg VirtualReg -> () -> ()
forall a b. a -> b -> b
`seq` ()

seqRealReg :: RealReg -> ()
seqRealReg :: RealReg -> ()
seqRealReg RealReg
reg = RealReg
reg RealReg -> () -> ()
forall a b. a -> b -> b
`seq` ()

seqRegClass :: RegClass -> ()
seqRegClass :: RegClass -> ()
seqRegClass RegClass
c = RegClass
c RegClass -> () -> ()
forall a b. a -> b -> b
`seq` ()

seqMaybeRealReg :: Maybe RealReg -> ()
seqMaybeRealReg :: Maybe RealReg -> ()
seqMaybeRealReg Maybe RealReg
mr
 = case Maybe RealReg
mr of
        Maybe RealReg
Nothing         -> ()
        Just RealReg
r          -> RealReg -> ()
seqRealReg RealReg
r

seqVirtualRegList :: [VirtualReg] -> ()
seqVirtualRegList :: [VirtualReg] -> ()
seqVirtualRegList [VirtualReg]
rs
 = case [VirtualReg]
rs of
        []              -> ()
        (VirtualReg
r : [VirtualReg]
rs)        -> VirtualReg -> ()
seqVirtualReg VirtualReg
r () -> () -> ()
forall a b. a -> b -> b
`seq` [VirtualReg] -> ()
seqVirtualRegList [VirtualReg]
rs

seqRealRegList :: [RealReg] -> ()
seqRealRegList :: [RealReg] -> ()
seqRealRegList [RealReg]
rs
 = case [RealReg]
rs of
        []              -> ()
        (RealReg
r : [RealReg]
rs)        -> RealReg -> ()
seqRealReg RealReg
r () -> () -> ()
forall a b. a -> b -> b
`seq` [RealReg] -> ()
seqRealRegList [RealReg]
rs