2 % (c) The AQUA Project, Glasgow University, 1993-1996
4 \section[AsmRegAlloc]{Register allocator}
7 #include "HsVersions.h"
9 module AsmRegAlloc ( runRegAllocate, runHairyRegAllocate ) where
13 import MachCode ( InstrList(..) )
14 import MachMisc ( Instr )
18 import BitSet ( BitSet )
19 import FiniteMap ( emptyFM, addListToFM, delListFromFM, lookupFM, keysFM )
20 import Maybes ( maybeToBool )
21 import OrdList ( mkEmptyList, mkUnitList, mkSeqList, mkParList,
22 flattenOrdList, OrdList
24 import Stix ( StixTree )
25 import UniqSupply ( mkBuiltinUnique )
26 import Util ( mapAccumB, panic )
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)
80 = if null deadSrcs && maybeToBool newAlloc && maybeToBool instrs2 then
81 Just (instr3 : instrs3)
85 instr3 = patchRegs instr (lookup env2)
87 (srcs, dsts) = case regUsage instr of { RU s d -> (regSetToList s, regSetToList d) }
89 lookup env x = case lookupFM env x of {Just y -> y; Nothing -> x}
91 deadSrcs = [r | r@(UnmappedReg _ _) <- srcs, lookup env r `not_elem` live]
92 newDsts = [r | r@(UnmappedReg _ _) <- dsts, r `not_elem` keysFM env]
94 newAlloc = foldr allocateNewReg (Just (free, [])) newDsts
95 (free2, new) = case newAlloc of Just x -> x
97 env2 = env `addListToFM` new
99 live2 = map snd new ++ [x | x <- live, x `not_elem` dsts]
101 instrs2 = simpleRegAlloc free2 live2 env2 instrs
102 instrs3 = case instrs2 of Just x -> x
106 -> Maybe (MRegsState, [(Reg, Reg)])
107 -> Maybe (MRegsState, [(Reg, Reg)])
109 allocateNewReg _ Nothing = Nothing
111 allocateNewReg d@(UnmappedReg _ pk) (Just (free, prs)) =
112 if null choices then Nothing
113 else Just (free2, prs2)
115 choices = possibleMRegs pk free
117 free2 = free `useMReg` (case reg of {IBOX(reg2) -> reg2} )
118 prs2 = ((d, MappedReg (case reg of {IBOX(reg2) -> reg2})) : prs)
121 Here is the ``clever'' bit. First go backward (i.e. left), looking for
122 the last use of dynamic registers. Then go forward (i.e. right), filling
123 registers with static placements.
132 hairyRegAlloc regs reserve_regs instrs
133 = case mapAccumB (doRegAlloc reserve_regs)
134 (RH regs' 1 emptyFM) noFuture instrs
135 of (RH _ loc' _, _, instrs') ->
136 if loc' == 1 then instrs' else
137 case mapAccumB do_RegAlloc_Nil
138 (RH regs'' loc' emptyFM) noFuture (flattenOrdList (patchMem instrs'))
139 of ((RH _ loc'' _),_,instrs'') ->
140 if loc'' == loc' then instrs'' else panic "runRegAllocate"
142 regs' = regs `useMRegs` reserve_regs
143 regs'' = mkMRegsState reserve_regs
145 do_RegAlloc_Nil = doRegAlloc [] -- out here to avoid CAF (sigh)
147 :: RegHistory MRegsState
150 -> (RegHistory MRegsState, RegFuture, Instr)
152 noFuture :: RegFuture
153 noFuture = RF emptyRegSet (FL emptyRegSet emptyFM) emptyFM
156 Here we patch instructions that reference ``registers'' which are really in
157 memory somewhere (the mapping is under the control of the machine-specific
158 code generator). We place the appropriate load sequences before any instructions
159 that use memory registers as sources, and we place the appropriate spill sequences
160 after any instructions that use memory registers as destinations. The offending
161 instructions are rewritten with new dynamic registers, so we have to run register
162 allocation again after all of this is said and done.
165 patchMem :: [Instr] -> InstrList
167 patchMem cs = foldr (mkSeqList . patchMem') mkEmptyList cs
169 patchMem' :: Instr -> InstrList
172 = if null memSrcs && null memDsts then mkUnitList instr
174 (foldr mkParList mkEmptyList loadSrcs)
176 (foldr mkParList mkEmptyList spillDsts))
179 (RU srcs dsts) = regUsage instr
181 memToDyn (MemoryReg i pk) = UnmappedReg (mkBuiltinUnique i) pk
182 memToDyn other = other
184 memSrcs = [ r | r@(MemoryReg _ _) <- regSetToList srcs]
185 memDsts = [ r | r@(MemoryReg _ _) <- regSetToList dsts]
187 loadSrcs = map load memSrcs
188 spillDsts = map spill memDsts
190 load mem = loadReg mem (memToDyn mem)
191 spill mem = spillReg (memToDyn mem) mem
193 instr' = mkUnitList (patchRegs instr memToDyn)
199 -> RegHistory MRegsState
202 -> (RegHistory MRegsState, RegFuture, Instr)
204 doRegAlloc reserved_regs free_env in_use instr = (free_env', in_use', instr')
206 (free_env', instr') = doRegAlloc' reserved_regs free_env info instr
207 (in_use', info) = getUsage in_use instr
214 -> (RegFuture, RegInfo Instr)
216 getUsage (RF next_in_use future reg_conflicts) instr
217 = (RF in_use' future' reg_conflicts',
218 RI in_use' srcs dsts last_used reg_conflicts')
219 where (RU srcs dsts) = regUsage instr
220 (RL in_use future') = regLiveness instr (RL next_in_use future)
221 live_through = in_use `minusRegSet` dsts
222 last_used = [ r | r <- regSetToList srcs,
223 not (r `elementOfRegSet` (fstFL future) || r `elementOfRegSet` in_use)]
224 in_use' = srcs `unionRegSets` live_through
225 reg_conflicts' = case new_conflicts of
227 _ -> addListToFM reg_conflicts new_conflicts
228 new_conflicts = if isEmptyRegSet live_dynamics then []
229 else [ (r, merge_conflicts r)
230 | r <- extractMappedRegNos (regSetToList dsts) ]
231 merge_conflicts reg = case lookupFM reg_conflicts reg of
232 Nothing -> live_dynamics
233 Just conflicts -> conflicts `unionRegSets` live_dynamics
234 live_dynamics = mkRegSet
235 [ r | r@(UnmappedReg _ _) <- regSetToList live_through ]
239 -> RegHistory MRegsState
242 -> (RegHistory MRegsState, Instr)
244 doRegAlloc' reserved (RH frs loc env) (RI in_use srcs dsts lastu conflicts) instr =
246 (RH frs'' loc' env'', patchRegs instr dynToStatic)
250 -- free up new registers
252 free = extractMappedRegNos (map dynToStatic lastu)
254 -- (1) free registers that are used last as source operands in this instruction
255 frs_not_in_use = frs `useMRegs` (extractMappedRegNos (regSetToList in_use))
256 frs' = (frs_not_in_use `freeMRegs` free) `useMRegs` reserved
258 -- (2) allocate new registers for the destination operands
259 -- allocate registers for new dynamics
261 new_dynamix = [ r | r@(UnmappedReg _ _) <- regSetToList dsts, r `not_elem` keysFM env ]
263 (frs'', loc', new) = foldr allocateNewRegs (frs', loc, []) new_dynamix
265 env' = addListToFM env new
267 env'' = delListFromFM env' lastu
269 dynToStatic :: Reg -> Reg
270 dynToStatic dyn@(UnmappedReg _ _) =
271 case lookupFM env' dyn of
273 Nothing -> trace "Lost register; possibly a floating point type error in a _ccall_?" dyn
274 dynToStatic other = other
277 :: Reg -> (MRegsState, Int, [(Reg, Reg)]) -> (MRegsState, Int, [(Reg, Reg)])
279 allocateNewRegs d@(UnmappedReg _ pk) (fs, mem, lst) = (fs', mem', (d, f) : lst)
280 where (fs', f, mem') = case acceptable fs of
281 [] -> (fs, MemoryReg mem pk, mem + 1)
282 (IBOX(x2):_) -> (fs `useMReg` x2, MappedReg x2, mem)
284 acceptable regs = filter no_conflict (possibleMRegs pk regs)
285 no_conflict reg = case lookupFM conflicts reg of
287 Just conflicts -> not (d `elementOfRegSet` conflicts)
290 We keep a local copy of the Prelude function \tr{notElem},
291 so that it can be specialised. (Hack me gently. [WDP 94/11])
294 not_elem x (y:ys) = x /= y && not_elem x ys