diff options
Diffstat (limited to 'compiler/nativeGen/RegAlloc/Graph')
| -rw-r--r-- | compiler/nativeGen/RegAlloc/Graph/Coalesce.hs | 23 | ||||
| -rw-r--r-- | compiler/nativeGen/RegAlloc/Graph/Main.hs | 56 | ||||
| -rw-r--r-- | compiler/nativeGen/RegAlloc/Graph/Spill.hs | 46 | ||||
| -rw-r--r-- | compiler/nativeGen/RegAlloc/Graph/SpillClean.hs | 95 | ||||
| -rw-r--r-- | compiler/nativeGen/RegAlloc/Graph/SpillCost.hs | 48 | ||||
| -rw-r--r-- | compiler/nativeGen/RegAlloc/Graph/Stats.hs | 149 | ||||
| -rw-r--r-- | compiler/nativeGen/RegAlloc/Graph/TrivColorable.hs | 176 |
7 files changed, 395 insertions, 198 deletions
diff --git a/compiler/nativeGen/RegAlloc/Graph/Coalesce.hs b/compiler/nativeGen/RegAlloc/Graph/Coalesce.hs index 18e4b0edd1..8521e92601 100644 --- a/compiler/nativeGen/RegAlloc/Graph/Coalesce.hs +++ b/compiler/nativeGen/RegAlloc/Graph/Coalesce.hs @@ -8,11 +8,11 @@ module RegAlloc.Graph.Coalesce ( where -import Cmm -import Regs import RegAlloc.Liveness -import RegAllocInfo +import Instruction +import Reg +import Cmm import Bag import UniqFM import UniqSet @@ -26,7 +26,11 @@ import Data.List -- then the mov only serves to join live ranges. The two regs can be renamed to be -- the same and the move instruction safely erased. -regCoalesce :: [LiveCmmTop] -> UniqSM [LiveCmmTop] +regCoalesce + :: Instruction instr + => [LiveCmmTop instr] + -> UniqSM [LiveCmmTop instr] + regCoalesce code = do let joins = foldl' unionBags emptyBag @@ -57,7 +61,11 @@ sinkReg fm r -- During a mov, if the source reg dies and the destiation reg is born -- then we can rename the two regs to the same thing and eliminate the move. -- -slurpJoinMovs :: LiveCmmTop -> Bag (Reg, Reg) +slurpJoinMovs + :: Instruction instr + => LiveCmmTop instr + -> Bag (Reg, Reg) + slurpJoinMovs live = slurpCmm emptyBag live where @@ -68,7 +76,7 @@ slurpJoinMovs live slurpLI rs (Instr _ Nothing) = rs slurpLI rs (Instr instr (Just live)) - | Just (r1, r2) <- isRegRegMove instr + | Just (r1, r2) <- takeRegRegMoveInstr instr , elementOfUniqSet r1 $ liveDieRead live , elementOfUniqSet r2 $ liveBorn live @@ -80,4 +88,7 @@ slurpJoinMovs live | otherwise = rs + slurpLI rs SPILL{} = rs + slurpLI rs RELOAD{} = rs + diff --git a/compiler/nativeGen/RegAlloc/Graph/Main.hs b/compiler/nativeGen/RegAlloc/Graph/Main.hs index fe99aba120..2e584617e9 100644 --- a/compiler/nativeGen/RegAlloc/Graph/Main.hs +++ b/compiler/nativeGen/RegAlloc/Graph/Main.hs @@ -5,8 +5,7 @@ -- module RegAlloc.Graph.Main ( - regAlloc, - regDotColor + regAlloc ) where @@ -17,9 +16,12 @@ import RegAlloc.Graph.Spill import RegAlloc.Graph.SpillClean import RegAlloc.Graph.SpillCost import RegAlloc.Graph.Stats -import Regs -import Instrs -import PprMach +import RegAlloc.Graph.TrivColorable +import Instruction +import TargetReg +import RegClass +import Reg + import UniqSupply import UniqSet @@ -43,18 +45,26 @@ maxSpinCount = 10 -- | The top level of the graph coloring register allocator. -- regAlloc - :: DynFlags + :: (Outputable instr, Instruction instr) + => DynFlags -> UniqFM (UniqSet Reg) -- ^ the registers we can use for allocation -> UniqSet Int -- ^ the set of available spill slots. - -> [LiveCmmTop] -- ^ code annotated with liveness information. - -> UniqSM ( [NatCmmTop], [RegAllocStats] ) + -> [LiveCmmTop instr] -- ^ code annotated with liveness information. + -> UniqSM ( [NatCmmTop instr], [RegAllocStats instr] ) -- ^ code with registers allocated and stats for each stage of -- allocation regAlloc dflags regsFree slotsFree code = do + -- TODO: the regClass function is currently hard coded to the default target + -- architecture. Would prefer to determine this from dflags. + -- There are other uses of targetRegClass later in this module. + let triv = trivColorable targetRegClass + (code_final, debug_codeGraphs, _) - <- regAlloc_spin dflags 0 trivColorable regsFree slotsFree [] code + <- regAlloc_spin dflags 0 + triv + regsFree slotsFree [] code return ( code_final , reverse debug_codeGraphs ) @@ -74,7 +84,7 @@ regAlloc_spin dflags spinCount triv regsFree slotsFree debug_codeGraphs code $ 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 (docToSDoc . pprUserReg) + $$ text "regsFree = " <> (hcat $ punctuate space $ map ppr $ uniqSetToList $ unionManyUniqSets $ eltsUFM regsFree) $$ text "slotsFree = " <> ppr (sizeUniqSet slotsFree)) @@ -139,12 +149,12 @@ regAlloc_spin dflags spinCount triv regsFree slotsFree debug_codeGraphs code -- clean out unneeded SPILL/RELOADs let code_spillclean = map cleanSpills code_patched - -- strip off liveness information - let code_nat = map stripLive code_spillclean + -- strip off liveness information, + -- and rewrite SPILL/RELOAD pseudos into real instructions along the way + let code_final = map stripLive code_spillclean - -- rewrite SPILL/RELOAD pseudos into real instructions - let spillNatTop = mapGenBlockTop spillNatBlock - let code_final = map spillNatTop code_nat +-- let spillNatTop = mapGenBlockTop spillNatBlock +-- let code_final = map spillNatTop code_nat -- record what happened in this stage for debugging let stat = @@ -213,7 +223,8 @@ regAlloc_spin dflags spinCount triv regsFree slotsFree debug_codeGraphs code -- | Build a graph from the liveness and coalesce information in this code. buildGraph - :: [LiveCmmTop] + :: Instruction instr + => [LiveCmmTop instr] -> UniqSM (Color.Graph Reg RegClass Reg) buildGraph code @@ -248,8 +259,8 @@ graphAddConflictSet set graph = let reals = filterUFM isRealReg set virtuals = filterUFM (not . isRealReg) set - graph1 = Color.addConflicts virtuals regClass graph - graph2 = foldr (\(r1, r2) -> Color.addExclusion r1 regClass r2) + graph1 = Color.addConflicts virtuals targetRegClass graph + graph2 = foldr (\(r1, r2) -> Color.addExclusion r1 targetRegClass r2) graph1 [ (a, b) | a <- uniqSetToList virtuals @@ -276,13 +287,14 @@ graphAddCoalesce (r1, r2) graph | otherwise = Color.addCoalesce (regWithClass r1) (regWithClass r2) graph - where regWithClass r = (r, regClass r) + where regWithClass r = (r, targetRegClass r) -- | Patch registers in code using the reg -> reg mapping in this graph. patchRegsFromGraph - :: Color.Graph Reg RegClass Reg - -> LiveCmmTop -> LiveCmmTop + :: (Outputable instr, Instruction instr) + => Color.Graph Reg RegClass Reg + -> LiveCmmTop instr -> LiveCmmTop instr patchRegsFromGraph graph code = let @@ -303,7 +315,7 @@ patchRegsFromGraph graph code = pprPanic "patchRegsFromGraph: register mapping failed." ( text "There is no node in the graph for register " <> ppr reg $$ ppr code - $$ Color.dotGraph (\_ -> text "white") trivColorable graph) + $$ Color.dotGraph (\_ -> text "white") (trivColorable targetRegClass) graph) in patchEraseLive patchF code diff --git a/compiler/nativeGen/RegAlloc/Graph/Spill.hs b/compiler/nativeGen/RegAlloc/Graph/Spill.hs index b5a645188f..e6e5622a02 100644 --- a/compiler/nativeGen/RegAlloc/Graph/Spill.hs +++ b/compiler/nativeGen/RegAlloc/Graph/Spill.hs @@ -10,9 +10,8 @@ module RegAlloc.Graph.Spill ( where import RegAlloc.Liveness -import RegAllocInfo -import Regs -import Instrs +import Instruction +import Reg import Cmm import State @@ -35,11 +34,12 @@ import Data.Maybe -- address the spill slot directly. -- regSpill - :: [LiveCmmTop] -- ^ the code + :: Instruction instr + => [LiveCmmTop instr] -- ^ the code -> UniqSet Int -- ^ available stack slots -> UniqSet Reg -- ^ the regs to spill -> UniqSM - ([LiveCmmTop] -- code will spill instructions + ([LiveCmmTop instr] -- code will spill instructions , UniqSet Int -- left over slots , SpillStats ) -- stats about what happened during spilling @@ -75,6 +75,20 @@ regSpill_block regSlotMap (BasicBlock i instrs) = do instrss' <- mapM (regSpill_instr regSlotMap) instrs return $ BasicBlock i (concat instrss') + +regSpill_instr + :: Instruction instr + => UniqFM Int + -> LiveInstr instr -> SpillM [LiveInstr instr] + +-- | The thing we're spilling shouldn't already have spill or reloads in it +regSpill_instr _ SPILL{} + = panic "regSpill_instr: unexpected SPILL" + +regSpill_instr _ RELOAD{} + = panic "regSpill_instr: unexpected RELOAD" + + regSpill_instr _ li@(Instr _ Nothing) = do return [li] @@ -82,7 +96,7 @@ regSpill_instr regSlotMap (Instr instr (Just _)) = do -- work out which regs are read and written in this instr - let RU rlRead rlWritten = regUsage instr + let RU rlRead rlWritten = regUsageOfInstr instr -- sometimes a register is listed as being read more than once, -- nub this so we don't end up inserting two lots of spill code. @@ -109,9 +123,9 @@ regSpill_instr regSlotMap let postfixes = concat mPostfixes -- final code - let instrs' = map (\i -> Instr i Nothing) prefixes - ++ [ Instr instr3 Nothing ] - ++ map (\i -> Instr i Nothing) postfixes + let instrs' = prefixes + ++ [Instr instr3 Nothing] + ++ postfixes return {- $ pprTrace "* regSpill_instr spill" @@ -139,6 +153,7 @@ spillRead regSlotMap instr reg | otherwise = panic "RegSpill.spillRead: no slot defined for spilled reg" + spillWrite regSlotMap instr reg | Just slot <- lookupUFM regSlotMap reg = do (instr', nReg) <- patchInstr reg instr @@ -152,6 +167,7 @@ spillWrite regSlotMap instr reg | otherwise = panic "RegSpill.spillWrite: no slot defined for spilled reg" + spillModify regSlotMap instr reg | Just slot <- lookupUFM regSlotMap reg = do (instr', nReg) <- patchInstr reg instr @@ -168,19 +184,25 @@ spillModify regSlotMap instr reg -- | rewrite uses of this virtual reg in an instr to use a different virtual reg -patchInstr :: Reg -> Instr -> SpillM (Instr, Reg) +patchInstr + :: Instruction instr + => Reg -> instr -> SpillM (instr, Reg) + patchInstr reg instr = do nUnique <- newUnique let nReg = renameVirtualReg nUnique reg let instr' = patchReg1 reg nReg instr return (instr', nReg) -patchReg1 :: Reg -> Reg -> Instr -> Instr +patchReg1 + :: Instruction instr + => Reg -> Reg -> instr -> instr + patchReg1 old new instr = let patchF r | r == old = new | otherwise = r - in patchRegs instr patchF + in patchRegsOfInstr instr patchF ------------------------------------------------------ diff --git a/compiler/nativeGen/RegAlloc/Graph/SpillClean.hs b/compiler/nativeGen/RegAlloc/Graph/SpillClean.hs index b68648bdaf..4f129c468a 100644 --- a/compiler/nativeGen/RegAlloc/Graph/SpillClean.hs +++ b/compiler/nativeGen/RegAlloc/Graph/SpillClean.hs @@ -29,13 +29,12 @@ module RegAlloc.Graph.SpillClean ( ) where -import BlockId import RegAlloc.Liveness -import RegAllocInfo -import Regs -import Instrs -import Cmm +import Instruction +import Reg +import BlockId +import Cmm import UniqSet import UniqFM import Unique @@ -51,12 +50,19 @@ type Slot = Int -- | Clean out unneeded spill\/reloads from this top level thing. -cleanSpills :: LiveCmmTop -> LiveCmmTop +cleanSpills + :: Instruction instr + => LiveCmmTop instr -> LiveCmmTop instr + cleanSpills cmm = evalState (cleanSpin 0 cmm) initCleanS -- | do one pass of cleaning -cleanSpin :: Int -> LiveCmmTop -> CleanM LiveCmmTop +cleanSpin + :: Instruction instr + => Int + -> LiveCmmTop instr + -> CleanM (LiveCmmTop instr) {- cleanSpin spinCount code @@ -103,7 +109,11 @@ cleanSpin spinCount code -- | Clean one basic block -cleanBlockForward :: LiveBasicBlock -> CleanM LiveBasicBlock +cleanBlockForward + :: Instruction instr + => LiveBasicBlock instr + -> CleanM (LiveBasicBlock instr) + cleanBlockForward (BasicBlock blockId instrs) = do -- see if we have a valid association for the entry to this block @@ -116,7 +126,11 @@ cleanBlockForward (BasicBlock blockId instrs) return $ BasicBlock blockId instrs_reload -cleanBlockBackward :: LiveBasicBlock -> CleanM LiveBasicBlock +cleanBlockBackward + :: Instruction instr + => LiveBasicBlock instr + -> CleanM (LiveBasicBlock instr) + cleanBlockBackward (BasicBlock blockId instrs) = do instrs_spill <- cleanBackward emptyUniqSet [] instrs return $ BasicBlock blockId instrs_spill @@ -130,11 +144,12 @@ cleanBlockBackward (BasicBlock blockId instrs) -- then we don't need to do the reload. -- cleanForward - :: BlockId -- ^ the block that we're currently in - -> Assoc Store -- ^ two store locations are associated if they have the same value - -> [LiveInstr] -- ^ acc - -> [LiveInstr] -- ^ instrs to clean (in backwards order) - -> CleanM [LiveInstr] -- ^ cleaned instrs (in forward order) + :: Instruction instr + => BlockId -- ^ the block that we're currently in + -> Assoc Store -- ^ two store locations are associated if they have the same value + -> [LiveInstr instr] -- ^ acc + -> [LiveInstr instr] -- ^ instrs to clean (in backwards order) + -> CleanM [LiveInstr instr] -- ^ cleaned instrs (in forward order) cleanForward _ _ acc [] = return acc @@ -142,19 +157,19 @@ cleanForward _ _ acc [] -- write out live range joins via spill slots to just a spill and a reg-reg move -- hopefully the spill will be also be cleaned in the next pass -- -cleanForward blockId assoc acc (Instr i1 live1 : Instr i2 _ : instrs) +cleanForward blockId assoc acc (li1 : li2 : instrs) - | SPILL reg1 slot1 <- i1 - , RELOAD slot2 reg2 <- i2 + | SPILL reg1 slot1 <- li1 + , RELOAD slot2 reg2 <- li2 , slot1 == slot2 = do modify $ \s -> s { sCleanedReloadsAcc = sCleanedReloadsAcc s + 1 } cleanForward blockId assoc acc - (Instr i1 live1 : Instr (mkRegRegMoveInstr reg1 reg2) Nothing : instrs) + (li1 : Instr (mkRegRegMoveInstr reg1 reg2) Nothing : instrs) cleanForward blockId assoc acc (li@(Instr i1 _) : instrs) - | Just (r1, r2) <- isRegRegMove i1 + | Just (r1, r2) <- takeRegRegMoveInstr i1 = if r1 == r2 -- erase any left over nop reg reg moves while we're here -- this will also catch any nop moves that the "write out live range joins" case above @@ -170,38 +185,50 @@ cleanForward blockId assoc acc (li@(Instr i1 _) : instrs) cleanForward blockId assoc' (li : acc) instrs -cleanForward blockId assoc acc (li@(Instr instr _) : instrs) +cleanForward blockId assoc acc (li : instrs) -- update association due to the spill - | SPILL reg slot <- instr + | SPILL reg slot <- li = let assoc' = addAssoc (SReg reg) (SSlot slot) $ delAssoc (SSlot slot) $ assoc in cleanForward blockId assoc' (li : acc) instrs -- clean a reload instr - | RELOAD{} <- instr + | RELOAD{} <- li = do (assoc', mli) <- cleanReload blockId assoc li case mli of Nothing -> cleanForward blockId assoc' acc instrs Just li' -> cleanForward blockId assoc' (li' : acc) instrs -- remember the association over a jump - | targets <- jumpDests instr [] + | Instr instr _ <- li + , targets <- jumpDestsOfInstr instr , not $ null targets = do mapM_ (accJumpValid assoc) targets cleanForward blockId assoc (li : acc) instrs -- writing to a reg changes its value. - | RU _ written <- regUsage instr + | Instr instr _ <- li + , RU _ written <- regUsageOfInstr instr = let assoc' = foldr delAssoc assoc (map SReg $ nub written) in cleanForward blockId assoc' (li : acc) instrs +-- bogus, to stop pattern match warning +cleanForward _ _ _ _ + = panic "RegAlloc.Graph.SpillClean.cleanForward: no match" + -- | Try and rewrite a reload instruction to something more pleasing -- -cleanReload :: BlockId -> Assoc Store -> LiveInstr -> CleanM (Assoc Store, Maybe LiveInstr) -cleanReload blockId assoc li@(Instr (RELOAD slot reg) _) +cleanReload + :: Instruction instr + => BlockId + -> Assoc Store + -> LiveInstr instr + -> CleanM (Assoc Store, Maybe (LiveInstr instr)) + +cleanReload blockId assoc li@(RELOAD slot reg) -- if the reg we're reloading already has the same value as the slot -- then we can erase the instruction outright @@ -264,10 +291,10 @@ cleanReload _ _ _ -- we should really be updating the noReloads set as we cross jumps also. -- cleanBackward - :: UniqSet Int -- ^ slots that have been spilled, but not reloaded from - -> [LiveInstr] -- ^ acc - -> [LiveInstr] -- ^ instrs to clean (in forwards order) - -> CleanM [LiveInstr] -- ^ cleaned instrs (in backwards order) + :: UniqSet Int -- ^ slots that have been spilled, but not reloaded from + -> [LiveInstr instr] -- ^ acc + -> [LiveInstr instr] -- ^ instrs to clean (in forwards order) + -> CleanM [LiveInstr instr] -- ^ cleaned instrs (in backwards order) cleanBackward noReloads acc lis @@ -277,15 +304,15 @@ cleanBackward noReloads acc lis cleanBackward' _ _ acc [] = return acc -cleanBackward' reloadedBy noReloads acc (li@(Instr instr _) : instrs) +cleanBackward' reloadedBy noReloads acc (li : instrs) -- if nothing ever reloads from this slot then we don't need the spill - | SPILL _ slot <- instr + | SPILL _ slot <- li , Nothing <- lookupUFM reloadedBy (SSlot slot) = do modify $ \s -> s { sCleanedSpillsAcc = sCleanedSpillsAcc s + 1 } cleanBackward noReloads acc instrs - | SPILL _ slot <- instr + | SPILL _ slot <- li = if elementOfUniqSet slot noReloads -- we can erase this spill because the slot won't be read until after the next one @@ -299,7 +326,7 @@ cleanBackward' reloadedBy noReloads acc (li@(Instr instr _) : instrs) cleanBackward noReloads' (li : acc) instrs -- if we reload from a slot then it's no longer unused - | RELOAD slot _ <- instr + | RELOAD slot _ <- li , noReloads' <- delOneFromUniqSet noReloads slot = cleanBackward noReloads' (li : acc) instrs diff --git a/compiler/nativeGen/RegAlloc/Graph/SpillCost.hs b/compiler/nativeGen/RegAlloc/Graph/SpillCost.hs index 1d37cf71d6..d4dd75a4b7 100644 --- a/compiler/nativeGen/RegAlloc/Graph/SpillCost.hs +++ b/compiler/nativeGen/RegAlloc/Graph/SpillCost.hs @@ -16,14 +16,16 @@ module RegAlloc.Graph.SpillCost ( where -import GraphBase import RegAlloc.Liveness -import RegAllocInfo -import Instrs -import Regs +import Instruction +import RegClass +import Reg + +import GraphBase + + import BlockId import Cmm - import UniqFM import UniqSet import Outputable @@ -62,7 +64,8 @@ plusSpillCostRecord (r1, a1, b1, c1) (r2, a2, b2, c2) -- and the number of instructions it was live on entry to (lifetime) -- slurpSpillCostInfo - :: LiveCmmTop + :: (Outputable instr, Instruction instr) + => LiveCmmTop instr -> SpillCostInfo slurpSpillCostInfo cmm @@ -89,11 +92,14 @@ slurpSpillCostInfo cmm = return () -- skip over comment and delta pseudo instrs - countLIs rsLive (Instr instr Nothing : lis) - | COMMENT{} <- instr + countLIs rsLive (SPILL{} : lis) + = countLIs rsLive lis + + countLIs rsLive (RELOAD{} : lis) = countLIs rsLive lis - | DELTA{} <- instr + countLIs rsLive (Instr instr Nothing : lis) + | isMetaInstr instr = countLIs rsLive lis | otherwise @@ -106,7 +112,7 @@ slurpSpillCostInfo cmm mapM_ incLifetime $ uniqSetToList rsLiveEntry -- increment counts for what regs were read/written from - let (RU read written) = regUsage instr + let (RU read written) = regUsageOfInstr instr mapM_ incUses $ filter (not . isRealReg) $ nub read mapM_ incDefs $ filter (not . isRealReg) $ nub written @@ -226,8 +232,11 @@ lifeMapFromSpillCostInfo info -- | Work out the degree (number of neighbors) of this node which have the same class. -nodeDegree :: Graph Reg RegClass Reg -> Reg -> Int -nodeDegree graph reg +nodeDegree + :: (Reg -> RegClass) + -> Graph Reg RegClass Reg -> Reg -> Int + +nodeDegree regClass graph reg | Just node <- lookupUFM (graphMap graph) reg , virtConflicts <- length $ filter (\r -> regClass r == regClass reg) $ uniqSetToList $ nodeConflicts node @@ -238,12 +247,17 @@ nodeDegree graph reg -- | Show a spill cost record, including the degree from the graph and final calulated spill cos -pprSpillCostRecord :: Graph Reg RegClass Reg -> SpillCostRecord -> SDoc -pprSpillCostRecord graph (reg, uses, defs, life) +pprSpillCostRecord + :: (Reg -> RegClass) + -> (Reg -> SDoc) + -> Graph Reg RegClass Reg -> SpillCostRecord -> SDoc + +pprSpillCostRecord regClass pprReg graph (reg, uses, defs, life) = hsep - [ ppr reg + [ pprReg reg , ppr uses , ppr defs , ppr life - , ppr $ nodeDegree graph reg - , text $ show $ (fromIntegral (uses + defs) / fromIntegral (nodeDegree graph reg) :: Float) ] + , ppr $ nodeDegree regClass graph reg + , text $ show $ (fromIntegral (uses + defs) + / fromIntegral (nodeDegree regClass graph reg) :: Float) ] diff --git a/compiler/nativeGen/RegAlloc/Graph/Stats.hs b/compiler/nativeGen/RegAlloc/Graph/Stats.hs index 8082f9e975..5e3dd3265b 100644 --- a/compiler/nativeGen/RegAlloc/Graph/Stats.hs +++ b/compiler/nativeGen/RegAlloc/Graph/Stats.hs @@ -5,7 +5,6 @@ module RegAlloc.Graph.Stats ( RegAllocStats (..), - regDotColor, pprStats, pprStatsSpills, @@ -22,13 +21,13 @@ where import qualified GraphColor as Color import RegAlloc.Liveness -import RegAllocInfo import RegAlloc.Graph.Spill import RegAlloc.Graph.SpillCost -import Regs -import Instrs -import Cmm +import Instruction +import RegClass +import Reg +import Cmm import Outputable import UniqFM import UniqSet @@ -36,11 +35,11 @@ import State import Data.List -data RegAllocStats +data RegAllocStats instr -- initial graph = RegAllocStatsStart - { raLiveCmm :: [LiveCmmTop] -- ^ initial code, with liveness + { raLiveCmm :: [LiveCmmTop instr] -- ^ initial code, with liveness , raGraph :: Color.Graph Reg RegClass Reg -- ^ the initial, uncolored graph , raSpillCosts :: SpillCostInfo } -- ^ information to help choose which regs to spill @@ -50,35 +49,35 @@ data RegAllocStats , raCoalesced :: UniqFM Reg -- ^ the regs that were coaleced , raSpillStats :: SpillStats -- ^ spiller stats , raSpillCosts :: SpillCostInfo -- ^ number of instrs each reg lives for - , raSpilled :: [LiveCmmTop] } -- ^ code with spill instructions added + , raSpilled :: [LiveCmmTop instr] } -- ^ code with spill instructions added -- a successful coloring | RegAllocStatsColored { raGraph :: Color.Graph Reg RegClass Reg -- ^ the uncolored graph , raGraphColored :: Color.Graph Reg RegClass Reg -- ^ the coalesced and colored graph , raCoalesced :: UniqFM Reg -- ^ the regs that were coaleced - , raPatched :: [LiveCmmTop] -- ^ code with vregs replaced by hregs - , raSpillClean :: [LiveCmmTop] -- ^ code with unneeded spill\/reloads cleaned out - , raFinal :: [NatCmmTop] -- ^ final code + , raPatched :: [LiveCmmTop instr] -- ^ code with vregs replaced by hregs + , raSpillClean :: [LiveCmmTop instr] -- ^ code with unneeded spill\/reloads cleaned out + , raFinal :: [NatCmmTop instr] -- ^ final code , raSRMs :: (Int, Int, Int) } -- ^ spill\/reload\/reg-reg moves present in this code -instance Outputable RegAllocStats where +instance Outputable instr => Outputable (RegAllocStats instr) where ppr (s@RegAllocStatsStart{}) = text "# Start" $$ text "# Native code with liveness information." $$ ppr (raLiveCmm s) $$ text "" - $$ text "# Initial register conflict graph." - $$ Color.dotGraph regDotColor trivColorable (raGraph s) +-- $$ text "# Initial register conflict graph." +-- $$ Color.dotGraph regDotColor trivColorable (raGraph s) ppr (s@RegAllocStatsSpill{}) = text "# Spill" - $$ text "# Register conflict graph." - $$ Color.dotGraph regDotColor trivColorable (raGraph s) - $$ text "" +-- $$ text "# Register conflict graph." +-- $$ Color.dotGraph regDotColor trivColorable (raGraph s) +-- $$ text "" $$ (if (not $ isNullUFM $ raCoalesced s) then text "# Registers coalesced." @@ -86,9 +85,9 @@ instance Outputable RegAllocStats where $$ text "" else empty) - $$ text "# Spill costs. reg uses defs lifetime degree cost" - $$ vcat (map (pprSpillCostRecord (raGraph s)) $ eltsUFM $ raSpillCosts s) - $$ text "" +-- $$ text "# Spill costs. reg uses defs lifetime degree cost" +-- $$ vcat (map (pprSpillCostRecord (raGraph s)) $ eltsUFM $ raSpillCosts s) +-- $$ text "" $$ text "# Spills inserted." $$ ppr (raSpillStats s) @@ -101,13 +100,13 @@ instance Outputable RegAllocStats where ppr (s@RegAllocStatsColored { raSRMs = (spills, reloads, moves) }) = text "# Colored" - $$ text "# Register conflict graph (initial)." - $$ Color.dotGraph regDotColor trivColorable (raGraph s) - $$ text "" +-- $$ text "# Register conflict graph (initial)." +-- $$ Color.dotGraph regDotColor trivColorable (raGraph s) +-- $$ text "" - $$ text "# Register conflict graph (colored)." - $$ Color.dotGraph regDotColor trivColorable (raGraphColored s) - $$ text "" +-- $$ text "# Register conflict graph (colored)." +-- $$ Color.dotGraph regDotColor trivColorable (raGraphColored s) +-- $$ text "" $$ (if (not $ isNullUFM $ raCoalesced s) then text "# Registers coalesced." @@ -133,7 +132,7 @@ instance Outputable RegAllocStats where $$ text "" -- | Do all the different analysis on this list of RegAllocStats -pprStats :: [RegAllocStats] -> Color.Graph Reg RegClass Reg -> SDoc +pprStats :: [RegAllocStats instr] -> Color.Graph Reg RegClass Reg -> SDoc pprStats stats graph = let outSpills = pprStatsSpills stats outLife = pprStatsLifetimes stats @@ -145,7 +144,7 @@ pprStats stats graph -- | Dump a table of how many spill loads \/ stores were inserted for each vreg. pprStatsSpills - :: [RegAllocStats] -> SDoc + :: [RegAllocStats instr] -> SDoc pprStatsSpills stats = let @@ -163,7 +162,7 @@ pprStatsSpills stats -- | Dump a table of how long vregs tend to live for in the initial code. pprStatsLifetimes - :: [RegAllocStats] -> SDoc + :: [RegAllocStats instr] -> SDoc pprStatsLifetimes stats = let info = foldl' plusSpillCostInfo zeroSpillCostInfo @@ -191,7 +190,7 @@ binLifetimeCount fm -- | Dump a table of how many conflicts vregs tend to have in the initial code. pprStatsConflict - :: [RegAllocStats] -> SDoc + :: [RegAllocStats instr] -> SDoc pprStatsConflict stats = let confMap = foldl' (plusUFM_C (\(c1, n1) (_, n2) -> (c1, n1 + n2))) @@ -208,7 +207,7 @@ pprStatsConflict stats -- | For every vreg, dump it's how many conflicts it has and its lifetime -- good for making a scatter plot. pprStatsLifeConflict - :: [RegAllocStats] + :: [RegAllocStats instr] -> Color.Graph Reg RegClass Reg -- ^ global register conflict graph -> SDoc @@ -238,7 +237,10 @@ pprStatsLifeConflict stats graph -- | Count spill/reload/reg-reg moves. -- Lets us see how well the register allocator has done. -- -countSRMs :: LiveCmmTop -> (Int, Int, Int) +countSRMs + :: Instruction instr + => LiveCmmTop instr -> (Int, Int, Int) + countSRMs cmm = execState (mapBlockTopM countSRM_block cmm) (0, 0, 0) @@ -246,16 +248,17 @@ countSRM_block (BasicBlock i instrs) = do instrs' <- mapM countSRM_instr instrs return $ BasicBlock i instrs' -countSRM_instr li@(Instr instr _) - | SPILL _ _ <- instr +countSRM_instr li + | SPILL _ _ <- li = do modify $ \(s, r, m) -> (s + 1, r, m) return li - | RELOAD _ _ <- instr + | RELOAD _ _ <- li = do modify $ \(s, r, m) -> (s, r + 1, m) return li - | Just _ <- isRegRegMove instr + | Instr instr _ <- li + , Just _ <- takeRegRegMoveInstr instr = do modify $ \(s, r, m) -> (s, r, m + 1) return li @@ -266,77 +269,9 @@ countSRM_instr li@(Instr instr _) addSRM (s1, r1, m1) (s2, r2, m2) = (s1+s2, r1+r2, m1+m2) ------ --- Register colors for drawing conflict graphs --- Keep this out of MachRegs.hs because it's specific to the graph coloring allocator. - - --- reg colors for x86 -#if i386_TARGET_ARCH -regDotColor :: Reg -> SDoc -regDotColor reg - = let Just str = lookupUFM regColors reg - in text str - -regColors - = listToUFM - $ [ (eax, "#00ff00") - , (ebx, "#0000ff") - , (ecx, "#00ffff") - , (edx, "#0080ff") - - , (fake0, "#ff00ff") - , (fake1, "#ff00aa") - , (fake2, "#aa00ff") - , (fake3, "#aa00aa") - , (fake4, "#ff0055") - , (fake5, "#5500ff") ] - - --- reg colors for x86_64 -#elif x86_64_TARGET_ARCH -regDotColor :: Reg -> SDoc -regDotColor reg - = let Just str = lookupUFM regColors reg - in text str - -regColors - = listToUFM - $ [ (rax, "#00ff00"), (eax, "#00ff00") - , (rbx, "#0000ff"), (ebx, "#0000ff") - , (rcx, "#00ffff"), (ecx, "#00ffff") - , (rdx, "#0080ff"), (edx, "#00ffff") - , (r8, "#00ff80") - , (r9, "#008080") - , (r10, "#0040ff") - , (r11, "#00ff40") - , (r12, "#008040") - , (r13, "#004080") - , (r14, "#004040") - , (r15, "#002080") ] - - ++ zip (map RealReg [16..31]) (repeat "red") - - --- reg colors for ppc -#elif powerpc_TARGET_ARCH -regDotColor :: Reg -> SDoc -regDotColor reg - = case regClass reg of - RcInteger -> text "blue" - RcFloat -> text "red" - RcDouble -> text "green" - -#elif sparc_TARGET_ARCH -regDotColor :: Reg -> SDoc -regDotColor reg - = case regClass reg of - RcInteger -> text "blue" - RcFloat -> text "red" - RcDouble -> text "green" -#else -#error ToDo: regDotColor -#endif + + + {- diff --git a/compiler/nativeGen/RegAlloc/Graph/TrivColorable.hs b/compiler/nativeGen/RegAlloc/Graph/TrivColorable.hs new file mode 100644 index 0000000000..6a7211dd06 --- /dev/null +++ b/compiler/nativeGen/RegAlloc/Graph/TrivColorable.hs @@ -0,0 +1,176 @@ + +module RegAlloc.Graph.TrivColorable ( + trivColorable, +) + +where + +#include "HsVersions.h" + +import RegClass +import Reg + +import GraphBase + +import UniqFM +import FastTypes + +{- +-- allocatableRegs is allMachRegNos with the fixed-use regs removed. +-- i.e., these are the regs for which we are prepared to allow the +-- register allocator to attempt to map VRegs to. +allocatableRegs :: [RegNo] +allocatableRegs + = let isFree i = isFastTrue (freeReg i) + in filter isFree allMachRegNos + + +-- | The number of regs in each class. +-- We go via top level CAFs to ensure that we're not recomputing +-- the length of these lists each time the fn is called. +allocatableRegsInClass :: RegClass -> Int +allocatableRegsInClass cls + = case cls of + RcInteger -> allocatableRegsInteger + RcDouble -> allocatableRegsDouble + RcFloat -> panic "Regs.allocatableRegsInClass: no match\n" + +allocatableRegsInteger :: Int +allocatableRegsInteger + = length $ filter (\r -> regClass r == RcInteger) + $ map RealReg allocatableRegs + +allocatableRegsDouble :: Int +allocatableRegsDouble + = length $ filter (\r -> regClass r == RcDouble) + $ map RealReg allocatableRegs +-} + + +-- trivColorable --------------------------------------------------------------- + +-- trivColorable function for the graph coloring allocator +-- This gets hammered by scanGraph during register allocation, +-- so needs to be fairly efficient. +-- +-- NOTE: This only works for arcitectures with just RcInteger and RcDouble +-- (which are disjoint) ie. x86, x86_64 and ppc +-- + +-- BL 2007/09 +-- Doing a nice fold over the UniqSet makes trivColorable use +-- 32% of total compile time and 42% of total alloc when compiling SHA1.lhs from darcs. +{- +trivColorable :: RegClass -> UniqSet Reg -> UniqSet Reg -> Bool +trivColorable classN conflicts exclusions + = let + + acc :: Reg -> (Int, Int) -> (Int, Int) + acc r (cd, cf) + = case regClass r of + RcInteger -> (cd+1, cf) + RcDouble -> (cd, cf+1) + _ -> panic "Regs.trivColorable: reg class not handled" + + tmp = foldUniqSet acc (0, 0) conflicts + (countInt, countFloat) = foldUniqSet acc tmp exclusions + + squeese = worst countInt classN RcInteger + + worst countFloat classN RcDouble + + in squeese < allocatableRegsInClass classN + +-- | Worst case displacement +-- node N of classN has n neighbors of class C. +-- +-- We currently only have RcInteger and RcDouble, which don't conflict at all. +-- This is a bit boring compared to what's in RegArchX86. +-- +worst :: Int -> RegClass -> RegClass -> Int +worst n classN classC + = case classN of + RcInteger + -> case classC of + RcInteger -> min n (allocatableRegsInClass RcInteger) + RcDouble -> 0 + + RcDouble + -> case classC of + RcDouble -> min n (allocatableRegsInClass RcDouble) + RcInteger -> 0 +-} + + +-- The number of allocatable regs is hard coded here so we can do a fast comparision +-- in trivColorable. It's ok if these numbers are _less_ than the actual number of +-- free regs, but they can't be more or the register conflict graph won't color. +-- +-- There is an allocatableRegsInClass :: RegClass -> Int, but doing the unboxing +-- is too slow for us here. +-- +-- Compare Regs.freeRegs and MachRegs.h to get these numbers. +-- +#if i386_TARGET_ARCH +#define ALLOCATABLE_REGS_INTEGER (_ILIT(3)) +#define ALLOCATABLE_REGS_DOUBLE (_ILIT(6)) +#define ALLOCATABLE_REGS_FLOAT (_ILIT(0)) + +#elif x86_64_TARGET_ARCH +#define ALLOCATABLE_REGS_INTEGER (_ILIT(5)) +#define ALLOCATABLE_REGS_DOUBLE (_ILIT(2)) +#define ALLOCATABLE_REGS_FLOAT (_ILIT(0)) + +#elif powerpc_TARGET_ARCH +#define ALLOCATABLE_REGS_INTEGER (_ILIT(16)) +#define ALLOCATABLE_REGS_DOUBLE (_ILIT(26)) +#define ALLOCATABLE_REGS_FLOAT (_ILIT(0)) + +#elif sparc_TARGET_ARCH +#define ALLOCATABLE_REGS_INTEGER (_ILIT(3)) +#define ALLOCATABLE_REGS_DOUBLE (_ILIT(6)) +#define ALLOCATABLE_REGS_FLOAT (_ILIT(0)) + +#else +#error ToDo: define ALLOCATABLE_REGS_INTEGER and ALLOCATABLE_REGS_DOUBLE +#endif + +trivColorable + :: (Reg -> RegClass) + -> Triv Reg RegClass Reg + +trivColorable regClass _ conflicts exclusions + = {-# SCC "trivColorable" #-} + let + isSqueesed cI cF ufm + = case ufm of + NodeUFM _ _ left right + -> case isSqueesed cI cF right of + (# s, cI', cF' #) + -> case s of + False -> isSqueesed cI' cF' left + True -> (# True, cI', cF' #) + + LeafUFM _ reg + -> case regClass reg of + RcInteger + -> case cI +# _ILIT(1) of + cI' -> (# cI' >=# ALLOCATABLE_REGS_INTEGER, cI', cF #) + + RcDouble + -> case cF +# _ILIT(1) of + cF' -> (# cF' >=# ALLOCATABLE_REGS_DOUBLE, cI, cF' #) + + RcFloat + -> case cF +# _ILIT(1) of + cF' -> (# cF' >=# ALLOCATABLE_REGS_FLOAT, cI, cF' #) + + EmptyUFM + -> (# False, cI, cF #) + + in case isSqueesed (_ILIT(0)) (_ILIT(0)) conflicts of + (# False, cI', cF' #) + -> case isSqueesed cI' cF' exclusions of + (# s, _, _ #) -> not s + + (# True, _, _ #) + -> False |
