packages feed

hoopl 3.7.8.0 → 3.7.12.1

raw patch · 17 files changed

+1880/−175 lines, 17 filesdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

- Compiler.Hoopl: data Body n
- Compiler.Hoopl: data Graph n e x
- Compiler.Hoopl: type AGraph n e x = FuelMonad (Graph n e x)
- Compiler.Hoopl: type LabelSet = IntSet
+ Compiler.Hoopl: (|*><*|) :: AGraph n e C -> AGraph n C x -> AGraph n e x
+ Compiler.Hoopl: analyzeAndRewriteBwd' :: (Edges n) => BwdPass n f -> Graph n e x -> Fact x f -> FuelMonad (Graph n e x, FactBase f, MaybeO e f)
+ Compiler.Hoopl: analyzeAndRewriteFwd' :: (Edges n) => FwdPass n f -> Graph n e x -> Fact e f -> FuelMonad (Graph n e x, FactBase f, MaybeO x f)
+ Compiler.Hoopl: data AGraph n e x
+ Compiler.Hoopl: data Body' block n
+ Compiler.Hoopl: data Graph' block n e x
+ Compiler.Hoopl: data LabelSet
+ Compiler.Hoopl: debugBwdJoins :: (Show f) => TraceFn -> ChangePred -> BwdPass n f -> BwdPass n f
+ Compiler.Hoopl: debugFwdJoins :: (Show f) => TraceFn -> ChangePred -> FwdPass n f -> FwdPass n f
+ Compiler.Hoopl: graphOfAGraph :: AGraph n e x -> FuelMonad (Graph n e x)
+ Compiler.Hoopl: showGraph :: (Edges n) => Showing n -> Graph n e x -> String
+ Compiler.Hoopl: type Body = Body' Block
+ Compiler.Hoopl: type Graph = Graph' Block
+ Compiler.Hoopl: type TraceFn = forall a. String -> a -> a
+ Compiler.Hoopl.ZipDataflowNoRG: BwdPass :: DataflowLattice f -> BwdTransfer n f -> BwdRewrite n f -> BwdPass n f
+ Compiler.Hoopl.ZipDataflowNoRG: BwdRes :: (AGraph n e x) -> (BwdRewrite n f) -> BwdRes n f e x
+ Compiler.Hoopl.ZipDataflowNoRG: FwdPass :: DataflowLattice f -> FwdTransfer n f -> FwdRewrite n f -> FwdPass n f
+ Compiler.Hoopl.ZipDataflowNoRG: FwdRes :: (AGraph n e x) -> (FwdRewrite n f) -> FwdRes n f e x
+ Compiler.Hoopl.ZipDataflowNoRG: analyzeAndRewriteBwd :: (Edges n) => BwdPass n f -> ZBody n -> FactBase f -> FuelMonad (ZBody n, FactBase f)
+ Compiler.Hoopl.ZipDataflowNoRG: analyzeAndRewriteBwd' :: (Edges n) => BwdPass n f -> ZGraph n e x -> Fact x f -> FuelMonad (ZGraph n e x, FactBase f, MaybeO e f)
+ Compiler.Hoopl.ZipDataflowNoRG: analyzeAndRewriteFwd :: (Edges n) => FwdPass n f -> ZBody n -> FactBase f -> FuelMonad (ZBody n, FactBase f)
+ Compiler.Hoopl.ZipDataflowNoRG: analyzeAndRewriteFwd' :: (Edges n) => FwdPass n f -> ZGraph n e x -> Fact e f -> FuelMonad (ZGraph n e x, FactBase f, MaybeO x f)
+ Compiler.Hoopl.ZipDataflowNoRG: bp_lattice :: BwdPass n f -> DataflowLattice f
+ Compiler.Hoopl.ZipDataflowNoRG: bp_rewrite :: BwdPass n f -> BwdRewrite n f
+ Compiler.Hoopl.ZipDataflowNoRG: bp_transfer :: BwdPass n f -> BwdTransfer n f
+ Compiler.Hoopl.ZipDataflowNoRG: data BwdPass n f
+ Compiler.Hoopl.ZipDataflowNoRG: data BwdRes n f e x
+ Compiler.Hoopl.ZipDataflowNoRG: data FwdPass n f
+ Compiler.Hoopl.ZipDataflowNoRG: data FwdRes n f e x
+ Compiler.Hoopl.ZipDataflowNoRG: fp_lattice :: FwdPass n f -> DataflowLattice f
+ Compiler.Hoopl.ZipDataflowNoRG: fp_rewrite :: FwdPass n f -> FwdRewrite n f
+ Compiler.Hoopl.ZipDataflowNoRG: fp_transfer :: FwdPass n f -> FwdTransfer n f
+ Compiler.Hoopl.ZipDataflowNoRG: type BwdRewrite n f = forall e x. n e x -> Fact x f -> Maybe (BwdRes n f e x)
+ Compiler.Hoopl.ZipDataflowNoRG: type BwdTransfer n f = forall e x. n e x -> Fact x f -> Fact e f
+ Compiler.Hoopl.ZipDataflowNoRG: type FwdRewrite n f = forall e x. n e x -> Fact e f -> Maybe (FwdRes n f e x)
+ Compiler.Hoopl.ZipDataflowNoRG: type FwdTransfer n f = forall e x. n e x -> Fact e f -> Fact x f
+ Compiler.Hoopl.Zipper: ZCat :: ZBlock n O O -> ZBlock n O O -> ZBlock n O O
+ Compiler.Hoopl.Zipper: ZClosed :: ZBlock n C O -> ZBlock n O C -> ZBlock n C C
+ Compiler.Hoopl.Zipper: ZFirst :: n C O -> ZBlock n C O
+ Compiler.Hoopl.Zipper: ZHead :: ZBlock n C O -> n O O -> ZBlock n C O
+ Compiler.Hoopl.Zipper: ZLast :: n O C -> ZBlock n O C
+ Compiler.Hoopl.Zipper: ZMiddle :: n O O -> ZBlock n O O
+ Compiler.Hoopl.Zipper: ZTail :: n O O -> ZBlock n O C -> ZBlock n O C
+ Compiler.Hoopl.Zipper: backBiasBlock :: ZBlock n e x -> ZBlock n e x
+ Compiler.Hoopl.Zipper: data ZBlock n e x
+ Compiler.Hoopl.Zipper: frontBiasBlock :: ZBlock n e x -> ZBlock n e x
+ Compiler.Hoopl.Zipper: instance (Edges n) => Edges (ZBlock n)
+ Compiler.Hoopl.Zipper: type ZBody = Body' ZBlock
+ Compiler.Hoopl.Zipper: type ZGraph = Graph' ZBlock
- Compiler.Hoopl: BodyCat :: Body n -> Body n -> Body n
+ Compiler.Hoopl: BodyCat :: Body' block n -> Body' block n -> Body' block n
- Compiler.Hoopl: BodyEmpty :: Body n
+ Compiler.Hoopl: BodyEmpty :: Body' block n
- Compiler.Hoopl: BodyUnit :: Block n C C -> Body n
+ Compiler.Hoopl: BodyUnit :: block n C C -> Body' block n
- Compiler.Hoopl: GMany :: MaybeO e (Block n O C) -> Body n -> MaybeO x (Block n C O) -> Graph n e x
+ Compiler.Hoopl: GMany :: MaybeO e (block n O C) -> Body' block n -> MaybeO x (block n C O) -> Graph' block n e x
- Compiler.Hoopl: GNil :: Graph n O O
+ Compiler.Hoopl: GNil :: Graph' block n O O
- Compiler.Hoopl: GUnit :: Block n O O -> Graph n O O
+ Compiler.Hoopl: GUnit :: block n O O -> Graph' block n O O
- Compiler.Hoopl: addBlock :: Block n C C -> Body n -> Body n
+ Compiler.Hoopl: addBlock :: block n C C -> Body' block n -> Body' block n
- Compiler.Hoopl: bodyList :: (Edges n) => Body n -> [(Label, Block n C C)]
+ Compiler.Hoopl: bodyList :: (Edges (block n)) => Body' block n -> [(Label, block n C C)]
- Compiler.Hoopl: bodyMap :: (Edges n) => Body n -> LabelMap (Block n C C)
+ Compiler.Hoopl: bodyMap :: (Edges (block n)) => Body' block n -> LabelMap (block n C C)
- Compiler.Hoopl: type JoinFun a = OldFact a -> NewFact a -> (ChangeFlag, a)
+ Compiler.Hoopl: type JoinFun a = Label -> OldFact a -> NewFact a -> (ChangeFlag, a)

Files

CHANGES view
@@ -1,3 +1,22 @@+3.7.12.1++  - Added a bunch of zipper experiments.+  - Existing clients should not be affected.+++3.7.12.0++  - More expressive debugging support+  - retract arfGraph and normalization; export analyzeAndRewriterFwd'++3.7.11.1++  - Expose arfGraph and normalization functions++3.7.11.0++  - Debugging support+ 3.7.8.0    - Rationalized AGraph splicing functions.
Compiler/Hoopl.hs view
@@ -1,14 +1,20 @@ module Compiler.Hoopl-  ( module Compiler.Hoopl.Dataflow+  ( module Compiler.Hoopl.Combinators+  , module Compiler.Hoopl.Dataflow+  , module Compiler.Hoopl.Debug   , module Compiler.Hoopl.Fuel   , module Compiler.Hoopl.Graph   , module Compiler.Hoopl.Label   , module Compiler.Hoopl.MkGraph+  , module Compiler.Hoopl.Show   ) where +import Compiler.Hoopl.Combinators import Compiler.Hoopl.Dataflow+import Compiler.Hoopl.Debug import Compiler.Hoopl.Fuel hiding (withFuel, getFuel, setFuel) import Compiler.Hoopl.Graph hiding (BodyEmpty, BodyUnit, BodyCat) import Compiler.Hoopl.Label hiding (allLabels) import Compiler.Hoopl.MkGraph+import Compiler.Hoopl.Show
+ Compiler/Hoopl/Combinators.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE RankNTypes #-}++module Compiler.Hoopl.Combinators+  ( SimpleFwdRewrite, noFwdRewrite, thenFwdRw, shallowFwdRw, deepFwdRw, iterFwdRw+  , SimpleBwdRewrite, noBwdRewrite, thenBwdRw, shallowBwdRw, deepBwdRw, iterBwdRw+  )++where++import Compiler.Hoopl.Dataflow+import Compiler.Hoopl.MkGraph++type SimpleFwdRewrite n f +  = forall e x. n e x -> Fact e f+             -> Maybe (AGraph n e x)++noFwdRewrite :: FwdRewrite n f+noFwdRewrite _ _ = Nothing++shallowFwdRw :: SimpleFwdRewrite n f -> FwdRewrite n f+shallowFwdRw rw n f = case (rw n f) of+                         Nothing -> Nothing+                         Just ag -> Just (FwdRes ag noFwdRewrite)++deepFwdRw :: SimpleFwdRewrite n f -> FwdRewrite n f+deepFwdRw r = iterFwdRw (shallowFwdRw r)++thenFwdRw :: FwdRewrite n f -> FwdRewrite n f -> FwdRewrite n f+thenFwdRw rw1 rw2 n f+  = case rw1 n f of+      Nothing               -> rw2 n f+      Just (FwdRes ag rw1a) -> Just (FwdRes ag (rw1a `thenFwdRw` rw2))++iterFwdRw :: FwdRewrite n f -> FwdRewrite n f+iterFwdRw rw =+  \ n f -> case rw n f of+             Just (FwdRes g rw2) -> Just $ FwdRes g (rw2 `thenFwdRw` iterFwdRw rw)+             Nothing             -> Nothing++----------------------------------------------------------------++type SimpleBwdRewrite n f +  = forall e x. n e x -> Fact x f+             -> Maybe (AGraph n e x)++noBwdRewrite :: BwdRewrite n f+noBwdRewrite _ _ = Nothing++shallowBwdRw :: SimpleBwdRewrite n f -> BwdRewrite n f+shallowBwdRw rw n f = case (rw n f) of+                         Nothing -> Nothing+                         Just ag -> Just (BwdRes ag noBwdRewrite)++deepBwdRw :: SimpleBwdRewrite n f -> BwdRewrite n f+deepBwdRw r = iterBwdRw (shallowBwdRw r)+++thenBwdRw :: BwdRewrite n f -> BwdRewrite n f -> BwdRewrite n f+thenBwdRw rw1 rw2 n f+  = case rw1 n f of+      Nothing               -> rw2 n f+      Just (BwdRes ag rw1a) -> Just (BwdRes ag (rw1a `thenBwdRw` rw2))++iterBwdRw :: BwdRewrite n f -> BwdRewrite n f+iterBwdRw rw =+  \ n f -> case rw n f of+             Just (BwdRes g rw2) -> Just $ BwdRes g (rw2 `thenBwdRw` iterBwdRw rw)+             Nothing             -> Nothing++{-+productFwd :: FwdPass n f -> FwdPass n f' -> FwdPass n (f, f')+productFwd pass pass' = FwdPass lattice transfer rewrite+    where -- can't tell if I have a FactBase of pairs or a pair of facts+          transfer n fb = (fp_transfer pass  $ factBaseMap fst fb,+                           fp_transfer pass' $ factBaseMap snd fb)+          transfer n (f, f') = (fp_transfer pass f, fp_transfer pass' f')+             ...              ++-}
Compiler/Hoopl/Dataflow.hs view
@@ -58,12 +58,11 @@ module Compiler.Hoopl.Dataflow    ( DataflowLattice(..), JoinFun, OldFact(..), NewFact(..)   , ChangeFlag(..), changeIf-  , FwdPass(..),  FwdTransfer, FwdRewrite, SimpleFwdRewrite, FwdRes(..)-  , noFwdRewrite, thenFwdRw, shallowFwdRw, deepFwdRw, iterFwdRw-  , BwdPass(..), BwdTransfer, BwdRewrite, SimpleBwdRewrite, BwdRes(..)-  , noBwdRewrite, thenBwdRw, shallowBwdRw, deepBwdRw, iterBwdRw+  , FwdPass(..),  FwdTransfer, FwdRewrite, FwdRes(..)+  , BwdPass(..), BwdTransfer, BwdRewrite, BwdRes(..)   , Fact-  , analyzeAndRewriteFwd, analyzeAndRewriteBwd+  , analyzeAndRewriteFwd,  analyzeAndRewriteBwd+  , analyzeAndRewriteFwd', analyzeAndRewriteBwd'   ) where @@ -71,8 +70,8 @@ import Compiler.Hoopl.Graph import qualified Compiler.Hoopl.GraphUtil as U import Compiler.Hoopl.Label-import Compiler.Hoopl.MkGraph (AGraph)-+import Compiler.Hoopl.MkGraph (AGraph, graphOfAGraph)+import Compiler.Hoopl.Util  ----------------------------------------------------------------------------- --		DataflowLattice@@ -86,11 +85,12 @@  , fact_do_logging :: Bool            -- log changes  } -type JoinFun a = OldFact a -> NewFact a -> (ChangeFlag, a)+type JoinFun a = Label -> OldFact a -> NewFact a -> (ChangeFlag, a)+  -- the label argument is for debugging purposes only newtype OldFact a = OldFact a newtype NewFact a = NewFact a -data ChangeFlag = NoChange | SomeChange+data ChangeFlag = NoChange | SomeChange deriving (Eq, Ord) changeIf :: Bool -> ChangeFlag changeIf changed = if changed then SomeChange else NoChange @@ -115,33 +115,6 @@ type instance Fact C f = FactBase f type instance Fact O f = f -type SimpleFwdRewrite n f -  = forall e x. n e x -> Fact e f-             -> Maybe (AGraph n e x)--noFwdRewrite :: FwdRewrite n f-noFwdRewrite _ _ = Nothing--shallowFwdRw :: SimpleFwdRewrite n f -> FwdRewrite n f-shallowFwdRw rw n f = case (rw n f) of-                         Nothing -> Nothing-                         Just ag -> Just (FwdRes ag noFwdRewrite)--deepFwdRw :: SimpleFwdRewrite n f -> FwdRewrite n f-deepFwdRw r = iterFwdRw (shallowFwdRw r)--thenFwdRw :: FwdRewrite n f -> FwdRewrite n f -> FwdRewrite n f-thenFwdRw rw1 rw2 n f-  = case rw1 n f of-      Nothing               -> rw2 n f-      Just (FwdRes ag rw1a) -> Just (FwdRes ag (rw1a `thenFwdRw` rw2))--iterFwdRw :: FwdRewrite n f -> FwdRewrite n f-iterFwdRw rw =-  \ n f -> case rw n f of-             Just (FwdRes g rw2) -> Just $ FwdRes g (rw2 `thenFwdRw` iterFwdRw rw)-             Nothing             -> Nothing- analyzeAndRewriteFwd    :: forall n f. Edges n    => FwdPass n f@@ -152,6 +125,35 @@   = do { (rg, _) <- arfBody pass body facts        ; return (normaliseBody rg) } +-- | if the graph being analyzed is open at the entry, there must+--   be no other entry point, or all goes horribly wrong...+analyzeAndRewriteFwd'+   :: forall n f e x. Edges n+   => FwdPass n f+   -> Graph n e x -> Fact e f+   -> FuelMonad (Graph n e x, FactBase f, MaybeO x f)+analyzeAndRewriteFwd' pass g f =+  do (rg, fout) <- arfGraph pass g f+     let (g', fb) = normalizeGraph g rg+     return (g', fb, distinguishedExitFact g' fout)++distinguishedExitFact :: forall n e x f . Graph n e x -> Fact x f -> MaybeO x f+distinguishedExitFact g f = maybe g+    where maybe :: Graph n e x -> MaybeO x f+          maybe GNil       = JustO f+          maybe (GUnit {}) = JustO f+          maybe (GMany _ _ x) = case x of NothingO -> NothingO+                                          JustO _  -> JustO f++normalizeGraph :: Edges n => Graph n e x -> RG n f e x -> GraphWithFacts n f e x+normalizeGraph GNil = normOO+normalizeGraph (GUnit {}) = normOO+normalizeGraph (GMany NothingO  _ NothingO)  = normCC+normalizeGraph (GMany (JustO _) _ NothingO)  = normOC+normalizeGraph (GMany NothingO  _ (JustO _)) = normCO+normalizeGraph (GMany (JustO _) _ (JustO _)) = normOO++ ---------------------------------------------------------------- --       Forward Implementation ----------------------------------------------------------------@@ -209,13 +211,11 @@        ; (exit', fx)  <- arfBlock pass exit fb        ; return (entry' `RGCatC` body' `RGCatC` exit', fx) } -forwardBlockList :: Edges n => [Label] -> Body n -> [((Label,Block n C C), [Label])]+forwardBlockList :: (Edges n, LabelsPtr entry)+                 => entry -> Body n -> [Block n C C] -- This produces a list of blocks in order suitable for forward analysis, -- along with the list of Labels it may depend on for facts.--- ToDo: Do a topological sort to improve convergence rate of fixpoint---       This will require a (HavingSuccessors l) class constraint-forwardBlockList  _ blks = map withLbl $ bodyList blks-  where withLbl (l, b) = ((l, b), [l])+forwardBlockList entries blks = postorder_dfs_from (bodyMap blks) entries  ----------------------------------------------------------------------------- --		Backward analysis and rewriting: the interface@@ -232,34 +232,6 @@   = forall e x. n e x -> Fact x f -> Maybe (BwdRes n f e x) data BwdRes n f e x = BwdRes (AGraph n e x) (BwdRewrite n f) -type SimpleBwdRewrite n f -  = forall e x. n e x -> Fact x f-             -> Maybe (AGraph n e x)--noBwdRewrite :: BwdRewrite n f-noBwdRewrite _ _ = Nothing--shallowBwdRw :: SimpleBwdRewrite n f -> BwdRewrite n f-shallowBwdRw rw n f = case (rw n f) of-                         Nothing -> Nothing-                         Just ag -> Just (BwdRes ag noBwdRewrite)--deepBwdRw :: SimpleBwdRewrite n f -> BwdRewrite n f-deepBwdRw r = iterBwdRw (shallowBwdRw r)---thenBwdRw :: BwdRewrite n f -> BwdRewrite n f -> BwdRewrite n f-thenBwdRw rw1 rw2 n f-  = case rw1 n f of-      Nothing               -> rw2 n f-      Just (BwdRes ag rw1a) -> Just (BwdRes ag (rw1a `thenBwdRw` rw2))--iterBwdRw :: BwdRewrite n f -> BwdRewrite n f-iterBwdRw rw =-  \ n f -> case rw n f of-             Just (BwdRes g rw2) -> Just $ BwdRes g (rw2 `thenBwdRw` iterBwdRw rw)-             Nothing             -> Nothing- ----------------------------------------------------------------------------- --		Backward implementation -----------------------------------------------------------------------------@@ -294,7 +266,7 @@         -> FuelMonad (RG n f C C, FactBase f) arbBody pass blocks init_fbase   = fixpoint False (bp_lattice pass) (arbBlock pass) init_fbase $-    backwardBlockList (factBaseLabels init_fbase) blocks +    backwardBlockList blocks   arbGraph :: Edges n => ARB (Graph n) n arbGraph _    GNil        f = return (RGNil, f)@@ -316,12 +288,52 @@        ; (entry', fe) <- arbBlock pass entry fb        ; return (entry' `RGCatC` body' `RGCatC` exit', fe) } -backwardBlockList :: Edges n => [Label] -> Body n -> [((Label, Block n C C), [Label])]+backwardBlockList :: Edges n => Body n -> [Block n C C] -- This produces a list of blocks in order suitable for backward analysis, -- along with the list of Labels it may depend on for facts.-backwardBlockList _ blks = map withSuccs $ bodyList blks-  where withSuccs (l, b) = ((l, b), successors b)+backwardBlockList body = reachable ++ missing+  where reachable = reverse $ forwardBlockList entries body+        entries = externalEntryLabels body+        all = bodyList body+        missingLabels =+            mkLabelSet (map fst all) `minusLabelSet`+            mkLabelSet (map entryLabel reachable)+        missing = map snd $ filter (flip elemLabelSet missingLabels . fst) all +{-++The forward and backward dataflow analyses now use postorder depth-first+order for faster convergence.++The forward and backward cases are not dual.  In the forward case, the+entry points are known, and one simply traverses the body blocks from+those points.  In the backward case, something is known about the exit+points, but this information is essentially useless, because we don't+actually have a dual graph (that is, one with edges reversed) to+compute with.  (Even if we did have a dual graph, it would not avail+us---a backward analysis must include reachable blocks that don't+reach the exit, as in a procedure that loops forever and has side+effects.)++Since in the general case, no information is available about entry+points, I have put in a horrible hack.  First, I assume that every+label defined but not used is an entry point.  Then, because an entry+point might also be a loop header, I add, in arbitrary order, all the+remaining "missing" blocks.  Needless to say, I am not pleased.  +I am not satisfied.  I am not Senator Morgan.++Wait! I believe that the Right Thing here is to require that anyone+wishing to analyze a graph closed at the entry provide a way of+determining the entry points, if any, of that graph.  This requirement+can apply equally to forward and backward analyses; I believe that+using the input FactBase to determine the entry points of a closed+graph is *also* a hack.++NR++-}++ analyzeAndRewriteBwd    :: forall n f. Edges n    => BwdPass n f @@ -332,7 +344,27 @@   = do { (rg, _) <- arbBody pass body facts        ; return (normaliseBody rg) } +-- | if the graph being analyzed is open at the exit, I don't+--   quite understand the implications of possible other exits+analyzeAndRewriteBwd'+   :: forall n f e x. Edges n+   => BwdPass n f+   -> Graph n e x -> Fact x f+   -> FuelMonad (Graph n e x, FactBase f, MaybeO e f)+analyzeAndRewriteBwd' pass g f =+  do (rg, fout) <- arbGraph pass g f+     let (g', fb) = normalizeGraph g rg+     return (g', fb, distinguishedEntryFact g' fout) +distinguishedEntryFact :: forall n e x f . Graph n e x -> Fact e f -> MaybeO e f+distinguishedEntryFact g f = maybe g+    where maybe :: Graph n e x -> MaybeO e f+          maybe GNil       = JustO f+          maybe (GUnit {}) = JustO f+          maybe (GMany e _ _) = case e of NothingO -> NothingO+                                          JustO _  -> JustO f++ ----------------------------------------------------------------------------- --      fixpoint: finding fixed points -----------------------------------------------------------------------------@@ -359,10 +391,11 @@   | lbl `elemLabelSet` lbls = (SomeChange, new_fbase)   | otherwise               = (cha,        new_fbase)   where-    (cha2, res_fact) +    (cha2, res_fact) -- Note [Unreachable blocks]        = case lookupFact fbase lbl of-           Nothing -> (SomeChange, new_fact)  -- Note [Unreachable blocks]-           Just old_fact -> fact_extend lat (OldFact old_fact) (NewFact new_fact)+           Nothing -> (SomeChange, snd $ join $ fact_bot lat)  -- Note [Unreachable blocks]+           Just old_fact -> join old_fact+         where join old_fact = fact_extend lat lbl (OldFact old_fact) (NewFact new_fact)     new_fbase = extendFactBase fbase lbl res_fact  fixpoint :: forall n f. Edges n@@ -370,9 +403,10 @@          -> DataflowLattice f          -> (Block n C C -> FactBase f               -> FuelMonad (RG n f C C, FactBase f))-         -> FactBase f -> [((Label, Block n C C), [Label])]+         -> FactBase f +         -> [Block n C C]          -> FuelMonad (RG n f C C, FactBase f)-fixpoint is_fwd lat do_block init_fbase blocks+fixpoint is_fwd lat do_block init_fbase untagged_blocks   = do { fuel <- getFuel          ; tx_fb <- loop fuel init_fbase        ; return (tfb_rg tx_fb, @@ -380,7 +414,10 @@ 	     -- The successors of the Graph are the the Labels for which 	     -- we have facts, that are *not* in the blocks of the graph   where-    tx_blocks :: [((Label, Block n C C), [Label])] +    blocks = map tag untagged_blocks+     where tag b = ((entryLabel b, b), if is_fwd then [entryLabel b] else successors b)++    tx_blocks :: [((Label, Block n C C), [Label])]   -- I do not understand this type               -> TxFactBase n f -> FuelMonad (TxFactBase n f)     tx_blocks []              tx_fb = return tx_fb     tx_blocks (((lbl,blk), deps):bs) tx_fb = tx_block lbl blk deps tx_fb >>= tx_blocks bs@@ -439,6 +476,10 @@        bottom        the points above bottom +* Even if the fact is going from UNR to bottom, we still call the+  client's fact_extend function because it might give the client+  some useful debugging information.+ * All of this only applies for *forward* fixpoints.  For the backward   case we must treat every block as reachable; it might finish with a   'return', and therefore have no successors, for example.@@ -503,9 +544,3 @@ bwfUnion :: BodyWithFacts n f -> BodyWithFacts n f -> BodyWithFacts n f bwfUnion (bg1, fb1) (bg2, fb2) = (bg1 `BodyCat` bg2, fb1 `unionFactBase` fb2) -}---------------------------------------------------------------------------------graphOfAGraph :: AGraph node e x -> FuelMonad (Graph node e x)-graphOfAGraph ag = ag-
+ Compiler/Hoopl/Debug.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE RankNTypes, GADTs, ScopedTypeVariables, FlexibleContexts #-}++module Compiler.Hoopl.Debug +  ( TraceFn , debugFwdJoins , debugBwdJoins+  )+where++import Compiler.Hoopl.Dataflow++--------------------------------------------------------------------------------+-- | Debugging combinators:+-- Each combinator takes a dataflow pass and produces+-- a dataflow pass that can output debugging messages.+-- You provide the function, we call it with the applicable message.+-- +-- The most common use case is probably to:+--+--   1. import 'Debug.Trace'+--+--   2. pass 'trace' as the 1st argument to the debug combinator+--+--   3. pass 'const true' as the 2nd argument to the debug combinator+--------------------------------------------------------------------------------+++debugFwdJoins :: forall n f . Show f => TraceFn -> ChangePred -> FwdPass n f -> FwdPass n f+debugBwdJoins :: forall n f . Show f => TraceFn -> ChangePred -> BwdPass n f -> BwdPass n f++type TraceFn    = forall a . String -> a -> a+type ChangePred = ChangeFlag -> Bool++debugFwdJoins trace pred p = p { fp_lattice = debugJoins trace pred $ fp_lattice p }+debugBwdJoins trace pred p = p { bp_lattice = debugJoins trace pred $ bp_lattice p }++debugJoins :: Show f => TraceFn -> ChangePred -> DataflowLattice f -> DataflowLattice f+debugJoins trace showOutput l@(DataflowLattice {fact_extend = extend}) = l {fact_extend = extend'}+  where+   extend' l f1@(OldFact of1) f2@(NewFact nf2) =+     if showOutput c then trace output res else res+       where res@(c, f') = extend l f1 f2+             output = case c of+                        SomeChange -> "+ Join@" ++ show l ++ ": " ++ show of1 ++ " |_| "+                                                                  ++ show nf2 ++ " = " ++ show f'+                        NoChange   -> "_ Join@" ++ show l ++ ": " ++ show nf2 ++ " <= " ++ show of1++--------------------------------------------------------------------------------+-- Functions we'd like to have, but don't know how to implement generically:+--------------------------------------------------------------------------------++-- type Showing n = forall e x . n e x -> String+-- debugFwdTransfers, debugFwdRewrites, debugFwdAll ::+--   forall n f . Show f => TraceFn -> Showing n -> FwdPass n f -> FwdPass n f+-- debugBwdTransfers, debugBwdRewrites, debugBwdAll ::+--   forall n f . Show f => TraceFn -> Showing n -> BwdPass n f -> BwdPass n f+
Compiler/Hoopl/Graph.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE GADTs, EmptyDataDecls #-}  module Compiler.Hoopl.Graph -  ( O, C, Block(..), Body(..), bodyMap, Graph(..), MaybeO(..)+  ( O, C, Block(..), Body, Body'(..), bodyMap, Graph, Graph'(..), MaybeO(..)   , Edges(entryLabel, successors)   , addBlock, bodyList   )@@ -21,23 +21,29 @@   BUnit :: n e x -> Block n e x   BCat  :: Block n e O -> Block n O x -> Block n e x -data Body n where-  BodyEmpty :: Body n-  BodyUnit  :: Block n C C -> Body n-  BodyCat   :: Body n -> Body n -> Body n+type Body = Body' Block+data Body' block n where+  BodyEmpty :: Body' block n+  BodyUnit  :: block n C C -> Body' block n+  BodyCat   :: Body' block n -> Body' block n -> Body' block n -data Graph n e x where-  GNil  :: Graph n O O-  GUnit :: Block n O O -> Graph n O O-  GMany :: MaybeO e (Block n O C) -        -> Body n-        -> MaybeO x (Block n C O)-        -> Graph n e x+type Graph = Graph' Block+data Graph' block n e x where+  GNil  :: Graph' block n O O+  GUnit :: block n O O -> Graph' block n O O+  GMany :: MaybeO e (block n O C) +        -> Body' block n+        -> MaybeO x (block n C O)+        -> Graph' block n e x  data MaybeO ex t where   JustO    :: t -> MaybeO O t   NothingO ::      MaybeO C t +instance Functor (MaybeO ex) where+  fmap f NothingO = NothingO+  fmap f (JustO a) = JustO (f a)+ ------------------------------- class Edges thing where   entryLabel :: thing C x -> Label@@ -50,16 +56,16 @@   successors (BCat _ b)  = successors b  -------------------------------addBlock :: Block n C C -> Body n -> Body n+addBlock :: block n C C -> Body' block n -> Body' block n addBlock b body = BodyUnit b `BodyCat` body -bodyList :: Edges n => Body n -> [(Label,Block n C C)]+bodyList :: Edges (block n) => Body' block n -> [(Label,block n C C)] bodyList body = go body []   where     go BodyEmpty       bs = bs     go (BodyUnit b)    bs = (entryLabel b, b) : bs     go (BodyCat b1 b2) bs = go b1 (go b2 bs) -bodyMap :: Edges n => Body n -> LabelMap (Block n C C)+bodyMap :: Edges (block n) => Body' block n -> LabelMap (block n C C) bodyMap = mkFactBase . bodyList 
Compiler/Hoopl/GraphUtil.hs view
@@ -1,38 +1,65 @@-{-# LANGUAGE GADTs #-}+{-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} -- bug in GHC  -- N.B. addBasicBlocks won't work on OO without a Node (branch/label) constraint  module Compiler.Hoopl.GraphUtil-  ( gSplice+  ( splice, gSplice, zSplice+  , zCat   , bodyGraph   )  where  import Compiler.Hoopl.Graph+import Compiler.Hoopl.Zipper  bodyGraph :: Body n -> Graph n C C bodyGraph b = GMany NothingO b NothingO +splice :: forall block n e a x .+          (forall e x . block n e O -> block n O x -> block n e x)+       -> (Graph' block n e a -> Graph' block n a x -> Graph' block n e x)+splice bcat = sp+  where sp :: forall e a x .+              Graph' block n e a -> Graph' block n a x -> Graph' block n e x -gSplice :: Graph n e a -> Graph n a x -> Graph n e x+        sp GNil g2 = g2+        sp g1 GNil = g1 -gSplice GNil g2 = g2-gSplice g1 GNil = g1+        sp (GUnit b1) (GUnit b2) = GUnit (b1 `bcat` b2) -gSplice (GUnit b1) (GUnit b2)             -  = GUnit (b1 `BCat` b2)+        sp (GUnit b) (GMany (JustO e) bs x) = GMany (JustO (b `bcat` e)) bs x -gSplice (GUnit b) (GMany (JustO e) bs x) -  = GMany (JustO (b `BCat` e)) bs x+        sp (GMany e bs (JustO x)) (GUnit b2) = GMany e bs (JustO (x `bcat` b2)) -gSplice (GMany e bs (JustO x)) (GUnit b2) -  = GMany e bs (JustO (x `BCat` b2))+        sp (GMany e1 bs1 (JustO x1)) (GMany (JustO e2) bs2 x2)+          = GMany e1 (addBlock (x1 `bcat` e2) bs1 `BodyCat` bs2) x2 -gSplice (GMany e1 bs1 (JustO x1)) (GMany (JustO e2) bs2 x2)-  = GMany e1 (addBlock (x1 `BCat` e2) bs1 `BodyCat` bs2) x2+        sp (GMany e1 bs1 NothingO) (GMany NothingO bs2 x2)+           = GMany e1 (bs1 `BodyCat` bs2) x2 -gSplice (GMany e1 bs1 NothingO) (GMany NothingO bs2 x2)-   = GMany e1 (bs1 `BodyCat` bs2) x2++gSplice :: Graph  n e a -> Graph  n a x -> Graph  n e x+zSplice :: ZGraph n e a -> ZGraph n a x -> ZGraph n e x++gSplice = splice BCat+zSplice = splice zCat++zCat :: ZBlock n e O -> ZBlock n O x -> ZBlock n e x+zCat b1@(ZFirst {})     (ZMiddle n)  = ZHead   b1 n+zCat b1@(ZFirst {})  b2@(ZLast{})    = ZClosed b1 b2+zCat b1@(ZFirst {})  b2@(ZTail{})    = ZClosed b1 b2+zCat b1@(ZFirst {})     (ZCat b2 b3) = (b1 `zCat` b2) `zCat` b3+zCat b1@(ZHead {})      (ZCat b2 b3) = (b1 `zCat` b2) `zCat` b3+zCat b1@(ZHead {})      (ZMiddle n)  = ZHead   b1 n+zCat b1@(ZHead {})   b2@(ZLast{})    = ZClosed b1 b2+zCat b1@(ZHead {})   b2@(ZTail{})    = ZClosed b1 b2+zCat    (ZMiddle n)  b2@(ZLast{})    = ZTail    n b2+zCat b1@(ZMiddle {}) b2@(ZCat{})     = ZCat    b1 b2+zCat    (ZMiddle n)  b2@(ZTail{})    = ZTail    n b2+zCat    (ZCat b1 b2) b3@(ZLast{})    = b1 `zCat` (b2 `zCat` b3)+zCat    (ZCat b1 b2) b3@(ZTail{})    = b1 `zCat` (b2 `zCat` b3)+zCat b1@(ZCat {})    b2@(ZCat{})     = ZCat    b1 b2+ 
Compiler/Hoopl/Label.hs view
@@ -74,36 +74,40 @@ delFromFactBase fb blks = foldr (M.delete . unLabel . fst) fb blks  -----------------------type LabelSet = S.IntSet -- ought to be a newtype or we expose the rep...+newtype LabelSet = LS { unLS :: S.IntSet }  emptyLabelSet :: LabelSet-emptyLabelSet = S.empty+emptyLabelSet = LS S.empty  extendLabelSet :: LabelSet -> Label -> LabelSet-extendLabelSet lbls (Label bid) = S.insert bid lbls+extendLabelSet lbls (Label bid) = LS $ S.insert bid $ unLS lbls  reduceLabelSet :: LabelSet -> Label -> LabelSet-reduceLabelSet lbls (Label bid) = S.delete bid lbls+reduceLabelSet lbls (Label bid) = LS $ S.delete bid $ unLS lbls  elemLabelSet :: Label -> LabelSet -> Bool-elemLabelSet (Label bid) lbls = S.member bid lbls+elemLabelSet (Label bid) lbls = S.member bid (unLS lbls)  labelSetElems :: LabelSet -> [Label]-labelSetElems = map Label . S.toList+labelSetElems = map Label . S.toList . unLS +set2 :: (S.IntSet -> S.IntSet -> S.IntSet)+     -> (LabelSet -> LabelSet -> LabelSet)+set2 f (LS ls) (LS ls') = LS (f ls ls')+ minusLabelSet :: LabelSet -> LabelSet -> LabelSet-minusLabelSet = S.difference+minusLabelSet = set2 S.difference  unionLabelSet :: LabelSet -> LabelSet -> LabelSet-unionLabelSet = S.union+unionLabelSet = set2 S.union  interLabelSet :: LabelSet -> LabelSet -> LabelSet-interLabelSet = S.intersection+interLabelSet = set2 S.intersection  sizeLabelSet :: LabelSet -> Int-sizeLabelSet = S.size+sizeLabelSet = S.size . unLS  mkLabelSet :: [Label] -> LabelSet-mkLabelSet = S.fromList . map unLabel+mkLabelSet = LS . S.fromList . map unLabel  
Compiler/Hoopl/MkGraph.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE ScopedTypeVariables, GADTs #-} module Compiler.Hoopl.MkGraph-    ( AGraph, (<*>), catAGraphs, addEntrySeq, addExitSeq, addBlocks, unionBlocks+    ( AGraph, graphOfAGraph+    , (<*>), (|*><*|), catAGraphs, addEntrySeq, addExitSeq, addBlocks, unionBlocks     , emptyAGraph, emptyClosedAGraph, withFreshLabels     , mkFirst, mkMiddle, mkMiddles, mkLast, mkBranch, mkLabel, mkWhileDo     , IfThenElseable(mkIfThenElse)@@ -16,16 +17,16 @@  import Control.Monad (liftM2) -type AGraph n e x = FuelMonad (Graph n e x)+newtype AGraph n e x = A { graphOfAGraph :: FuelMonad (Graph n e x) }  class Labels l where   withFreshLabels :: (l -> AGraph n e x) -> AGraph n e x  emptyAGraph :: AGraph n O O-emptyAGraph = return GNil+emptyAGraph = A $ return GNil  emptyClosedAGraph :: AGraph n C C-emptyClosedAGraph = return $ GMany NothingO BodyEmpty NothingO+emptyClosedAGraph = A $ return $ GMany NothingO BodyEmpty NothingO  {-| As noted in the paper, we can define a single, polymorphic type of @@ -55,6 +56,17 @@     redundant with 'addBlocks', because 'addBlocks' requires a 'HooplNode'     constraint but 'unionBlocks' does not. +  * The operator |*><*| splices two graphs at a closed point. The+    vertical bar stands for "closed point" just as the angle brackets+    above stand for "open point".  Unlike the <*> operator, the |*><*|+    can create a control-flow graph with dangling outedges or+    unreachable blocks.  The operator must be used carefully, so we+    have chosen a long name on purpose, to help call people's+    attention to what they're doing.++  * We have discussed a dynamic assertion about dangling outedges and+    unreachable blocks, but nothing is implemented yet.+ There is some redundancy in this representation (any instance of 'addEntrySeq' is also an instance of either 'addExitSeq' or 'addBlocks'), but because the different operators restrict polymorphism in different ways, @@ -65,7 +77,9 @@   infixl 3 <*>-(<*>) :: AGraph n e O -> AGraph n O x -> AGraph n e x+infixl 2 |*><*|+(<*>)    :: AGraph n e O -> AGraph n O x -> AGraph n e x+(|*><*|) :: AGraph n e C -> AGraph n C x -> AGraph n e x   addEntrySeq    :: AGraph n O C -> AGraph n C x -> AGraph n O x@@ -74,19 +88,24 @@                => AGraph n e x -> AGraph n C C -> AGraph n e x unionBlocks    :: AGraph n C C -> AGraph n C C -> AGraph n C C -addEntrySeq = liftM2 U.gSplice-addExitSeq  = liftM2 U.gSplice-unionBlocks = liftM2 U.gSplice+liftA2 :: (Graph  n a b -> Graph  n c d -> Graph  n e f)+       -> (AGraph n a b -> AGraph n c d -> AGraph n e f) -addBlocks g blocks = g >>= \g -> blocks >>= add g-  where add :: HooplNode n => Graph n e x -> Graph n C C -> AGraph n e x+liftA2 f (A g) (A g') = A (liftM2 f g g')++addEntrySeq = liftA2 U.gSplice+addExitSeq  = liftA2 U.gSplice+unionBlocks = liftA2 U.gSplice++addBlocks (A g) (A blocks) = A $ g >>= \g -> blocks >>= add g+  where add :: HooplNode n => Graph n e x -> Graph n C C -> FuelMonad (Graph n e x)         add (GMany e body x) (GMany NothingO body' NothingO) =           return $ GMany e (body `BodyCat` body') x         add g@GNil      blocks = spliceOO g blocks         add g@(GUnit _) blocks = spliceOO g blocks-        spliceOO :: HooplNode n => Graph n O O -> Graph n C C -> AGraph n O O-        spliceOO g blocks = withFreshLabels $ \l ->-          return g <*> mkBranch l `addEntrySeq` return blocks `addExitSeq` mkLabel l+        spliceOO :: HooplNode n => Graph n O O -> Graph n C C -> FuelMonad(Graph n O O)+        spliceOO g blocks = graphOfAGraph $ withFreshLabels $ \l ->+          A (return g) <*> mkBranch l |*><*| A (return blocks) |*><*| mkLabel l   mkFirst  :: n C O -> AGraph n C O@@ -126,7 +145,8 @@ --                          IMPLEMENTATION -- ================================================================ -(<*>) = liftM2 U.gSplice +(<*>)    = liftA2 U.gSplice +(|*><*|) = liftA2 U.gSplice  catAGraphs :: [AGraph n O O] -> AGraph n O O catAGraphs = foldr (<*>) emptyAGraph @@ -136,16 +156,13 @@  mkLabel  id     = mkFirst $ mkLabelNode id mkBranch target = mkLast  $ mkBranchNode target-mkMiddles ms = foldr (<*>) (return GNil) (map mkMiddle ms)+mkMiddles ms = foldr (<*>) emptyAGraph (map mkMiddle ms)  instance IfThenElseable O where-  mkIfThenElse cbranch tbranch fbranch = do-    endif  <- freshLabel-    ltrue  <- freshLabel-    lfalse <- freshLabel-    cbranch ltrue lfalse `addEntrySeq`-      (mkLabel ltrue  <*> tbranch <*> mkBranch endif) `addBlocks`-      (mkLabel lfalse <*> fbranch <*> mkBranch endif) `addExitSeq`+  mkIfThenElse cbranch tbranch fbranch = withFreshLabels $ \(endif, ltrue, lfalse) ->+    cbranch ltrue lfalse |*><*|+      mkLabel ltrue  <*> tbranch <*> mkBranch endif |*><*|+      mkLabel lfalse <*> fbranch <*> mkBranch endif |*><*|       mkLabel endif  {-@@ -153,24 +170,19 @@ -}  instance IfThenElseable C where-  mkIfThenElse cbranch tbranch fbranch = do-    ltrue  <- freshLabel-    lfalse <- freshLabel-    cbranch ltrue lfalse `addEntrySeq`-       (mkLabel ltrue  <*> tbranch) `addBlocks`-       (mkLabel lfalse <*> fbranch)+  mkIfThenElse cbranch tbranch fbranch = withFreshLabels $ \(ltrue, lfalse) ->+    cbranch ltrue lfalse |*><*|+       mkLabel ltrue  <*> tbranch |*><*|+       mkLabel lfalse <*> fbranch {-   fallThroughTo _ g = g -} -mkWhileDo cbranch body = do-  test <- freshLabel-  head <- freshLabel-  endwhile <- freshLabel+mkWhileDo cbranch body = withFreshLabels $ \(test, head, endwhile) ->      -- Forrest Baskett's while-loop layout-  mkBranch test `addEntrySeq`-    (mkLabel head <*> body <*> mkBranch test) `addBlocks`-    (mkLabel test <*> cbranch head endwhile)  `addExitSeq`+  mkBranch test |*><*|+    mkLabel head <*> body <*> mkBranch test |*><*|+    mkLabel test <*> cbranch head endwhile  |*><*|     mkLabel endwhile  -------------------------------------@@ -194,7 +206,7 @@   instance Labels Label where-  withFreshLabels f = freshLabel >>= f+  withFreshLabels f = A $ freshLabel >>= (graphOfAGraph . f)  instance (Labels l1, Labels l2) => Labels (l1, l2) where   withFreshLabels f = withFreshLabels $ \l1 ->@@ -215,9 +227,9 @@                       f (l1, l2, l3, l4)  -mkExit   block = return $ GMany NothingO      BodyEmpty (JustO block)-mkEntry  block = return $ GMany (JustO block) BodyEmpty NothingO+mkExit   block = A $ return $ GMany NothingO      BodyEmpty (JustO block)+mkEntry  block = A $ return $ GMany (JustO block) BodyEmpty NothingO  mkFirst  = mkExit  . BUnit mkLast   = mkEntry . BUnit-mkMiddle = return  . GUnit . BUnit+mkMiddle = A . return  . GUnit . BUnit
+ Compiler/Hoopl/Show.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE RankNTypes, GADTs, ScopedTypeVariables, FlexibleContexts #-}++module Compiler.Hoopl.Show +  ( showGraph+  )+where++import Compiler.Hoopl.Graph++--------------------------------------------------------------------------------+-- Prettyprinting+--------------------------------------------------------------------------------++type Showing n = forall e x . n e x -> String+ ++showGraph :: forall n e x . (Edges n) => Showing n -> Graph n e x -> String+showGraph node = g+  where g :: (Edges n) => Graph n e x -> String+        g GNil = ""+        g (GUnit block) = b block+        g (GMany g_entry g_blocks g_exit) =+            open b g_entry ++ body g_blocks ++ open b g_exit+        body blocks = concatMap b (map snd $ bodyList blocks)+        b :: forall e x . Block n e x -> String+        b (BUnit n)    = node n ++ "\n"+        b (BCat b1 b2) = b b1 ++ b b2++open :: (a -> String) -> MaybeO z a -> String+open _ NothingO  = ""+open p (JustO n) = p n
Compiler/Hoopl/Util.hs view
@@ -1,14 +1,216 @@+{-# LANGUAGE GADTs, ScopedTypeVariables, FlexibleInstances, RankNTypes #-}+ module Compiler.Hoopl.Util   ( gUnitOO, gUnitOC, gUnitCO, gUnitCC+  , graphMapBlocks+  , zblockGraph+  , postorder_dfs, postorder_dfs_from, postorder_dfs_from_except+  , preorder_dfs, preorder_dfs_from_except+  , labelsDefined, labelsUsed, externalEntryLabels+  , LabelsPtr(..)   ) where +import Control.Monad+ import Compiler.Hoopl.Graph-gUnitOO :: Block n O O -> Graph n O O-gUnitOC :: Block n O C -> Graph n O C-gUnitCO :: Block n C O -> Graph n C O-gUnitCC :: Block n C C -> Graph n C C+import Compiler.Hoopl.Label+import Compiler.Hoopl.Zipper++gUnitOO :: block n O O -> Graph' block n O O+gUnitOC :: block n O C -> Graph' block n O C+gUnitCO :: block n C O -> Graph' block n C O+gUnitCC :: block n C C -> Graph' block n C C gUnitOO b = GUnit b gUnitOC b = GMany (JustO b) BodyEmpty   NothingO gUnitCO b = GMany NothingO  BodyEmpty   (JustO b) gUnitCC b = GMany NothingO  (BodyUnit b) NothingO++zblockGraph :: ZBlock n e x -> ZGraph n e x+zblockGraph b@(ZFirst  {}) = gUnitCO b+zblockGraph b@(ZMiddle {}) = gUnitOO b+zblockGraph b@(ZLast   {}) = gUnitOC b+zblockGraph b@(ZCat {})    = gUnitOO b+zblockGraph b@(ZHead {})   = gUnitCO b+zblockGraph b@(ZTail {})   = gUnitOC b+zblockGraph b@(ZClosed {}) = gUnitCC b+++graphMapBlocks :: forall block n block' n' e x .+                  (forall e x . block n e x -> block' n' e x)+               -> (Graph' block n e x -> Graph' block' n' e x)+bodyMapBlocks  :: forall block n block' n' .+                  (block n C C -> block' n' C C)+               -> (Body' block n -> Body' block' n')++graphMapBlocks f = map+  where map :: Graph' block n e x -> Graph' block' n' e x+        map GNil = GNil+        map (GUnit b) = GUnit (f b)+        map (GMany e b x) = GMany (fmap f e) (bodyMapBlocks f b) (fmap f x)++bodyMapBlocks f = map+  where map BodyEmpty = BodyEmpty+        map (BodyUnit b) = BodyUnit (f b)+        map (BodyCat b1 b2) = BodyCat (map b1) (map b2)+++----------------------------------------------------------------++class LabelsPtr l where+  targetLabels :: l -> [Label]++instance Edges n => LabelsPtr (n e C) where+  targetLabels n = successors n++instance LabelsPtr Label where+  targetLabels l = [l]++instance LabelsPtr LabelSet where+  targetLabels = labelSetElems++instance LabelsPtr l => LabelsPtr [l] where+  targetLabels = concatMap targetLabels+++-- | Traversal: 'postorder_dfs' returns a list of blocks reachable+-- from the entry of enterable graph. The entry and exit are *not* included.+-- The list has the following property:+--+--	Say a "back reference" exists if one of a block's+--	control-flow successors precedes it in the output list+--+--	Then there are as few back references as possible+--+-- The output is suitable for use in+-- a forward dataflow problem.  For a backward problem, simply reverse+-- the list.  ('postorder_dfs' is sufficiently tricky to implement that+-- one doesn't want to try and maintain both forward and backward+-- versions.)++postorder_dfs :: Edges (block n) => Graph' block n O x -> [block n C C]+preorder_dfs  :: Edges (block n) => Graph' block n O x -> [block n C C]++-- | This is the most important traversal over this data structure.  It drops+-- unreachable code and puts blocks in an order that is good for solving forward+-- dataflow problems quickly.  The reverse order is good for solving backward+-- dataflow problems quickly.  The forward order is also reasonably good for+-- emitting instructions, except that it will not usually exploit Forrest+-- Baskett's trick of eliminating the unconditional branch from a loop.  For+-- that you would need a more serious analysis, probably based on dominators, to+-- identify loop headers.+--+-- The ubiquity of 'postorder_dfs' is one reason for the ubiquity of the 'LGraph'+-- representation, when for most purposes the plain 'Graph' representation is+-- more mathematically elegant (but results in more complicated code).+--+-- Here's an easy way to go wrong!  Consider+-- @+--	A -> [B,C]+--	B -> D+--	C -> D+-- @+-- Then ordinary dfs would give [A,B,D,C] which has a back ref from C to D.+-- Better to get [A,B,C,D]+++graphDfs :: (Edges (block n))+         => (LabelMap (block n C C) -> block n O C -> LabelSet -> [block n C C])+         -> (Graph' block n O x -> [block n C C])+graphDfs _     (GNil)    = []+graphDfs _     (GUnit{}) = []+graphDfs order (GMany (JustO entry) body _) = order blockenv entry emptyLabelSet+  where blockenv = bodyMap body++postorder_dfs = graphDfs postorder_dfs_from_except+preorder_dfs  = graphDfs preorder_dfs_from_except++postorder_dfs_from_except :: forall block e . (Edges block, LabelsPtr e)+                          => LabelMap (block C C) -> e -> LabelSet -> [block C C]+postorder_dfs_from_except blocks b visited =+ vchildren (get_children b) (\acc _visited -> acc) [] visited+ where+   vnode :: block C C -> ([block C C] -> LabelSet -> a) -> [block C C] -> LabelSet -> a+   vnode block cont acc visited =+        if elemLabelSet id visited then+            cont acc visited+        else+            let cont' acc visited = cont (block:acc) visited in+            vchildren (get_children block) cont' acc (extendLabelSet visited id)+      where id = entryLabel block+   vchildren bs cont acc visited = next bs acc visited+      where next children acc visited =+                case children of []     -> cont acc visited+                                 (b:bs) -> vnode b (next bs) acc visited+   get_children block = foldr add_id [] $ targetLabels block+   add_id id rst = case lookupFact blocks id of+                      Just b -> b : rst+                      Nothing -> rst++postorder_dfs_from+    :: (Edges block, LabelsPtr b) => LabelMap (block C C) -> b -> [block C C]+postorder_dfs_from blocks b = postorder_dfs_from_except blocks b emptyLabelSet+++----------------------------------------------------------------++data VM a = VM { unVM :: LabelSet -> (a, LabelSet) }+marked :: Label -> VM Bool+mark   :: Label -> VM ()+instance Monad VM where+  return a = VM $ \visited -> (a, visited)+  m >>= k  = VM $ \visited -> let (a, v') = unVM m visited in unVM (k a) v'+marked l = VM $ \v -> (elemLabelSet l v, v)+mark   l = VM $ \v -> ((), extendLabelSet v l)++preorder_dfs_from_except :: forall block e . (Edges block, LabelsPtr e)+                         => LabelMap (block C C) -> e -> LabelSet -> [block C C]+preorder_dfs_from_except blocks b visited =+    (fst $ unVM (children (get_children b)) visited) []+  where children [] = return id+        children (b:bs) = liftM2 (.) (visit b) (children bs)+        visit :: block C C -> VM (HL (block C C))+        visit b = do already <- marked (entryLabel b)+                     if already then return id+                      else do mark (entryLabel b)+                              bs <- children $ get_children b+                              return $ b `cons` bs+        get_children block = foldr add_id [] $ targetLabels block+        add_id id rst = case lookupFact blocks id of+                          Just b -> b : rst+                          Nothing -> rst++type HL a = [a] -> [a] -- Hughes list (constant-time concatenation)+cons :: a -> HL a -> HL a+cons a as tail = a : as tail++----------------------------------------------------------------++labelsDefined :: forall block n e x . Edges (block n) => Graph' block n e x -> LabelSet+labelsDefined GNil      = emptyLabelSet+labelsDefined (GUnit{}) = emptyLabelSet+labelsDefined (GMany _ body x) = foldBodyBlocks addEntry body $ exitLabel x+  where addEntry block labels = extendLabelSet labels (entryLabel block)+        exitLabel :: MaybeO x (block n C O) -> LabelSet+        exitLabel NothingO = emptyLabelSet+        exitLabel (JustO b) = mkLabelSet [entryLabel b]++labelsUsed :: forall block n e x. Edges (block n) => Graph' block n e x -> LabelSet+labelsUsed GNil      = emptyLabelSet+labelsUsed (GUnit{}) = emptyLabelSet+labelsUsed (GMany e body _) = foldBodyBlocks addTargets body $ entryTargets e+  where addTargets block labels = foldl extendLabelSet labels (successors block)+        entryTargets :: MaybeO e (block n O C) -> LabelSet+        entryTargets NothingO = emptyLabelSet+        entryTargets (JustO b) = addTargets b emptyLabelSet++foldBodyBlocks :: (block n C C -> a -> a) -> Body' block n -> a -> a+foldBodyBlocks _ BodyEmpty      = id+foldBodyBlocks f (BodyUnit b)   = f b+foldBodyBlocks f (BodyCat b b') = foldBodyBlocks f b . foldBodyBlocks f b'++externalEntryLabels :: Edges (block n) => Body' block n -> LabelSet+externalEntryLabels body = defined `minusLabelSet` used+  where defined = labelsDefined g+        used = labelsUsed g+        g = GMany NothingO body NothingO
+ Compiler/Hoopl/ZipDataflow.hs view
@@ -0,0 +1,568 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs, EmptyDataDecls, PatternGuards, TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} -- bug in GHC++{- Notes about the genesis of Hoopl7+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Hoopl7 has the following major chages++a) GMany has symmetric entry and exit+b) GMany closed-entry does not record a BlockId+c) GMany open-exit does not record a BlockId+d) The body of a GMany is called Body+e) A Body is just a list of blocks, not a map. I've argued+   elsewhere that this is consistent with (c)++A consequence is that Graph is no longer an instance of Edges,+but nevertheless I managed to keep the ARF and ARB signatures+nice and uniform.++This was made possible by++* FwdTransfer looks like this:+    type FwdTransfer n f+      = forall e x. n e x -> Fact e f -> Fact x f +    type family   Fact x f :: *+    type instance Fact C f = FactBase f+    type instance Fact O f = f++  Note that the incoming fact is a Fact (not just 'f' as in Hoopl5,6).+  It's up to the *transfer function* to look up the appropriate fact+  in the FactBase for a closed-entry node.  Example:+	constProp (Label l) fb = lookupFact fb l+  That is how Hoopl can avoid having to know the block-id for the+  first node: it defers to the client.++  [Side note: that means the client must know about +  bottom, in case the looupFact returns Nothing]++* Note also that FwdTransfer *returns* a Fact too;+  that is, the types in both directions are symmetrical.+  Previously we returned a [(BlockId,f)] but I could not see+  how to make everything line up if we do this.++  Indeed, the main shortcoming of Hoopl7 is that we are more+  or less forced into this uniform representation of the facts+  flowing into or out of a closed node/block/graph, whereas+  previously we had more flexibility.++  In exchange the code is neater, with fewer distinct types.+  And morally a FactBase is equivalent to [(BlockId,f)] and+  nearly equivalent to (BlockId -> f).++* I've realised that forwardBlockList and backwardBlockList+  both need (Edges n), and that goes everywhere.++* I renamed BlockId to Label+-}++module Compiler.Hoopl.ZipDataflow +  ( FwdPass(..),  FwdTransfer, FwdRewrite, FwdRes(..)+  , BwdPass(..), BwdTransfer, BwdRewrite, BwdRes(..)+  , analyzeAndRewriteFwd,  analyzeAndRewriteBwd+  , analyzeAndRewriteFwd', analyzeAndRewriteBwd'+  )+where++import Compiler.Hoopl.Dataflow +           ( DataflowLattice(..), OldFact(..), NewFact(..)+           , ChangeFlag(..)+           , Fact+           )+import Compiler.Hoopl.Fuel+import Compiler.Hoopl.Graph+import qualified Compiler.Hoopl.GraphUtil as U+import Compiler.Hoopl.Label+import Compiler.Hoopl.Util+import Compiler.Hoopl.Zipper++type AGraph n e x = FuelMonad (ZGraph n e x)+graphOfAGraph :: AGraph n e x -> FuelMonad (ZGraph n e x)+graphOfAGraph = id++-----------------------------------------------------------------------------+--		Analyze and rewrite forward: the interface+-----------------------------------------------------------------------------++data FwdPass n f+  = FwdPass { fp_lattice  :: DataflowLattice f+            , fp_transfer :: FwdTransfer n f+            , fp_rewrite  :: FwdRewrite n f }++type FwdTransfer n f +  = forall e x. n e x -> Fact e f -> Fact x f ++type FwdRewrite n f +  = forall e x. n e x -> Fact e f -> Maybe (FwdRes n f e x)+data FwdRes n f e x = FwdRes (AGraph n e x) (FwdRewrite n f)+  -- result of a rewrite is a new graph and a (possibly) new rewrite function++analyzeAndRewriteFwd+   :: forall n f. Edges n+   => FwdPass n f+   -> ZBody n -> FactBase f+   -> FuelMonad (ZBody n, FactBase f)++analyzeAndRewriteFwd pass body facts+  = do { (rg, _) <- arfBody pass body facts+       ; return (normaliseBody rg) }++-- | if the graph being analyzed is open at the entry, there must+--   be no other entry point, or all goes horribly wrong...+analyzeAndRewriteFwd'+   :: forall n f e x. Edges n+   => FwdPass n f+   -> ZGraph n e x -> Fact e f+   -> FuelMonad (ZGraph n e x, FactBase f, MaybeO x f)+analyzeAndRewriteFwd' pass g f =+  do (rg, fout) <- arfGraph pass g f+     let (g', fb) = normalizeGraph g rg+     return (g', fb, distinguishedExitFact g' fout)++distinguishedExitFact :: forall n e x f . ZGraph n e x -> Fact x f -> MaybeO x f+distinguishedExitFact g f = maybe g+    where maybe :: ZGraph n e x -> MaybeO x f+          maybe GNil       = JustO f+          maybe (GUnit {}) = JustO f+          maybe (GMany _ _ x) = case x of NothingO -> NothingO+                                          JustO _  -> JustO f++normalizeGraph :: Edges n => ZGraph n e x -> RG n f e x -> GraphWithFacts n f e x+normalizeGraph GNil = normOO+normalizeGraph (GUnit {}) = normOO+normalizeGraph (GMany NothingO  _ NothingO)  = normCC+normalizeGraph (GMany (JustO _) _ NothingO)  = normOC+normalizeGraph (GMany NothingO  _ (JustO _)) = normCO+normalizeGraph (GMany (JustO _) _ (JustO _)) = normOO+++----------------------------------------------------------------+--       Forward Implementation+----------------------------------------------------------------+++type ARF' n f thing e x+  = FwdPass n f -> thing e x -> Fact e f -> FuelMonad (RG n f e x, Fact x f)++type ARF thing n = forall f e x . ARF' n f thing e x+++arfNode :: Edges n+        => (n e x -> ZBlock n e x)+        -> ARF' n f n e x+arfNode bunit pass node f+  = do { mb_g <- withFuel (fp_rewrite pass node f)+       ; case mb_g of+           Nothing -> return (RGUnit f (bunit node),+                              fp_transfer pass node f)+      	   Just (FwdRes ag rw) -> do { g <- graphOfAGraph ag+                                     ; let pass' = pass { fp_rewrite = rw }+                                     ; arfGraph pass' g f } }++-- type demonstration+_arfBlock :: Edges n => ARF' n f (ZBlock n) e x+_arfBlock = arfBlock+_arfGraph :: Edges n => ARF' n f (ZGraph n) e x+_arfGraph = arfGraph+++arfMiddle :: Edges n => ARF' n f n O O+arfMiddle = arfNode ZMiddle+++arfBlock :: Edges n => ARF (ZBlock n) n+-- Lift from nodes to blocks+arfBlock pass (ZFirst  node)  = arfNode ZFirst  pass node+arfBlock pass (ZMiddle node)  = arfNode ZMiddle pass node+arfBlock pass (ZLast   node)  = arfNode ZLast   pass node+arfBlock pass (ZCat b1 b2)    = arfCat arfBlock  arfBlock  pass b1 b2+arfBlock pass (ZHead h n)     = arfCat arfBlock  arfMiddle pass h n+arfBlock pass (ZTail n t)     = arfCat arfMiddle arfBlock  pass n t+arfBlock pass (ZClosed h t)   = arfCat arfBlock  arfBlock  pass h t++arfCat :: Edges n => ARF' n f thing1 e O -> ARF' n f thing2 O x+       -> FwdPass n f -> thing1 e O -> thing2 O x+       -> Fact e f -> FuelMonad (RG n f e x, Fact x f)+arfCat arf1 arf2 pass thing1 thing2 f = do { (g1,f1) <- arf1 pass thing1 f+                                           ; (g2,f2) <- arf2 pass thing2 f1+                                           ; return (g1 `RGCatO` g2, f2) }+arfBody :: Edges n+                  +        => FwdPass n f -> ZBody n -> FactBase f+        -> FuelMonad (RG n f C C, FactBase f)+		-- Outgoing factbase is restricted to Labels *not* in+		-- in the Body; the facts for Labels *in*+                -- the Body are in the BodyWithFacts+arfBody pass blocks init_fbase+  = fixpoint True (fp_lattice pass) (arfBlock pass) init_fbase $+    forwardBlockList (factBaseLabels init_fbase) blocks++arfGraph :: Edges n => ARF (ZGraph n) n+-- Lift from blocks to graphs+arfGraph _    GNil        f = return (RGNil, f)+arfGraph pass (GUnit blk) f = arfBlock pass blk f+arfGraph pass (GMany NothingO body NothingO) f+  = do { (body', fb) <- arfBody pass body f+       ; return (body', fb) }+arfGraph pass (GMany NothingO body (JustO exit)) f+  = do { (body', fb) <- arfBody  pass body f+       ; (exit', fx) <- arfBlock pass exit fb+       ; return (body' `RGCatC` exit', fx) }+arfGraph pass (GMany (JustO entry) body NothingO) f+  = do { (entry', fe) <- arfBlock pass entry f+       ; (body', fb)  <- arfBody  pass body fe+       ; return (entry' `RGCatC` body', fb) }+arfGraph pass (GMany (JustO entry) body (JustO exit)) f+  = do { (entry', fe) <- arfBlock pass entry f+       ; (body', fb)  <- arfBody  pass body fe+       ; (exit', fx)  <- arfBlock pass exit fb+       ; return (entry' `RGCatC` body' `RGCatC` exit', fx) }++forwardBlockList :: (Edges n, LabelsPtr entry)+                 => entry -> ZBody n -> [ZBlock n C C]+-- This produces a list of blocks in order suitable for forward analysis,+-- along with the list of Labels it may depend on for facts.+forwardBlockList entries blks = postorder_dfs_from (bodyMap blks) entries++-----------------------------------------------------------------------------+--		Backward analysis and rewriting: the interface+-----------------------------------------------------------------------------++data BwdPass n f+  = BwdPass { bp_lattice  :: DataflowLattice f+            , bp_transfer :: BwdTransfer n f+            , bp_rewrite  :: BwdRewrite n f }++type BwdTransfer n f +  = forall e x. n e x -> Fact x f -> Fact e f +type BwdRewrite n f +  = forall e x. n e x -> Fact x f -> Maybe (BwdRes n f e x)+data BwdRes n f e x = BwdRes (AGraph n e x) (BwdRewrite n f)++-----------------------------------------------------------------------------+--		Backward implementation+-----------------------------------------------------------------------------++type ARB' n f thing e x+  = BwdPass n f -> thing e x -> Fact x f -> FuelMonad (RG n f e x, Fact e f)++type ARB thing n = forall f e x. ARB' n f thing e x ++arbNode :: Edges n+        => (n e x -> ZBlock n e x)+        -> ARB' n f n e x+-- Lifts (BwdTransfer,BwdRewrite) to ARB_Node; +-- this time we do rewriting as well. +-- The ARB_Graph parameters specifies what to do with the rewritten graph+arbNode bunit pass node f+  = do { mb_g <- withFuel (bp_rewrite pass node f)+       ; case mb_g of+           Nothing -> return (RGUnit entry_f (bunit node), entry_f)+                    where+                      entry_f = bp_transfer pass node f+      	   Just (BwdRes ag rw) -> do { g <- graphOfAGraph ag+                                     ; let pass' = pass { bp_rewrite = rw }+                                     ; arbGraph pass' g f} }++arbMiddle :: Edges n => ARB' n f n O O+arbMiddle = arbNode ZMiddle++arbBlock :: Edges n => ARB (ZBlock n) n+-- Lift from nodes to blocks+arbBlock pass (ZFirst  node)  = arbNode ZFirst  pass node+arbBlock pass (ZMiddle node)  = arbNode ZMiddle pass node+arbBlock pass (ZLast   node)  = arbNode ZLast   pass node+arbBlock pass (ZCat b1 b2)    = arbCat arbBlock  arbBlock  pass b1 b2+arbBlock pass (ZHead h n)     = arbCat arbBlock  arbMiddle pass h n+arbBlock pass (ZTail n t)     = arbCat arbMiddle arbBlock  pass n t+arbBlock pass (ZClosed h t)   = arbCat arbBlock  arbBlock  pass h t++arbCat :: Edges n => ARB' n f thing1 e O -> ARB' n f thing2 O x+       -> BwdPass n f -> thing1 e O -> thing2 O x+       -> Fact x f -> FuelMonad (RG n f e x, Fact e f)+arbCat arb1 arb2 pass thing1 thing2 f = do { (g2,f2) <- arb2 pass thing2 f+                                           ; (g1,f1) <- arb1 pass thing1 f2+                                           ; return (g1 `RGCatO` g2, f1) }++arbBody :: Edges n+        => BwdPass n f -> ZBody n -> FactBase f+        -> FuelMonad (RG n f C C, FactBase f)+arbBody pass blocks init_fbase+  = fixpoint False (bp_lattice pass) (arbBlock pass) init_fbase $+    backwardBlockList blocks ++arbGraph :: Edges n => ARB (ZGraph n) n+arbGraph _    GNil        f = return (RGNil, f)+arbGraph pass (GUnit blk) f = arbBlock pass blk f+arbGraph pass (GMany NothingO body NothingO) f+  = do { (body', fb) <- arbBody pass body f+       ; return (body', fb) }+arbGraph pass (GMany NothingO body (JustO exit)) f+  = do { (exit', fx) <- arbBlock pass exit f+       ; (body', fb) <- arbBody  pass body fx+       ; return (body' `RGCatC` exit', fb) }+arbGraph pass (GMany (JustO entry) body NothingO) f+  = do { (body', fb)  <- arbBody  pass body f+       ; (entry', fe) <- arbBlock pass entry fb+       ; return (entry' `RGCatC` body', fe) }+arbGraph pass (GMany (JustO entry) body (JustO exit)) f+  = do { (exit', fx)  <- arbBlock pass exit f+       ; (body', fb)  <- arbBody  pass body fx+       ; (entry', fe) <- arbBlock pass entry fb+       ; return (entry' `RGCatC` body' `RGCatC` exit', fe) }++backwardBlockList :: Edges n => ZBody n -> [ZBlock n C C]+-- This produces a list of blocks in order suitable for backward analysis,+-- along with the list of Labels it may depend on for facts.+backwardBlockList body = reachable ++ missing+  where reachable = reverse $ forwardBlockList entries body+        entries = externalEntryLabels body+        all = bodyList body+        missingLabels =+            mkLabelSet (map fst all) `minusLabelSet`+            mkLabelSet (map entryLabel reachable)+        missing = map snd $ filter (flip elemLabelSet missingLabels . fst) all++{-++The forward and backward dataflow analyses now use postorder depth-first+order for faster convergence.++The forward and backward cases are not dual.  In the forward case, the+entry points are known, and one simply traverses the body blocks from+those points.  In the backward case, something is known about the exit+points, but this information is essentially useless, because we don't+actually have a dual graph (that is, one with edges reversed) to+compute with.  (Even if we did have a dual graph, it would not avail+us---a backward analysis must include reachable blocks that don't+reach the exit, as in a procedure that loops forever and has side+effects.)++Since in the general case, no information is available about entry+points, I have put in a horrible hack.  First, I assume that every+label defined but not used is an entry point.  Then, because an entry+point might also be a loop header, I add, in arbitrary order, all the+remaining "missing" blocks.  Needless to say, I am not pleased.  +I am not satisfied.  I am not Senator Morgan.++Wait! I believe that the Right Thing here is to require that anyone+wishing to analyze a graph closed at the entry provide a way of+determining the entry points, if any, of that graph.  This requirement+can apply equally to forward and backward analyses; I believe that+using the input FactBase to determine the entry points of a closed+graph is *also* a hack.++NR++-}+++analyzeAndRewriteBwd+   :: forall n f. Edges n+   => BwdPass n f +   -> ZBody n -> FactBase f +   -> FuelMonad (ZBody n, FactBase f)++analyzeAndRewriteBwd pass body facts+  = do { (rg, _) <- arbBody pass body facts+       ; return (normaliseBody rg) }++-- | if the graph being analyzed is open at the exit, I don't+--   quite understand the implications of possible other exits+analyzeAndRewriteBwd'+   :: forall n f e x. Edges n+   => BwdPass n f+   -> ZGraph n e x -> Fact x f+   -> FuelMonad (ZGraph n e x, FactBase f, MaybeO e f)+analyzeAndRewriteBwd' pass g f =+  do (rg, fout) <- arbGraph pass g f+     let (g', fb) = normalizeGraph g rg+     return (g', fb, distinguishedEntryFact g' fout)++distinguishedEntryFact :: forall n e x f . ZGraph n e x -> Fact e f -> MaybeO e f+distinguishedEntryFact g f = maybe g+    where maybe :: ZGraph n e x -> MaybeO e f+          maybe GNil       = JustO f+          maybe (GUnit {}) = JustO f+          maybe (GMany e _ _) = case e of NothingO -> NothingO+                                          JustO _  -> JustO f++-----------------------------------------------------------------------------+--      fixpoint: finding fixed points+-----------------------------------------------------------------------------++data TxFactBase n f+  = TxFB { tfb_fbase :: FactBase f+         , tfb_rg  :: RG n f C C -- Transformed blocks+         , tfb_cha   :: ChangeFlag+         , tfb_lbls  :: LabelSet }+ -- Note [TxFactBase change flag]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Set the tfb_cha flag iff + --   (a) the fact in tfb_fbase for or a block L changes+ --   (b) L is in tfb_lbls.+ -- The tfb_lbls are all Labels of the *original* + -- (not transformed) blocks++updateFact :: DataflowLattice f -> LabelSet -> (Label, f)+           -> (ChangeFlag, FactBase f) +           -> (ChangeFlag, FactBase f)+-- See Note [TxFactBase change flag]+updateFact lat lbls (lbl, new_fact) (cha, fbase)+  | NoChange <- cha2        = (cha,        fbase)+  | lbl `elemLabelSet` lbls = (SomeChange, new_fbase)+  | otherwise               = (cha,        new_fbase)+  where+    (cha2, res_fact) -- Note [Unreachable blocks]+       = case lookupFact fbase lbl of+           Nothing -> (SomeChange, snd $ join $ fact_bot lat)  -- Note [Unreachable blocks]+           Just old_fact -> join old_fact+         where join old_fact = fact_extend lat lbl (OldFact old_fact) (NewFact new_fact)+    new_fbase = extendFactBase fbase lbl res_fact++fixpoint :: forall block n f. Edges (block n)+         => Bool	-- Going forwards?+         -> DataflowLattice f+         -> (block n C C -> FactBase f+              -> FuelMonad (RG n f C C, FactBase f))+         -> FactBase f +         -> [block n C C]+         -> FuelMonad (RG n f C C, FactBase f)+fixpoint is_fwd lat do_block init_fbase untagged_blocks+  = do { fuel <- getFuel  +       ; tx_fb <- loop fuel init_fbase+       ; return (tfb_rg tx_fb, +                 tfb_fbase tx_fb `delFromFactBase` map fst blocks) }+	     -- The successors of the ZGraph are the the Labels for which+	     -- we have facts, that are *not* in the blocks of the graph+  where+    blocks = map tag untagged_blocks+     where tag b = ((entryLabel b, b), if is_fwd then [entryLabel b] else successors b)++    tx_blocks :: [((Label, block n C C), [Label])]   -- I do not understand this type+              -> TxFactBase n f -> FuelMonad (TxFactBase n f)+    tx_blocks []              tx_fb = return tx_fb+    tx_blocks (((lbl,blk), deps):bs) tx_fb = tx_block lbl blk deps tx_fb >>= tx_blocks bs+     -- "deps" == Labels the block may _depend_ upon for facts++    tx_block :: Label -> block n C C -> [Label]+             -> TxFactBase n f -> FuelMonad (TxFactBase n f)+    tx_block lbl blk deps tx_fb@(TxFB { tfb_fbase = fbase, tfb_lbls = lbls+                                      , tfb_rg = blks, tfb_cha = cha })+      | is_fwd && not (lbl `elemFactBase` fbase)+      = return tx_fb {tfb_lbls = lbls `unionLabelSet` mkLabelSet deps}	-- Note [Unreachable blocks]+      | otherwise+      = do { (rg, out_facts) <- do_block blk fbase+           ; let (cha',fbase') +                   = foldr (updateFact lat lbls) (cha,fbase) +                           (factBaseList out_facts)+                 lbls' = lbls `unionLabelSet` mkLabelSet deps+           ; return (TxFB { tfb_lbls  = lbls'+                          , tfb_rg    = rg `RGCatC` blks+                          , tfb_fbase = fbase', tfb_cha = cha' }) }++    loop :: Fuel -> FactBase f -> FuelMonad (TxFactBase n f)+    loop fuel fbase +      = do { let init_tx_fb = TxFB { tfb_fbase = fbase+                                   , tfb_cha   = NoChange+                                   , tfb_rg    = RGNil+                                   , tfb_lbls  = emptyLabelSet }+           ; tx_fb <- tx_blocks blocks init_tx_fb+           ; case tfb_cha tx_fb of+               NoChange   -> return tx_fb+               SomeChange -> do { setFuel fuel+                                ; loop fuel (tfb_fbase tx_fb) } }++{- Note [Unreachable blocks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A block that is not in the domain of tfb_fbase is "currently unreachable".+A currently-unreachable block is not even analyzed.  Reason: consider +constant prop and this graph, with entry point L1:+  L1: x:=3; goto L4+  L2: x:=4; goto L4+  L4: if x>3 goto L2 else goto L5+Here L2 is actually unreachable, but if we process it with bottom input fact,+we'll propagate (x=4) to L4, and nuke the otherwise-good rewriting of L4.++* If a currently-unreachable block is not analyzed, then its rewritten+  graph will not be accumulated in tfb_rg.  And that is good:+  unreachable blocks simply do not appear in the output.++* Note that clients must be careful to provide a fact (even if bottom)+  for each entry point. Otherwise useful blocks may be garbage collected.++* Note that updateFact must set the change-flag if a label goes from+  not-in-fbase to in-fbase, even if its fact is bottom.  In effect the+  real fact lattice is+       UNR+       bottom+       the points above bottom++* Even if the fact is going from UNR to bottom, we still call the+  client's fact_extend function because it might give the client+  some useful debugging information.++* All of this only applies for *forward* fixpoints.  For the backward+  case we must treat every block as reachable; it might finish with a+  'return', and therefore have no successors, for example.+-}++-----------------------------------------------------------------------------+--	RG: an internal data type for graphs under construction+--          TOTALLY internal to Hoopl+-----------------------------------------------------------------------------++-- this type exists because we have not yet found a way to write arfNode+-- to return a Graph; the invariants of ZGraph seem too strong++data RG' block n f e x where+  RGNil   :: RG' block n f a a+  RGUnit  :: Fact e f -> block n e x -> RG' block n f e x+  RGCatO  :: RG' block n f e O -> RG' block n f O x -> RG' block n f e x+  RGCatC  :: RG' block n f e C -> RG' block n f C x -> RG' block n f e x+type RG = RG' ZBlock++type BodyWithFacts  n f     = (ZBody n, FactBase f)+type GraphWithFacts n f e x = (ZGraph n e x, FactBase f)+  -- A ZGraph together with the facts for that graph+  -- The domains of the two maps should be identical++normaliseBody :: Edges n => RG n f C C -> BodyWithFacts n f+normaliseBody rg = (body, fact_base)+  where+    (GMany _ body _, fact_base) = normCC rg++normOO :: Edges n => RG n f O O -> GraphWithFacts n f O O+normOO RGNil          = (GNil, noFacts)+normOO (RGUnit _ b)   = (GUnit b, noFacts)+normOO (RGCatO g1 g2) = normOO g1 `gwfCat` normOO g2+normOO (RGCatC g1 g2) = normOC g1 `gwfCat` normCO g2++normOC :: Edges n => RG n f O C -> GraphWithFacts n f O C+normOC (RGUnit _ b)   = (GMany (JustO b) BodyEmpty NothingO, noFacts)+normOC (RGCatO g1 g2) = normOO g1 `gwfCat` normOC g2+normOC (RGCatC g1 g2) = normOC g1 `gwfCat` normCC g2++normCO :: Edges n => RG n f C O -> GraphWithFacts n f C O+normCO (RGUnit f b) = (GMany NothingO BodyEmpty (JustO b), unitFact l f)+                    where+                      l = entryLabel b+normCO (RGCatO g1 g2) = normCO g1 `gwfCat` normOO g2+normCO (RGCatC g1 g2) = normCC g1 `gwfCat` normCO g2++normCC :: Edges n => RG n f C C -> GraphWithFacts n f C C+normCC RGNil        = (GMany NothingO BodyEmpty NothingO, noFacts)+normCC (RGUnit f b) = (GMany NothingO (BodyUnit b) NothingO, unitFact l f)+                    where+                      l = entryLabel b+normCC (RGCatO g1 g2) = normCO g1 `gwfCat` normOC g2+normCC (RGCatC g1 g2) = normCC g1 `gwfCat` normCC g2++gwfCat :: Edges n => GraphWithFacts n f e a+                  -> GraphWithFacts n f a x +                  -> GraphWithFacts n f e x+gwfCat (g1, fb1) (g2, fb2) = (g1 `U.zSplice` g2, fb1 `unionFactBase` fb2)++{-+bwfUnion :: BodyWithFacts n f -> BodyWithFacts n f -> BodyWithFacts n f+bwfUnion (bg1, fb1) (bg2, fb2) = (bg1 `BodyCat` bg2, fb1 `unionFactBase` fb2)+-}
+ Compiler/Hoopl/ZipDataflowNoRG.hs view
@@ -0,0 +1,556 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs, EmptyDataDecls, PatternGuards, TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} -- bug in GHC++{- Notes about the genesis of Hoopl7+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Hoopl7 has the following major chages++a) GMany has symmetric entry and exit+b) GMany closed-entry does not record a BlockId+c) GMany open-exit does not record a BlockId+d) The body of a GMany is called Body+e) A Body is just a list of blocks, not a map. I've argued+   elsewhere that this is consistent with (c)++A consequence is that Graph is no longer an instance of Edges,+but nevertheless I managed to keep the ARF and ARB signatures+nice and uniform.++This was made possible by++* FwdTransfer looks like this:+    type FwdTransfer n f+      = forall e x. n e x -> Fact e f -> Fact x f +    type family   Fact x f :: *+    type instance Fact C f = FactBase f+    type instance Fact O f = f++  Note that the incoming fact is a Fact (not just 'f' as in Hoopl5,6).+  It's up to the *transfer function* to look up the appropriate fact+  in the FactBase for a closed-entry node.  Example:+	constProp (Label l) fb = lookupFact fb l+  That is how Hoopl can avoid having to know the block-id for the+  first node: it defers to the client.++  [Side note: that means the client must know about +  bottom, in case the looupFact returns Nothing]++* Note also that FwdTransfer *returns* a Fact too;+  that is, the types in both directions are symmetrical.+  Previously we returned a [(BlockId,f)] but I could not see+  how to make everything line up if we do this.++  Indeed, the main shortcoming of Hoopl7 is that we are more+  or less forced into this uniform representation of the facts+  flowing into or out of a closed node/block/graph, whereas+  previously we had more flexibility.++  In exchange the code is neater, with fewer distinct types.+  And morally a FactBase is equivalent to [(BlockId,f)] and+  nearly equivalent to (BlockId -> f).++* I've realised that forwardBlockList and backwardBlockList+  both need (Edges n), and that goes everywhere.++* I renamed BlockId to Label+-}++module Compiler.Hoopl.ZipDataflowNoRG+  ( FwdPass(..),  FwdTransfer, FwdRewrite, FwdRes(..)+  , BwdPass(..), BwdTransfer, BwdRewrite, BwdRes(..)+  , analyzeAndRewriteFwd,  analyzeAndRewriteBwd+  , analyzeAndRewriteFwd', analyzeAndRewriteBwd'+  )+where++import Compiler.Hoopl.Dataflow +           ( DataflowLattice(..), OldFact(..), NewFact(..)+           , ChangeFlag(..)+           , Fact+           )+import Compiler.Hoopl.Fuel+import Compiler.Hoopl.Graph+import qualified Compiler.Hoopl.GraphUtil as U+import Compiler.Hoopl.Label+import Compiler.Hoopl.Util+import Compiler.Hoopl.Zipper++type AGraph n e x = FuelMonad (ZGraph n e x)+graphOfAGraph :: AGraph n e x -> FuelMonad (ZGraph n e x)+graphOfAGraph = id++-----------------------------------------------------------------------------+--		Analyze and rewrite forward: the interface+-----------------------------------------------------------------------------++data FwdPass n f+  = FwdPass { fp_lattice  :: DataflowLattice f+            , fp_transfer :: FwdTransfer n f+            , fp_rewrite  :: FwdRewrite n f }++type FwdTransfer n f +  = forall e x. n e x -> Fact e f -> Fact x f ++type FwdRewrite n f +  = forall e x. n e x -> Fact e f -> Maybe (FwdRes n f e x)+data FwdRes n f e x = FwdRes (AGraph n e x) (FwdRewrite n f)+  -- result of a rewrite is a new graph and a (possibly) new rewrite function++analyzeAndRewriteFwd+   :: forall n f. Edges n+   => FwdPass n f+   -> ZBody n -> FactBase f+   -> FuelMonad (ZBody n, FactBase f)++analyzeAndRewriteFwd pass body facts+  = do { (rg, _) <- arfBody pass body facts+       ; return (normaliseBody rg) }++-- | if the graph being analyzed is open at the entry, there must+--   be no other entry point, or all goes horribly wrong...+analyzeAndRewriteFwd'+   :: forall n f e x. Edges n+   => FwdPass n f+   -> ZGraph n e x -> Fact e f+   -> FuelMonad (ZGraph n e x, FactBase f, MaybeO x f)+analyzeAndRewriteFwd' pass g f =+  do (rg, fout) <- arfGraph pass g f+     let (g', fb) = normalizeGraph rg+     return (g', fb, distinguishedExitFact g' fout)++distinguishedExitFact :: forall n e x f . ZGraph n e x -> Fact x f -> MaybeO x f+distinguishedExitFact g f = maybe g+    where maybe :: ZGraph n e x -> MaybeO x f+          maybe GNil       = JustO f+          maybe (GUnit {}) = JustO f+          maybe (GMany _ _ x) = case x of NothingO -> NothingO+                                          JustO _  -> JustO f++----------------------------------------------------------------+--       Forward Implementation+----------------------------------------------------------------+++type ARF' n f thing e x+  = FwdPass n f -> thing e x -> Fact e f -> FuelMonad (RG f n e x, Fact x f)++type ARF thing n = forall f e x . ARF' n f thing e x+++arfNode :: Edges n+        => (n e x -> ZBlock n e x)+        -> ARF' n f n e x+arfNode bunit pass node f+  = do { mb_g <- withFuel (fp_rewrite pass node f)+       ; case mb_g of+           Nothing -> return (rgunit f (bunit node),+                              fp_transfer pass node f)+      	   Just (FwdRes ag rw) -> do { g <- graphOfAGraph ag+                                     ; let pass' = pass { fp_rewrite = rw }+                                     ; arfGraph pass' g f } }++-- type demonstration+_arfBlock :: Edges n => ARF' n f (ZBlock n) e x+_arfBlock = arfBlock+_arfGraph :: Edges n => ARF' n f (ZGraph n) e x+_arfGraph = arfGraph+++arfMiddle :: Edges n => ARF' n f n O O+arfMiddle = arfNode ZMiddle+++arfBlock :: Edges n => ARF (ZBlock n) n+-- Lift from nodes to blocks+arfBlock pass (ZFirst  node)  = arfNode ZFirst  pass node+arfBlock pass (ZMiddle node)  = arfNode ZMiddle pass node+arfBlock pass (ZLast   node)  = arfNode ZLast   pass node+arfBlock pass (ZCat b1 b2)    = arfCat arfBlock  arfBlock  pass b1 b2+arfBlock pass (ZHead h n)     = arfCat arfBlock  arfMiddle pass h n+arfBlock pass (ZTail n t)     = arfCat arfMiddle arfBlock  pass n t+arfBlock pass (ZClosed h t)   = arfCat arfBlock  arfBlock  pass h t++arfCat :: Edges n => ARF' n f thing1 e O -> ARF' n f thing2 O x+       -> FwdPass n f -> thing1 e O -> thing2 O x+       -> Fact e f -> FuelMonad (RG f n e x, Fact x f)+arfCat arf1 arf2 pass thing1 thing2 f = do { (g1,f1) <- arf1 pass thing1 f+                                           ; (g2,f2) <- arf2 pass thing2 f1+                                           ; return (g1 `rgCat` g2, f2) }+arfBody :: Edges n+                  +        => FwdPass n f -> ZBody n -> FactBase f+        -> FuelMonad (RG f n C C, FactBase f)+		-- Outgoing factbase is restricted to Labels *not* in+		-- in the Body; the facts for Labels *in*+                -- the Body are in the BodyWithFacts+arfBody pass blocks init_fbase+  = fixpoint True (fp_lattice pass) (arfBlock pass) init_fbase $+    forwardBlockList (factBaseLabels init_fbase) blocks++arfGraph :: Edges n => ARF (ZGraph n) n+-- Lift from blocks to graphs+arfGraph _    GNil        f = return (rgnil, f)+arfGraph pass (GUnit blk) f = arfBlock pass blk f+arfGraph pass (GMany NothingO body NothingO) f+  = do { (body', fb) <- arfBody pass body f+       ; return (body', fb) }+arfGraph pass (GMany NothingO body (JustO exit)) f+  = do { (body', fb) <- arfBody  pass body f+       ; (exit', fx) <- arfBlock pass exit fb+       ; return (body' `rgCat` exit', fx) }+arfGraph pass (GMany (JustO entry) body NothingO) f+  = do { (entry', fe) <- arfBlock pass entry f+       ; (body', fb)  <- arfBody  pass body fe+       ; return (entry' `rgCat` body', fb) }+arfGraph pass (GMany (JustO entry) body (JustO exit)) f+  = do { (entry', fe) <- arfBlock pass entry f+       ; (body', fb)  <- arfBody  pass body fe+       ; (exit', fx)  <- arfBlock pass exit fb+       ; return (entry' `rgCat` body' `rgCat` exit', fx) }++forwardBlockList :: (Edges n, LabelsPtr entry)+                 => entry -> ZBody n -> [ZBlock n C C]+-- This produces a list of blocks in order suitable for forward analysis,+-- along with the list of Labels it may depend on for facts.+forwardBlockList entries blks = postorder_dfs_from (bodyMap blks) entries++-----------------------------------------------------------------------------+--		Backward analysis and rewriting: the interface+-----------------------------------------------------------------------------++data BwdPass n f+  = BwdPass { bp_lattice  :: DataflowLattice f+            , bp_transfer :: BwdTransfer n f+            , bp_rewrite  :: BwdRewrite n f }++type BwdTransfer n f +  = forall e x. n e x -> Fact x f -> Fact e f +type BwdRewrite n f +  = forall e x. n e x -> Fact x f -> Maybe (BwdRes n f e x)+data BwdRes n f e x = BwdRes (AGraph n e x) (BwdRewrite n f)++-----------------------------------------------------------------------------+--		Backward implementation+-----------------------------------------------------------------------------++type ARB' n f thing e x+  = BwdPass n f -> thing e x -> Fact x f -> FuelMonad (RG f n e x, Fact e f)++type ARB thing n = forall f e x. ARB' n f thing e x ++arbNode :: Edges n+        => (n e x -> ZBlock n e x)+        -> ARB' n f n e x+-- Lifts (BwdTransfer,BwdRewrite) to ARB_Node; +-- this time we do rewriting as well. +-- The ARB_Graph parameters specifies what to do with the rewritten graph+arbNode bunit pass node f+  = do { mb_g <- withFuel (bp_rewrite pass node f)+       ; case mb_g of+           Nothing -> return (rgunit entry_f (bunit node), entry_f)+                    where+                      entry_f = bp_transfer pass node f+      	   Just (BwdRes ag rw) -> do { g <- graphOfAGraph ag+                                     ; let pass' = pass { bp_rewrite = rw }+                                     ; arbGraph pass' g f} }++arbMiddle :: Edges n => ARB' n f n O O+arbMiddle = arbNode ZMiddle++arbBlock :: Edges n => ARB (ZBlock n) n+-- Lift from nodes to blocks+arbBlock pass (ZFirst  node)  = arbNode ZFirst  pass node+arbBlock pass (ZMiddle node)  = arbNode ZMiddle pass node+arbBlock pass (ZLast   node)  = arbNode ZLast   pass node+arbBlock pass (ZCat b1 b2)    = arbCat arbBlock  arbBlock  pass b1 b2+arbBlock pass (ZHead h n)     = arbCat arbBlock  arbMiddle pass h n+arbBlock pass (ZTail n t)     = arbCat arbMiddle arbBlock  pass n t+arbBlock pass (ZClosed h t)   = arbCat arbBlock  arbBlock  pass h t++arbCat :: Edges n => ARB' n f thing1 e O -> ARB' n f thing2 O x+       -> BwdPass n f -> thing1 e O -> thing2 O x+       -> Fact x f -> FuelMonad (RG f n e x, Fact e f)+arbCat arb1 arb2 pass thing1 thing2 f = do { (g2,f2) <- arb2 pass thing2 f+                                           ; (g1,f1) <- arb1 pass thing1 f2+                                           ; return (g1 `rgCat` g2, f1) }++arbBody :: Edges n+        => BwdPass n f -> ZBody n -> FactBase f+        -> FuelMonad (RG f n C C, FactBase f)+arbBody pass blocks init_fbase+  = fixpoint False (bp_lattice pass) (arbBlock pass) init_fbase $+    backwardBlockList blocks ++arbGraph :: Edges n => ARB (ZGraph n) n+arbGraph _    GNil        f = return (rgnil, f)+arbGraph pass (GUnit blk) f = arbBlock pass blk f+arbGraph pass (GMany NothingO body NothingO) f+  = do { (body', fb) <- arbBody pass body f+       ; return (body', fb) }+arbGraph pass (GMany NothingO body (JustO exit)) f+  = do { (exit', fx) <- arbBlock pass exit f+       ; (body', fb) <- arbBody  pass body fx+       ; return (body' `rgCat` exit', fb) }+arbGraph pass (GMany (JustO entry) body NothingO) f+  = do { (body', fb)  <- arbBody  pass body f+       ; (entry', fe) <- arbBlock pass entry fb+       ; return (entry' `rgCat` body', fe) }+arbGraph pass (GMany (JustO entry) body (JustO exit)) f+  = do { (exit', fx)  <- arbBlock pass exit f+       ; (body', fb)  <- arbBody  pass body fx+       ; (entry', fe) <- arbBlock pass entry fb+       ; return (entry' `rgCat` body' `rgCat` exit', fe) }++backwardBlockList :: Edges n => ZBody n -> [ZBlock n C C]+-- This produces a list of blocks in order suitable for backward analysis,+-- along with the list of Labels it may depend on for facts.+backwardBlockList body = reachable ++ missing+  where reachable = reverse $ forwardBlockList entries body+        entries = externalEntryLabels body+        all = bodyList body+        missingLabels =+            mkLabelSet (map fst all) `minusLabelSet`+            mkLabelSet (map entryLabel reachable)+        missing = map snd $ filter (flip elemLabelSet missingLabels . fst) all++{-++The forward and backward dataflow analyses now use postorder depth-first+order for faster convergence.++The forward and backward cases are not dual.  In the forward case, the+entry points are known, and one simply traverses the body blocks from+those points.  In the backward case, something is known about the exit+points, but this information is essentially useless, because we don't+actually have a dual graph (that is, one with edges reversed) to+compute with.  (Even if we did have a dual graph, it would not avail+us---a backward analysis must include reachable blocks that don't+reach the exit, as in a procedure that loops forever and has side+effects.)++Since in the general case, no information is available about entry+points, I have put in a horrible hack.  First, I assume that every+label defined but not used is an entry point.  Then, because an entry+point might also be a loop header, I add, in arbitrary order, all the+remaining "missing" blocks.  Needless to say, I am not pleased.  +I am not satisfied.  I am not Senator Morgan.++Wait! I believe that the Right Thing here is to require that anyone+wishing to analyze a graph closed at the entry provide a way of+determining the entry points, if any, of that graph.  This requirement+can apply equally to forward and backward analyses; I believe that+using the input FactBase to determine the entry points of a closed+graph is *also* a hack.++NR++-}+++analyzeAndRewriteBwd+   :: forall n f. Edges n+   => BwdPass n f +   -> ZBody n -> FactBase f +   -> FuelMonad (ZBody n, FactBase f)++analyzeAndRewriteBwd pass body facts+  = do { (rg, _) <- arbBody pass body facts+       ; return (normaliseBody rg) }++-- | if the graph being analyzed is open at the exit, I don't+--   quite understand the implications of possible other exits+analyzeAndRewriteBwd'+   :: forall n f e x. Edges n+   => BwdPass n f+   -> ZGraph n e x -> Fact x f+   -> FuelMonad (ZGraph n e x, FactBase f, MaybeO e f)+analyzeAndRewriteBwd' pass g f =+  do (rg, fout) <- arbGraph pass g f+     let (g', fb) = normalizeGraph rg+     return (g', fb, distinguishedEntryFact g' fout)++distinguishedEntryFact :: forall n e x f . ZGraph n e x -> Fact e f -> MaybeO e f+distinguishedEntryFact g f = maybe g+    where maybe :: ZGraph n e x -> MaybeO e f+          maybe GNil       = JustO f+          maybe (GUnit {}) = JustO f+          maybe (GMany e _ _) = case e of NothingO -> NothingO+                                          JustO _  -> JustO f++-----------------------------------------------------------------------------+--      fixpoint: finding fixed points+-----------------------------------------------------------------------------++data TxFactBase n f+  = TxFB { tfb_fbase :: FactBase f+         , tfb_rg  :: RG f n C C -- Transformed blocks+         , tfb_cha   :: ChangeFlag+         , tfb_lbls  :: LabelSet }+ -- Note [TxFactBase change flag]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Set the tfb_cha flag iff + --   (a) the fact in tfb_fbase for or a block L changes+ --   (b) L is in tfb_lbls.+ -- The tfb_lbls are all Labels of the *original* + -- (not transformed) blocks++updateFact :: DataflowLattice f -> LabelSet -> (Label, f)+           -> (ChangeFlag, FactBase f) +           -> (ChangeFlag, FactBase f)+-- See Note [TxFactBase change flag]+updateFact lat lbls (lbl, new_fact) (cha, fbase)+  | NoChange <- cha2        = (cha,        fbase)+  | lbl `elemLabelSet` lbls = (SomeChange, new_fbase)+  | otherwise               = (cha,        new_fbase)+  where+    (cha2, res_fact) -- Note [Unreachable blocks]+       = case lookupFact fbase lbl of+           Nothing -> (SomeChange, snd $ join $ fact_bot lat)  -- Note [Unreachable blocks]+           Just old_fact -> join old_fact+         where join old_fact = fact_extend lat lbl (OldFact old_fact) (NewFact new_fact)+    new_fbase = extendFactBase fbase lbl res_fact++fixpoint :: forall block n f. Edges (block n)+         => Bool	-- Going forwards?+         -> DataflowLattice f+         -> (block n C C -> FactBase f+              -> FuelMonad (RG f n C C, FactBase f))+         -> FactBase f +         -> [block n C C]+         -> FuelMonad (RG f n C C, FactBase f)+fixpoint is_fwd lat do_block init_fbase untagged_blocks+  = do { fuel <- getFuel  +       ; tx_fb <- loop fuel init_fbase+       ; return (tfb_rg tx_fb, +                 tfb_fbase tx_fb `delFromFactBase` map fst blocks) }+	     -- The successors of the ZGraph are the the Labels for which+	     -- we have facts, that are *not* in the blocks of the graph+  where+    blocks = map tag untagged_blocks+     where tag b = ((entryLabel b, b), if is_fwd then [entryLabel b] else successors b)++    tx_blocks :: [((Label, block n C C), [Label])]   -- I do not understand this type+              -> TxFactBase n f -> FuelMonad (TxFactBase n f)+    tx_blocks []              tx_fb = return tx_fb+    tx_blocks (((lbl,blk), deps):bs) tx_fb = tx_block lbl blk deps tx_fb >>= tx_blocks bs+     -- "deps" == Labels the block may _depend_ upon for facts++    tx_block :: Label -> block n C C -> [Label]+             -> TxFactBase n f -> FuelMonad (TxFactBase n f)+    tx_block lbl blk deps tx_fb@(TxFB { tfb_fbase = fbase, tfb_lbls = lbls+                                      , tfb_rg = blks, tfb_cha = cha })+      | is_fwd && not (lbl `elemFactBase` fbase)+      = return tx_fb {tfb_lbls = lbls `unionLabelSet` mkLabelSet deps}	-- Note [Unreachable blocks]+      | otherwise+      = do { (rg, out_facts) <- do_block blk fbase+           ; let (cha',fbase') +                   = foldr (updateFact lat lbls) (cha,fbase) +                           (factBaseList out_facts)+                 lbls' = lbls `unionLabelSet` mkLabelSet deps+           ; return (TxFB { tfb_lbls  = lbls'+                          , tfb_rg    = rg `rgCat` blks+                          , tfb_fbase = fbase', tfb_cha = cha' }) }++    loop :: Fuel -> FactBase f -> FuelMonad (TxFactBase n f)+    loop fuel fbase +      = do { let init_tx_fb = TxFB { tfb_fbase = fbase+                                   , tfb_cha   = NoChange+                                   , tfb_rg    = rgnilC+                                   , tfb_lbls  = emptyLabelSet }+           ; tx_fb <- tx_blocks blocks init_tx_fb+           ; case tfb_cha tx_fb of+               NoChange   -> return tx_fb+               SomeChange -> do { setFuel fuel+                                ; loop fuel (tfb_fbase tx_fb) } }++{- Note [Unreachable blocks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A block that is not in the domain of tfb_fbase is "currently unreachable".+A currently-unreachable block is not even analyzed.  Reason: consider +constant prop and this graph, with entry point L1:+  L1: x:=3; goto L4+  L2: x:=4; goto L4+  L4: if x>3 goto L2 else goto L5+Here L2 is actually unreachable, but if we process it with bottom input fact,+we'll propagate (x=4) to L4, and nuke the otherwise-good rewriting of L4.++* If a currently-unreachable block is not analyzed, then its rewritten+  graph will not be accumulated in tfb_rg.  And that is good:+  unreachable blocks simply do not appear in the output.++* Note that clients must be careful to provide a fact (even if bottom)+  for each entry point. Otherwise useful blocks may be garbage collected.++* Note that updateFact must set the change-flag if a label goes from+  not-in-fbase to in-fbase, even if its fact is bottom.  In effect the+  real fact lattice is+       UNR+       bottom+       the points above bottom++* Even if the fact is going from UNR to bottom, we still call the+  client's fact_extend function because it might give the client+  some useful debugging information.++* All of this only applies for *forward* fixpoints.  For the backward+  case we must treat every block as reachable; it might finish with a+  'return', and therefore have no successors, for example.+-}++-----------------------------------------------------------------------------+--	RG: an internal data type for graphs under construction+--          TOTALLY internal to Hoopl; each block carries its fact+-----------------------------------------------------------------------------++type RG      f n e x = Graph' (FZBlock f) n e x+data FZBlock f n e x = FZBlock (Fact e f) (ZBlock n e x)++--- constructors++rgnil  :: RG f n O O+rgnilC :: RG f n C C+rgunit :: Fact e f -> ZBlock n e x -> RG f n e x+rgCat  :: RG f n e a -> RG f n a x -> RG f n e x++---- observers++type BodyWithFacts  n f     = (ZBody n, FactBase f)+type GraphWithFacts n f e x = (ZGraph n e x, FactBase f)+  -- A ZGraph together with the facts for that graph+  -- The domains of the two maps should be identical++normalizeGraph :: forall n f e x .+                  Edges n => RG f n e x -> GraphWithFacts n f e x+normaliseBody  :: Edges n => RG f n C C -> BodyWithFacts n f++normalizeGraph g = (graphMapBlocks dropFact g, facts g)+    where dropFact (FZBlock _ b) = b+          facts :: RG f n e x -> FactBase f+          facts GNil = noFacts+          facts (GUnit _) = noFacts+          facts (GMany _ body exit) = bodyFacts body `unionFactBase` exitFacts exit+          exitFacts :: MaybeO x (FZBlock f n C O) -> FactBase f+          exitFacts NothingO = noFacts+          exitFacts (JustO (FZBlock f b)) = unitFact (entryLabel b) f+          bodyFacts :: Body' (FZBlock f) n -> FactBase f+          bodyFacts (BodyUnit (FZBlock f b)) = unitFact (entryLabel b) f+          bodyFacts (b1 `BodyCat` b2) = bodyFacts b1 `unionFactBase` bodyFacts b2++normaliseBody rg = (body, fact_base)+  where (GMany _ body _, fact_base) = normalizeGraph rg++--- implementation of the constructors (boring)++rgnil  = GNil+rgnilC = GMany NothingO BodyEmpty NothingO++rgunit f b@(ZFirst  {}) = gUnitCO (FZBlock f b)+rgunit f b@(ZMiddle {}) = gUnitOO (FZBlock f b)+rgunit f b@(ZLast   {}) = gUnitOC (FZBlock f b)+rgunit f b@(ZCat {})    = gUnitOO (FZBlock f b)+rgunit f b@(ZHead {})   = gUnitCO (FZBlock f b)+rgunit f b@(ZTail {})   = gUnitOC (FZBlock f b)+rgunit f b@(ZClosed {}) = gUnitCC (FZBlock f b)++rgCat = U.splice fzCat+  where fzCat (FZBlock f b1) (FZBlock _ b2) = FZBlock f (b1 `U.zCat` b2)
+ Compiler/Hoopl/Zipper.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE GADTs #-}++module Compiler.Hoopl.Zipper+  ( ZBlock(..), ZGraph, ZBody+  , frontBiasBlock, backBiasBlock+  )+where++import Compiler.Hoopl.Graph++data ZBlock n e x where+  -- nodes+  ZFirst  :: n C O                 -> ZBlock n C O+  ZMiddle :: n O O                 -> ZBlock n O O+  ZLast   :: n O C                 -> ZBlock n O C++  -- concatenation operations+  ZCat    :: ZBlock n O O -> ZBlock n O O -> ZBlock n O O -- non-list-like+  ZHead   :: ZBlock n C O -> n O O        -> ZBlock n C O+  ZTail   :: n O O        -> ZBlock n O C -> ZBlock n O C  ++  ZClosed :: ZBlock n C O -> ZBlock n O C -> ZBlock n C C -- the zipper++type ZGraph = Graph' ZBlock+type ZBody  = Body'  ZBlock++instance Edges n => Edges (ZBlock n) where+  entryLabel (ZFirst n)    = entryLabel n+  entryLabel (ZHead h _)   = entryLabel h+  entryLabel (ZClosed h _) = entryLabel h+  successors (ZLast n)     = successors n+  successors (ZTail _ t)   = successors t+  successors (ZClosed _ t) = successors t+++----------------------------------------------------------------++-- | A block is "front biased" if the left child of every+-- concatenation operation is a node, not a general block; a+-- front-biased block is analogous to an ordinary list.  If a block is+-- front-biased, then its nodes can be traversed from front to back+-- without general recusion; tail recursion suffices.  Not all shapes+-- can be front-biased; a closed/open block is inherently back-biased.++frontBiasBlock :: ZBlock n e x -> ZBlock n e x+frontBiasBlock b@(ZFirst  {}) = b+frontBiasBlock b@(ZMiddle {}) = b+frontBiasBlock b@(ZLast   {}) = b+frontBiasBlock b@(ZCat {}) = rotate b+  where -- rotate and append ensure every left child of ZCat is ZMiddle+        -- provided 2nd argument to append already has this property+    rotate :: ZBlock n O O -> ZBlock n O O+    append :: ZBlock n O O -> ZBlock n O O -> ZBlock n O O+    rotate (ZCat h t)     = append h (rotate t)+    rotate b@(ZMiddle {}) = b+    append b@(ZMiddle {}) t = b `ZCat` t+    append (ZCat b1 b2) b3 = b1 `append` (b2 `append` b3)+frontBiasBlock b@(ZHead {}) = b -- back-biased by nature; cannot fix+frontBiasBlock b@(ZTail {}) = b -- statically front-biased+frontBiasBlock (ZClosed h t) = shiftRight h t+    where shiftRight :: ZBlock n C O -> ZBlock n O C -> ZBlock n C C+          shiftRight (ZHead b1 b2) b3 = shiftRight b1 (ZTail b2 b3)+          shiftRight b1@(ZFirst {}) b2 = ZClosed b1 b2++-- | A block is "back biased" if the right child of every+-- concatenation operation is a node, not a general block; a+-- back-biased block is analogous to a snoc-list.  If a block is+-- back-biased, then its nodes can be traversed from back to back+-- without general recusion; tail recursion suffices.  Not all shapes+-- can be back-biased; an open/closed block is inherently front-biased.++backBiasBlock :: ZBlock n e x -> ZBlock n e x+backBiasBlock b@(ZFirst  {}) = b+backBiasBlock b@(ZMiddle {}) = b+backBiasBlock b@(ZLast   {}) = b+backBiasBlock b@(ZCat {}) = rotate b+  where -- rotate and append ensure every right child of ZCat is ZMiddle+        -- provided 1st argument to append already has this property+    rotate :: ZBlock n O O -> ZBlock n O O+    append :: ZBlock n O O -> ZBlock n O O -> ZBlock n O O+    rotate (ZCat h t)     = append (rotate h) t+    rotate b@(ZMiddle {}) = b+    append h b@(ZMiddle {}) = h `ZCat` b+    append b1 (ZCat b2 b3) = (b1 `append` b2) `append` b3+backBiasBlock b@(ZHead {}) = b -- statically back-biased+backBiasBlock b@(ZTail {}) = b -- front-biased by nature; cannot fix+backBiasBlock (ZClosed h t) = shiftLeft h t+    where shiftLeft :: ZBlock n C O -> ZBlock n O C -> ZBlock n C C+          shiftLeft b1 (ZTail b2 b3) = shiftLeft (ZHead b1 b2) b3+          shiftLeft b1 b2@(ZLast {}) = ZClosed b1 b2
README view
@@ -23,4 +23,13 @@   git clone -o tufts git://ghc.cs.tufts.edu/hoopl/hoopl.git  If you are not familiar with git, we recommend the tutorial 'Git Magic'-by Ben Lynn.+by Ben Lynn.  To get some ideas about how to use git effectively,++  http://whygitisbetterthanx.com/ ++is also useful.++If you've been given an account at Tufts with write privileges to the+git repository, you'll want to use a different URL:++  git clone -o tufts linux.cs.tufts.edu:/r/ghc/www/hoopl/hoopl.git
hoopl.cabal view
@@ -1,5 +1,5 @@ Name:                hoopl-Version:             3.7.8.0+Version:             3.7.12.1 Description:         Higher-order optimization library License:             BSD3 License-file:        LICENSE@@ -15,14 +15,20 @@  Library   Build-Depends:     base >= 3 && < 5, containers-  Exposed-modules:   Compiler.Hoopl+  Exposed-modules:   Compiler.Hoopl,+                       Compiler.Hoopl.Zipper,+                       Compiler.Hoopl.ZipDataflowNoRG   Other-modules:     Compiler.Hoopl.GraphUtil,                      -- GraphUtil should *never* be seen by clients.                      -- The remaining modules are hidden *provisionally*-                       Compiler.Hoopl.Dataflow, Compiler.Hoopl.Graph, +                       Compiler.Hoopl.Combinators,+                       Compiler.Hoopl.Dataflow,+                       Compiler.Hoopl.Debug,+                       Compiler.Hoopl.Graph,                         Compiler.Hoopl.MkGraph,                        Compiler.Hoopl.Fuel, Compiler.Hoopl.Label,-                       Compiler.Hoopl.Util+                       Compiler.Hoopl.Show, Compiler.Hoopl.Util+                       Compiler.Hoopl.ZipDataflow   ghc-options:       -Wall -fno-warn-name-shadowing  
hoopl.pdf view

binary file changed (256581 → 258240 bytes)