2 ( DataflowLattice(..) , DataflowAnalysis
3 , markFactsUnchanged, factsStatus, getFact, setFact, getExitFact, setExitFact
4 , forgetFact, botFact, setAllFacts, getAllFacts, factsEnv
5 , addLastOutFact, bareLastOutFacts, forgetLastOutFacts, checkFactMatch
8 , DFM, runDFM, liftToDFM
9 , markGraphRewritten, graphWasRewritten
10 , module OptimizationFuel
17 import OptimizationFuel
26 A dataflow monad maintains a mapping from BlockIds to dataflow facts,
27 where a dataflow fact is a value of type [[a]]. Values of type [[a]]
28 must form a lattice, as described by type [[Fact a]].
30 The dataflow engine uses the lattice structure to compute a least
31 solution to a set of dataflow equations. To compute a greatest
32 solution, flip the lattice over.
34 The engine works by starting at the bottom and iterating to a fixed
35 point, so in principle we require the bottom element, a join (least
36 upper bound) operation, and a comparison to find out if a value has
37 changed (grown). In practice, the comparison is only ever used in
38 conjunction with the join, so we have [[fact_add_to]]:
41 let j = join new old in
42 if j <= old then noTx old -- nothing changed
43 else aTx j -- the fact changed
47 data DataflowLattice a = DataflowLattice {
48 fact_name :: String, -- documentation
49 fact_bot :: a, -- lattice bottom element
50 fact_add_to :: a -> a -> TxRes a, -- lattice join and compare
51 -- ^ compute join of two args; something changed iff join is greater than 2nd arg
52 fact_do_logging :: Bool -- log changes
56 -- DFM is the monad of combined analysis and transformation,
57 -- which needs a UniqSupply and may consume optimization fuel
58 -- DFM is defined using a monad transformer, DFM', which is the general
59 -- case of DFM, parameterized over any monad.
60 -- In practice, we apply DFM' to the FuelMonad, which provides optimization fuel and
62 data DFState f = DFState { df_rewritten :: ChangeFlag
63 , df_facts :: BlockEnv f
65 , df_last_outs :: [(BlockId, f)]
66 , df_facts_change :: ChangeFlag
69 newtype DFM' m fact a = DFM' (DataflowLattice fact -> DFState fact
70 -> m (a, DFState fact))
71 type DFM fact a = DFM' FuelMonad fact a
74 runDFM :: Monad m => DataflowLattice f -> DFM' m f a -> m a
75 runDFM lattice (DFM' f) =
76 (f lattice $ DFState NoChange emptyBlockEnv (fact_bot lattice) [] NoChange)
79 class DataflowAnalysis m where
80 markFactsUnchanged :: m f () -- ^ Useful for starting a new iteration
81 factsStatus :: m f ChangeFlag
82 subAnalysis :: m f a -> m f a -- ^ Do a new analysis and then throw away
83 -- /all/ the related state.
85 getFact :: BlockId -> m f f
86 setFact :: Outputable f => BlockId -> f -> m f ()
88 setExitFact :: Outputable f => f -> m f ()
89 checkFactMatch :: Outputable f =>
90 BlockId -> f -> m f () -- ^ assert fact already at this val
92 forgetFact :: BlockId -> m f ()
93 -- | It might be surprising these next two are needed in a pure analysis,
94 -- but for some problems we do a 'shallow' rewriting in which a rewritten
95 -- graph is not itself considered for further rewriting but merely undergoes
96 -- an analysis. In this case the results of a forward analysis might produce
97 -- new facts that go on BlockId's that reside outside the graph being analyzed.
98 -- Thus these 'lastOutFacts' need to be available even in a pure analysis.
99 addLastOutFact :: (BlockId, f) -> m f ()
100 bareLastOutFacts :: m f [(BlockId, f)]
101 forgetLastOutFacts :: m f ()
102 getAllFacts :: m f (BlockEnv f)
103 setAllFacts :: BlockEnv f -> m f ()
104 factsEnv :: Monad (m f) => m f (BlockId -> f)
106 lattice :: m f (DataflowLattice f)
107 factsEnv = do { map <- getAllFacts
109 ; return $ \id -> lookupBlockEnv map id `orElse` bot }
111 instance Monad m => DataflowAnalysis (DFM' m) where
112 markFactsUnchanged = DFM' f
113 where f _ s = return ((), s {df_facts_change = NoChange})
114 factsStatus = DFM' f'
115 where f' _ s = return (df_facts_change s, s)
116 subAnalysis (DFM' f) = DFM' f'
117 where f' l s = do (a, _) <- f l (subAnalysisState s)
119 getFact id = DFM' get
120 where get lattice s =
121 return (lookupBlockEnv (df_facts s) id `orElse` fact_bot lattice, s)
122 setFact id a = DFM' set
123 where set (DataflowLattice name bot add_fact log) s =
124 case add_fact a old of
125 TxRes NoChange _ -> if initialized then return ((), s) else update old old
126 TxRes SomeChange join -> update join old
127 where (old, initialized) =
128 case lookupBlockEnv (df_facts s) id of
130 Nothing -> (bot, False)
132 let facts' = extendBlockEnv (df_facts s) id join
133 debug = if log then pprTrace else \_ _ a -> a
134 in debug name (pprSetFact id old a join) $
135 return ((), s { df_facts = facts', df_facts_change = SomeChange })
136 getExitFact = DFM' get
137 where get _ s = return (df_exit_fact s, s)
139 do old <- getExitFact
140 DataflowLattice { fact_add_to = add_fact
141 , fact_name = name, fact_do_logging = log } <- lattice
142 case add_fact a old of
143 TxRes NoChange _ -> return ()
144 TxRes SomeChange join -> DFM' $ \_ s ->
145 let debug = if log then pprTrace else \_ _ a -> a
146 in debug name (pprSetFact "exit" old a join) $
147 return ((), s { df_exit_fact = join, df_facts_change = SomeChange })
149 where f _ s = return (df_facts s, s)
150 setAllFacts env = DFM' f
151 where f _ s = return ((), s { df_facts = env})
153 where f lattice s = return (fact_bot lattice, s)
154 forgetFact id = DFM' f
155 where f _ s = return ((), s { df_facts = delFromBlockEnv (df_facts s) id })
156 addLastOutFact pair = DFM' f
157 where f _ s = return ((), s { df_last_outs = pair : df_last_outs s })
158 bareLastOutFacts = DFM' f
159 where f _ s = return (df_last_outs s, s)
160 forgetLastOutFacts = DFM' f
161 where f _ s = return ((), s { df_last_outs = [] })
162 checkFactMatch id a =
164 ; old_a <- getFact id
165 ; case fact_add_to fact a old_a of
166 TxRes NoChange _ -> return ()
167 TxRes SomeChange new ->
168 do { facts <- getAllFacts
169 ; pprPanic "checkFactMatch"
170 (f4sep [text (fact_name fact), text "at id" <+> ppr id,
171 text "changed from", nest 4 (ppr old_a), text "to",
173 text "after supposedly reaching fixed point;",
174 text "env is", pprFacts facts])
177 where pprFacts env = vcat (map pprFact (blockEnvToList env))
178 pprFact (id, a) = hang (ppr id <> colon) 4 (ppr a)
181 where f l s = return (l, s)
183 subAnalysisState :: DFState f -> DFState f
184 subAnalysisState s = s {df_facts_change = NoChange}
187 markGraphRewritten :: Monad m => DFM' m f ()
188 markGraphRewritten = DFM' f
189 where f _ s = return ((), s {df_rewritten = SomeChange})
191 graphWasRewritten :: DFM f ChangeFlag
192 graphWasRewritten = DFM' f
193 where f _ s = return (df_rewritten s, s)
195 instance Monad m => Monad (DFM' m f) where
196 DFM' f >>= k = DFM' (\l s -> do (a, s') <- f l s
197 let DFM' f' = k a in f' l s')
198 return a = DFM' (\_ s -> return (a, s))
200 instance FuelUsingMonad (DFM' FuelMonad f) where
201 fuelRemaining = liftToDFM' fuelRemaining
202 lastFuelPass = liftToDFM' lastFuelPass
203 fuelExhausted = liftToDFM' fuelExhausted
204 fuelDecrement p f f' = liftToDFM' (fuelDecrement p f f')
205 fuelDec1 = liftToDFM' fuelDec1
206 instance MonadUnique (DFM' FuelMonad f) where
207 getUniqueSupplyM = liftToDFM' getUniqueSupplyM
208 getUniqueM = liftToDFM' getUniqueM
209 getUniquesM = liftToDFM' getUniquesM
211 liftToDFM' :: Monad m => m x -> DFM' m f x
212 liftToDFM' m = DFM' (\ _ s -> m >>= (\a -> return (a, s)))
213 liftToDFM :: FuelMonad x -> DFM f x
214 liftToDFM m = DFM' (\ _ s -> m >>= (\a -> return (a, s)))
217 pprSetFact :: (Show a, Outputable f) => a -> f -> f -> f -> SDoc
218 pprSetFact id old a join =
219 f4sep [text "at" <+> text (show id),
220 text "added" <+> ppr a, text "to" <+> ppr old,
221 text "yielding" <+> ppr join]
223 f4sep :: [SDoc] -> SDoc
225 f4sep (d:ds) = fsep (d : map (nest 4) ds)