diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/cmm/Cmm.hs | 1 | ||||
-rw-r--r-- | compiler/cmm/CmmCPSZ.hs | 58 | ||||
-rw-r--r-- | compiler/cmm/CmmLiveZ.hs | 2 | ||||
-rw-r--r-- | compiler/cmm/CmmProcPointZ.hs | 4 | ||||
-rw-r--r-- | compiler/cmm/CmmSpillReload.hs | 43 | ||||
-rw-r--r-- | compiler/cmm/DFMonad.hs | 162 | ||||
-rw-r--r-- | compiler/cmm/OptimizationFuel.hs | 124 | ||||
-rw-r--r-- | compiler/cmm/StackColor.hs | 2 | ||||
-rw-r--r-- | compiler/cmm/ZipCfg.hs | 4 | ||||
-rw-r--r-- | compiler/cmm/ZipCfgCmmRep.hs | 2 | ||||
-rw-r--r-- | compiler/cmm/ZipDataflow0.hs (renamed from compiler/cmm/ZipDataflow.hs) | 311 |
11 files changed, 531 insertions, 182 deletions
diff --git a/compiler/cmm/Cmm.hs b/compiler/cmm/Cmm.hs index b535c8dbd2..790d072293 100644 --- a/compiler/cmm/Cmm.hs +++ b/compiler/cmm/Cmm.hs @@ -21,6 +21,7 @@ module Cmm ( CmmSafety(..), CmmCallTarget(..), CmmStatic(..), Section(..), + module CmmExpr, BlockId(..), mkBlockId, BlockEnv, emptyBlockEnv, lookupBlockEnv, extendBlockEnv, mkBlockEnv, diff --git a/compiler/cmm/CmmCPSZ.hs b/compiler/cmm/CmmCPSZ.hs index 4dff9bc1d4..35c20c048e 100644 --- a/compiler/cmm/CmmCPSZ.hs +++ b/compiler/cmm/CmmCPSZ.hs @@ -12,14 +12,17 @@ import CmmProcPointZ import CmmSpillReload import CmmTx import DFMonad +import PprCmmZ() +import ZipCfg hiding (zip, unzip) +import ZipCfgCmmRep +import ZipDataflow0 + import DynFlags import ErrUtils import Outputable -import PprCmmZ() import UniqSupply -import ZipCfg hiding (zip, unzip) -import ZipCfgCmmRep -import ZipDataflow + +import Data.IORef ----------------------------------------------------------------------------- -- |Top level driver for the CPS pass @@ -30,25 +33,42 @@ protoCmmCPSZ :: DynFlags -- ^ Dynamic flags: -dcmm-lint -ddump-cps-cmm protoCmmCPSZ dflags (Cmm tops) = do { showPass dflags "CPSZ" ; u <- mkSplitUniqSupply 'p' + ; pass_ref <- newIORef "unoptimized program" -- XXX see [Note global fuel] + ; fuel_ref <- newIORef (tankFilledTo maxBound) -- XXX see [Note global fuel] ; let txtops = initUs_ u $ mapM cpsTop tops - ; let pgm = Cmm $ runDFTx maxBound $ sequence txtops - --- XXX calling runDFTx is totally bogus - ; dumpIfSet_dyn dflags Opt_D_dump_cps_cmm "CPS Cmm" (ppr pgm) - ; return pgm + ; tops <- runFuelIO pass_ref fuel_ref (sequence txtops) + ; dumpIfSet_dyn dflags Opt_D_dump_cps_cmm "CPS Cmm" (ppr (Cmm tops)) + ; return $ Cmm tops } -cpsTop :: CmmTopZ -> UniqSM (DFTx CmmTopZ) -cpsTop p@(CmmData {}) = return $ return p +{- [Note global fuel] +~~~~~~~~~~~~~~~~~~~~~ +In a correct world, the identity and the last pass would be stored in +mutable reference cells associated with an 'HscEnv' and would be +global to one compiler session. Unfortunately the 'HscEnv' is not +plumbed sufficiently close to this function; only the DynFlags are +plumbed here. One day the plumbing will be extended, in which case +this pass will use the global 'pass_ref' and 'fuel_ref' instead of the +bogus facsimiles in place here. +-} + +cpsTop :: CmmTopZ -> UniqSM (FuelMonad CmmTopZ) +cpsTop p@(CmmData {}) = return (return p) cpsTop (CmmProc h l args g) = let procPoints = minimalProcPointSet (runTx cmmCfgOptsZ g) g' = addProcPointProtocols procPoints args g g'' = map_nodes id NotSpillOrReload id g' - in do g <- dual_rewrite dualLivenessWithInsertion g'' - g <- return (g >>= insertLateReloads) - u <- getUs - let g' = g >>= (initUs_ u . dual_rewrite removeDeadAssignmentsAndReloads) - return $ do g <- g' >>= return . map_nodes id spillAndReloadComments id - return $ CmmProc h l args g - where dual_rewrite pass g = - do us <- getUs - return $ runDFM us dualLiveLattice $ b_rewrite pass g + in do { u1 <- getUs; u2 <- getUs; u3 <- getUs + ; entry <- getUniqueUs >>= return . BlockId + ; return $ + do { g <- return g'' + ; g <- dual_rewrite u1 dualLivenessWithInsertion g + ; g <- insertLateReloads' u2 (extend g) + ; g <- dual_rewrite u3 removeDeadAssignmentsAndReloads (trim entry g) + ; return $ CmmProc h l args $ map_nodes id spillAndReloadComments id g + } + } + where dual_rewrite u pass g = runDFM u dualLiveLattice $ b_rewrite pass g + extend (LGraph eid blocks) = Graph (ZLast $ mkBranchNode eid) blocks + trim _ (Graph (ZLast (LastOther (LastBranch id))) blocks) = LGraph id blocks + trim e (Graph tail blocks) = LGraph e (insertBlock (Block e tail) blocks) diff --git a/compiler/cmm/CmmLiveZ.hs b/compiler/cmm/CmmLiveZ.hs index cd969710ba..07801be49f 100644 --- a/compiler/cmm/CmmLiveZ.hs +++ b/compiler/cmm/CmmLiveZ.hs @@ -13,7 +13,7 @@ import CmmTx import DFMonad import PprCmm() import PprCmmZ() -import ZipDataflow +import ZipDataflow0 import ZipCfgCmmRep import Maybes diff --git a/compiler/cmm/CmmProcPointZ.hs b/compiler/cmm/CmmProcPointZ.hs index ac016a7538..b2dbd871c8 100644 --- a/compiler/cmm/CmmProcPointZ.hs +++ b/compiler/cmm/CmmProcPointZ.hs @@ -23,7 +23,7 @@ import UniqFM import UniqSet import ZipCfg import ZipCfgCmmRep -import ZipDataflow +import ZipDataflow0 -- Compute a minimal set of proc points for a control-flow graph. @@ -118,7 +118,7 @@ forward = FComp "proc-point reachability" first middle last exit middle x _ = x last _ (LastCall _ (Just id)) = LastOutFacts [(id, ProcPoint)] last x l = LastOutFacts $ map (\id -> (id, x)) (succs l) - exit _ = LastOutFacts [] + exit x = x minimalProcPointSet :: CmmGraph -> ProcPointSet minimalProcPointSet g = extendPPSet g (postorder_dfs g) entryPoint diff --git a/compiler/cmm/CmmSpillReload.hs b/compiler/cmm/CmmSpillReload.hs index 6f59e8f093..4067f89fb1 100644 --- a/compiler/cmm/CmmSpillReload.hs +++ b/compiler/cmm/CmmSpillReload.hs @@ -10,6 +10,7 @@ module CmmSpillReload , availRegsLattice , cmmAvailableReloads , insertLateReloads + , insertLateReloads' , removeDeadAssignmentsAndReloads ) where @@ -22,7 +23,7 @@ import MkZipCfg import PprCmm() import ZipCfg import ZipCfgCmmRep -import ZipDataflow +import ZipDataflow0 import FastString import Maybes @@ -30,6 +31,7 @@ import Outputable hiding (empty) import qualified Outputable as PP import Panic import UniqSet +import UniqSupply import Maybe import Prelude hiding (zip) @@ -238,14 +240,15 @@ elemAvail (AvailRegs s) r = elemRegSet r s cmmAvailableReloads :: LGraph M Last -> BlockEnv AvailRegs cmmAvailableReloads g = env where env = runDFA availRegsLattice $ - do run_f_anal transfer (fact_bot availRegsLattice) g + do run_f_anal avail_reloads_transfer (fact_bot availRegsLattice) g allFacts - transfer :: FAnalysis M Last AvailRegs - transfer = FComp "available-reloads analysis" first middle last exit - exit _ = LastOutFacts [] - first avail _ = avail - middle = flip middleAvail - last = lastAvail + +avail_reloads_transfer :: FAnalysis M Last AvailRegs +avail_reloads_transfer = FComp "available-reloads analysis" first middle last exit + where exit avail = avail + first avail _ = avail + middle = flip middleAvail + last = lastAvail -- | The transfer equations use the traditional 'gen' and 'kill' @@ -270,11 +273,11 @@ lastAvail :: AvailRegs -> Last -> LastOutFacts AvailRegs lastAvail _ (LastCall _ (Just k)) = LastOutFacts [(k, AvailRegs emptyRegSet)] lastAvail avail l = LastOutFacts $ map (\id -> (id, avail)) $ succs l -insertLateReloads :: LGraph M Last -> DFTx (LGraph M Last) +insertLateReloads :: LGraph M Last -> FuelMonad (LGraph M Last) insertLateReloads g = mapM_blocks insertM g where env = cmmAvailableReloads g avail id = lookupBlockEnv env id `orElse` AvailRegs emptyRegSet - insertM b = functionalDFTx "late reloads" (insert b) + insertM b = fuelConsumingPass "late reloads" (insert b) insert (Block id tail) fuel = propagate (ZFirst id) (avail id) tail fuel propagate h avail (ZTail m t) fuel = let (h', fuel') = maybe_add_reload h avail m fuel in @@ -284,9 +287,23 @@ insertLateReloads g = mapM_blocks insertM g (zipht h' (ZLast l), fuel') maybe_add_reload h avail node fuel = let used = filterRegsUsed (elemAvail avail) node - in if fuel == 0 || isEmptyUniqSet used then (h, fuel) - else (ZHead h (Reload used), fuel-1) - + in if not (canRewriteWithFuel fuel) || isEmptyUniqSet used then (h,fuel) + else (ZHead h (Reload used), oneLessFuel fuel) + +insertLateReloads' :: UniqSupply -> (Graph M Last) -> FuelMonad (Graph M Last) +insertLateReloads' us g = + runDFM us availRegsLattice $ + f_shallow_rewrite avail_reloads_transfer insert bot g + where bot = fact_bot availRegsLattice + insert = null_f_ft { fc_middle_out = middle, fc_last_outs = last } + middle :: AvailRegs -> M -> Maybe (Graph M Last) + last :: AvailRegs -> Last -> Maybe (Graph M Last) + middle avail m = maybe_reload_before avail m (ZTail m (ZLast LastExit)) + last avail l = maybe_reload_before avail l (ZLast (LastOther l)) + maybe_reload_before avail node tail = + let used = filterRegsUsed (elemAvail avail) node + in if isEmptyUniqSet used then Nothing + else Just $ graphOfZTail $ ZTail (Reload used) tail _lateReloadsWithoutFuel :: LGraph M Last -> LGraph M Last _lateReloadsWithoutFuel g = map_blocks insert g diff --git a/compiler/cmm/DFMonad.hs b/compiler/cmm/DFMonad.hs index 970cdcb943..65c033ebb8 100644 --- a/compiler/cmm/DFMonad.hs +++ b/compiler/cmm/DFMonad.hs @@ -1,34 +1,32 @@ module DFMonad - ( OptimizationFuel - , DFTx, runDFTx, lastTxPass, txDecrement, txRemaining, txExhausted - , functionalDFTx - - , DataflowLattice(..) + ( DataflowLattice(..) , DataflowAnalysis - , markFactsUnchanged, factsStatus, getFact, setFact, botFact - , forgetFact, allFacts, factsEnv, checkFactMatch - , addLastOutFact, lastOutFacts, forgetLastOutFacts + , markFactsUnchanged, factsStatus, getFact, setFact, getExitFact, setExitFact + , forgetFact, botFact, allFacts, factsEnv, checkFactMatch + , addLastOutFact, bareLastOutFacts, forgetLastOutFacts , subAnalysis , DFA, runDFA - , DFM, runDFM, liftTx, liftAnal + , DFM, runDFM, liftAnal , markGraphRewritten , freshBlockId , liftUSM + , module OptimizationFuel ) where import CmmTx -import Control.Monad -import Maybes import PprCmm() -import UniqFM -import UniqSupply +import OptimizationFuel import ZipCfg -import qualified ZipCfg as G +import Maybes import Outputable +import UniqFM +import UniqSupply + +import Control.Monad {- @@ -62,27 +60,24 @@ data DataflowLattice a = DataflowLattice { } --- There are three monads here: --- 1. DFTx, the monad of transactions, to be carried through all --- graph-changing computations in the program --- 2. DFA, the monad of analysis, which never changes anything --- 3. DFM, the monad of combined analysis and transformation, +-- 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 DFTxState = DFTxState { df_txlimit :: OptimizationFuel, df_lastpass :: String } data DFState f = DFState { df_uniqs :: UniqSupply , df_rewritten :: ChangeFlag , df_astate :: DFAState f - , df_txstate :: DFTxState - , df_last_outs :: [(BlockId, f)] + , df_fstate :: FuelState } -newtype DFTx a = DFTx (DFTxState -> (a, DFTxState)) newtype DFA fact a = DFA (DataflowLattice fact -> DFAState fact -> (a, DFAState fact)) newtype DFM fact a = DFM (DataflowLattice fact -> DFState fact -> (a, DFState fact)) @@ -92,55 +87,17 @@ liftAnal (DFA f) = DFM f' where f' l s = let (a, anal) = f l (df_astate s) in (a, s {df_astate = anal}) -liftTx :: DFTx a -> DFM f a -liftTx (DFTx f) = DFM f' - where f' _ s = let (a, txs) = f (df_txstate s) - in (a, s {df_txstate = txs}) - -newtype OptimizationFuel = OptimizationFuel Int - deriving (Ord, Eq, Num, Show, Bounded) - -initDFAState :: DFAState f -initDFAState = DFAState emptyBlockEnv NoChange +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 - --- XXX DFTx really needs to be in IO, so we can dump programs in --- intermediate states of optimization ---NR - -functionalDFTx :: String -> (OptimizationFuel -> (a, OptimizationFuel)) -> DFTx a -functionalDFTx name pass = DFTx f - where f s = let (a, fuel) = pass (df_txlimit s) - in (a, DFTxState fuel name) - -runDFTx :: OptimizationFuel -> DFTx a -> a --- should only be called once per program! -runDFTx lim (DFTx f) = fst $ f $ DFTxState lim "<none>" - -lastTxPass :: DFTx String -lastTxPass = DFTx f - where f s = (df_lastpass s, s) - -runDFM :: UniqSupply -> DataflowLattice f -> DFM f a -> DFTx a -runDFM uniqs lattice (DFM f) = DFTx f' - where f' txs = - let (a, s) = f lattice $ DFState uniqs NoChange initDFAState txs [] in - (a, df_txstate s) - -txExhausted :: DFTx Bool -txExhausted = DFTx f - where f s = (df_txlimit s <= 0, s) - -txRemaining :: DFTx OptimizationFuel -txRemaining = DFTx f - where f s = (df_txlimit s, s) - -txDecrement :: String -> OptimizationFuel -> OptimizationFuel -> DFTx () -txDecrement optimizer old new = DFTx f - where f s = ((), s { df_txlimit = lim s, df_lastpass = optimizer }) - lim s = if old == df_txlimit s then new - else panic $ concat ["lost track of ", optimizer, "'s transactions"] +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) class DataflowAnalysis m where markFactsUnchanged :: m f () -- ^ Useful for starting a new iteration @@ -151,10 +108,20 @@ class DataflowAnalysis m where getFact :: BlockId -> m f f setFact :: Outputable f => BlockId -> f -> m f () + getExitFact :: m f f + setExitFact :: Outputable f => f -> m f () checkFactMatch :: Outputable f => BlockId -> f -> m f () -- ^ assert fact already at this val botFact :: m f f forgetFact :: BlockId -> m f () + -- | It might be surprising these next two are needed in a pure analysis, + -- but for some problems we do a 'shallow' rewriting in which a rewritten + -- graph is not itself considered for further rewriting but merely undergoes + -- an analysis. In this case the results of a forward analysis might produce + -- new facts that go on BlockId's that reside outside the graph being analyzed. + -- Thus these 'lastOutFacts' need to be available even in a pure analysis. + addLastOutFact :: (BlockId, f) -> m f () + bareLastOutFacts :: m f [(BlockId, f)] forgetLastOutFacts :: m f () allFacts :: m f (BlockEnv f) factsEnv :: Monad (m f) => m f (BlockId -> f) @@ -184,11 +151,28 @@ instance DataflowAnalysis DFA where 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) + 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 -> + 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 }) - forgetLastOutFacts = return () + 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) checkFactMatch id a = @@ -222,9 +206,13 @@ instance DataflowAnalysis DFM where 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 - forgetLastOutFacts = dfmForgetLastOutFacts + addLastOutFact p = liftAnal $ addLastOutFact p + bareLastOutFacts = liftAnal $ bareLastOutFacts + forgetLastOutFacts = liftAnal $ forgetLastOutFacts allFacts = liftAnal $ allFacts checkFactMatch id a = liftAnal $ checkFactMatch id a @@ -236,17 +224,6 @@ dfmSubAnalysis (DFM f) = DFM f' (a, _) = f l s' in (a, s) -dfmForgetLastOutFacts :: DFM f () -dfmForgetLastOutFacts = DFM f - where f _ s = ((), s { df_last_outs = [] }) - -addLastOutFact :: (BlockId, f) -> DFM f () -addLastOutFact pair = DFM f - where f _ s = ((), s { df_last_outs = pair : df_last_outs s }) - -lastOutFacts :: DFM f [(BlockId, f)] -lastOutFacts = DFM f - where f _ s = (df_last_outs s, s) markGraphRewritten :: DFM f () markGraphRewritten = DFM f @@ -272,13 +249,18 @@ instance Monad (DFM f) where in f' l s') return a = DFM (\_ s -> (a, s)) -instance Monad (DFTx) where - DFTx f >>= k = DFTx (\s -> let (a, s') = f s - DFTx f' = k a - in f' s') - return a = DFTx (\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 -pprSetFact :: Outputable f => BlockId -> f -> f -> f -> SDoc +extract :: (FuelState -> a) -> DFM f a +extract f = DFM (\_ s -> (f $ df_fstate s, s)) + + +pprSetFact :: (Show a, Outputable f) => a -> f -> f -> f -> SDoc pprSetFact id old a join = f4sep [text "at" <+> text (show id), text "added" <+> ppr a, text "to" <+> ppr old, @@ -287,7 +269,3 @@ pprSetFact id old a join = f4sep :: [SDoc] -> SDoc f4sep [] = fsep [] f4sep (d:ds) = fsep (d : map (nest 4) ds) - - -_I_am_abstract :: Int -> OptimizationFuel -_I_am_abstract = OptimizationFuel -- prevents warning: OptimizationFuel unused diff --git a/compiler/cmm/OptimizationFuel.hs b/compiler/cmm/OptimizationFuel.hs new file mode 100644 index 0000000000..c15bd4d630 --- /dev/null +++ b/compiler/cmm/OptimizationFuel.hs @@ -0,0 +1,124 @@ +module OptimizationFuel + ( OptimizationFuel, canRewriteWithFuel, maybeRewriteWithFuel, oneLessFuel + , tankFilledTo, diffFuel + , FuelConsumer + , FuelUsingMonad, FuelState + , lastFuelPass, fuelExhausted, fuelRemaining, fuelDecrement + , lastFuelPassInState, fuelExhaustedInState, fuelRemainingInState + , fuelDecrementState + , runFuel, runFuelIO, runFuelWithLastPass, fuelConsumingPass + , FuelMonad(..) + ) +where + +import GHC.Prim +import Panic + +import Data.IORef + +#include "HsVersions.h" + +type FuelConsumer a = OptimizationFuel -> (a, OptimizationFuel) + +canRewriteWithFuel :: OptimizationFuel -> Bool +oneLessFuel :: OptimizationFuel -> OptimizationFuel +maybeRewriteWithFuel :: OptimizationFuel -> Maybe a -> Maybe a +diffFuel :: OptimizationFuel -> OptimizationFuel -> Int + -- to measure consumption during compilation +tankFilledTo :: Int -> OptimizationFuel + +#ifdef DEBUG +newtype OptimizationFuel = OptimizationFuel Int + deriving Show + +tankFilledTo = OptimizationFuel +canRewriteWithFuel (OptimizationFuel f) = f > 0 +maybeRewriteWithFuel fuel ma = if canRewriteWithFuel fuel then ma else Nothing +oneLessFuel (OptimizationFuel f) = ASSERT (f > 0) (OptimizationFuel (f - 1)) +diffFuel (OptimizationFuel f) (OptimizationFuel f') = f - f' +#else +-- type OptimizationFuel = State# () -- would like this, but it won't work +data OptimizationFuel = OptimizationFuel + deriving Show +tankFilledTo _ = undefined -- should be impossible to evaluate + -- realWorld# might come in handy, too... +canRewriteWithFuel OptimizationFuel = True +maybeRewriteWithFuel _ ma = ma +oneLessFuel f = f +diffFuel _ _ = 0 +#endif + +-- stop warnings about things that aren't used +_unused :: State# () -> FS.FastString +_unused = undefined panic + + +data FuelState = FuelState { fs_fuellimit :: OptimizationFuel, fs_lastpass :: String } +newtype FuelMonad a = FuelMonad (FuelState -> (a, FuelState)) + +fuelConsumingPass :: String -> FuelConsumer a -> FuelMonad a +fuelConsumingPass name f = do fuel <- fuelRemaining + let (a, fuel') = f fuel + fuelDecrement name fuel fuel' + return a + +runFuel :: FuelMonad a -> FuelConsumer a +runFuelWithLastPass :: FuelMonad a -> FuelConsumer (a, String) + +runFuelIO :: IORef String -> IORef OptimizationFuel -> FuelMonad a -> IO a +runFuelIO pass_ref fuel_ref (FuelMonad f) = + do { pass <- readIORef pass_ref + ; fuel <- readIORef fuel_ref + ; let (a, FuelState fuel' pass') = f (FuelState fuel pass) + ; writeIORef pass_ref pass' + ; writeIORef fuel_ref fuel' + ; return a + } + +initialFuelState :: OptimizationFuel -> FuelState +initialFuelState fuel = FuelState fuel "unoptimized program" + +runFuel (FuelMonad f) fuel = let (a, s) = f $ initialFuelState fuel + in (a, fs_fuellimit s) +runFuelWithLastPass (FuelMonad f) fuel = let (a, s) = f $ initialFuelState fuel + in ((a, fs_lastpass s), fs_fuellimit s) + +lastFuelPassInState :: FuelState -> String +lastFuelPassInState = fs_lastpass + +fuelExhaustedInState :: FuelState -> Bool +fuelExhaustedInState = canRewriteWithFuel . fs_fuellimit + +fuelRemainingInState :: FuelState -> OptimizationFuel +fuelRemainingInState = fs_fuellimit + +fuelDecrementState + :: String -> OptimizationFuel -> OptimizationFuel -> FuelState -> FuelState +fuelDecrementState new_optimizer old new s = + FuelState { fs_fuellimit = lim, fs_lastpass = optimizer } + where lim = if diffFuel old (fs_fuellimit s) == 0 then new + else panic $ + concat ["lost track of ", new_optimizer, "'s transactions"] + optimizer = if diffFuel old new > 0 then new_optimizer else fs_lastpass s + +class Monad m => FuelUsingMonad m where + fuelRemaining :: m OptimizationFuel + fuelDecrement :: String -> OptimizationFuel -> OptimizationFuel -> m () + fuelExhausted :: m Bool + lastFuelPass :: m String + + +instance Monad FuelMonad where + FuelMonad f >>= k = FuelMonad (\s -> let (a, s') = f s + FuelMonad f' = k a + in f' s') + return a = FuelMonad (\s -> (a, s)) + +instance FuelUsingMonad FuelMonad where + fuelRemaining = extract fuelRemainingInState + lastFuelPass = extract lastFuelPassInState + fuelExhausted = extract fuelExhaustedInState + fuelDecrement p f f' = FuelMonad (\s -> ((), fuelDecrementState p f f' s)) + +extract :: (FuelState -> a) -> FuelMonad a +extract f = FuelMonad (\s -> (f s, s)) diff --git a/compiler/cmm/StackColor.hs b/compiler/cmm/StackColor.hs index 2f97a18877..94bb5c602d 100644 --- a/compiler/cmm/StackColor.hs +++ b/compiler/cmm/StackColor.hs @@ -10,7 +10,7 @@ import qualified GraphOps import MachOp import ZipCfg import ZipCfgCmmRep -import ZipDataflow +import ZipDataflow0 import Maybes import Panic diff --git a/compiler/cmm/ZipCfg.hs b/compiler/cmm/ZipCfg.hs index 30843e5bb8..228504ce7c 100644 --- a/compiler/cmm/ZipCfg.hs +++ b/compiler/cmm/ZipCfg.hs @@ -21,7 +21,7 @@ module ZipCfg , pprLgraph, pprGraph - , entry -- exported for the convenience of ZipDataflow, at least for now + , entry -- exported for the convenience of ZipDataflow0, at least for now {- -- the following functions might one day be useful and can be found @@ -75,7 +75,7 @@ the data constructor 'LastExit'. A graph may contain at most one 'LastExit' node, and a graph representing a full procedure should not contain any 'LastExit' nodes. 'LastExit' nodes are used only to splice graphs together, either during graph construction (see module 'MkZipCfg') -or during optimization (see module 'ZipDataflow'). +or during optimization (see module 'ZipDataflow0'). A graph is parameterized over the types of middle and last nodes. Each of these types will typically be instantiated with a subset of C-- statements diff --git a/compiler/cmm/ZipCfgCmmRep.hs b/compiler/cmm/ZipCfgCmmRep.hs index b710a941b0..c5464e2b42 100644 --- a/compiler/cmm/ZipCfgCmmRep.hs +++ b/compiler/cmm/ZipCfgCmmRep.hs @@ -25,7 +25,7 @@ import ClosureInfo import FastString import ForeignCall import MachOp -import qualified ZipDataflow as DF +import qualified ZipDataflow0 as DF import ZipCfg import MkZipCfg diff --git a/compiler/cmm/ZipDataflow.hs b/compiler/cmm/ZipDataflow0.hs index 2087b9ce34..3a3b0a8b75 100644 --- a/compiler/cmm/ZipDataflow.hs +++ b/compiler/cmm/ZipDataflow0.hs @@ -1,16 +1,18 @@ {-# LANGUAGE MultiParamTypeClasses #-} -module ZipDataflow +module ZipDataflow0 ( Answer(..) , BComputation(..), BAnalysis, BTransformation, BFunctionalTransformation , BPass, BUnlimitedPass - , FComputation(..), FAnalysis, FTransformation, FPass, FUnlimitedPass + , FComputation(..), FAnalysis, FTransformation, FFunctionalTransformation + , FPass, FUnlimitedPass , LastOutFacts(..) , DebugNodes , anal_b, a_t_b, a_ft_b, a_ft_b_unlimited, ignore_transactions_b , anal_f, a_t_f + , null_f_ft, null_b_ft , run_b_anal, run_f_anal , refine_f_anal, refine_b_anal, fold_edge_facts_b, fold_edge_facts_with_nodes_b - , b_rewrite, f_rewrite + , b_rewrite, f_rewrite, b_shallow_rewrite, f_shallow_rewrite , solve_graph_b, solve_graph_f ) where @@ -145,7 +147,7 @@ data FComputation middle last input outmid outlast = FComp , fc_first_out :: input -> BlockId -> outmid , fc_middle_out :: input -> middle -> outmid , fc_last_outs :: input -> last -> outlast - , fc_exit_outs :: input -> outlast + , fc_exit_out :: input -> outmid } -- | The notions of analysis, pass, and transformation are analogous to the @@ -159,6 +161,11 @@ newtype LastOutFacts a = LastOutFacts [(BlockId, a)] type FAnalysis m l a = FComputation m l a a (LastOutFacts a) type FTransformation m l a = FComputation m l a (Maybe (UniqSM (Graph m l))) (Maybe (UniqSM (Graph m l))) +type FFunctionalTransformation m l a = + FComputation m l a (Maybe (Graph m l)) + (Maybe (Graph m l)) + -- ToDo: consider replacing UniqSM (Graph l m) with (AGraph m l) + type FPass m l a = FComputation m l a (OptimizationFuel -> DFM a (Answer m l a)) (OptimizationFuel -> DFM a (Answer m l (LastOutFacts a))) @@ -177,6 +184,9 @@ We can make an analysis pass, or we can combine a related analysis and transformation into a full pass. -} +null_b_ft :: BFunctionalTransformation m l a +null_f_ft :: FFunctionalTransformation m l a + anal_b :: BAnalysis m l a -> BPass m l a a_t_b :: BAnalysis m l a -> BTransformation m l a -> BPass m l a a_ft_b :: BAnalysis m l a -> BFunctionalTransformation m l a -> BPass m l a @@ -248,6 +258,19 @@ f_rewrite :: (DebugNodes m l, LastNode l, Outputable m, Outputable a) => FPass m l a -> a -> LGraph m l -> DFM a (LGraph m l) -- ^ extra parameter is the entry fact +b_shallow_rewrite + :: (DebugNodes m l, Outputable a) + => BAnalysis m l a -> BFunctionalTransformation m l a -> + Graph m l -> DFM a (Graph m l) + +b_shallow_rewrite = error "unimp" + +f_shallow_rewrite + :: (DebugNodes m l, Outputable a) + => FAnalysis m l a -> FFunctionalTransformation m l a -> + a -> Graph m l -> DFM a (Graph m l) + + -- | If the solution to a problem is already sitting in a monad, we -- should be able to take a short cut and just rewrite it in one pass. -- But not yet implemented. @@ -396,7 +419,7 @@ solve_graph_b comp fuel graph exit_fact = Rewrite g -> do { bot <- botFact ; (fuel, a) <- subAnalysis' $ - solve_graph_b_g comp (fuel-1) g bot + solve_graph_b_g comp (oneLessFuel fuel) g bot ; head_in fuel h a } ; my_trace "result of" (text (bc_name comp) <+> text "on" <+> ppr (G.blockId b) <+> text "is" <+> ppr block_in) $ @@ -407,14 +430,14 @@ solve_graph_b comp fuel graph exit_fact = bc_middle_in comp out m fuel >>= \x -> case x of Dataflow a -> head_in fuel h a Rewrite g -> - do { (fuel, a) <- subAnalysis' $ solve_graph_b_g comp (fuel-1) g out + do { (fuel, a) <- subAnalysis' $ solve_graph_b_g comp (oneLessFuel fuel) g out ; my_trace "Rewrote middle node" (f4sep [ppr m, text "to", pprGraph g]) $ head_in fuel h a } head_in fuel (G.ZFirst id) out = bc_first_in comp out id fuel >>= \x -> case x of Dataflow a -> return (fuel, a) - Rewrite g -> do { subAnalysis' $ solve_graph_b_g comp (fuel-1) g out } + Rewrite g -> do { subAnalysis' $ solve_graph_b_g comp (oneLessFuel fuel) g out } in do { fuel <- run "backward" (bc_name comp) (return ()) set_block_fact fuel blocks @@ -498,7 +521,7 @@ solve_and_rewrite_b comp fuel graph exit_fact = Rewrite g -> do { markGraphRewritten ; bot <- botFact - ; (fuel, a, g') <- solve_and_rewrite_b_graph comp (fuel-1) g bot + ; (fuel, a, g') <- solve_and_rewrite_b_graph comp (oneLessFuel fuel) g bot ; let G.Graph t new_blocks = g' ; let rewritten' = new_blocks `plusUFM` rewritten ; propagate fuel h a t rewritten' -- continue at entry of g' @@ -514,7 +537,7 @@ solve_and_rewrite_b comp fuel graph exit_fact = Dataflow a -> propagate fuel h a (G.ZTail m tail) rewritten Rewrite g -> do { markGraphRewritten - ; (fuel, a, g') <- solve_and_rewrite_b_graph comp (fuel-1) g out + ; (fuel, a, g') <- solve_and_rewrite_b_graph comp (oneLessFuel fuel) g out ; let G.Graph t newblocks = G.splice_tail g' tail ; my_trace "Rewrote middle node" (f4sep [ppr m, text "to", pprGraph g']) $ @@ -527,7 +550,7 @@ solve_and_rewrite_b comp fuel graph exit_fact = ; rewrite_blocks comp fuel (extendBlockEnv rewritten id b) bs } Rewrite g -> do { markGraphRewritten - ; (fuel, a, g') <- solve_and_rewrite_b_graph comp (fuel-1) g out + ; (fuel, a, g') <- solve_and_rewrite_b_graph comp (oneLessFuel fuel) g out ; let G.Graph t newblocks = G.splice_tail g' tail ; my_trace "Rewrote label " (f4sep [ppr id,text "to",pprGraph g])$ propagate fuel h a t (newblocks `plusUFM` rewritten) } @@ -551,11 +574,11 @@ solve_and_rewrite_b_graph comp fuel graph exit_fact = (fuel, a, g') <- solve_and_rewrite_b comp fuel g exit_fact return (fuel, a, remove_entry_label g') -b_rewrite comp g = - do { fuel <- liftTx txRemaining +b_rewrite comp g = + do { fuel <- fuelRemaining ; bot <- botFact ; (fuel', _, gc) <- solve_and_rewrite_b comp fuel g bot - ; liftTx $ txDecrement (bc_name comp) fuel fuel' + ; fuelDecrement (bc_name comp) fuel fuel' ; return gc } @@ -603,7 +626,8 @@ ignore_transactions_b comp = answer' :: (b -> DFM f (Graph m l)) -> OptimizationFuel -> Maybe b -> a -> DFM f (Answer m l a) answer' lift fuel r a = - case r of Just gc | fuel > 0 -> do { g <- lift gc; return $ Rewrite g } + case r of Just gc | canRewriteWithFuel fuel + -> do { g <- lift gc; return $ Rewrite g } _ -> return $ Dataflow a unlimited_answer' @@ -652,24 +676,20 @@ refine_f_anal comp graph initial = where blocks = G.postorder_dfs graph set_successor_facts () (G.Block id t) = let forward in' (G.ZTail m t) = forward (fc_middle_out comp in' m) t - forward in' (G.ZLast l) = setEdgeFacts (last_outs comp in' l) + forward in' (G.ZLast l) = last_outs setEdgeFacts comp in' l _blockname = if id == G.lg_entry graph then "<entry>" else show id in getFact id >>= \a -> forward (fc_first_out comp a id) t setEdgeFacts (LastOutFacts fs) = mapM_ setEdgeFact fs setEdgeFact (id, a) = setFact id a -last_outs :: FComputation m l i om ol -> i -> G.ZLast l -> ol -last_outs comp i (G.LastExit) = fc_exit_outs comp i -last_outs comp i (G.LastOther l) = fc_last_outs comp i l +last_outs :: (DataflowAnalysis df, Outputable a) => (LastOutFacts a -> df a ()) -> FComputation m l i a (LastOutFacts a) -> i -> G.ZLast l -> df a () +last_outs _do_last_outs comp i (G.LastExit) = setExitFact (fc_exit_out comp i) +last_outs do_last_outs comp i (G.LastOther l) = do_last_outs $ fc_last_outs comp i l --- | In the general case we solve a graph in the context of a larger subgraph. --- To do this, we need a locally modified computation that allows an --- ``exit fact'' to flow out of the exit node. We pass in a fresh BlockId --- to which the exit fact can flow +last_rewrite :: FComputation m l i a a -> i -> G.ZLast l -> a +last_rewrite comp i (G.LastExit) = fc_exit_out comp i +last_rewrite comp i (G.LastOther l) = fc_last_outs comp i l -comp_with_exit_f :: FPass m l a -> BlockId -> FPass m l a -comp_with_exit_f comp exit_fact_id = comp { fc_exit_outs = exit_outs } - where exit_outs in' _fuel = return $ Dataflow $ LastOutFacts [(exit_fact_id, in')] -- | Given [[comp_with_exit_f]], we can now solve a graph simply by doing a -- forward analysis on the modified computation. @@ -678,15 +698,13 @@ solve_graph_f :: FPass m l a -> OptimizationFuel -> G.LGraph m l -> a -> DFM a (OptimizationFuel, a, LastOutFacts a) solve_graph_f comp fuel g in_fact = - do { exit_fact_id <- freshBlockId "proxy for exit node" - ; fuel <- general_forward (comp_with_exit_f comp exit_fact_id) fuel in_fact g - ; a <- getFact exit_fact_id + do { fuel <- general_forward fuel in_fact g + ; a <- getExitFact ; outs <- lastOutFacts - ; forgetFact exit_fact_id -- close space leak - ; return (fuel, a, LastOutFacts outs) } + ; return (fuel, a, outs) } where -- general_forward :: FPass m l a -> OptimizationFuel -> a -> G.LGraph m l -> DFM a OptimizationFuel - general_forward comp fuel entry_fact graph = + general_forward fuel entry_fact graph = let blocks = G.postorder_dfs g is_local id = isJust $ lookupBlockEnv (G.lg_blocks g) id -- set_or_save :: LastOutFacts a -> DFM a () @@ -702,15 +720,19 @@ solve_graph_f comp fuel g in_fact = Dataflow a -> set_tail_facts fuel a t Rewrite g -> do (fuel, out, last_outs) <- - subAnalysis' $ solve_graph_f_g comp (fuel-1) g in' + subAnalysis' $ solve_graph_f_g comp (oneLessFuel fuel) g in' set_or_save last_outs set_tail_facts fuel out t - set_tail_facts fuel in' (G.ZLast l) = - last_outs comp in' l fuel >>= \x -> case x of + set_tail_facts fuel in' (G.ZLast LastExit) = + fc_exit_out comp in' fuel >>= \x -> case x of + Dataflow a -> do { setExitFact a; return fuel } + Rewrite _g -> error "rewriting exit node not implemented" + set_tail_facts fuel in' (G.ZLast (G.LastOther l)) = + fc_last_outs comp in' l fuel >>= \x -> case x of Dataflow outs -> do { set_or_save outs; return fuel } Rewrite g -> do (fuel, _, last_outs) <- - subAnalysis' $ solve_graph_f_g comp (fuel-1) g in' + subAnalysis' $ solve_graph_f_g comp (oneLessFuel fuel) g in' set_or_save last_outs return fuel G.Block id t = b @@ -719,7 +741,7 @@ solve_graph_f comp fuel g in_fact = case infact of Dataflow a -> set_tail_facts fuel a t Rewrite g -> do (fuel, out, last_outs) <- subAnalysis' $ - solve_graph_f_g comp (fuel-1) g idfact + solve_graph_f_g comp (oneLessFuel fuel) g idfact set_or_save last_outs set_tail_facts fuel out t in run "forward" (fc_name comp) set_entry set_successor_facts fuel blocks @@ -747,11 +769,180 @@ solve_and_rewrite_f :: DFM a (OptimizationFuel, a, LGraph m l) solve_and_rewrite_f comp fuel graph in_fact = do solve_graph_f comp fuel graph in_fact -- pass 1 - exit_id <- freshBlockId "proxy for exit node" - (fuel, g) <- forward_rewrite (comp_with_exit_f comp exit_id) fuel graph in_fact - exit_fact <- getFact exit_id + (fuel, g) <- forward_rewrite comp fuel graph in_fact + exit_fact <- getExitFact --- XXX should drop this; it's in the monad return (fuel, exit_fact, g) +f_shallow_rewrite anal ftx in_fact g = + do { fuel <- fuelRemaining + ; solve_shallow_graph_f (return ()) anal ftx in_fact g fuel + ; id <- freshBlockId "temporary entry id" + ; (blocks, fuel') <- + forward_rewrite_gen don't_rewrite anal ftx (ZFirst id) in_fact g fuel + ; fuelDecrement (fc_name ftx) fuel fuel' + ; return (remove_entry_label (LGraph id blocks)) + } + where don't_rewrite finish g fuel = finish >>= \b -> return (b, g, fuel) + + +shallow_tail_solve_f + :: (DebugNodes m l, Outputable a) + => DFM a b -- final action and result after solving this tail + -> FAnalysis m l a -> FFunctionalTransformation m l a + -> (BlockId -> Bool) -- local blocks + -> a -> ZTail m l -> OptimizationFuel -> DFM a (b, OptimizationFuel) +shallow_tail_solve_f finish anal ftx is_local in' (G.ZTail m t) fuel = + my_trace "Solving middle node" (ppr m) $ + case maybeRewriteWithFuel fuel $ fc_middle_out ftx in' m of + Just g -> do out <- subAnalysis' $ liftAnal $ + anal_f_general getExitFact anal in' g + shallow_tail_solve_f finish anal ftx is_local out t (oneLessFuel fuel) + Nothing -> shallow_tail_solve_f finish anal ftx is_local + (fc_middle_out anal in' m) t fuel +shallow_tail_solve_f finish anal ftx is_local in' (G.ZLast (G.LastOther l)) fuel = + case maybeRewriteWithFuel fuel $ fc_last_outs ftx in' l of + Just g -> do { last_outs <- + subAnalysis' $ liftAnal $ anal_f_general lastOutFacts anal in' g + ; set_or_save last_outs + ; b <- finish + ; return (b, oneLessFuel fuel) } + Nothing -> do { set_or_save (fc_last_outs anal in' l) + ; b <- finish + ; return (b, fuel) } + where set_or_save = mk_set_or_save is_local +shallow_tail_solve_f finish anal ftx _is_local in' (G.ZLast LastExit) fuel = + case maybeRewriteWithFuel fuel $ fc_exit_out ftx in' of + Just g -> do { a <- + subAnalysis' $ liftAnal $ anal_f_general getExitFact anal in' g + ; setExitFact a + ; b <- finish + ; return (b, oneLessFuel fuel) } + Nothing -> do { setExitFact $ fc_exit_out anal in' + ; b <- finish + ; return (b, fuel) } + +anal_f_general :: (DebugNodes m l, Outputable a) + => DFA a b -> FAnalysis m l a -> a -> Graph m l -> DFA a b +anal_f_general finish anal in_fact (Graph entry blockenv) = + general_forward in_fact + where + is_local id = isJust $ lookupBlockEnv blockenv id + set_or_save = mk_set_or_save is_local + anal_tail = gen_tail_anal_f set_or_save anal + blocks = G.postorder_dfs_from blockenv entry + general_forward in_fact = + do { let setup = anal_tail in_fact entry -- sufficient to do once + ; let set_successor_facts () (Block id tail) = + do { idfact <- getFact id + ; anal_tail (fc_first_out anal idfact id) tail } + ; run "forward" (fc_name anal) setup set_successor_facts () blocks + ; finish + } + +gen_tail_anal_f :: (Outputable a) => + (LastOutFacts a -> DFA a ()) -> FAnalysis m l a -> a -> ZTail m l -> DFA a () +gen_tail_anal_f do_last_outs anal a tail = propagate a tail + where propagate a (ZTail m t) = propagate (fc_middle_out anal a m) t + propagate a (ZLast LastExit) = setExitFact (fc_exit_out anal a) + propagate a (ZLast (LastOther l)) = do_last_outs $ fc_last_outs anal a l + + +solve_shallow_graph_f :: + (DebugNodes m l, Outputable a) => + DFM a b -> + FAnalysis m l a -> FFunctionalTransformation m l a -> a -> G.Graph m l + -> OptimizationFuel -> DFM a (b, OptimizationFuel) +solve_shallow_graph_f finish anal ftx in_fact (Graph entry blockenv) fuel = + do { fuel <- general_forward in_fact fuel + ; b <- finish + ; return (b, fuel) } + where + is_local id = isJust $ lookupBlockEnv blockenv id + set_or_save = mk_set_or_save is_local + solve_tail = shallow_tail_solve_f lastOutFacts anal ftx is_local + blocks = G.postorder_dfs_from blockenv entry + name = concat [fc_name anal, " and ", fc_name ftx] + general_forward in_fact fuel = + do { (last_outs, fuel) <- solve_tail in_fact entry fuel + ; set_or_save last_outs + ; let set_successor_facts fuel (Block id tail) = + do { idfact <- getFact id + ; (last_outs, fuel) <- + case maybeRewriteWithFuel fuel $ fc_first_out ftx idfact id of + Nothing -> solve_tail idfact tail fuel + Just g -> + do outfact <- + subAnalysis' $ liftAnal $ + anal_f_general getExitFact anal idfact g + solve_tail outfact tail (oneLessFuel fuel) + ; set_or_save last_outs + ; return fuel } + ; run "forward" name (return ()) set_successor_facts fuel blocks } + +mk_set_or_save :: (DataflowAnalysis df, Monad (df a), Outputable a) => + (BlockId -> Bool) -> LastOutFacts a -> df a () +mk_set_or_save is_local (LastOutFacts l) = mapM_ set_or_save_one l + where set_or_save_one (id, a) = + if is_local id then setFact id a else addLastOutFact (id, a) + +lastOutFacts :: (DataflowAnalysis m, Monad (m f)) => m f (LastOutFacts f) +lastOutFacts = bareLastOutFacts >>= return . LastOutFacts + + +fwd_rew_tail_gen :: (DebugNodes m l, Outputable a) => + (forall b . DFM a b -> Graph m l -> OptimizationFuel -> DFM a (b, Graph m l, OptimizationFuel)) -> + FAnalysis m l a -> FFunctionalTransformation m l a -> ZHead m -> a -> ZTail m l + -> BlockEnv (Block m l) + -> OptimizationFuel -> DFM a (BlockEnv (Block m l), OptimizationFuel) +fwd_rew_tail_gen recursive_rewrite anal ftx head in_fact tail rewritten fuel = + propagate head in_fact tail rewritten fuel + where + propagate h in' (G.ZTail m t) rewritten fuel = + my_trace "Rewriting middle node" (ppr m) $ + case maybeRewriteWithFuel fuel $ fc_middle_out ftx in' m of + Nothing -> propagate (G.ZHead h m) (fc_middle_out anal in' m) t rewritten fuel + Just g -> do markGraphRewritten + (a, g, fuel) <- recursive_rewrite getExitFact g fuel + let (blocks, h') = G.splice_head' h g + propagate h' a t (blocks `plusUFM` rewritten) fuel + propagate h in' (G.ZLast l) rewritten fuel = + case maybeRewriteWithFuel fuel $ last_rewrite ftx in' l of + Nothing -> -- can throw away facts because this is the rewriting phase + return (insertBlock (zipht h (G.ZLast l)) rewritten, fuel) + Just g -> do markGraphRewritten + ((), g, fuel) <- recursive_rewrite (return ()) g fuel + let g' = G.splice_head_only' h g + return (G.lg_blocks g' `plusUFM` rewritten, fuel) + +forward_rewrite_gen :: + (DebugNodes m l, Outputable a) => + (forall b . DFM a b -> Graph m l -> OptimizationFuel -> DFM a (b, Graph m l, OptimizationFuel)) -> + FAnalysis m l a -> FFunctionalTransformation m l a -> ZHead m -> a -> Graph m l + -> OptimizationFuel -> DFM a (BlockEnv (Block m l), OptimizationFuel) +forward_rewrite_gen recursive_rewrite anal ftx head a (Graph entry blockenv) fuel = + do (rewritten, fuel) <- rewrite_tail head a entry emptyBlockEnv fuel + rewrite_blocks (G.postorder_dfs_from blockenv entry) rewritten fuel + where + -- need to build in some checking for consistency of facts + rewrite_tail = fwd_rew_tail_gen recursive_rewrite anal ftx + rewrite_blocks [] rewritten fuel = return (rewritten, fuel) + rewrite_blocks (G.Block id t : bs) rewritten fuel = + do id_fact <- getFact id + case maybeRewriteWithFuel fuel $ fc_first_out ftx id_fact id of + Nothing -> do { (rewritten, fuel) <- + rewrite_tail (ZFirst id) id_fact t rewritten fuel + ; rewrite_blocks bs rewritten fuel } + Just g -> do { (outfact, g, fuel) <- recursive_rewrite getExitFact g fuel + ; let (blocks, h) = splice_head' (ZFirst id) g + ; (rewritten, fuel) <- + rewrite_tail h outfact t (blocks `plusUFM` rewritten) fuel + ; rewrite_blocks bs rewritten fuel } + + + + + + solve_and_rewrite_f_graph :: (DebugNodes m l, Outputable a) => FPass m l a -> OptimizationFuel -> Graph m l -> a -> @@ -786,7 +977,7 @@ forward_rewrite comp fuel graph entry_fact = case first_out of Dataflow a -> propagate fuel (G.ZFirst id) a t rewritten bs Rewrite g -> do { markGraphRewritten - ; rewrite_blocks (fuel-1) rewritten + ; rewrite_blocks (oneLessFuel fuel) rewritten (G.postorder_dfs (labelGraph id g) ++ bs) } -- propagate :: OptimizationFuel -> G.ZHead m -> a -> G.ZTail m l -> BlockEnv (G.Block m l) -> -- [G.Block m l] -> DFM a (OptimizationFuel, G.LGraph m l) @@ -796,25 +987,36 @@ forward_rewrite comp fuel graph entry_fact = Dataflow a -> propagate fuel (G.ZHead h m) a t rewritten bs Rewrite g -> do markGraphRewritten - (fuel, a, g) <- solve_and_rewrite_f_graph comp (fuel-1) g in' + (fuel, a, g) <- solve_and_rewrite_f_graph comp (oneLessFuel fuel) g in' let (blocks, h') = G.splice_head' h g propagate fuel h' a t (blocks `plusUFM` rewritten) bs - propagate fuel h in' (G.ZLast l) rewritten bs = - do last_outs comp in' l fuel >>= \x -> case x of + propagate fuel h in' t@(G.ZLast G.LastExit) rewritten bs = + do fc_exit_out comp in' fuel >>= \x -> case x of + Dataflow a -> + do setExitFact a + let b = G.zipht h t + rewrite_blocks fuel (G.insertBlock b rewritten) bs + Rewrite g -> + do markGraphRewritten + (fuel, _, g) <- solve_and_rewrite_f_graph comp (oneLessFuel fuel) g in' + let g' = G.splice_head_only' h g + rewrite_blocks fuel (G.lg_blocks g' `plusUFM` rewritten) bs + propagate fuel h in' t@(G.ZLast (G.LastOther l)) rewritten bs = + do fc_last_outs comp in' l fuel >>= \x -> case x of Dataflow outs -> do set_or_save outs - let b = G.zip (G.ZBlock h (G.ZLast l)) + let b = G.zipht h t rewrite_blocks fuel (G.insertBlock b rewritten) bs Rewrite g -> do markGraphRewritten - (fuel, _, g) <- solve_and_rewrite_f_graph comp (fuel-1) g in' + (fuel, _, g) <- solve_and_rewrite_f_graph comp (oneLessFuel fuel) g in' let g' = G.splice_head_only' h g rewrite_blocks fuel (G.lg_blocks g' `plusUFM` rewritten) bs f_rewrite comp entry_fact g = - do { fuel <- liftTx txRemaining + do { fuel <- fuelRemaining ; (fuel', _, gc) <- solve_and_rewrite_f comp fuel g entry_fact - ; liftTx $ txDecrement (fc_name comp) fuel fuel' + ; fuelDecrement (fc_name comp) fuel fuel' ; return gc } @@ -848,7 +1050,7 @@ let debug s (f, comp) = anal_f comp = comp { fc_first_out = wrap2 $ fc_first_out comp , fc_middle_out = wrap2 $ fc_middle_out comp , fc_last_outs = wrap2 $ fc_last_outs comp - , fc_exit_outs = wrap1 $ fc_exit_outs comp + , fc_exit_out = wrap1 $ fc_exit_out comp } where wrap2 f out node _fuel = return $ Dataflow (f out node) wrap1 f fact _fuel = return $ Dataflow (f fact) @@ -862,11 +1064,11 @@ a_t_f anal tx = answer fuel (fc_middle_out tx in' m) (fc_middle_out anal in' m) last_outs in' l fuel = answer fuel (fc_last_outs tx in' l) (fc_last_outs anal in' l) - exit_outs in' fuel = undefined - answer fuel (fc_exit_outs tx in') (fc_exit_outs anal in') + exit_out in' fuel = undefined + answer fuel (fc_exit_out tx in') (fc_exit_out anal in') in FComp { fc_name = concat [fc_name anal, " and ", fc_name tx] , fc_last_outs = last_outs, fc_middle_out = middle_out - , fc_first_out = first_out, fc_exit_outs = exit_outs } + , fc_first_out = first_out, fc_exit_out = exit_out } f4sep :: [SDoc] -> SDoc @@ -889,3 +1091,10 @@ subAnalysis' m = _unused :: FS.FastString _unused = undefined + +null_b_ft = BComp "do nothing" Nothing no2 no2 no2 + where no2 _ _ = Nothing + +null_f_ft = FComp "do nothing" no2 no2 no2 (\_ -> Nothing) + where no2 _ _ = Nothing + |