2 % (c) The AQUA Project, Glasgow University, 1993-1998
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 FiniteMap ( emptyFM, addListToFM, delListFromFM, lookupFM, keysFM )
17 import Maybes ( maybeToBool )
18 import OrdList ( mkEmptyList, mkUnitList, mkSeqList, mkParList,
19 flattenOrdList, OrdList
21 import Unique ( mkBuiltinUnique )
22 import Util ( mapAccumB )
26 This is the generic register allocator.
28 First we try something extremely simple. If that fails, we have to do
34 -> ([Instr] -> [[RegNo]])
38 runRegAllocate regs find_reserve_regs instrs
41 Nothing -> tryHairy reserves
44 = error "nativeGen: register allocator: too difficult! Try -fvia-C.\n"
46 = case hairyAlloc resv of
47 Just success -> success
48 Nothing -> fooble resvs (tryHairy resvs)
51 fooble (resvs:_) x = trace ("nativeGen: spilling with "
52 ++ show (length resvs - 2) ++
55 reserves = find_reserve_regs flatInstrs
56 flatInstrs = flattenOrdList instrs
57 simpleAlloc = simpleRegAlloc regs [] emptyFM flatInstrs
58 hairyAlloc resvd = hairyRegAlloc regs resvd flatInstrs
67 runHairyRegAllocate regs reserve_regs instrs
68 = hairyRegAlloc regs reserve_regs flatInstrs
70 flatInstrs = flattenOrdList instrs
73 Here is the simple register allocator. Just dole out registers until
74 we run out, or until one gets clobbered before its last use. Don't
75 do anything fancy with branches. Just pretend that you've got a block
76 of straight-line code and hope for the best. Experience indicates that
77 this approach will suffice for about 96 percent of the code blocks that
82 :: MRegsState -- registers to select from
83 -> [Reg] -- live static registers
84 -> RegAssignment -- mapping of dynamics to statics
88 simpleRegAlloc _ _ _ [] = Just []
90 simpleRegAlloc free live env (instr:instrs)
92 maybeToBool newAlloc &&
94 = Just (instr3 : instrs3)
98 instr3 = patchRegs instr (lookup env2)
100 (srcs, dsts) = case regUsage instr of
101 (RU s d) -> (regSetToList s, regSetToList d)
103 lookup env x = case lookupFM env x of Just y -> y; Nothing -> x
105 deadSrcs = [r | r@(UnmappedReg _ _) <- srcs, lookup env r `not_elem` live]
106 newDsts = [r | r@(UnmappedReg _ _) <- dsts, r `not_elem` keysFM env]
108 newAlloc = foldr allocateNewReg (Just (free, [])) newDsts
109 (free2, new) = case newAlloc of Just x -> x
111 env2 = env `addListToFM` new
113 live2 = map snd new ++ [x | x <- live, x `not_elem` dsts]
115 instrs2 = simpleRegAlloc free2 live2 env2 instrs
116 instrs3 = case instrs2 of Just x -> x
120 -> Maybe (MRegsState, [(Reg, Reg)])
121 -> Maybe (MRegsState, [(Reg, Reg)])
123 allocateNewReg _ Nothing = Nothing
125 allocateNewReg d@(UnmappedReg _ pk) (Just (free, prs))
126 | null choices = Nothing
127 | otherwise = Just (free2, prs2)
129 choices = possibleMRegs pk free
131 free2 = free `useMReg` (case reg of {IBOX(reg2) -> reg2} )
132 prs2 = ((d, MappedReg (case reg of {IBOX(reg2) -> reg2})) : prs)
135 Here is the ``clever'' bit. First go backward (i.e. left), looking for
136 the last use of dynamic registers. Then go forward (i.e. right), filling
137 registers with static placements.
139 hairyRegAlloc takes reserve_regs as the regs to use as spill
140 temporaries. First it tries to allocate using all regs except
141 reserve_regs. If that fails, it inserts spill code and tries again to
142 allocate regs, but this time with the spill temporaries available.
143 Even this might not work if there are insufficient spill temporaries:
144 in the worst case on x86, we'd need 3 of them, for insns like
145 addl (reg1,reg2,4) reg3, since this insn uses all 3 regs as input.
154 hairyRegAlloc regs reserve_regs instrs =
155 case mapAccumB (doRegAlloc reserve_regs)
156 (RH regs' 1 emptyFM) noFuture instrs of
157 (RH _ mloc1 _, _, instrs')
158 -- succeeded w/out using reserves
159 | mloc1 == 1 -> Just instrs'
160 -- failed, and no reserves avail, so pointless to attempt spilling
161 | null reserve_regs -> Nothing
162 -- failed, but we have reserves, so attempt to do spilling
164 -> let instrs_patched' = patchMem instrs'
165 instrs_patched = flattenOrdList instrs_patched'
167 case mapAccumB (doRegAlloc []) (RH regs'' mloc1 emptyFM)
168 noFuture instrs_patched of
169 ((RH _ mloc2 _),_,instrs'')
170 -- successfully allocated the patched code
171 | mloc2 == mloc1 -> Just instrs''
172 -- no; we have to give up
173 | otherwise -> Nothing
175 -- pprPanic "runRegAllocate" (ppr mloc2 <+> ppr mloc1)
177 regs' = regs `useMRegs` reserve_regs
178 regs'' = mkMRegsState reserve_regs
180 noFuture :: RegFuture
181 noFuture = RF emptyRegSet (FL emptyRegSet emptyFM) emptyFM
184 Here we patch instructions that reference ``registers'' which are really in
185 memory somewhere (the mapping is under the control of the machine-specific
186 code generator). We place the appropriate load sequences before any instructions
187 that use memory registers as sources, and we place the appropriate spill sequences
188 after any instructions that use memory registers as destinations. The offending
189 instructions are rewritten with new dynamic registers, so we have to run register
190 allocation again after all of this is said and done.
193 patchMem :: [Instr] -> InstrList
195 patchMem cs = foldr (mkSeqList . patchMem') mkEmptyList cs
197 patchMem' :: Instr -> InstrList
200 | null memSrcs && null memDsts = mkUnitList instr
203 (foldr mkParList mkEmptyList loadSrcs)
205 (foldr mkParList mkEmptyList spillDsts))
208 (RU srcs dsts) = regUsage instr
210 memToDyn (MemoryReg i pk) = UnmappedReg (mkBuiltinUnique i) pk
211 memToDyn other = other
213 memSrcs = [ r | r@(MemoryReg _ _) <- regSetToList srcs]
214 memDsts = [ r | r@(MemoryReg _ _) <- regSetToList dsts]
216 loadSrcs = map load memSrcs
217 spillDsts = map spill memDsts
219 load mem = loadReg mem (memToDyn mem)
220 spill mem = spillReg (memToDyn mem) mem
222 instr' = mkUnitList (patchRegs instr memToDyn)
228 -> RegHistory MRegsState
231 -> (RegHistory MRegsState, RegFuture, Instr)
233 doRegAlloc reserved_regs free_env in_use instr = (free_env', in_use', instr')
235 (free_env', instr') = doRegAlloc' reserved_regs free_env info instr
236 (in_use', info) = getUsage in_use instr
243 -> (RegFuture, RegInfo Instr)
245 getUsage (RF next_in_use future reg_conflicts) instr
246 = (RF in_use' future' reg_conflicts',
247 RI in_use' srcs dsts last_used reg_conflicts')
248 where (RU srcs dsts) = regUsage instr
249 (RL in_use future') = regLiveness instr (RL next_in_use future)
250 live_through = in_use `minusRegSet` dsts
251 last_used = [ r | r <- regSetToList srcs,
252 not (r `elementOfRegSet` (fstFL future)
253 || r `elementOfRegSet` in_use)]
255 in_use' = srcs `unionRegSets` live_through
258 case new_conflicts of
260 _ -> addListToFM reg_conflicts new_conflicts
263 | isEmptyRegSet live_dynamics = []
265 [ (r, merge_conflicts r)
266 | r <- extractMappedRegNos (regSetToList dsts) ]
268 merge_conflicts reg =
269 case lookupFM reg_conflicts reg of
270 Nothing -> live_dynamics
271 Just conflicts -> conflicts `unionRegSets` live_dynamics
274 = mkRegSet [ r | r@(UnmappedReg _ _)
275 <- regSetToList live_through ]
279 -> RegHistory MRegsState
282 -> (RegHistory MRegsState, Instr)
284 doRegAlloc' reserved (RH frs loc env)
285 (RI in_use srcs dsts lastu conflicts) instr =
287 (RH frs'' loc' env'', patchRegs instr dynToStatic)
291 -- free up new registers
293 free = extractMappedRegNos (map dynToStatic lastu)
295 -- (1) free registers that are used last as
296 -- source operands in this instruction
297 frs_not_in_use = frs `useMRegs`
298 (extractMappedRegNos (regSetToList in_use))
299 frs' = (frs_not_in_use `freeMRegs` free) `useMRegs` reserved
301 -- (2) allocate new registers for the destination operands
302 -- allocate registers for new dynamics
304 new_dynamix = [ r | r@(UnmappedReg _ _) <- regSetToList dsts,
305 r `not_elem` keysFM env ]
307 (frs'', loc', new) = foldr allocateNewRegs (frs', loc, []) new_dynamix
309 env' = addListToFM env new
311 env'' = delListFromFM env' lastu
313 dynToStatic :: Reg -> Reg
314 dynToStatic dyn@(UnmappedReg _ _) =
315 case lookupFM env' dyn of
317 Nothing -> trace ("Lost register; possibly a floating point"
318 ++" type error in a _ccall_?") dyn
319 dynToStatic other = other
321 allocateNewRegs :: Reg
322 -> (MRegsState, Int, [(Reg, Reg)])
323 -> (MRegsState, Int, [(Reg, Reg)])
325 allocateNewRegs d@(UnmappedReg _ pk) (fs, mem, lst)
326 = (fs', mem', (d, f) : lst)
329 case acceptable fs of
330 [] -> (fs, MemoryReg mem pk, mem + 1)
331 (IBOX(x2):_) -> (fs `useMReg` x2, MappedReg x2, mem)
333 acceptable regs = filter no_conflict (possibleMRegs pk regs)
336 case lookupFM conflicts reg of
338 Just conflicts -> not (d `elementOfRegSet` conflicts)
341 We keep a local copy of the Prelude function \tr{notElem},
342 so that it can be specialised. (Hack me gently. [WDP 94/11])
345 not_elem x (y:ys) = x /= y && not_elem x ys