-
module DFMonad
- ( DataflowLattice(..)
- , DataflowAnalysis
+ ( DataflowLattice(..) , DataflowAnalysis
, markFactsUnchanged, factsStatus, getFact, setFact, getExitFact, setExitFact
- , forgetFact, botFact, allFacts, factsEnv, checkFactMatch
- , addLastOutFact, bareLastOutFacts, forgetLastOutFacts
+ , forgetFact, botFact, setAllFacts, getAllFacts, factsEnv
+ , addLastOutFact, bareLastOutFacts, forgetLastOutFacts, checkFactMatch
, subAnalysis
- , DFA, runDFA
- , DFM, runDFM, liftAnal
- , markGraphRewritten
+ , DFM, runDFM, liftToDFM
+ , markGraphRewritten, graphWasRewritten
, freshBlockId
- , liftUSM
, module OptimizationFuel
)
where
+import BlockId
import CmmTx
import PprCmm()
import OptimizationFuel
-import ZipCfg
+import Control.Monad
import Maybes
import Outputable
import UniqFM
import UniqSupply
-import Control.Monad
-
{-
A dataflow monad maintains a mapping from BlockIds to dataflow facts,
}
--- There are two monads here:
--- 1. DFA, the monad of analysis, which never changes anything
--- 2. DFM, the monad of combined analysis and transformation,
--- which needs a UniqSupply and may consume transactions
-
-data DFAState f = DFAState { df_facts :: BlockEnv f
- , df_exit_fact :: f
- , df_last_outs :: [(BlockId, f)]
- , df_facts_change :: ChangeFlag
- }
-
-
-data DFState f = DFState { df_uniqs :: UniqSupply
- , df_rewritten :: ChangeFlag
- , df_astate :: DFAState f
- , df_fstate :: FuelState
+-- DFM is the monad of combined analysis and transformation,
+-- which needs a UniqSupply and may consume optimization fuel
+-- DFM is defined using a monad transformer, DFM', which is the general
+-- case of DFM, parameterized over any monad.
+-- In practice, we apply DFM' to the FuelMonad, which provides optimization fuel and
+-- the unique supply.
+data DFState f = DFState { df_rewritten :: ChangeFlag
+ , df_facts :: BlockEnv f
+ , df_exit_fact :: f
+ , df_last_outs :: [(BlockId, f)]
+ , df_facts_change :: ChangeFlag
}
-newtype DFA fact a = DFA (DataflowLattice fact -> DFAState fact -> (a, DFAState fact))
-newtype DFM fact a = DFM (DataflowLattice fact -> DFState fact -> (a, DFState fact))
-
-
-liftAnal :: DFA f a -> DFM f a
-liftAnal (DFA f) = DFM f'
- where f' l s = let (a, anal) = f l (df_astate s)
- in (a, s {df_astate = anal})
+newtype DFM' m fact a = DFM' (DataflowLattice fact -> DFState fact
+ -> m (a, DFState fact))
+type DFM fact a = DFM' FuelMonad fact a
-initDFAState :: f -> DFAState f
-initDFAState bot = DFAState emptyBlockEnv bot [] NoChange
-runDFA :: DataflowLattice f -> DFA f a -> a
-runDFA lattice (DFA f) = fst $ f lattice (initDFAState $ fact_bot lattice)
-
-runDFM :: UniqSupply -> DataflowLattice f -> DFM f a -> FuelMonad a
-runDFM uniqs lattice (DFM f) = FuelMonad (\s ->
- let (a, s') = f lattice $ DFState uniqs NoChange dfa_state s
- in (a, df_fstate s'))
- where dfa_state = initDFAState (fact_bot lattice)
+runDFM :: Monad m => DataflowLattice f -> DFM' m f a -> m a
+runDFM lattice (DFM' f) =
+ (f lattice $ DFState NoChange emptyBlockEnv (fact_bot lattice)[] NoChange)
+ >>= return . fst
class DataflowAnalysis m where
markFactsUnchanged :: m f () -- ^ Useful for starting a new iteration
factsStatus :: m f ChangeFlag
subAnalysis :: m f a -> m f a -- ^ Do a new analysis and then throw away
- -- *all* the related state. Even the Uniques
- -- will be reused.
+ -- /all/ the related state.
getFact :: BlockId -> m f f
setFact :: Outputable f => BlockId -> f -> m f ()
addLastOutFact :: (BlockId, f) -> m f ()
bareLastOutFacts :: m f [(BlockId, f)]
forgetLastOutFacts :: m f ()
- allFacts :: m f (BlockEnv f)
+ getAllFacts :: m f (BlockEnv f)
+ setAllFacts :: BlockEnv f -> m f ()
factsEnv :: Monad (m f) => m f (BlockId -> f)
lattice :: m f (DataflowLattice f)
- factsEnv = do { map <- allFacts
+ factsEnv = do { map <- getAllFacts
; bot <- botFact
; return $ \id -> lookupBlockEnv map id `orElse` bot }
-instance DataflowAnalysis DFA where
- markFactsUnchanged = DFA f
- where f _ s = ((), s {df_facts_change = NoChange})
- factsStatus = DFA f'
- where f' _ s = (df_facts_change s, s)
- subAnalysis (DFA f) = DFA f'
- where f' l s = let (a, _) = f l (subAnalysisState s) in (a, s)
- getFact id = DFA get
- where get lattice s = (lookupBlockEnv (df_facts s) id `orElse` fact_bot lattice, s)
- setFact id a =
- do old <- getFact id
- DataflowLattice { fact_add_to = add_fact
- , fact_name = name, fact_do_logging = log } <- lattice
- case add_fact a old of
- TxRes NoChange _ -> return ()
- TxRes SomeChange join -> DFA $ \_ s ->
- let facts' = extendBlockEnv (df_facts s) id join
- debug = if log then pprTrace else \_ _ a -> a
- in debug name (pprSetFact id old a join) $
- ((), s { df_facts = facts', df_facts_change = SomeChange })
- getExitFact = DFA get
- where get _ s = (df_exit_fact s, s)
+instance Monad m => DataflowAnalysis (DFM' m) where
+ markFactsUnchanged = DFM' f
+ where f _ s = return ((), s {df_facts_change = NoChange})
+ factsStatus = DFM' f'
+ where f' _ s = return (df_facts_change s, s)
+ subAnalysis (DFM' f) = DFM' f'
+ where f' l s = do (a, _) <- f l (subAnalysisState s)
+ return (a, s)
+ getFact id = DFM' get
+ where get lattice s =
+ return (lookupBlockEnv (df_facts s) id `orElse` fact_bot lattice, s)
+ setFact id a = DFM' set
+ where set (DataflowLattice name bot add_fact log) s =
+ case add_fact a old of
+ TxRes NoChange _ -> if initialized then return ((), s) else update old old
+ TxRes SomeChange join -> update join old
+ where (old, initialized) =
+ case lookupBlockEnv (df_facts s) id of
+ Just f -> (f, True)
+ Nothing -> (bot, False)
+ update join old =
+ let facts' = extendBlockEnv (df_facts s) id join
+ debug = if log then pprTrace else \_ _ a -> a
+ in debug name (pprSetFact id old a join) $
+ return ((), s { df_facts = facts', df_facts_change = SomeChange })
+ getExitFact = DFM' get
+ where get _ s = return (df_exit_fact s, s)
setExitFact a =
do old <- getExitFact
DataflowLattice { fact_add_to = add_fact
, fact_name = name, fact_do_logging = log } <- lattice
case add_fact a old of
TxRes NoChange _ -> return ()
- TxRes SomeChange join -> DFA $ \_ s ->
+ TxRes SomeChange join -> DFM' $ \_ s ->
let debug = if log then pprTrace else \_ _ a -> a
in debug name (pprSetFact "exit" old a join) $
- ((), s { df_exit_fact = join, df_facts_change = SomeChange })
- botFact = DFA f
- where f lattice s = (fact_bot lattice, s)
- forgetFact id = DFA f
- where f _ s = ((), s { df_facts = delFromUFM (df_facts s) id })
- addLastOutFact pair = DFA f
- where f _ s = ((), s { df_last_outs = pair : df_last_outs s })
- bareLastOutFacts = DFA f
- where f _ s = (df_last_outs s, s)
- forgetLastOutFacts = DFA f
- where f _ s = ((), s { df_last_outs = [] })
- allFacts = DFA f
- where f _ s = (df_facts s, s)
+ return ((), s { df_exit_fact = join, df_facts_change = SomeChange })
+ getAllFacts = DFM' f
+ where f _ s = return (df_facts s, s)
+ setAllFacts env = DFM' f
+ where f _ s = return ((), s { df_facts = env})
+ botFact = DFM' f
+ where f lattice s = return (fact_bot lattice, s)
+ forgetFact id = DFM' f
+ where f _ s = return ((), s { df_facts = delFromUFM (df_facts s) id })
+ addLastOutFact pair = DFM' f
+ where f _ s = return ((), s { df_last_outs = pair : df_last_outs s })
+ bareLastOutFacts = DFM' f
+ where f _ s = return (df_last_outs s, s)
+ forgetLastOutFacts = DFM' f
+ where f _ s = return ((), s { df_last_outs = [] })
checkFactMatch id a =
do { fact <- lattice
; old_a <- getFact id
; case fact_add_to fact a old_a of
TxRes NoChange _ -> return ()
TxRes SomeChange new ->
- do { facts <- allFacts
+ do { facts <- getAllFacts
; pprPanic "checkFactMatch"
(f4sep [text (fact_name fact), text "at id" <+> ppr id,
text "changed from", nest 4 (ppr old_a), text "to",
where pprFacts env = vcat (map pprFact (ufmToList env))
pprFact (id, a) = hang (ppr id <> colon) 4 (ppr a)
- lattice = DFA f
- where f l s = (l, s)
+ lattice = DFM' f
+ where f l s = return (l, s)
-subAnalysisState :: DFAState f -> DFAState f
+subAnalysisState :: DFState f -> DFState f
subAnalysisState s = s {df_facts_change = NoChange}
-instance DataflowAnalysis DFM where
- markFactsUnchanged = liftAnal $ markFactsUnchanged
- factsStatus = liftAnal $ factsStatus
- subAnalysis = dfmSubAnalysis
- getFact id = liftAnal $ getFact id
- setFact id new = liftAnal $ setFact id new
- getExitFact = liftAnal $ getExitFact
- setExitFact new = liftAnal $ setExitFact new
- botFact = liftAnal $ botFact
- forgetFact id = liftAnal $ forgetFact id
- addLastOutFact p = liftAnal $ addLastOutFact p
- bareLastOutFacts = liftAnal $ bareLastOutFacts
- forgetLastOutFacts = liftAnal $ forgetLastOutFacts
- allFacts = liftAnal $ allFacts
- checkFactMatch id a = liftAnal $ checkFactMatch id a
-
- lattice = liftAnal $ lattice
-
-dfmSubAnalysis :: DFM f a -> DFM f a
-dfmSubAnalysis (DFM f) = DFM f'
- where f' l s = let s' = s { df_astate = subAnalysisState (df_astate s) }
- (a, _) = f l s'
- in (a, s)
-
-
-markGraphRewritten :: DFM f ()
-markGraphRewritten = DFM f
- where f _ s = ((), s {df_rewritten = SomeChange})
+markGraphRewritten :: Monad m => DFM' m f ()
+markGraphRewritten = DFM' f
+ where f _ s = return ((), s {df_rewritten = SomeChange})
+graphWasRewritten :: DFM f ChangeFlag
+graphWasRewritten = DFM' f
+ where f _ s = return (df_rewritten s, s)
+
freshBlockId :: String -> DFM f BlockId
-freshBlockId _s = liftUSM $ getUniqueUs >>= return . BlockId
-
-liftUSM :: UniqSM a -> DFM f a
-liftUSM uc = DFM f
- where f _ s = let (a, us') = initUs (df_uniqs s) uc
- in (a, s {df_uniqs = us'})
-
-instance Monad (DFA f) where
- DFA f >>= k = DFA (\l s -> let (a, s') = f l s
- DFA f' = k a
- in f' l s')
- return a = DFA (\_ s -> (a, s))
-
-instance Monad (DFM f) where
- DFM f >>= k = DFM (\l s -> let (a, s') = f l s
- DFM f' = k a
- in f' l s')
- return a = DFM (\_ s -> (a, s))
-
-instance FuelUsingMonad (DFM f) where
- fuelRemaining = extract fuelRemainingInState
- lastFuelPass = extract lastFuelPassInState
- fuelExhausted = extract fuelExhaustedInState
- fuelDecrement p f f' = DFM (\_ s -> ((), s { df_fstate = fs' s }))
- where fs' s = fuelDecrementState p f f' $ df_fstate s
-
-extract :: (FuelState -> a) -> DFM f a
-extract f = DFM (\_ s -> (f $ df_fstate s, s))
+freshBlockId _s = getUniqueM >>= return . BlockId
+
+instance Monad m => Monad (DFM' m f) where
+ DFM' f >>= k = DFM' (\l s -> do (a, s') <- f l s
+ let DFM' f' = k a in f' l s')
+ return a = DFM' (\_ s -> return (a, s))
+
+instance FuelUsingMonad (DFM' FuelMonad f) where
+ fuelRemaining = liftToDFM' fuelRemaining
+ lastFuelPass = liftToDFM' lastFuelPass
+ fuelExhausted = liftToDFM' fuelExhausted
+ fuelDecrement p f f' = liftToDFM' (fuelDecrement p f f')
+ fuelDec1 = liftToDFM' fuelDec1
+instance MonadUnique (DFM' FuelMonad f) where
+ getUniqueSupplyM = liftToDFM' getUniqueSupplyM
+ getUniqueM = liftToDFM' getUniqueM
+ getUniquesM = liftToDFM' getUniquesM
+
+liftToDFM' :: Monad m => m x -> DFM' m f x
+liftToDFM' m = DFM' (\ _ s -> m >>= (\a -> return (a, s)))
+liftToDFM :: FuelMonad x -> DFM f x
+liftToDFM m = DFM' (\ _ s -> m >>= (\a -> return (a, s)))
pprSetFact :: (Show a, Outputable f) => a -> f -> f -> f -> SDoc