2 % (c) The AQUA Project, Glasgow University, 1993-1996
4 \section[AsmRegAlloc]{Register allocator}
7 module AsmRegAlloc ( runRegAllocate, runHairyRegAllocate ) where
9 #include "HsVersions.h"
11 import MachCode ( InstrList )
12 import MachMisc ( Instr )
16 import AbsCSyn ( MagicId )
17 import BitSet ( BitSet )
18 import FiniteMap ( emptyFM, addListToFM, delListFromFM, lookupFM, keysFM )
19 import Maybes ( maybeToBool )
20 import OrdList ( mkEmptyList, mkUnitList, mkSeqList, mkParList,
21 flattenOrdList, OrdList
23 import Stix ( StixTree )
24 import Unique ( mkBuiltinUnique )
25 import Util ( mapAccumB, panic )
26 import GlaExts ( trace )
30 This is the generic register allocator.
32 First we try something extremely simple. If that fails, we have to do
42 runRegAllocate regs reserve_regs instrs
47 flatInstrs = flattenOrdList instrs
48 simpleAlloc = simpleRegAlloc regs [] emptyFM flatInstrs
49 hairyAlloc = hairyRegAlloc regs reserve_regs flatInstrs
51 runHairyRegAllocate -- use only hairy for i386!
57 runHairyRegAllocate regs reserve_regs instrs
58 = hairyRegAlloc regs reserve_regs flatInstrs
60 flatInstrs = flattenOrdList instrs
63 Here is the simple register allocator. Just dole out registers until
64 we run out, or until one gets clobbered before its last use. Don't
65 do anything fancy with branches. Just pretend that you've got a block
66 of straight-line code and hope for the best. Experience indicates that
67 this approach will suffice for about 96 percent of the code blocks that
72 :: MRegsState -- registers to select from
73 -> [Reg] -- live static registers
74 -> RegAssignment -- mapping of dynamics to statics
78 simpleRegAlloc _ _ _ [] = Just []
80 simpleRegAlloc free live env (instr:instrs)
82 maybeToBool newAlloc &&
84 = Just (instr3 : instrs3)
88 instr3 = patchRegs instr (lookup env2)
90 (srcs, dsts) = case regUsage instr of (RU s d) -> (regSetToList s, regSetToList d)
92 lookup env x = case lookupFM env x of Just y -> y; Nothing -> x
94 deadSrcs = [r | r@(UnmappedReg _ _) <- srcs, lookup env r `not_elem` live]
95 newDsts = [r | r@(UnmappedReg _ _) <- dsts, r `not_elem` keysFM env]
97 newAlloc = foldr allocateNewReg (Just (free, [])) newDsts
98 (free2, new) = case newAlloc of Just x -> x
100 env2 = env `addListToFM` new
102 live2 = map snd new ++ [x | x <- live, x `not_elem` dsts]
104 instrs2 = simpleRegAlloc free2 live2 env2 instrs
105 instrs3 = case instrs2 of Just x -> x
109 -> Maybe (MRegsState, [(Reg, Reg)])
110 -> Maybe (MRegsState, [(Reg, Reg)])
112 allocateNewReg _ Nothing = Nothing
114 allocateNewReg d@(UnmappedReg _ pk) (Just (free, prs))
115 | null choices = Nothing
116 | otherwise = Just (free2, prs2)
118 choices = possibleMRegs pk free
120 free2 = free `useMReg` (case reg of {IBOX(reg2) -> reg2} )
121 prs2 = ((d, MappedReg (case reg of {IBOX(reg2) -> reg2})) : prs)
124 Here is the ``clever'' bit. First go backward (i.e. left), looking for
125 the last use of dynamic registers. Then go forward (i.e. right), filling
126 registers with static placements.
135 hairyRegAlloc regs reserve_regs instrs =
136 case mapAccumB (doRegAlloc reserve_regs) (RH regs' 1 emptyFM) noFuture instrs of
137 (RH _ mloc1 _, _, instrs')
138 | mloc1 == 1 -> instrs'
141 instrs_patched' = patchMem instrs'
142 instrs_patched = flattenOrdList instrs_patched'
144 case mapAccumB do_RegAlloc_Nil (RH regs'' mloc1 emptyFM) noFuture instrs_patched of
145 ((RH _ mloc2 _),_,instrs'')
146 | mloc2 == mloc1 -> instrs''
147 | otherwise -> instrs''
148 --pprPanic "runRegAllocate" (ppr mloc2 <+> ppr mloc1)
150 regs' = regs `useMRegs` reserve_regs
151 regs'' = mkMRegsState reserve_regs
153 do_RegAlloc_Nil = doRegAlloc [] -- out here to avoid CAF (sigh)
155 :: RegHistory MRegsState
158 -> (RegHistory MRegsState, RegFuture, Instr)
160 noFuture :: RegFuture
161 noFuture = RF emptyRegSet (FL emptyRegSet emptyFM) emptyFM
164 Here we patch instructions that reference ``registers'' which are really in
165 memory somewhere (the mapping is under the control of the machine-specific
166 code generator). We place the appropriate load sequences before any instructions
167 that use memory registers as sources, and we place the appropriate spill sequences
168 after any instructions that use memory registers as destinations. The offending
169 instructions are rewritten with new dynamic registers, so we have to run register
170 allocation again after all of this is said and done.
173 patchMem :: [Instr] -> InstrList
175 patchMem cs = foldr (mkSeqList . patchMem') mkEmptyList cs
177 patchMem' :: Instr -> InstrList
180 | null memSrcs && null memDsts = mkUnitList instr
183 (foldr mkParList mkEmptyList loadSrcs)
185 (foldr mkParList mkEmptyList spillDsts))
188 (RU srcs dsts) = regUsage instr
190 memToDyn (MemoryReg i pk) = UnmappedReg (mkBuiltinUnique i) pk
191 memToDyn other = other
193 memSrcs = [ r | r@(MemoryReg _ _) <- regSetToList srcs]
194 memDsts = [ r | r@(MemoryReg _ _) <- regSetToList dsts]
196 loadSrcs = map load memSrcs
197 spillDsts = map spill memDsts
199 load mem = loadReg mem (memToDyn mem)
200 spill mem = spillReg (memToDyn mem) mem
202 instr' = mkUnitList (patchRegs instr memToDyn)
208 -> RegHistory MRegsState
211 -> (RegHistory MRegsState, RegFuture, Instr)
213 doRegAlloc reserved_regs free_env in_use instr = (free_env', in_use', instr')
215 (free_env', instr') = doRegAlloc' reserved_regs free_env info instr
216 (in_use', info) = getUsage in_use instr
223 -> (RegFuture, RegInfo Instr)
225 getUsage (RF next_in_use future reg_conflicts) instr
226 = (RF in_use' future' reg_conflicts',
227 RI in_use' srcs dsts last_used reg_conflicts')
228 where (RU srcs dsts) = regUsage instr
229 (RL in_use future') = regLiveness instr (RL next_in_use future)
230 live_through = in_use `minusRegSet` dsts
231 last_used = [ r | r <- regSetToList srcs,
232 not (r `elementOfRegSet` (fstFL future) || r `elementOfRegSet` in_use)]
234 in_use' = srcs `unionRegSets` live_through
237 case new_conflicts of
239 _ -> addListToFM reg_conflicts new_conflicts
242 | isEmptyRegSet live_dynamics = []
244 [ (r, merge_conflicts r)
245 | r <- extractMappedRegNos (regSetToList dsts) ]
247 merge_conflicts reg =
248 case lookupFM reg_conflicts reg of
249 Nothing -> live_dynamics
250 Just conflicts -> conflicts `unionRegSets` live_dynamics
252 live_dynamics = mkRegSet [ r | r@(UnmappedReg _ _) <- regSetToList live_through ]
256 -> RegHistory MRegsState
259 -> (RegHistory MRegsState, Instr)
261 doRegAlloc' reserved (RH frs loc env) (RI in_use srcs dsts lastu conflicts) instr =
263 (RH frs'' loc' env'', patchRegs instr dynToStatic)
267 -- free up new registers
269 free = extractMappedRegNos (map dynToStatic lastu)
271 -- (1) free registers that are used last as source operands in this instruction
272 frs_not_in_use = frs `useMRegs` (extractMappedRegNos (regSetToList in_use))
273 frs' = (frs_not_in_use `freeMRegs` free) `useMRegs` reserved
275 -- (2) allocate new registers for the destination operands
276 -- allocate registers for new dynamics
278 new_dynamix = [ r | r@(UnmappedReg _ _) <- regSetToList dsts, r `not_elem` keysFM env ]
280 (frs'', loc', new) = foldr allocateNewRegs (frs', loc, []) new_dynamix
282 env' = addListToFM env new
284 env'' = delListFromFM env' lastu
286 dynToStatic :: Reg -> Reg
287 dynToStatic dyn@(UnmappedReg _ _) =
288 case lookupFM env' dyn of
290 Nothing -> trace "Lost register; possibly a floating point type error in a _ccall_?" dyn
291 dynToStatic other = other
293 allocateNewRegs :: Reg
294 -> (MRegsState, Int, [(Reg, Reg)])
295 -> (MRegsState, Int, [(Reg, Reg)])
297 allocateNewRegs d@(UnmappedReg _ pk) (fs, mem, lst) = (fs', mem', (d, f) : lst)
300 case acceptable fs of
301 [] -> (fs, MemoryReg mem pk, mem + 1)
302 (IBOX(x2):_) -> (fs `useMReg` x2, MappedReg x2, mem)
304 acceptable regs = filter no_conflict (possibleMRegs pk regs)
307 case lookupFM conflicts reg of
309 Just conflicts -> not (d `elementOfRegSet` conflicts)
312 We keep a local copy of the Prelude function \tr{notElem},
313 so that it can be specialised. (Hack me gently. [WDP 94/11])
316 not_elem x (y:ys) = x /= y && not_elem x ys