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, trace )
29 This is the generic register allocator.
31 First we try something extremely simple. If that fails, we have to do
41 runRegAllocate regs reserve_regs instrs
46 flatInstrs = flattenOrdList instrs
47 simpleAlloc = simpleRegAlloc regs [] emptyFM flatInstrs
48 hairyAlloc = hairyRegAlloc regs reserve_regs flatInstrs
50 runHairyRegAllocate -- use only hairy for i386!
56 runHairyRegAllocate regs reserve_regs instrs
57 = hairyRegAlloc regs reserve_regs flatInstrs
59 flatInstrs = flattenOrdList instrs
62 Here is the simple register allocator. Just dole out registers until
63 we run out, or until one gets clobbered before its last use. Don't
64 do anything fancy with branches. Just pretend that you've got a block
65 of straight-line code and hope for the best. Experience indicates that
66 this approach will suffice for about 96 percent of the code blocks that
71 :: MRegsState -- registers to select from
72 -> [Reg] -- live static registers
73 -> RegAssignment -- mapping of dynamics to statics
77 simpleRegAlloc _ _ _ [] = Just []
79 simpleRegAlloc free live env (instr:instrs)
81 maybeToBool newAlloc &&
83 = Just (instr3 : instrs3)
87 instr3 = patchRegs instr (lookup env2)
89 (srcs, dsts) = case regUsage instr of (RU s d) -> (regSetToList s, regSetToList d)
91 lookup env x = case lookupFM env x of Just y -> y; Nothing -> x
93 deadSrcs = [r | r@(UnmappedReg _ _) <- srcs, lookup env r `not_elem` live]
94 newDsts = [r | r@(UnmappedReg _ _) <- dsts, r `not_elem` keysFM env]
96 newAlloc = foldr allocateNewReg (Just (free, [])) newDsts
97 (free2, new) = case newAlloc of Just x -> x
99 env2 = env `addListToFM` new
101 live2 = map snd new ++ [x | x <- live, x `not_elem` dsts]
103 instrs2 = simpleRegAlloc free2 live2 env2 instrs
104 instrs3 = case instrs2 of Just x -> x
108 -> Maybe (MRegsState, [(Reg, Reg)])
109 -> Maybe (MRegsState, [(Reg, Reg)])
111 allocateNewReg _ Nothing = Nothing
113 allocateNewReg d@(UnmappedReg _ pk) (Just (free, prs))
114 | null choices = Nothing
115 | otherwise = Just (free2, prs2)
117 choices = possibleMRegs pk free
119 free2 = free `useMReg` (case reg of {IBOX(reg2) -> reg2} )
120 prs2 = ((d, MappedReg (case reg of {IBOX(reg2) -> reg2})) : prs)
123 Here is the ``clever'' bit. First go backward (i.e. left), looking for
124 the last use of dynamic registers. Then go forward (i.e. right), filling
125 registers with static placements.
134 hairyRegAlloc regs reserve_regs instrs =
135 case mapAccumB (doRegAlloc reserve_regs) (RH regs' 1 emptyFM) noFuture instrs of
136 (RH _ mloc1 _, _, instrs')
137 | mloc1 == 1 -> instrs'
140 instrs_patched' = patchMem instrs'
141 instrs_patched = flattenOrdList instrs_patched'
143 case mapAccumB do_RegAlloc_Nil (RH regs'' mloc1 emptyFM) noFuture instrs_patched of
144 ((RH _ mloc2 _),_,instrs'')
145 | mloc2 == mloc1 -> instrs''
146 | otherwise -> instrs''
147 --pprPanic "runRegAllocate" (ppr mloc2 <+> ppr mloc1)
149 regs' = regs `useMRegs` reserve_regs
150 regs'' = mkMRegsState reserve_regs
152 do_RegAlloc_Nil = doRegAlloc [] -- out here to avoid CAF (sigh)
154 :: RegHistory MRegsState
157 -> (RegHistory MRegsState, RegFuture, Instr)
159 noFuture :: RegFuture
160 noFuture = RF emptyRegSet (FL emptyRegSet emptyFM) emptyFM
163 Here we patch instructions that reference ``registers'' which are really in
164 memory somewhere (the mapping is under the control of the machine-specific
165 code generator). We place the appropriate load sequences before any instructions
166 that use memory registers as sources, and we place the appropriate spill sequences
167 after any instructions that use memory registers as destinations. The offending
168 instructions are rewritten with new dynamic registers, so we have to run register
169 allocation again after all of this is said and done.
172 patchMem :: [Instr] -> InstrList
174 patchMem cs = foldr (mkSeqList . patchMem') mkEmptyList cs
176 patchMem' :: Instr -> InstrList
179 | null memSrcs && null memDsts = mkUnitList instr
182 (foldr mkParList mkEmptyList loadSrcs)
184 (foldr mkParList mkEmptyList spillDsts))
187 (RU srcs dsts) = regUsage instr
189 memToDyn (MemoryReg i pk) = UnmappedReg (mkBuiltinUnique i) pk
190 memToDyn other = other
192 memSrcs = [ r | r@(MemoryReg _ _) <- regSetToList srcs]
193 memDsts = [ r | r@(MemoryReg _ _) <- regSetToList dsts]
195 loadSrcs = map load memSrcs
196 spillDsts = map spill memDsts
198 load mem = loadReg mem (memToDyn mem)
199 spill mem = spillReg (memToDyn mem) mem
201 instr' = mkUnitList (patchRegs instr memToDyn)
207 -> RegHistory MRegsState
210 -> (RegHistory MRegsState, RegFuture, Instr)
212 doRegAlloc reserved_regs free_env in_use instr = (free_env', in_use', instr')
214 (free_env', instr') = doRegAlloc' reserved_regs free_env info instr
215 (in_use', info) = getUsage in_use instr
222 -> (RegFuture, RegInfo Instr)
224 getUsage (RF next_in_use future reg_conflicts) instr
225 = (RF in_use' future' reg_conflicts',
226 RI in_use' srcs dsts last_used reg_conflicts')
227 where (RU srcs dsts) = regUsage instr
228 (RL in_use future') = regLiveness instr (RL next_in_use future)
229 live_through = in_use `minusRegSet` dsts
230 last_used = [ r | r <- regSetToList srcs,
231 not (r `elementOfRegSet` (fstFL future) || r `elementOfRegSet` in_use)]
233 in_use' = srcs `unionRegSets` live_through
236 case new_conflicts of
238 _ -> addListToFM reg_conflicts new_conflicts
241 | isEmptyRegSet live_dynamics = []
243 [ (r, merge_conflicts r)
244 | r <- extractMappedRegNos (regSetToList dsts) ]
246 merge_conflicts reg =
247 case lookupFM reg_conflicts reg of
248 Nothing -> live_dynamics
249 Just conflicts -> conflicts `unionRegSets` live_dynamics
251 live_dynamics = mkRegSet [ r | r@(UnmappedReg _ _) <- regSetToList live_through ]
255 -> RegHistory MRegsState
258 -> (RegHistory MRegsState, Instr)
260 doRegAlloc' reserved (RH frs loc env) (RI in_use srcs dsts lastu conflicts) instr =
262 (RH frs'' loc' env'', patchRegs instr dynToStatic)
266 -- free up new registers
268 free = extractMappedRegNos (map dynToStatic lastu)
270 -- (1) free registers that are used last as source operands in this instruction
271 frs_not_in_use = frs `useMRegs` (extractMappedRegNos (regSetToList in_use))
272 frs' = (frs_not_in_use `freeMRegs` free) `useMRegs` reserved
274 -- (2) allocate new registers for the destination operands
275 -- allocate registers for new dynamics
277 new_dynamix = [ r | r@(UnmappedReg _ _) <- regSetToList dsts, r `not_elem` keysFM env ]
279 (frs'', loc', new) = foldr allocateNewRegs (frs', loc, []) new_dynamix
281 env' = addListToFM env new
283 env'' = delListFromFM env' lastu
285 dynToStatic :: Reg -> Reg
286 dynToStatic dyn@(UnmappedReg _ _) =
287 case lookupFM env' dyn of
289 Nothing -> trace "Lost register; possibly a floating point type error in a _ccall_?" dyn
290 dynToStatic other = other
292 allocateNewRegs :: Reg
293 -> (MRegsState, Int, [(Reg, Reg)])
294 -> (MRegsState, Int, [(Reg, Reg)])
296 allocateNewRegs d@(UnmappedReg _ pk) (fs, mem, lst) = (fs', mem', (d, f) : lst)
299 case acceptable fs of
300 [] -> (fs, MemoryReg mem pk, mem + 1)
301 (IBOX(x2):_) -> (fs `useMReg` x2, MappedReg x2, mem)
303 acceptable regs = filter no_conflict (possibleMRegs pk regs)
306 case lookupFM conflicts reg of
308 Just conflicts -> not (d `elementOfRegSet` conflicts)
311 We keep a local copy of the Prelude function \tr{notElem},
312 so that it can be specialised. (Hack me gently. [WDP 94/11])
315 not_elem x (y:ys) = x /= y && not_elem x ys