2 module RegAlloc.Graph.SpillCost (
14 lifeMapFromSpillCostInfo
19 import RegAlloc.Liveness
30 import Digraph (flattenSCCs)
34 import Data.List (nub, minimumBy)
38 = ( VirtualReg -- register name
39 , Int -- number of writes to this reg
40 , Int -- number of reads from this reg
41 , Int) -- number of instrs this reg was live on entry to
44 = UniqFM SpillCostRecord
47 zeroSpillCostInfo :: SpillCostInfo
48 zeroSpillCostInfo = emptyUFM
50 -- | Add two spillCostInfos
51 plusSpillCostInfo :: SpillCostInfo -> SpillCostInfo -> SpillCostInfo
52 plusSpillCostInfo sc1 sc2
53 = plusUFM_C plusSpillCostRecord sc1 sc2
55 plusSpillCostRecord :: SpillCostRecord -> SpillCostRecord -> SpillCostRecord
56 plusSpillCostRecord (r1, a1, b1, c1) (r2, a2, b2, c2)
57 | r1 == r2 = (r1, a1 + a2, b1 + b2, c1 + c2)
58 | otherwise = error "RegSpillCost.plusRegInt: regs don't match"
61 -- | Slurp out information used for determining spill costs
62 -- for each vreg, the number of times it was written to, read from,
63 -- and the number of instructions it was live on entry to (lifetime)
66 :: (Outputable instr, Instruction instr)
70 slurpSpillCostInfo cmm
71 = execState (countCmm cmm) zeroSpillCostInfo
73 countCmm CmmData{} = return ()
74 countCmm (CmmProc info _ _ sccs)
75 = mapM_ (countBlock info)
78 -- lookup the regs that are live on entry to this block in
79 -- the info table from the CmmProc
80 countBlock info (BasicBlock blockId instrs)
81 | LiveInfo _ _ (Just blockLive) <- info
82 , Just rsLiveEntry <- lookupBlockEnv blockLive blockId
84 , rsLiveEntry_virt <- mapUniqSet (\(RegVirtual vr) -> vr)
85 $ filterUniqSet isVirtualReg rsLiveEntry
87 = countLIs rsLiveEntry_virt instrs
90 = error "RegAlloc.SpillCost.slurpSpillCostInfo: bad block"
95 -- skip over comment and delta pseudo instrs
96 countLIs rsLive (SPILL{} : lis)
99 countLIs rsLive (RELOAD{} : lis)
100 = countLIs rsLive lis
102 countLIs rsLive (Instr instr Nothing : lis)
104 = countLIs rsLive lis
107 = pprPanic "RegSpillCost.slurpSpillCostInfo"
108 (text "no liveness information on instruction " <> ppr instr)
110 countLIs rsLiveEntry (Instr instr (Just live) : lis)
112 -- increment the lifetime counts for regs live on entry to this instr
113 mapM_ incLifetime $ uniqSetToList rsLiveEntry
115 -- increment counts for what regs were read/written from
116 let (RU read written) = regUsageOfInstr instr
117 mapM_ incUses $ catMaybes $ map takeVirtualReg $ nub read
118 mapM_ incDefs $ catMaybes $ map takeVirtualReg $ nub written
120 -- compute liveness for entry to next instruction.
122 = mapUniqSet (\(RegVirtual vr) -> vr)
123 $ filterUniqSet isVirtualReg set
125 let liveDieRead_virt = takeVirtuals (liveDieRead live)
126 let liveDieWrite_virt = takeVirtuals (liveDieWrite live)
127 let liveBorn_virt = takeVirtuals (liveBorn live)
130 = rsLiveEntry `minusUniqSet` liveDieRead_virt
133 = (rsLiveAcross `unionUniqSets` liveBorn_virt)
134 `minusUniqSet` liveDieWrite_virt
136 countLIs rsLiveNext lis
138 incDefs reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 1, 0, 0)
139 incUses reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 1, 0)
140 incLifetime reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 0, 1)
143 -- | Choose a node to spill from this graph
147 -> Graph VirtualReg RegClass RealReg
150 chooseSpill info graph
151 = let cost = spillCost_length info graph
152 node = minimumBy (\n1 n2 -> compare (cost $ nodeId n1) (cost $ nodeId n2))
153 $ eltsUFM $ graphMap graph
159 -- | Chaitins spill cost function is:
161 -- cost = sum loadCost * freq (u) + sum storeCost * freq (d)
162 -- u <- uses (v) d <- defs (v)
164 -- There are no loops in our code at the momemnt, so we can set the freq's to 1
165 -- We divide this by the degree if t
168 -- If we don't have live range splitting then Chaitins function performs badly if we have
169 -- lots of nested live ranges and very few registers.
182 -- defs uses degree cost
187 -- v3 has the lowest cost, but if we only have 2 hardregs and we insert spill code for v3
188 -- then this isn't going to improve the colorability of the graph.
190 -- When compiling SHA1, which as very long basic blocks and some vregs with very long live ranges
191 -- the allocator seems to try and spill from the inside out and eventually run out of stack slots.
193 -- Without live range splitting, its's better to spill from the outside in so set the cost of very
194 -- long live ranges to zero
199 -> Graph Reg RegClass Reg
203 spillCost_chaitin info graph reg
204 -- Spilling a live range that only lives for 1 instruction isn't going to help
205 -- us at all - and we definately want to avoid trying to re-spill previously
206 -- inserted spill code.
207 | lifetime <= 1 = 1/0
209 -- It's unlikely that we'll find a reg for a live range this long
210 -- better to spill it straight up and not risk trying to keep it around
211 -- and have to go through the build/color cycle again.
212 | lifetime > allocatableRegsInClass (regClass reg) * 10
215 -- otherwise revert to chaitin's regular cost function.
216 | otherwise = fromIntegral (uses + defs) / fromIntegral (nodeDegree graph reg)
217 where (_, defs, uses, lifetime)
218 = fromMaybe (reg, 0, 0, 0) $ lookupUFM info reg
221 -- Just spill the longest live range.
224 -> Graph VirtualReg RegClass RealReg
228 spillCost_length info _ reg
229 | lifetime <= 1 = 1/0
230 | otherwise = 1 / fromIntegral lifetime
231 where (_, _, _, lifetime)
232 = fromMaybe (reg, 0, 0, 0)
237 lifeMapFromSpillCostInfo :: SpillCostInfo -> UniqFM (VirtualReg, Int)
238 lifeMapFromSpillCostInfo info
240 $ map (\(r, _, _, life) -> (r, (r, life)))
244 -- | Work out the degree (number of neighbors) of this node which have the same class.
246 :: (VirtualReg -> RegClass)
247 -> Graph VirtualReg RegClass RealReg
251 nodeDegree classOfVirtualReg graph reg
252 | Just node <- lookupUFM (graphMap graph) reg
254 , virtConflicts <- length
255 $ filter (\r -> classOfVirtualReg r == classOfVirtualReg reg)
259 = virtConflicts + sizeUniqSet (nodeExclusions node)
265 -- | Show a spill cost record, including the degree from the graph and final calulated spill cos
267 :: (VirtualReg -> RegClass)
269 -> Graph VirtualReg RegClass RealReg
273 pprSpillCostRecord regClass pprReg graph (reg, uses, defs, life)
275 [ pprReg (RegVirtual reg)
279 , ppr $ nodeDegree regClass graph reg
280 , text $ show $ (fromIntegral (uses + defs)
281 / fromIntegral (nodeDegree regClass graph reg) :: Float) ]