1 {-# OPTIONS -Wall -fno-warn-name-shadowing #-}
4 , DFTx, runDFTx, lastTxPass, txDecrement, txRemaining, txExhausted
8 , markFactsUnchanged, factsStatus, getFact, setFact, botFact
9 , forgetFact, allFacts, factsEnv, checkFactMatch
10 , addLastOutFact, lastOutFacts, forgetLastOutFacts
14 , DFM, runDFM, liftTx, liftAnal
27 import ZipCfg hiding (freshBlockId)
28 import qualified ZipCfg as G
34 A dataflow monad maintains a mapping from BlockIds to dataflow facts,
35 where a dataflow fact is a value of type [[a]]. Values of type [[a]]
36 must form a lattice, as described by type [[Fact a]].
38 The dataflow engine uses the lattice structure to compute a least
39 solution to a set of dataflow equations. To compute a greatest
40 solution, flip the lattice over.
42 The engine works by starting at the bottom and iterating to a fixed
43 point, so in principle we require the bottom element, a join (least
44 upper bound) operation, and a comparison to find out if a value has
45 changed (grown). In practice, the comparison is only ever used in
46 conjunction with the join, so we have [[fact_add_to]]:
49 let j = join new old in
50 if j <= old then noTx old -- nothing changed
51 else aTx j -- the fact changed
55 data DataflowLattice a = DataflowLattice {
56 fact_name :: String, -- documentation
57 fact_bot :: a, -- lattice bottom element
58 fact_add_to :: a -> a -> TxRes a, -- lattice join and compare
59 -- ^ compute join of two args; something changed iff join is greater than 2nd arg
60 fact_do_logging :: Bool -- log changes
64 -- There are three monads here:
65 -- 1. DFTx, the monad of transactions, to be carried through all
66 -- graph-changing computations in the program
67 -- 2. DFA, the monad of analysis, which never changes anything
68 -- 3. DFM, the monad of combined analysis and transformation,
69 -- which needs a UniqSupply and may consume transactions
71 data DFAState f = DFAState { df_facts :: BlockEnv f
72 , df_facts_change :: ChangeFlag
75 data DFTxState = DFTxState { df_txlimit :: Txlimit, df_lastpass :: String }
77 data DFState f = DFState { df_uniqs :: UniqSupply
78 , df_rewritten :: ChangeFlag
79 , df_astate :: DFAState f
80 , df_txstate :: DFTxState
81 , df_last_outs :: [(BlockId, f)]
84 newtype DFTx a = DFTx (DFTxState -> (a, DFTxState))
85 newtype DFA fact a = DFA (DataflowLattice fact -> DFAState fact -> (a, DFAState fact))
86 newtype DFM fact a = DFM (DataflowLattice fact -> DFState fact -> (a, DFState fact))
89 liftAnal :: DFA f a -> DFM f a
90 liftAnal (DFA f) = DFM f'
91 where f' l s = let (a, anal) = f l (df_astate s)
92 in (a, s {df_astate = anal})
94 liftTx :: DFTx a -> DFM f a
95 liftTx (DFTx f) = DFM f'
96 where f' _ s = let (a, txs) = f (df_txstate s)
97 in (a, s {df_txstate = txs})
99 newtype Txlimit = Txlimit Int
100 deriving (Ord, Eq, Num, Show, Bounded)
102 initDFAState :: DFAState f
103 initDFAState = DFAState emptyBlockEnv NoChange
105 runDFA :: DataflowLattice f -> DFA f a -> a
106 runDFA lattice (DFA f) = fst $ f lattice initDFAState
108 -- XXX DFTx really needs to be in IO, so we can dump programs in
109 -- intermediate states of optimization ---NR
111 runDFTx :: Txlimit -> DFTx a -> a --- should only be called once per program!
112 runDFTx lim (DFTx f) = fst $ f $ DFTxState lim "<none>"
114 lastTxPass :: DFTx String
116 where f s = (df_lastpass s, s)
118 runDFM :: UniqSupply -> DataflowLattice f -> DFM f a -> DFTx a
119 runDFM uniqs lattice (DFM f) = DFTx f'
121 let (a, s) = f lattice $ DFState uniqs NoChange initDFAState txs [] in
124 txExhausted :: DFTx Bool
126 where f s = (df_txlimit s <= 0, s)
128 txRemaining :: DFTx Txlimit
130 where f s = (df_txlimit s, s)
132 txDecrement :: String -> Txlimit -> Txlimit -> DFTx ()
133 txDecrement optimizer old new = DFTx f
134 where f s = ((), s { df_txlimit = lim s, df_lastpass = optimizer })
135 lim s = if old == df_txlimit s then new
136 else panic $ concat ["lost track of ", optimizer, "'s transactions"]
139 class DataflowAnalysis m where
140 markFactsUnchanged :: m f () -- ^ Useful for starting a new iteration
141 factsStatus :: m f ChangeFlag
142 subAnalysis :: m f a -> m f a -- ^ Do a new analysis and then throw away
143 -- *all* the related state. Even the Uniques
146 getFact :: BlockId -> m f f
147 setFact :: Outputable f => BlockId -> f -> m f ()
148 checkFactMatch :: Outputable f =>
149 BlockId -> f -> m f () -- ^ assert fact already at this val
151 forgetFact :: BlockId -> m f ()
152 forgetLastOutFacts :: m f ()
153 allFacts :: m f (BlockEnv f)
154 factsEnv :: Monad (m f) => m f (BlockId -> f)
156 lattice :: m f (DataflowLattice f)
157 factsEnv = do { map <- allFacts
159 ; return $ \id -> lookupBlockEnv map id `orElse` bot }
161 instance DataflowAnalysis DFA where
162 markFactsUnchanged = DFA f
163 where f _ s = ((), s {df_facts_change = NoChange})
165 where f' _ s = (df_facts_change s, s)
166 subAnalysis (DFA f) = DFA f'
167 where f' l s = let (a, _) = f l (subAnalysisState s) in (a, s)
169 where get lattice s = (lookupBlockEnv (df_facts s) id `orElse` fact_bot lattice, s)
172 DataflowLattice { fact_add_to = add_fact
173 , fact_name = name, fact_do_logging = log } <- lattice
174 case add_fact a old of
175 TxRes NoChange _ -> return ()
176 TxRes SomeChange join -> DFA $ \_ s ->
177 let facts' = extendBlockEnv (df_facts s) id join
178 debug = if log then pprTrace else \_ _ a -> a
179 in debug name (pprSetFact id old a join) $
180 ((), s { df_facts = facts', df_facts_change = SomeChange })
182 where f lattice s = (fact_bot lattice, s)
183 forgetFact id = DFA f
184 where f _ s = ((), s { df_facts = delFromUFM (df_facts s) id })
185 forgetLastOutFacts = return ()
187 where f _ s = (df_facts s, s)
188 checkFactMatch id a =
190 ; old_a <- getFact id
191 ; case fact_add_to fact a old_a of
192 TxRes NoChange _ -> return ()
193 TxRes SomeChange new ->
194 do { facts <- allFacts
195 ; pprPanic "checkFactMatch"
196 (f4sep [text (fact_name fact), text "at id" <+> ppr id,
197 text "changed from", nest 4 (ppr old_a), text "to",
199 text "after supposedly reaching fixed point;",
200 text "env is", pprFacts facts])
203 where pprFacts env = vcat (map pprFact (ufmToList env))
204 pprFact (id, a) = hang (ppr id <> colon) 4 (ppr a)
209 subAnalysisState :: DFAState f -> DFAState f
210 subAnalysisState s = s {df_facts_change = NoChange}
213 instance DataflowAnalysis DFM where
214 markFactsUnchanged = liftAnal $ markFactsUnchanged
215 factsStatus = liftAnal $ factsStatus
216 subAnalysis = dfmSubAnalysis
217 getFact id = liftAnal $ getFact id
218 setFact id new = liftAnal $ setFact id new
219 botFact = liftAnal $ botFact
220 forgetFact id = liftAnal $ forgetFact id
221 forgetLastOutFacts = dfmForgetLastOutFacts
222 allFacts = liftAnal $ allFacts
223 checkFactMatch id a = liftAnal $ checkFactMatch id a
225 lattice = liftAnal $ lattice
227 dfmSubAnalysis :: DFM f a -> DFM f a
228 dfmSubAnalysis (DFM f) = DFM f'
229 where f' l s = let s' = s { df_astate = subAnalysisState (df_astate s) }
233 dfmForgetLastOutFacts :: DFM f ()
234 dfmForgetLastOutFacts = DFM f
235 where f _ s = ((), s { df_last_outs = [] })
237 addLastOutFact :: (BlockId, f) -> DFM f ()
238 addLastOutFact pair = DFM f
239 where f _ s = ((), s { df_last_outs = pair : df_last_outs s })
241 lastOutFacts :: DFM f [(BlockId, f)]
243 where f _ s = (df_last_outs s, s)
245 markGraphRewritten :: DFM f ()
246 markGraphRewritten = DFM f
247 where f _ s = ((), s {df_rewritten = SomeChange})
249 freshBlockId :: String -> DFM f BlockId
250 freshBlockId s = liftUSM $ G.freshBlockId s
252 liftUSM :: UniqSM a -> DFM f a
254 where f _ s = let (a, us') = initUs (df_uniqs s) uc
255 in (a, s {df_uniqs = us'})
257 instance Monad (DFA f) where
258 DFA f >>= k = DFA (\l s -> let (a, s') = f l s
261 return a = DFA (\_ s -> (a, s))
263 instance Monad (DFM f) where
264 DFM f >>= k = DFM (\l s -> let (a, s') = f l s
267 return a = DFM (\_ s -> (a, s))
269 instance Monad (DFTx) where
270 DFTx f >>= k = DFTx (\s -> let (a, s') = f s
273 return a = DFTx (\s -> (a, s))
275 pprSetFact :: Outputable f => BlockId -> f -> f -> f -> SDoc
276 pprSetFact id old a join =
277 f4sep [text "at" <+> text (show id),
278 text "added" <+> ppr a, text "to" <+> ppr old,
279 text "yielding" <+> ppr join]
281 f4sep :: [SDoc] -> SDoc
283 f4sep (d:ds) = fsep (d : map (nest 4) ds)
286 _I_am_abstract :: Int -> Txlimit
287 _I_am_abstract = Txlimit -- prevents a warning about Txlimit being unused