1 module Dataflow (mapCmmTop, onBasicBlock, cmmLivenessComment, cmmLiveness) where
16 cmmBranchSources :: [(BlockId, [BlockId])] -> [(BlockId, [BlockId])]
17 cmmBranchSources input =
18 [(target, [s | (s, ts) <- input, target `elem` ts])
19 | target <- targets] where
20 targets = nub [t | (s, ts) <- input, t <- ts]
22 cmmBranchTargets :: CmmBasicBlock -> UniqSet BlockId
23 cmmBranchTargets (BasicBlock _ stmts) =
24 mkUniqSet $ concatMap target stmts where
25 target (CmmBranch ident) = [ident]
26 target (CmmCondBranch _ ident) = [ident]
27 target (CmmSwitch _ blocks) = mapMaybe id blocks
30 --------------------------------------------------------------------------------
32 -- This should really be a state monad, but that is not in the core libraries
33 -- so we'll hack around it here.
34 -- The monad we're using is: type State a = s -> s
36 -- The variables that were made live and killed respectively
37 type CmmLiveness = (UniqSet LocalReg, UniqSet LocalReg)
38 addLocalLive new_live (live, killed) =
39 (live `unionUniqSets` new_live, killed `minusUniqSet` new_live)
40 addLocalKilled new_killed (live, killed) =
41 (live `minusUniqSet` new_killed, killed `unionUniqSets` new_killed)
43 -- Calculate the live and killed registers for a local block
44 cmmLocalLiveness :: CmmBasicBlock -> CmmLiveness
45 cmmLocalLiveness (BasicBlock _ stmts) =
46 foldr ((.) . cmmStmtLocalLiveness) id stmts (emptyUniqSet, emptyUniqSet)
48 -- Helper for cmmLocalLiveness
49 cmmStmtLocalLiveness :: CmmStmt -> (CmmLiveness -> CmmLiveness)
50 cmmStmtLocalLiveness (CmmNop) = id
51 cmmStmtLocalLiveness (CmmComment _) = id
52 cmmStmtLocalLiveness (CmmAssign reg expr) =
53 cmmExprLocalLiveness expr . reg_liveness where
56 (CmmLocal reg') -> addLocalKilled $ unitUniqSet reg'
58 cmmStmtLocalLiveness (CmmStore expr1 expr2) =
59 cmmExprLocalLiveness expr2 . cmmExprLocalLiveness expr1
60 cmmStmtLocalLiveness (CmmCall target results arguments _) =
62 foldr ((.) . cmmExprLocalLiveness) id (map fst arguments) .
63 addLocalKilled (mkUniqSet $ only_local_regs results) where
64 only_local_regs [] = []
65 only_local_regs ((CmmGlobal _,_):args) = only_local_regs args
66 only_local_regs ((CmmLocal r,_):args) = r:only_local_regs args
69 (CmmForeignCall target _) -> cmmExprLocalLiveness target
71 cmmStmtLocalLiveness (CmmBranch _) = const (emptyUniqSet, emptyUniqSet)
72 cmmStmtLocalLiveness (CmmCondBranch expr _) = cmmExprLocalLiveness expr
73 cmmStmtLocalLiveness (CmmSwitch expr _) = cmmExprLocalLiveness expr
74 cmmStmtLocalLiveness (CmmJump expr params) =
75 const (cmmExprLocalLiveness expr (mkUniqSet params, emptyUniqSet))
77 -- Helper for cmmLocalLiveness
78 cmmExprLocalLiveness :: CmmExpr -> (CmmLiveness -> CmmLiveness)
79 cmmExprLocalLiveness expr = addLocalLive (mkUniqSet $ expr_liveness expr) where
80 expr_liveness (CmmLit _) = []
81 expr_liveness (CmmLoad expr _) = expr_liveness expr
82 expr_liveness (CmmReg reg) = reg_liveness reg
83 expr_liveness (CmmMachOp _ exprs) = concatMap expr_liveness exprs
84 expr_liveness (CmmRegOff reg _) = reg_liveness reg
85 reg_liveness (CmmLocal reg) = [reg]
86 reg_liveness (CmmGlobal _) = []
90 UniqFM {-BlockId-} (UniqSet BlockId)
91 -> UniqFM {-BlockId-} CmmLiveness
93 -> UniqFM {-BlockId-} (UniqSet LocalReg)
94 -> Maybe (UniqFM {-BlockId-} (UniqSet LocalReg))
95 branch_update targets local_liveness ident input_state =
96 if (sizeUniqSet old_live) >= (sizeUniqSet new_live)
98 else Just $ addToUFM input_state ident new_live
100 old_live = lookupWithDefaultUFM input_state emptyUniqSet ident
103 local_liveness (emptyUniqSet, emptyUniqSet) ident
104 target_live = unionManyUniqSets $
105 map (lookupWithDefaultUFM input_state emptyUniqSet) target
106 target = uniqSetToList $ lookupWithDefaultUFM targets emptyUniqSet ident
107 new_live = (target_live `minusUniqSet` killed) `unionUniqSets` born
111 UniqFM {-BlockId-} CmmLiveness
114 -> UniqFM {-BlockId-} (UniqSet LocalReg)
115 -> Maybe (UniqFM {-BlockId-} (UniqSet LocalReg))
116 cmmBlockUpdate local_liveness ident cause input_state =
117 let (born, killed) = lookupWithDefaultUFM
118 local_liveness (emptyUniqSet, emptyUniqSet) ident
119 old_live = lookupWithDefaultUFM input_state emptyUniqSet ident
122 Just cause' -> lookupWithDefaultUFM input_state emptyUniqSet cause'
123 Nothing -> emptyUniqSet
125 `unionUniqSets` (cause_live `minusUniqSet` killed)
127 in {-trace (--(showSDoc $ ppr $ getUnique cause) ++ "-->" ++
128 (showSDoc $ ppr $ getUnique ident) ++ ":" ++
129 (showSDoc $ ppr $ map CmmLocal $ uniqSetToList $ cause_live) ++ ":" ++
130 (showSDoc $ ppr $ map CmmLocal $ uniqSetToList $ old_live) ++ ":" ++
131 (showSDoc $ ppr $ map CmmLocal $ uniqSetToList $ new_live) ++ "|" ++
132 (show $ map (\(k,v) -> (k, showSDoc $ ppr $ map CmmLocal $ uniqSetToList v)) $ ufmToList input_state)) $-}
133 if (sizeUniqSet old_live) == (sizeUniqSet new_live)
135 else Just $ addToUFM input_state ident new_live
137 cmmBlockDependants :: UniqFM {-BlockId-} (UniqSet BlockId) -> BlockId -> [BlockId]
138 cmmBlockDependants sources ident =
139 uniqSetToList $ lookupWithDefaultUFM sources emptyUFM ident
141 cmmBlockLiveness :: [CmmBasicBlock] -> UniqFM {-BlockId-} CmmLiveness
142 cmmBlockLiveness blocks = listToUFM $ map block_info blocks where
143 block_info block = (blockId block, cmmLocalLiveness block)
145 cmmBlockSourcesAndTargets ::
147 -> (UniqFM {-BlockId-} (UniqSet BlockId), UniqFM (UniqSet BlockId))
148 cmmBlockSourcesAndTargets blocks = foldr aux (emptyUFM, emptyUFM) blocks where
149 aux block (sourcesUFM, targetsUFM) =
150 (foldUniqSet add_source_edges sourcesUFM targets,
151 addToUFM_Acc unionUniqSets id targetsUFM ident targets) where
152 add_source_edges t ufm =
153 addToUFM_Acc (flip addOneToUniqSet) unitUniqSet ufm t ident
154 targets = cmmBranchTargets block
155 ident = blockId block
157 cmmLiveness :: [CmmBasicBlock] -> UniqFM {-BlockId-} (UniqSet LocalReg)
159 fixedpoint (cmmBlockDependants sources) (cmmBlockUpdate liveness)
160 (map blockId blocks) emptyUFM where
161 (sources, targets) = cmmBlockSourcesAndTargets blocks
162 liveness = cmmBlockLiveness blocks
164 cmmLivenessComment ::
165 UniqFM {-BlockId-} (UniqSet LocalReg)
166 -> CmmBasicBlock -> CmmBasicBlock
167 cmmLivenessComment live (BasicBlock ident stmts) =
168 BasicBlock ident stmts' where
169 stmts' = (CmmComment $ mkFastString $ showSDoc $ ppr $ live'):stmts
170 live' = map CmmLocal $ uniqSetToList $ lookupWithDefaultUFM live emptyUniqSet ident
172 onBasicBlock f (CmmProc ds ident args blocks) = CmmProc ds ident args (f blocks)
175 mapCmmTop f (Cmm xs) = Cmm (map f xs)
177 --------------------------------------------------------------------------------
179 -- Solve a fixed-point of a dataflow problem.
180 -- O(N+H*E) calls to update where
181 -- N = number of nodes,
182 -- E = number of edges,
183 -- H = maximum height of the lattice for any particular node.
184 -- dependants: map from nodes to those who's value depend on the argument node
186 -- Given the node which needs to be updated, and
187 -- which node caused that node to need to be updated,
189 -- (The causing node will be 'Nothing' if this is the initial update.)
190 -- Must return 'Nothing' if no change,
191 -- otherwise returrn 'Just' of the new state
192 -- nodes: a set of nodes that initially need updating
193 -- state: some sort of state (usually a map)
194 -- containing the initial value for each node
196 -- Sketch for proof of complexity:
197 -- Note that the state is threaded through the entire execution.
198 -- Also note that the height of the latice at any particular node
199 -- is the number of times 'update' can return non-Nothing for a particular node.
200 -- Every call (except for the top level one) must be caused by a non-Nothing
201 -- result and each non-Nothing result causes as many calls as it has
202 -- out-going edges. Thus any particular node, n, may cause in total
203 -- at most H*out(n) further calls. When summed over all nodes,
204 -- that is H*E. The N term of the complexity is from the initial call
205 -- when 'update' will be passed 'Nothing'.
208 -> (node -> Maybe node -> s -> Maybe s)
210 fixedpoint dependants update nodes state =
211 foldr (fixedpoint' Nothing) state nodes where
212 fixedpoint' cause node state =
213 case update node cause state of
216 foldr (fixedpoint' (Just node)) state' (dependants node)