packages feed

hoopl 3.8.6.0 → 3.8.7.0

raw patch · 46 files changed

+3385/−3292 lines, 46 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: addBlock :: (NonLocal thing) => thing C C -> LabelMap (thing C C) -> LabelMap (thing C C)
+ Compiler.Hoopl: addBlock :: NonLocal thing => thing C C -> LabelMap (thing C C) -> LabelMap (thing C C)
- Compiler.Hoopl: addBlocks :: (HooplNode n) => AGraph n e x -> AGraph n C C -> AGraph n e x
+ Compiler.Hoopl: addBlocks :: HooplNode n => AGraph n e x -> AGraph n C C -> AGraph n e x
- Compiler.Hoopl: addEntrySeq :: (NonLocal n) => AGraph n O C -> AGraph n C x -> AGraph n O x
+ Compiler.Hoopl: addEntrySeq :: NonLocal n => AGraph n O C -> AGraph n C x -> AGraph n O x
- Compiler.Hoopl: addExitSeq :: (NonLocal n) => AGraph n e C -> AGraph n C O -> AGraph n e O
+ Compiler.Hoopl: addExitSeq :: NonLocal n => AGraph n e C -> AGraph n C O -> AGraph n e O
- Compiler.Hoopl: blockGraph :: (NonLocal n) => Block n e x -> Graph n e x
+ Compiler.Hoopl: blockGraph :: NonLocal n => Block n e x -> Graph n e x
- Compiler.Hoopl: bodyList :: (NonLocal (block n)) => Body' block n -> [(Label, block n C C)]
+ Compiler.Hoopl: bodyList :: NonLocal (block n) => Body' block n -> [(Label, block n C C)]
- Compiler.Hoopl: catGraphNodeOC :: (NonLocal n) => Graph n e O -> n O C -> Graph n e C
+ Compiler.Hoopl: catGraphNodeOC :: NonLocal n => Graph n e O -> n O C -> Graph n e C
- Compiler.Hoopl: catNodeCOGraph :: (NonLocal n) => n C O -> Graph n O x -> Graph n C x
+ Compiler.Hoopl: catNodeCOGraph :: NonLocal n => n C O -> Graph n O x -> Graph n C x
- Compiler.Hoopl: checkpoint :: (CheckpointMonad m) => m (Checkpoint m)
+ Compiler.Hoopl: checkpoint :: CheckpointMonad m => m (Checkpoint m)
- Compiler.Hoopl: class (Monad m) => CheckpointMonad m where { type family Checkpoint m; }
+ Compiler.Hoopl: class Monad m => CheckpointMonad m where { type family Checkpoint m; }
- Compiler.Hoopl: class (Monad m) => FuelMonad m
+ Compiler.Hoopl: class Monad m => FuelMonad m
- Compiler.Hoopl: class (NonLocal n) => HooplNode n
+ Compiler.Hoopl: class NonLocal n => HooplNode n
- Compiler.Hoopl: class (Monad m) => UniqueMonad m
+ Compiler.Hoopl: class Monad m => UniqueMonad m
- Compiler.Hoopl: debugBwdJoins :: (Show f) => TraceFn -> ChangePred -> BwdPass m n f -> BwdPass m n f
+ Compiler.Hoopl: debugBwdJoins :: Show f => TraceFn -> ChangePred -> BwdPass m n f -> BwdPass m n f
- Compiler.Hoopl: debugBwdTransfers :: (Show f) => TraceFn -> ShowN n -> BPred n f -> BwdPass m n f -> BwdPass m n f
+ Compiler.Hoopl: debugBwdTransfers :: Show f => TraceFn -> ShowN n -> BPred n f -> BwdPass m n f -> BwdPass m n f
- Compiler.Hoopl: debugFwdJoins :: (Show f) => TraceFn -> ChangePred -> FwdPass m n f -> FwdPass m n f
+ Compiler.Hoopl: debugFwdJoins :: Show f => TraceFn -> ChangePred -> FwdPass m n f -> FwdPass m n f
- Compiler.Hoopl: debugFwdTransfers :: (Show f) => TraceFn -> ShowN n -> FPred n f -> FwdPass m n f -> FwdPass m n f
+ Compiler.Hoopl: debugFwdTransfers :: Show f => TraceFn -> ShowN n -> FPred n f -> FwdPass m n f -> FwdPass m n f
- Compiler.Hoopl: deepBwdRw :: (FuelMonad m) => (forall e x. n e x -> Fact x f -> m (Maybe (Graph n e x))) -> BwdRewrite m n f
+ Compiler.Hoopl: deepBwdRw :: FuelMonad m => (forall e x. n e x -> Fact x f -> m (Maybe (Graph n e x))) -> BwdRewrite m n f
- Compiler.Hoopl: deepBwdRw3 :: (FuelMonad m) => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> FactBase f -> m (Maybe (Graph n O C))) -> (BwdRewrite m n f)
+ Compiler.Hoopl: deepBwdRw3 :: FuelMonad m => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> FactBase f -> m (Maybe (Graph n O C))) -> (BwdRewrite m n f)
- Compiler.Hoopl: deepFwdRw :: (FuelMonad m) => (forall e x. n e x -> f -> m (Maybe (Graph n e x))) -> FwdRewrite m n f
+ Compiler.Hoopl: deepFwdRw :: FuelMonad m => (forall e x. n e x -> f -> m (Maybe (Graph n e x))) -> FwdRewrite m n f
- Compiler.Hoopl: deepFwdRw3 :: (FuelMonad m) => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> f -> m (Maybe (Graph n O C))) -> (FwdRewrite m n f)
+ Compiler.Hoopl: deepFwdRw3 :: FuelMonad m => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> f -> m (Maybe (Graph n O C))) -> (FwdRewrite m n f)
- Compiler.Hoopl: distributeFact :: (NonLocal n) => n O C -> f -> FactBase f
+ Compiler.Hoopl: distributeFact :: NonLocal n => n O C -> f -> FactBase f
- Compiler.Hoopl: distributeFactBwd :: (NonLocal n) => n C O -> f -> FactBase f
+ Compiler.Hoopl: distributeFactBwd :: NonLocal n => n C O -> f -> FactBase f
- Compiler.Hoopl: distributeXfer :: (NonLocal n) => DataflowLattice f -> (n O C -> f -> f) -> (n O C -> f -> FactBase f)
+ Compiler.Hoopl: distributeXfer :: NonLocal n => DataflowLattice f -> (n O C -> f -> f) -> (n O C -> f -> FactBase f)
- Compiler.Hoopl: emptyClosedGraph :: (GraphRep g) => g n C C
+ Compiler.Hoopl: emptyClosedGraph :: GraphRep g => g n C C
- Compiler.Hoopl: emptyGraph :: (GraphRep g) => g n O O
+ Compiler.Hoopl: emptyGraph :: GraphRep g => g n O O
- Compiler.Hoopl: entryLabel :: (NonLocal thing) => thing C x -> Label
+ Compiler.Hoopl: entryLabel :: NonLocal thing => thing C x -> Label
- Compiler.Hoopl: externalEntryLabels :: (NonLocal n) => LabelMap (Block n C C) -> LabelSet
+ Compiler.Hoopl: externalEntryLabels :: NonLocal n => LabelMap (Block n C C) -> LabelSet
- Compiler.Hoopl: firstXfer :: (NonLocal n) => (n C O -> f -> f) -> (n C O -> FactBase f -> f)
+ Compiler.Hoopl: firstXfer :: NonLocal n => (n C O -> f -> f) -> (n C O -> FactBase f -> f)
- Compiler.Hoopl: freshLabel :: (UniqueMonad m) => m Label
+ Compiler.Hoopl: freshLabel :: UniqueMonad m => m Label
- Compiler.Hoopl: freshUnique :: (UniqueMonad m) => m Unique
+ Compiler.Hoopl: freshUnique :: UniqueMonad m => m Unique
- Compiler.Hoopl: fuelRemaining :: (FuelMonad m) => m Fuel
+ Compiler.Hoopl: fuelRemaining :: FuelMonad m => m Fuel
- Compiler.Hoopl: gUnitCC :: (NonLocal (block n)) => block n C C -> Graph' block n C C
+ Compiler.Hoopl: gUnitCC :: NonLocal (block n) => block n C C -> Graph' block n C C
- Compiler.Hoopl: getFuel :: (FuelMonad m) => m Fuel
+ Compiler.Hoopl: getFuel :: FuelMonad m => m Fuel
- Compiler.Hoopl: graphOfAGraph :: AGraph n e x -> forall m. (UniqueMonad m) => m (Graph n e x)
+ Compiler.Hoopl: graphOfAGraph :: AGraph n e x -> forall m. UniqueMonad m => m (Graph n e x)
- Compiler.Hoopl: iterBwdRw :: (Monad m) => BwdRewrite m n f -> BwdRewrite m n f
+ Compiler.Hoopl: iterBwdRw :: Monad m => BwdRewrite m n f -> BwdRewrite m n f
- Compiler.Hoopl: iterFwdRw :: (Monad m) => FwdRewrite m n f -> FwdRewrite m n f
+ Compiler.Hoopl: iterFwdRw :: Monad m => FwdRewrite m n f -> FwdRewrite m n f
- Compiler.Hoopl: joinMaps :: (Ord k) => JoinFun v -> JoinFun (Map k v)
+ Compiler.Hoopl: joinMaps :: Ord k => JoinFun v -> JoinFun (Map k v)
- Compiler.Hoopl: joinOutFacts :: (NonLocal node) => DataflowLattice f -> node O C -> FactBase f -> f
+ Compiler.Hoopl: joinOutFacts :: NonLocal node => DataflowLattice f -> node O C -> FactBase f -> f
- Compiler.Hoopl: labelsDefined :: (NonLocal (block n)) => Graph' block n e x -> LabelSet
+ Compiler.Hoopl: labelsDefined :: NonLocal (block n) => Graph' block n e x -> LabelSet
- Compiler.Hoopl: labelsUsed :: (NonLocal (block n)) => Graph' block n e x -> LabelSet
+ Compiler.Hoopl: labelsUsed :: NonLocal (block n) => Graph' block n e x -> LabelSet
- Compiler.Hoopl: lookupBlock :: (NonLocal n) => Graph n e x -> Label -> BlockResult n x
+ Compiler.Hoopl: lookupBlock :: NonLocal n => Graph n e x -> Label -> BlockResult n x
- Compiler.Hoopl: mapDelete :: (IsMap map) => KeyOf map -> map a -> map a
+ Compiler.Hoopl: mapDelete :: IsMap map => KeyOf map -> map a -> map a
- Compiler.Hoopl: mapDeleteList :: (IsMap map) => [KeyOf map] -> map a -> map a
+ Compiler.Hoopl: mapDeleteList :: IsMap map => [KeyOf map] -> map a -> map a
- Compiler.Hoopl: mapDifference :: (IsMap map) => map a -> map a -> map a
+ Compiler.Hoopl: mapDifference :: IsMap map => map a -> map a -> map a
- Compiler.Hoopl: mapElems :: (IsMap map) => map a -> [a]
+ Compiler.Hoopl: mapElems :: IsMap map => map a -> [a]
- Compiler.Hoopl: mapEmpty :: (IsMap map) => map a
+ Compiler.Hoopl: mapEmpty :: IsMap map => map a
- Compiler.Hoopl: mapFindWithDefault :: (IsMap map) => a -> KeyOf map -> map a -> a
+ Compiler.Hoopl: mapFindWithDefault :: IsMap map => a -> KeyOf map -> map a -> a
- Compiler.Hoopl: mapFold :: (IsMap map) => (a -> b -> b) -> b -> map a -> b
+ Compiler.Hoopl: mapFold :: IsMap map => (a -> b -> b) -> b -> map a -> b
- Compiler.Hoopl: mapFoldWithKey :: (IsMap map) => (KeyOf map -> a -> b -> b) -> b -> map a -> b
+ Compiler.Hoopl: mapFoldWithKey :: IsMap map => (KeyOf map -> a -> b -> b) -> b -> map a -> b
- Compiler.Hoopl: mapFromList :: (IsMap map) => [(KeyOf map, a)] -> map a
+ Compiler.Hoopl: mapFromList :: IsMap map => [(KeyOf map, a)] -> map a
- Compiler.Hoopl: mapInsert :: (IsMap map) => KeyOf map -> a -> map a -> map a
+ Compiler.Hoopl: mapInsert :: IsMap map => KeyOf map -> a -> map a -> map a
- Compiler.Hoopl: mapInsertList :: (IsMap map) => [(KeyOf map, a)] -> map a -> map a
+ Compiler.Hoopl: mapInsertList :: IsMap map => [(KeyOf map, a)] -> map a -> map a
- Compiler.Hoopl: mapIntersection :: (IsMap map) => map a -> map a -> map a
+ Compiler.Hoopl: mapIntersection :: IsMap map => map a -> map a -> map a
- Compiler.Hoopl: mapKeys :: (IsMap map) => map a -> [KeyOf map]
+ Compiler.Hoopl: mapKeys :: IsMap map => map a -> [KeyOf map]
- Compiler.Hoopl: mapLookup :: (IsMap map) => KeyOf map -> map a -> Maybe a
+ Compiler.Hoopl: mapLookup :: IsMap map => KeyOf map -> map a -> Maybe a
- Compiler.Hoopl: mapMap :: (IsMap map) => (a -> b) -> map a -> map b
+ Compiler.Hoopl: mapMap :: IsMap map => (a -> b) -> map a -> map b
- Compiler.Hoopl: mapMapWithKey :: (IsMap map) => (KeyOf map -> a -> b) -> map a -> map b
+ Compiler.Hoopl: mapMapWithKey :: IsMap map => (KeyOf map -> a -> b) -> map a -> map b
- Compiler.Hoopl: mapMember :: (IsMap map) => KeyOf map -> map a -> Bool
+ Compiler.Hoopl: mapMember :: IsMap map => KeyOf map -> map a -> Bool
- Compiler.Hoopl: mapNull :: (IsMap map) => map a -> Bool
+ Compiler.Hoopl: mapNull :: IsMap map => map a -> Bool
- Compiler.Hoopl: mapSingleton :: (IsMap map) => KeyOf map -> a -> map a
+ Compiler.Hoopl: mapSingleton :: IsMap map => KeyOf map -> a -> map a
- Compiler.Hoopl: mapSize :: (IsMap map) => map a -> Int
+ Compiler.Hoopl: mapSize :: IsMap map => map a -> Int
- Compiler.Hoopl: mapToList :: (IsMap map) => map a -> [(KeyOf map, a)]
+ Compiler.Hoopl: mapToList :: IsMap map => map a -> [(KeyOf map, a)]
- Compiler.Hoopl: mapUnion :: (IsMap map) => map a -> map a -> map a
+ Compiler.Hoopl: mapUnion :: IsMap map => map a -> map a -> map a
- Compiler.Hoopl: mapUnionWithKey :: (IsMap map) => (KeyOf map -> a -> a -> a) -> map a -> map a -> map a
+ Compiler.Hoopl: mapUnionWithKey :: IsMap map => (KeyOf map -> a -> a -> a) -> map a -> map a -> map a
- Compiler.Hoopl: mapUnions :: (IsMap map) => [map a] -> map a
+ Compiler.Hoopl: mapUnions :: IsMap map => [map a] -> map a
- Compiler.Hoopl: mkBRewrite :: (FuelMonad m) => (forall e x. n e x -> Fact x f -> m (Maybe (Graph n e x))) -> BwdRewrite m n f
+ Compiler.Hoopl: mkBRewrite :: FuelMonad m => (forall e x. n e x -> Fact x f -> m (Maybe (Graph n e x))) -> BwdRewrite m n f
- Compiler.Hoopl: mkBRewrite3 :: (FuelMonad m) => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> FactBase f -> m (Maybe (Graph n O C))) -> BwdRewrite m n f
+ Compiler.Hoopl: mkBRewrite3 :: FuelMonad m => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> FactBase f -> m (Maybe (Graph n O C))) -> BwdRewrite m n f
- Compiler.Hoopl: mkBranchNode :: (HooplNode n) => Label -> n O C
+ Compiler.Hoopl: mkBranchNode :: HooplNode n => Label -> n O C
- Compiler.Hoopl: mkEntry :: (GraphRep g) => Block n O C -> g n O C
+ Compiler.Hoopl: mkEntry :: GraphRep g => Block n O C -> g n O C
- Compiler.Hoopl: mkExit :: (GraphRep g) => Block n C O -> g n C O
+ Compiler.Hoopl: mkExit :: GraphRep g => Block n C O -> g n C O
- Compiler.Hoopl: mkFRewrite :: (FuelMonad m) => (forall e x. n e x -> f -> m (Maybe (Graph n e x))) -> FwdRewrite m n f
+ Compiler.Hoopl: mkFRewrite :: FuelMonad m => (forall e x. n e x -> f -> m (Maybe (Graph n e x))) -> FwdRewrite m n f
- Compiler.Hoopl: mkFRewrite3 :: (FuelMonad m) => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> f -> m (Maybe (Graph n O C))) -> FwdRewrite m n f
+ Compiler.Hoopl: mkFRewrite3 :: FuelMonad m => (n C O -> f -> m (Maybe (Graph n C O))) -> (n O O -> f -> m (Maybe (Graph n O O))) -> (n O C -> f -> m (Maybe (Graph n O C))) -> FwdRewrite m n f
- Compiler.Hoopl: mkFirst :: (GraphRep g) => n C O -> g n C O
+ Compiler.Hoopl: mkFirst :: GraphRep g => n C O -> g n C O
- Compiler.Hoopl: mkLabelNode :: (HooplNode n) => Label -> n C O
+ Compiler.Hoopl: mkLabelNode :: HooplNode n => Label -> n C O
- Compiler.Hoopl: mkLast :: (GraphRep g) => n O C -> g n O C
+ Compiler.Hoopl: mkLast :: GraphRep g => n O C -> g n O C
- Compiler.Hoopl: mkMiddle :: (GraphRep g) => n O O -> g n O O
+ Compiler.Hoopl: mkMiddle :: GraphRep g => n O O -> g n O O
- Compiler.Hoopl: mkWhileDo :: (HooplNode n) => (Label -> Label -> AGraph n O C) -> AGraph n O O -> AGraph n O O
+ Compiler.Hoopl: mkWhileDo :: HooplNode n => (Label -> Label -> AGraph n O C) -> AGraph n O O -> AGraph n O O
- Compiler.Hoopl: noBwdRewrite :: (Monad m) => BwdRewrite m n f
+ Compiler.Hoopl: noBwdRewrite :: Monad m => BwdRewrite m n f
- Compiler.Hoopl: noFwdRewrite :: (Monad m) => FwdRewrite m n f
+ Compiler.Hoopl: noFwdRewrite :: Monad m => FwdRewrite m n f
- Compiler.Hoopl: pairBwd :: (Monad m) => BwdPass m n f -> BwdPass m n f' -> BwdPass m n (f, f')
+ Compiler.Hoopl: pairBwd :: Monad m => BwdPass m n f -> BwdPass m n f' -> BwdPass m n (f, f')
- Compiler.Hoopl: pairFwd :: (Monad m) => FwdPass m n f -> FwdPass m n f' -> FwdPass m n (f, f')
+ Compiler.Hoopl: pairFwd :: Monad m => FwdPass m n f -> FwdPass m n f' -> FwdPass m n (f, f')
- Compiler.Hoopl: postorder_dfs :: (NonLocal (block n)) => Graph' block n O x -> [block n C C]
+ Compiler.Hoopl: postorder_dfs :: NonLocal (block n) => Graph' block n O x -> [block n C C]
- Compiler.Hoopl: preorder_dfs :: (NonLocal (block n)) => Graph' block n O x -> [block n C C]
+ Compiler.Hoopl: preorder_dfs :: NonLocal (block n) => Graph' block n O x -> [block n C C]
- Compiler.Hoopl: restart :: (CheckpointMonad m) => Checkpoint m -> m ()
+ Compiler.Hoopl: restart :: CheckpointMonad m => Checkpoint m -> m ()
- Compiler.Hoopl: runUniqueMonadT :: (Monad m) => UniqueMonadT m a -> m a
+ Compiler.Hoopl: runUniqueMonadT :: Monad m => UniqueMonadT m a -> m a
- Compiler.Hoopl: setDelete :: (IsSet set) => ElemOf set -> set -> set
+ Compiler.Hoopl: setDelete :: IsSet set => ElemOf set -> set -> set
- Compiler.Hoopl: setDeleteList :: (IsSet set) => [ElemOf set] -> set -> set
+ Compiler.Hoopl: setDeleteList :: IsSet set => [ElemOf set] -> set -> set
- Compiler.Hoopl: setDifference :: (IsSet set) => set -> set -> set
+ Compiler.Hoopl: setDifference :: IsSet set => set -> set -> set
- Compiler.Hoopl: setElems :: (IsSet set) => set -> [ElemOf set]
+ Compiler.Hoopl: setElems :: IsSet set => set -> [ElemOf set]
- Compiler.Hoopl: setEmpty :: (IsSet set) => set
+ Compiler.Hoopl: setEmpty :: IsSet set => set
- Compiler.Hoopl: setFold :: (IsSet set) => (ElemOf set -> b -> b) -> b -> set -> b
+ Compiler.Hoopl: setFold :: IsSet set => (ElemOf set -> b -> b) -> b -> set -> b
- Compiler.Hoopl: setFromList :: (IsSet set) => [ElemOf set] -> set
+ Compiler.Hoopl: setFromList :: IsSet set => [ElemOf set] -> set
- Compiler.Hoopl: setFuel :: (FuelMonad m) => Fuel -> m ()
+ Compiler.Hoopl: setFuel :: FuelMonad m => Fuel -> m ()
- Compiler.Hoopl: setInsert :: (IsSet set) => ElemOf set -> set -> set
+ Compiler.Hoopl: setInsert :: IsSet set => ElemOf set -> set -> set
- Compiler.Hoopl: setInsertList :: (IsSet set) => [ElemOf set] -> set -> set
+ Compiler.Hoopl: setInsertList :: IsSet set => [ElemOf set] -> set -> set
- Compiler.Hoopl: setIntersection :: (IsSet set) => set -> set -> set
+ Compiler.Hoopl: setIntersection :: IsSet set => set -> set -> set
- Compiler.Hoopl: setIsSubsetOf :: (IsSet set) => set -> set -> Bool
+ Compiler.Hoopl: setIsSubsetOf :: IsSet set => set -> set -> Bool
- Compiler.Hoopl: setMember :: (IsSet set) => ElemOf set -> set -> Bool
+ Compiler.Hoopl: setMember :: IsSet set => ElemOf set -> set -> Bool
- Compiler.Hoopl: setNull :: (IsSet set) => set -> Bool
+ Compiler.Hoopl: setNull :: IsSet set => set -> Bool
- Compiler.Hoopl: setSingleton :: (IsSet set) => ElemOf set -> set
+ Compiler.Hoopl: setSingleton :: IsSet set => ElemOf set -> set
- Compiler.Hoopl: setSize :: (IsSet set) => set -> Int
+ Compiler.Hoopl: setSize :: IsSet set => set -> Int
- Compiler.Hoopl: setUnion :: (IsSet set) => set -> set -> set
+ Compiler.Hoopl: setUnion :: IsSet set => set -> set -> set
- Compiler.Hoopl: setUnions :: (IsSet set) => [set] -> set
+ Compiler.Hoopl: setUnions :: IsSet set => [set] -> set
- Compiler.Hoopl: showFactBase :: (Show f) => FactBase f -> String
+ Compiler.Hoopl: showFactBase :: Show f => FactBase f -> String
- Compiler.Hoopl: showGraph :: (NonLocal n) => Showing n -> Graph n e x -> String
+ Compiler.Hoopl: showGraph :: NonLocal n => Showing n -> Graph n e x -> String
- Compiler.Hoopl: successorFacts :: (NonLocal n) => n O C -> FactBase f -> [f]
+ Compiler.Hoopl: successorFacts :: NonLocal n => n O C -> FactBase f -> [f]
- Compiler.Hoopl: successors :: (NonLocal thing) => thing e C -> [Label]
+ Compiler.Hoopl: successors :: NonLocal thing => thing e C -> [Label]
- Compiler.Hoopl: targetLabels :: (LabelsPtr l) => l -> [Label]
+ Compiler.Hoopl: targetLabels :: LabelsPtr l => l -> [Label]
- Compiler.Hoopl: thenBwdRw :: (Monad m) => BwdRewrite m n f -> BwdRewrite m n f -> BwdRewrite m n f
+ Compiler.Hoopl: thenBwdRw :: Monad m => BwdRewrite m n f -> BwdRewrite m n f -> BwdRewrite m n f
- Compiler.Hoopl: thenFwdRw :: (Monad m) => FwdRewrite m n f -> FwdRewrite m n f -> FwdRewrite m n f
+ Compiler.Hoopl: thenFwdRw :: Monad m => FwdRewrite m n f -> FwdRewrite m n f -> FwdRewrite m n f
- Compiler.Hoopl: unionBlocks :: (NonLocal n) => AGraph n C C -> AGraph n C C -> AGraph n C C
+ Compiler.Hoopl: unionBlocks :: NonLocal n => AGraph n C C -> AGraph n C C -> AGraph n C C
- Compiler.Hoopl: withFresh :: (Uniques u) => (u -> AGraph n e x) -> AGraph n e x
+ Compiler.Hoopl: withFresh :: Uniques u => (u -> AGraph n e x) -> AGraph n e x
- Compiler.Hoopl: withFuel :: (FuelMonad m) => Maybe a -> m (Maybe a)
+ Compiler.Hoopl: withFuel :: FuelMonad m => Maybe a -> m (Maybe a)
- Compiler.Hoopl.GHC: getFuel :: (FuelMonad m) => m Fuel
+ Compiler.Hoopl.GHC: getFuel :: FuelMonad m => m Fuel
- Compiler.Hoopl.GHC: setFuel :: (FuelMonad m) => Fuel -> m ()
+ Compiler.Hoopl.GHC: setFuel :: FuelMonad m => Fuel -> m ()

Files

CHANGES view
@@ -1,3 +1,10 @@+3.8.7.0+  Works with GHC 7 (thanks Edward Yang)+  cabal sdist now sort of works (and is added to validate)++3.8.6.0+  Matches the camera-ready Haskell'10 paper+ 3.8.1.0    Major reorganization per simonpj visit to Tufts 20 April 2010
− Compiler/Hoopl.hs
@@ -1,37 +0,0 @@-module Compiler.Hoopl-  ( module Compiler.Hoopl.Graph-  , module Compiler.Hoopl.MkGraph-  , module Compiler.Hoopl.XUtil-  , module Compiler.Hoopl.Collections-  , module Compiler.Hoopl.Checkpoint-  , module Compiler.Hoopl.Dataflow-  , module Compiler.Hoopl.Label-  , module Compiler.Hoopl.Pointed-  , module Compiler.Hoopl.Combinators-  , module Compiler.Hoopl.Fuel-  , module Compiler.Hoopl.Unique-  , module Compiler.Hoopl.Util-  , module Compiler.Hoopl.Debug-  , module Compiler.Hoopl.Show-  )-where--import Compiler.Hoopl.Checkpoint-import Compiler.Hoopl.Collections-import Compiler.Hoopl.Combinators-import Compiler.Hoopl.Dataflow hiding ( wrapFR, wrapFR2, wrapBR, wrapBR2-                                      )-import Compiler.Hoopl.Debug-import Compiler.Hoopl.Fuel hiding (withFuel, getFuel, setFuel, FuelMonadT)-import Compiler.Hoopl.Graph hiding -   ( Body-   , BCat, BHead, BTail, BClosed -- OK to expose BFirst, BMiddle, BLast-   )-import Compiler.Hoopl.Graph (Body)-import Compiler.Hoopl.Label hiding (uniqueToLbl, lblToUnique)-import Compiler.Hoopl.MkGraph-import Compiler.Hoopl.Pointed-import Compiler.Hoopl.Show-import Compiler.Hoopl.Util-import Compiler.Hoopl.Unique hiding (uniqueToInt)-import Compiler.Hoopl.XUtil
− Compiler/Hoopl/Checkpoint.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE TypeFamilies #-}--module Compiler.Hoopl.Checkpoint-  ( CheckpointMonad(..)-  )-where---- | Obeys the following law:--- for all @m@ --- @---    do { s <- checkpoint; m; restart s } == return ()--- @-class Monad m => CheckpointMonad m where-  type Checkpoint m-  checkpoint :: m (Checkpoint m)-  restart    :: Checkpoint m -> m () -
− Compiler/Hoopl/Collections.hs
@@ -1,85 +0,0 @@-{- Baseclasses for Map-like and Set-like collections inspired by containers. -}--{-# LANGUAGE TypeFamilies #-}-module Compiler.Hoopl.Collections ( IsSet(..)-                                  , setInsertList, setDeleteList, setUnions-                                  , IsMap(..)-                                  , mapInsertList, mapDeleteList, mapUnions-                                  ) where--import Data.List (foldl', foldl1')--class IsSet set where-  type ElemOf set--  setNull :: set -> Bool-  setSize :: set -> Int-  setMember :: ElemOf set -> set -> Bool--  setEmpty :: set-  setSingleton :: ElemOf set -> set-  setInsert :: ElemOf set -> set -> set-  setDelete :: ElemOf set -> set -> set--  setUnion :: set -> set -> set-  setDifference :: set -> set -> set-  setIntersection :: set -> set -> set-  setIsSubsetOf :: set -> set -> Bool--  setFold :: (ElemOf set -> b -> b) -> b -> set -> b--  setElems :: set -> [ElemOf set]-  setFromList :: [ElemOf set] -> set---- Helper functions for IsSet class-setInsertList :: IsSet set => [ElemOf set] -> set -> set-setInsertList keys set = foldl' (flip setInsert) set keys--setDeleteList :: IsSet set => [ElemOf set] -> set -> set-setDeleteList keys set = foldl' (flip setDelete) set keys--setUnions :: IsSet set => [set] -> set-setUnions [] = setEmpty-setUnions sets = foldl1' setUnion sets---class IsMap map where-  type KeyOf map--  mapNull :: map a -> Bool-  mapSize :: map a -> Int-  mapMember :: KeyOf map -> map a -> Bool-  mapLookup :: KeyOf map -> map a -> Maybe a-  mapFindWithDefault :: a -> KeyOf map -> map a -> a--  mapEmpty :: map a-  mapSingleton :: KeyOf map -> a -> map a-  mapInsert :: KeyOf map -> a -> map a -> map a-  mapDelete :: KeyOf map -> map a -> map a--  mapUnion :: map a -> map a -> map a-  mapUnionWithKey :: (KeyOf map -> a -> a -> a) -> map a -> map a -> map a-  mapDifference :: map a -> map a -> map a-  mapIntersection :: map a -> map a -> map a-  mapIsSubmapOf :: Eq a => map a -> map a -> Bool--  mapMap :: (a -> b) -> map a -> map b-  mapMapWithKey :: (KeyOf map -> a -> b) -> map a -> map b-  mapFold :: (a -> b -> b) -> b -> map a -> b-  mapFoldWithKey :: (KeyOf map -> a -> b -> b) -> b -> map a -> b--  mapElems :: map a -> [a]-  mapKeys :: map a -> [KeyOf map]-  mapToList :: map a -> [(KeyOf map, a)]-  mapFromList :: [(KeyOf map, a)] -> map a---- Helper functions for IsMap class-mapInsertList :: IsMap map => [(KeyOf map, a)] -> map a -> map a-mapInsertList assocs map = foldl' (flip (uncurry mapInsert)) map assocs--mapDeleteList :: IsMap map => [KeyOf map] -> map a -> map a-mapDeleteList keys map = foldl' (flip mapDelete) map keys--mapUnions :: IsMap map => [map a] -> map a-mapUnions [] = mapEmpty-mapUnions maps = foldl1' mapUnion maps
− Compiler/Hoopl/Combinators.hs
@@ -1,182 +0,0 @@-{-# LANGUAGE RankNTypes, LiberalTypeSynonyms, ScopedTypeVariables, GADTs #-}--module Compiler.Hoopl.Combinators-  ( thenFwdRw-  , deepFwdRw3, deepFwdRw, iterFwdRw-  , thenBwdRw-  , deepBwdRw3, deepBwdRw, iterBwdRw-  , pairFwd, pairBwd, pairLattice-  )--where--import Control.Monad-import Data.Maybe--import Compiler.Hoopl.Collections-import Compiler.Hoopl.Dataflow-import Compiler.Hoopl.Fuel-import Compiler.Hoopl.Graph (Graph, C, O, Shape(..))-import Compiler.Hoopl.Label--------------------------------------------------------------------deepFwdRw3 :: FuelMonad m-           => (n C O -> f -> m (Maybe (Graph n C O)))-           -> (n O O -> f -> m (Maybe (Graph n O O)))-           -> (n O C -> f -> m (Maybe (Graph n O C)))-           -> (FwdRewrite m n f)-deepFwdRw :: FuelMonad m-          => (forall e x . n e x -> f -> m (Maybe (Graph n e x))) -> FwdRewrite m n f-deepFwdRw3 f m l = iterFwdRw $ mkFRewrite3 f m l-deepFwdRw f = deepFwdRw3 f f f---- N.B. rw3, rw3', and rw3a are triples of functions.--- But rw and rw' are single functions.--- @ start comb1.tex-thenFwdRw :: Monad m -          => FwdRewrite m n f -          -> FwdRewrite m n f -          -> FwdRewrite m n f--- @ end comb1.tex-thenFwdRw rw3 rw3' = wrapFR2 thenrw rw3 rw3'- where-  thenrw rw rw' n f = rw n f >>= fwdRes-     where fwdRes Nothing   = rw' n f-           fwdRes (Just gr) = return $ Just $ fadd_rw rw3' gr---- @ start iterf.tex-iterFwdRw :: Monad m -          => FwdRewrite m n f -          -> FwdRewrite m n f--- @ end iterf.tex-iterFwdRw rw3 = wrapFR iter rw3- where iter rw n = (liftM $ liftM $ fadd_rw (iterFwdRw rw3)) . rw n-       _iter = frewrite_cps (return . Just . fadd_rw (iterFwdRw rw3)) (return Nothing)---- | Function inspired by 'rew' in the paper-frewrite_cps :: Monad m-             => ((Graph n e x, FwdRewrite m n f) -> m a)-             -> m a-             -> (forall e x . n e x -> f -> m (Maybe (Graph n e x, FwdRewrite m n f)))-             -> n e x-             -> f-             -> m a-frewrite_cps j n rw node f =-    do mg <- rw node f-       case mg of Nothing -> n-                  Just gr -> j gr------ | Function inspired by 'add' in the paper-fadd_rw :: Monad m-       => FwdRewrite m n f-       -> (Graph n e x, FwdRewrite m n f)-       -> (Graph n e x, FwdRewrite m n f)-fadd_rw rw2 (g, rw1) = (g, rw1 `thenFwdRw` rw2)--------------------------------------------------------------------deepBwdRw3 :: FuelMonad m-           => (n C O -> f          -> m (Maybe (Graph n C O)))-           -> (n O O -> f          -> m (Maybe (Graph n O O)))-           -> (n O C -> FactBase f -> m (Maybe (Graph n O C)))-           -> (BwdRewrite m n f)-deepBwdRw  :: FuelMonad m-           => (forall e x . n e x -> Fact x f -> m (Maybe (Graph n e x)))-           -> BwdRewrite m n f-deepBwdRw3 f m l = iterBwdRw $ mkBRewrite3 f m l-deepBwdRw  f = deepBwdRw3 f f f---thenBwdRw :: Monad m => BwdRewrite m n f -> BwdRewrite m n f -> BwdRewrite m n f-thenBwdRw rw1 rw2 = wrapBR2 f rw1 rw2-  where f _ rw1 rw2' n f = do-          res1 <- rw1 n f-          case res1 of-            Nothing -> rw2' n f-            Just gr -> return $ Just $ badd_rw rw2 gr--iterBwdRw :: Monad m => BwdRewrite m n f -> BwdRewrite m n f-iterBwdRw rw = wrapBR f rw-  where f _ rw' n f = liftM (liftM (badd_rw (iterBwdRw rw))) (rw' n f)---- | Function inspired by 'add' in the paper-badd_rw :: Monad m-       => BwdRewrite m n f-       -> (Graph n e x, BwdRewrite m n f)-       -> (Graph n e x, BwdRewrite m n f)-badd_rw rw2 (g, rw1) = (g, rw1 `thenBwdRw` rw2)----- @ start pairf.tex-pairFwd :: Monad m-        => FwdPass m n f-        -> FwdPass m n f' -        -> FwdPass m n (f, f')--- @ end pairf.tex-pairFwd pass1 pass2 = FwdPass lattice transfer rewrite-  where-    lattice = pairLattice (fp_lattice pass1) (fp_lattice pass2)-    transfer = mkFTransfer3 (tf tf1 tf2) (tf tm1 tm2) (tfb tl1 tl2)-      where-        tf  t1 t2 n (f1, f2) = (t1 n f1, t2 n f2)-        tfb t1 t2 n (f1, f2) = mapMapWithKey withfb2 fb1-          where fb1 = t1 n f1-                fb2 = t2 n f2-                withfb2 l f = (f, fromMaybe bot2 $ lookupFact l fb2)-                bot2 = fact_bot (fp_lattice pass2)-        (tf1, tm1, tl1) = getFTransfer3 (fp_transfer pass1)-        (tf2, tm2, tl2) = getFTransfer3 (fp_transfer pass2)-    rewrite = lift fst (fp_rewrite pass1) `thenFwdRw` lift snd (fp_rewrite pass2) -      where-        lift proj = wrapFR project-          where project rw = \n pair -> liftM (liftM repair) $ rw n (proj pair)-                repair (g, rw') = (g, lift proj rw')--pairBwd :: forall m n f f' . -           Monad m => BwdPass m n f -> BwdPass m n f' -> BwdPass m n (f, f')-pairBwd pass1 pass2 = BwdPass lattice transfer rewrite-  where-    lattice = pairLattice (bp_lattice pass1) (bp_lattice pass2)-    transfer = mkBTransfer3 (tf tf1 tf2) (tf tm1 tm2) (tfb tl1 tl2)-      where-        tf  t1 t2 n (f1, f2) = (t1 n f1, t2 n f2)-        tfb t1 t2 n fb = (t1 n $ mapMap fst fb, t2 n $ mapMap snd fb)-        (tf1, tm1, tl1) = getBTransfer3 (bp_transfer pass1)-        (tf2, tm2, tl2) = getBTransfer3 (bp_transfer pass2)-    rewrite = lift fst (bp_rewrite pass1) `thenBwdRw` lift snd (bp_rewrite pass2) -      where-       lift :: forall f1 .-                ((f, f') -> f1) -> BwdRewrite m n f1 -> BwdRewrite m n (f, f')-       lift proj = wrapBR project-        where project :: forall e x . Shape x -               -> (n e x ->-                       Fact x f1     -> m (Maybe (Graph n e x, BwdRewrite m n f1)))-               -> (n e x ->-                       Fact x (f,f') -> m (Maybe (Graph n e x, BwdRewrite m n (f,f'))))-              project Open = -                 \rw n pair -> liftM (liftM repair) $ rw n (       proj pair)-              project Closed = -                 \rw n pair -> liftM (liftM repair) $ rw n (mapMap proj pair)-              repair (g, rw') = (g, lift proj rw')-                -- XXX specialize repair so that the cost-                -- of discriminating is one per combinator not one-                -- per rewrite--pairLattice :: forall f f' .-               DataflowLattice f -> DataflowLattice f' -> DataflowLattice (f, f')-pairLattice l1 l2 =-  DataflowLattice-    { fact_name = fact_name l1 ++ " x " ++ fact_name l2-    , fact_bot  = (fact_bot l1, fact_bot l2)-    , fact_join = join-    }-  where-    join lbl (OldFact (o1, o2)) (NewFact (n1, n2)) = (c', (f1, f2))-      where (c1, f1) = fact_join l1 lbl (OldFact o1) (NewFact n1)-            (c2, f2) = fact_join l2 lbl (OldFact o2) (NewFact n2)-            c' = case (c1, c2) of-                   (NoChange, NoChange) -> NoChange-                   _                    -> SomeChange
− Compiler/Hoopl/Dataflow.hs
@@ -1,809 +0,0 @@-{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs, EmptyDataDecls, PatternGuards, TypeFamilies, MultiParamTypeClasses #-}--module Compiler.Hoopl.Dataflow-  ( DataflowLattice(..), JoinFun, OldFact(..), NewFact(..), Fact, mkFactBase-  , ChangeFlag(..), changeIf-  , FwdPass(..), FwdTransfer, mkFTransfer, mkFTransfer3, getFTransfer3-  -- * Respecting Fuel--  -- $fuel-  , FwdRewrite,  mkFRewrite,  mkFRewrite3,  getFRewrite3, noFwdRewrite-  , wrapFR, wrapFR2-  , BwdPass(..), BwdTransfer, mkBTransfer, mkBTransfer3, getBTransfer3-  , wrapBR, wrapBR2-  , BwdRewrite,  mkBRewrite,  mkBRewrite3,  getBRewrite3, noBwdRewrite-  , analyzeAndRewriteFwd,  analyzeAndRewriteBwd-  )-where--import Control.Monad-import Data.Maybe--import Compiler.Hoopl.Checkpoint-import Compiler.Hoopl.Collections-import Compiler.Hoopl.Fuel-import Compiler.Hoopl.Graph hiding (Graph) -- hiding so we can redefine-                                           -- and include definition in paper-import qualified Compiler.Hoopl.GraphUtil as U-import Compiler.Hoopl.Label-import Compiler.Hoopl.Util----------------------------------------------------------------------------------              DataflowLattice--------------------------------------------------------------------------------data DataflowLattice a = DataflowLattice  - { fact_name       :: String          -- Documentation- , fact_bot        :: a               -- Lattice bottom element- , fact_join       :: JoinFun a       -- Lattice join plus change flag-                                      -- (changes iff result > old fact)- }--- ^ A transfer function might want to use the logging flag--- to control debugging, as in for example, it updates just one element--- in a big finite map.  We don't want Hoopl to show the whole fact,--- and only the transfer function knows exactly what changed.--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 deriving (Eq, Ord)-changeIf :: Bool -> ChangeFlag-changeIf changed = if changed then SomeChange else NoChange----- | 'mkFactBase' creates a 'FactBase' from a list of ('Label', fact)--- pairs.  If the same label appears more than once, the relevant facts--- are joined.--mkFactBase :: DataflowLattice f -> [(Label, f)] -> FactBase f-mkFactBase lattice = foldl add mapEmpty-  where add map (lbl, f) = mapInsert lbl newFact map-          where newFact = case mapLookup lbl map of-                            Nothing -> f-                            Just f' -> snd $ join lbl (OldFact f') (NewFact f)-                join = fact_join lattice-----------------------------------------------------------------------------------              Analyze and rewrite forward: the interface--------------------------------------------------------------------------------data FwdPass m n f-  = FwdPass { fp_lattice  :: DataflowLattice f-            , fp_transfer :: FwdTransfer n f-            , fp_rewrite  :: FwdRewrite m n f }--newtype FwdTransfer n f -  = FwdTransfer3 { getFTransfer3 ::-                     ( n C O -> f -> f-                     , n O O -> f -> f-                     , n O C -> f -> FactBase f-                     ) }--newtype FwdRewrite m n f   -- see Note [Respects Fuel]-  = FwdRewrite3 { getFRewrite3 ::-                    ( n C O -> f -> m (Maybe (Graph n C O, FwdRewrite m n f))-                    , n O O -> f -> m (Maybe (Graph n O O, FwdRewrite m n f))-                    , n O C -> f -> m (Maybe (Graph n O C, FwdRewrite m n f))-                    ) }--wrapFR :: (forall e x. (n  e x -> f  -> m  (Maybe (Graph n  e x, FwdRewrite m  n  f )))-                    -> (n' e x -> f' -> m' (Maybe (Graph n' e x, FwdRewrite m' n' f')))-          )-            -- ^ This argument may assume that any function passed to it-            -- respects fuel, and it must return a result that respects fuel.-       -> FwdRewrite m  n  f -       -> FwdRewrite m' n' f'      -- see Note [Respects Fuel]-wrapFR wrap (FwdRewrite3 (f, m, l)) = FwdRewrite3 (wrap f, wrap m, wrap l)-wrapFR2 -  :: (forall e x . (n1 e x -> f1 -> m1 (Maybe (Graph n1 e x, FwdRewrite m1 n1 f1))) ->-                   (n2 e x -> f2 -> m2 (Maybe (Graph n2 e x, FwdRewrite m2 n2 f2))) ->-                   (n3 e x -> f3 -> m3 (Maybe (Graph n3 e x, FwdRewrite m3 n3 f3)))-     )-            -- ^ This argument may assume that any function passed to it-            -- respects fuel, and it must return a result that respects fuel.-  -> FwdRewrite m1 n1 f1-  -> FwdRewrite m2 n2 f2-  -> FwdRewrite m3 n3 f3      -- see Note [Respects Fuel]-wrapFR2 wrap2 (FwdRewrite3 (f1, m1, l1)) (FwdRewrite3 (f2, m2, l2)) =-    FwdRewrite3 (wrap2 f1 f2, wrap2 m1 m2, wrap2 l1 l2)---mkFTransfer3 :: (n C O -> f -> f)-             -> (n O O -> f -> f)-             -> (n O C -> f -> FactBase f)-             -> FwdTransfer n f-mkFTransfer3 f m l = FwdTransfer3 (f, m, l)--mkFTransfer :: (forall e x . n e x -> f -> Fact x f) -> FwdTransfer n f-mkFTransfer f = FwdTransfer3 (f, f, f)---- | Functions passed to 'mkFRewrite3' should not be aware of the fuel supply.--- The result returned by 'mkFRewrite3' respects fuel.-mkFRewrite3 :: FuelMonad m-            => (n C O -> f -> m (Maybe (Graph n C O)))-            -> (n O O -> f -> m (Maybe (Graph n O O)))-            -> (n O C -> f -> m (Maybe (Graph n O C)))-            -> FwdRewrite m n f-mkFRewrite3 f m l = FwdRewrite3 (lift f, lift m, lift l)-  where lift rw node fact = liftM (liftM asRew) (withFuel =<< rw node fact)-        asRew g = (g, noFwdRewrite)--noFwdRewrite :: Monad m => FwdRewrite m n f-noFwdRewrite = FwdRewrite3 (noRewrite, noRewrite, noRewrite)--noRewrite :: Monad m => a -> b -> m (Maybe c)-noRewrite _ _ = return Nothing--                               ---- | Functions passed to 'mkFRewrite' should not be aware of the fuel supply.--- The result returned by 'mkFRewrite' respects fuel.-mkFRewrite :: FuelMonad m => (forall e x . n e x -> f -> m (Maybe (Graph n e x)))-           -> FwdRewrite m n f-mkFRewrite f = mkFRewrite3 f f f---type family   Fact x f :: *-type instance Fact C f = FactBase f-type instance Fact O f = f---- | if the graph being analyzed is open at the entry, there must---   be no other entry point, or all goes horribly wrong...-analyzeAndRewriteFwd-   :: forall m n f e x entries. (CheckpointMonad m, NonLocal n, LabelsPtr entries)-   => FwdPass m n f-   -> MaybeC e entries-   -> Graph n e x -> Fact e f-   -> m (Graph n e x, FactBase f, MaybeO x f)-analyzeAndRewriteFwd pass entries g f =-  do (rg, fout) <- arfGraph pass (fmap targetLabels entries) g f-     let (g', fb) = normalizeGraph 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---------------------------------------------------------------------       Forward Implementation-------------------------------------------------------------------type Entries e = MaybeC e [Label]--arfGraph :: forall m n f e x .-            (NonLocal n, CheckpointMonad m) => FwdPass m n f -> -            Entries e -> Graph n e x -> Fact e f -> m (DG f n e x, Fact x f)-arfGraph pass entries = graph-  where-    {- nested type synonyms would be so lovely here -    type ARF  thing = forall e x . thing e x -> f        -> m (DG f n e x, Fact x f)-    type ARFX thing = forall e x . thing e x -> Fact e f -> m (DG f n e x, Fact x f)-    -}-    graph ::              Graph n e x -> Fact e f -> m (DG f n e x, Fact x f)--- @ start block.tex -2-    block :: forall e x . -             Block n e x -> f -> m (DG f n e x, Fact x f)--- @ end block.tex--- @ start node.tex -4-    node :: forall e x . (ShapeLifter e x) -         => n e x -> f -> m (DG f n e x, Fact x f)--- @ end node.tex--- @ start bodyfun.tex-    body  :: [Label] -> LabelMap (Block n C C)-          -> Fact C f -> m (DG f n C C, Fact C f)--- @ end bodyfun.tex-                    -- Outgoing factbase is restricted to Labels *not* in-                    -- in the Body; the facts for Labels *in*-                    -- the Body are in the 'DG f n C C'--- @ start cat.tex -2-    cat :: forall e a x f1 f2 f3. -           (f1 -> m (DG f n e a, f2))-        -> (f2 -> m (DG f n a x, f3))-        -> (f1 -> m (DG f n e x, f3))--- @ end cat.tex--    graph GNil            = \f -> return (dgnil, f)-    graph (GUnit blk)     = block blk-    graph (GMany e bdy x) = (e `ebcat` bdy) `cat` exit x-     where-      ebcat :: MaybeO e (Block n O C) -> Body n -> Fact e f -> m (DG f n e C, Fact C f)-      exit  :: MaybeO x (Block n C O)           -> Fact C f -> m (DG f n C x, Fact x f)-      exit (JustO blk) = arfx block blk-      exit NothingO    = \fb -> return (dgnilC, fb)-      ebcat entry bdy = c entries entry-       where c :: MaybeC e [Label] -> MaybeO e (Block n O C)-                -> Fact e f -> m (DG f n e C, Fact C f)-             c NothingC (JustO entry)   = block entry `cat` body (successors entry) bdy-             c (JustC entries) NothingO = body entries bdy-             c _ _ = error "bogus GADT pattern match failure"--    -- Lift from nodes to blocks--- @ start block.tex -2-    block (BFirst  n)  = node n-    block (BMiddle n)  = node n-    block (BLast   n)  = node n-    block (BCat b1 b2) = block b1 `cat` block b2--- @ end block.tex-    block (BHead h n)  = block h  `cat` node n-    block (BTail n t)  = node  n  `cat` block t-    block (BClosed h t)= block h  `cat` block t---- @ start node.tex -4-    node n f-     = do { grw <- frewrite pass n f-          ; case grw of-              Nothing -> return ( singletonDG f n-                                , ftransfer pass n f )-              Just (g, rw) ->-                  let pass' = pass { fp_rewrite = rw }-                      f'    = fwdEntryFact n f-                  in  arfGraph pass' (fwdEntryLabel n) g f' }---- @ end node.tex--    -- | Compose fact transformers and concatenate the resulting-    -- rewritten graphs.-    {-# INLINE cat #-} --- @ start cat.tex -2-    cat ft1 ft2 f = do { (g1,f1) <- ft1 f-                       ; (g2,f2) <- ft2 f1-                       ; return (g1 `dgSplice` g2, f2) }--- @ end cat.tex-    arfx :: forall thing x .-            NonLocal thing-         => (thing C x ->        f -> m (DG f n C x, Fact x f))-         -> (thing C x -> Fact C f -> m (DG f n C x, Fact x f))-    arfx arf thing fb = -      arf thing $ fromJust $ lookupFact (entryLabel thing) $ joinInFacts lattice fb-     where lattice = fp_lattice pass-     -- joinInFacts adds debugging information---                    -- Outgoing factbase is restricted to Labels *not* in-                    -- in the Body; the facts for Labels *in*-                    -- the Body are in the 'DG f n C C'--- @ start bodyfun.tex-    body entries blockmap init_fbase-      = fixpoint Fwd lattice do_block blocks init_fbase-      where-        blocks  = forwardBlockList entries blockmap-        lattice = fp_lattice pass-        do_block b fb = block b entryFact-          where entryFact = getFact lattice (entryLabel b) fb--- @ end bodyfun.tex----- Join all the incoming facts with bottom.--- We know the results _shouldn't change_, but the transfer--- functions might, for example, generate some debugging traces.-joinInFacts :: DataflowLattice f -> FactBase f -> FactBase f-joinInFacts (lattice @ DataflowLattice {fact_bot = bot, fact_join = fj}) fb =-  mkFactBase lattice $ map botJoin $ mapToList fb-    where botJoin (l, f) = (l, snd $ fj l (OldFact bot) (NewFact f))--forwardBlockList :: (NonLocal 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.-forwardBlockList entries blks = postorder_dfs_from blks entries----------------------------------------------------------------------------------              Backward analysis and rewriting: the interface--------------------------------------------------------------------------------data BwdPass m n f-  = BwdPass { bp_lattice  :: DataflowLattice f-            , bp_transfer :: BwdTransfer n f-            , bp_rewrite  :: BwdRewrite m n f }--newtype BwdTransfer n f -  = BwdTransfer3 { getBTransfer3 ::-                     ( n C O -> f          -> f-                     , n O O -> f          -> f-                     , n O C -> FactBase f -> f-                     ) }-newtype BwdRewrite m n f -  = BwdRewrite3 { getBRewrite3 ::-                    ( n C O -> f          -> m (Maybe (Graph n C O, BwdRewrite m n f))-                    , n O O -> f          -> m (Maybe (Graph n O O, BwdRewrite m n f))-                    , n O C -> FactBase f -> m (Maybe (Graph n O C, BwdRewrite m n f))-                    ) }--wrapBR :: (forall e x .-                Shape x -             -> (n  e x -> Fact x f  -> m  (Maybe (Graph n  e x, BwdRewrite m  n  f )))-             -> (n' e x -> Fact x f' -> m' (Maybe (Graph n' e x, BwdRewrite m' n' f')))-          )-            -- ^ This argument may assume that any function passed to it-            -- respects fuel, and it must return a result that respects fuel.-       -> BwdRewrite m  n  f -       -> BwdRewrite m' n' f'      -- see Note [Respects Fuel]-wrapBR wrap (BwdRewrite3 (f, m, l)) = -  BwdRewrite3 (wrap Open f, wrap Open m, wrap Closed l)--wrapBR2 :: (forall e x . Shape x-            -> (n1 e x -> Fact x f1 -> m1 (Maybe (Graph n1 e x, BwdRewrite m1 n1 f1)))-            -> (n2 e x -> Fact x f2 -> m2 (Maybe (Graph n2 e x, BwdRewrite m2 n2 f2)))-            -> (n3 e x -> Fact x f3 -> m3 (Maybe (Graph n3 e x, BwdRewrite m3 n3 f3))))-            -- ^ This argument may assume that any function passed to it-            -- respects fuel, and it must return a result that respects fuel.-        -> BwdRewrite m1 n1 f1-        -> BwdRewrite m2 n2 f2-        -> BwdRewrite m3 n3 f3      -- see Note [Respects Fuel]-wrapBR2 wrap2 (BwdRewrite3 (f1, m1, l1)) (BwdRewrite3 (f2, m2, l2)) =-    BwdRewrite3 (wrap2 Open f1 f2, wrap2 Open m1 m2, wrap2 Closed l1 l2)----mkBTransfer3 :: (n C O -> f -> f) -> (n O O -> f -> f) ->-                (n O C -> FactBase f -> f) -> BwdTransfer n f-mkBTransfer3 f m l = BwdTransfer3 (f, m, l)--mkBTransfer :: (forall e x . n e x -> Fact x f -> f) -> BwdTransfer n f-mkBTransfer f = BwdTransfer3 (f, f, f)---- | Functions passed to 'mkBRewrite3' should not be aware of the fuel supply.--- The result returned by 'mkBRewrite3' respects fuel.-mkBRewrite3 :: FuelMonad m-            => (n C O -> f          -> m (Maybe (Graph n C O)))-            -> (n O O -> f          -> m (Maybe (Graph n O O)))-            -> (n O C -> FactBase f -> m (Maybe (Graph n O C)))-            -> BwdRewrite m n f-mkBRewrite3 f m l = BwdRewrite3 (lift f, lift m, lift l)-  where lift rw node fact = liftM (liftM asRew) (withFuel =<< rw node fact)-        asRew g = (g, noBwdRewrite)--noBwdRewrite :: Monad m => BwdRewrite m n f-noBwdRewrite = BwdRewrite3 (noRewrite, noRewrite, noRewrite)---- | Functions passed to 'mkBRewrite' should not be aware of the fuel supply.--- The result returned by 'mkBRewrite' respects fuel.-mkBRewrite :: FuelMonad m -           => (forall e x . n e x -> Fact x f -> m (Maybe (Graph n e x)))-           -> BwdRewrite m n f-mkBRewrite f = mkBRewrite3 f f f-----------------------------------------------------------------------------------              Backward implementation--------------------------------------------------------------------------------arbGraph :: forall m n f e x .-            (NonLocal n, CheckpointMonad m) => BwdPass m n f -> -            Entries e -> Graph n e x -> Fact x f -> m (DG f n e x, Fact e f)-arbGraph pass entries = graph-  where-    {- nested type synonyms would be so lovely here -    type ARB  thing = forall e x . thing e x -> Fact x f -> m (DG f n e x, f)-    type ARBX thing = forall e x . thing e x -> Fact x f -> m (DG f n e x, Fact e f)-    -}-    graph ::              Graph n e x -> Fact x f -> m (DG f n e x, Fact e f)-    block :: forall e x . Block n e x -> Fact x f -> m (DG f n e x, f)-    node  :: forall e x . (ShapeLifter e x) -                       => n e x       -> Fact x f -> m (DG f n e x, f)-    body  :: [Label] -> Body n -> Fact C f -> m (DG f n C C, Fact C f)-    cat :: forall e a x info info' info''.-           (info' -> m (DG f n e a, info''))-        -> (info  -> m (DG f n a x, info'))-        -> (info  -> m (DG f n e x, info''))--    graph GNil            = \f -> return (dgnil, f)-    graph (GUnit blk)     = block blk-    graph (GMany e bdy x) = (e `ebcat` bdy) `cat` exit x-     where-      ebcat :: MaybeO e (Block n O C) -> Body n -> Fact C f -> m (DG f n e C, Fact e f)-      exit  :: MaybeO x (Block n C O)           -> Fact x f -> m (DG f n C x, Fact C f)-      exit (JustO blk) = arbx block blk-      exit NothingO    = \fb -> return (dgnilC, fb)-      ebcat entry bdy = c entries entry-       where c :: MaybeC e [Label] -> MaybeO e (Block n O C)-                -> Fact C f -> m (DG f n e C, Fact e f)-             c NothingC (JustO entry)   = block entry `cat` body (successors entry) bdy-             c (JustC entries) NothingO = body entries bdy-             c _ _ = error "bogus GADT pattern match failure"--    -- Lift from nodes to blocks-    block (BFirst  n)  = node n-    block (BMiddle n)  = node n-    block (BLast   n)  = node n-    block (BCat b1 b2) = block b1 `cat` block b2-    block (BHead h n)  = block h  `cat` node n-    block (BTail n t)  = node  n  `cat` block t-    block (BClosed h t)= block h  `cat` block t--    node n f-      = do { bwdres <- brewrite pass n f-           ; case bwdres of-               Nothing -> return (singletonDG entry_f n, entry_f)-                            where entry_f = btransfer pass n f-               Just (g, rw) ->-                          do { let pass' = pass { bp_rewrite = rw }-                             ; (g, f) <- arbGraph pass' (fwdEntryLabel n) g f-                             ; return (g, bwdEntryFact (bp_lattice pass) n f)} }--    -- | Compose fact transformers and concatenate the resulting-    -- rewritten graphs.-    {-# INLINE cat #-} -    cat ft1 ft2 f = do { (g2,f2) <- ft2 f-                       ; (g1,f1) <- ft1 f2-                       ; return (g1 `dgSplice` g2, f1) }--    arbx :: forall thing x .-            NonLocal thing-         => (thing C x -> Fact x f -> m (DG f n C x, f))-         -> (thing C x -> Fact x f -> m (DG f n C x, Fact C f))--    arbx arb thing f = do { (rg, f) <- arb thing f-                          ; let fb = joinInFacts (bp_lattice pass) $-                                     mapSingleton (entryLabel thing) f-                          ; return (rg, fb) }-     -- joinInFacts adds debugging information--                    -- Outgoing factbase is restricted to Labels *not* in-                    -- in the Body; the facts for Labels *in*-                    -- the Body are in the 'DG f n C C'-    body entries blockmap init_fbase-      = fixpoint Bwd (bp_lattice pass) do_block blocks init_fbase-      where-        blocks = backwardBlockList entries blockmap-        do_block b f = do (g, f) <- block b f-                          return (g, mapSingleton (entryLabel b) f)---backwardBlockList :: (LabelsPtr entries, NonLocal n) => entries -> 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 entries body = reverse $ forwardBlockList entries body--{---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.)---}----- | if the graph being analyzed is open at the exit, I don't---   quite understand the implications of possible other exits-analyzeAndRewriteBwd-   :: (CheckpointMonad m, NonLocal n, LabelsPtr entries)-   => BwdPass m n f-   -> MaybeC e entries -> Graph n e x -> Fact x f-   -> m (Graph n e x, FactBase f, MaybeO e f)-analyzeAndRewriteBwd pass entries g f =-  do (rg, fout) <- arbGraph pass (fmap targetLabels entries) g f-     let (g', fb) = normalizeGraph 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--------------------------------------------------------------------------------- @ start txfb.tex-data TxFactBase n f-  = TxFB { tfb_fbase :: FactBase f-         , tfb_rg    :: DG f n C C -- Transformed blocks-         , tfb_cha   :: ChangeFlag-         , tfb_lbls  :: LabelSet }--- @ end txfb.tex-     -- See Note [TxFactBase invariants]--- @ start update.tex-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 `setMember` lbls = (SomeChange, new_fbase)-  | otherwise            = (cha,        new_fbase)-  where-    (cha2, res_fact) -- Note [Unreachable blocks]-       = case lookupFact lbl fbase of-           Nothing -> (SomeChange, new_fact_debug)  -- Note [Unreachable blocks]-           Just old_fact -> join old_fact-         where join old_fact = -                 fact_join lat lbl-                   (OldFact old_fact) (NewFact new_fact)-               (_, new_fact_debug) = join (fact_bot lat)-    new_fbase = mapInsert lbl res_fact fbase--- @ end update.tex---{---- this doesn't work because it can't be implemented-class Monad m => FixpointMonad m where-  observeChangedFactBase :: m (Maybe (FactBase f)) -> Maybe (FactBase f)--}---- @ start fptype.tex-data Direction = Fwd | Bwd-fixpoint :: forall m n f. (CheckpointMonad m, NonLocal n)- => Direction- -> DataflowLattice f- -> (Block n C C -> Fact C f -> m (DG f n C C, Fact C f))- -> [Block n C C]- -> (Fact C f -> m (DG f n C C, Fact C f))--- @ end fptype.tex--- @ start fpimp.tex-fixpoint direction lat do_block blocks init_fbase-  = do { tx_fb <- loop init_fbase-       ; return (tfb_rg tx_fb, -                 map (fst . fst) tagged_blocks -                    `mapDeleteList` tfb_fbase tx_fb ) }-    -- The successors of the Graph are the the Labels -    -- for which we have facts and which are *not* in-    -- the blocks of the graph-  where-    tagged_blocks = map tag blocks-    is_fwd = case direction of { Fwd -> True; -                                 Bwd -> False }-    tag b = ((entryLabel b, b), -             if is_fwd then [entryLabel b] -                        else successors b)-     -- 'tag' adds the in-labels of the block; -     -- see Note [TxFactBase invairants]--    tx_blocks :: [((Label, Block n C C), [Label])]   -- I do not understand this type-              -> TxFactBase n f -> m (TxFactBase n f)-    tx_blocks []              tx_fb = return tx_fb-    tx_blocks (((lbl,blk), in_lbls):bs) tx_fb -      = tx_block lbl blk in_lbls tx_fb >>= tx_blocks bs-     -- "in_lbls" == Labels the block may -     --                 _depend_ upon for facts--    tx_block :: Label -> Block n C C -> [Label]-             -> TxFactBase n f -> m (TxFactBase n f)-    tx_block lbl blk in_lbls -        tx_fb@(TxFB { tfb_fbase = fbase, tfb_lbls = lbls-                    , tfb_rg = blks, tfb_cha = cha })-      | is_fwd && not (lbl `mapMember` fbase)-      = return (tx_fb {tfb_lbls = lbls'})       -- Note [Unreachable blocks]-      | otherwise-      = do { (rg, out_facts) <- do_block blk fbase-           ; let (cha', fbase') = mapFoldWithKey-                                  (updateFact lat lbls) -                                  (cha,fbase) out_facts-           ; return $-               TxFB { tfb_lbls  = lbls'-                    , tfb_rg    = rg `dgSplice` blks-                    , tfb_fbase = fbase'-                    , tfb_cha = cha' } }-      where-        lbls' = lbls `setUnion` setFromList in_lbls-        --    loop :: FactBase f -> m (TxFactBase n f)-    loop fbase -      = do { s <- checkpoint-           ; let init_tx = TxFB { tfb_fbase = fbase-                                , tfb_cha   = NoChange-                                , tfb_rg    = dgnilC-                                , tfb_lbls  = setEmpty }-           ; tx_fb <- tx_blocks tagged_blocks init_tx-           ; case tfb_cha tx_fb of-               NoChange   -> return tx_fb-               SomeChange -                 -> do { restart s-                       ; loop (tfb_fbase tx_fb) } }--- @ end fpimp.tex           ---{-  Note [TxFactBase invariants]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-The TxFactBase is used only during a fixpoint iteration (or "sweep"),-and accumulates facts (and the transformed code) during the fixpoint-iteration.--* tfb_fbase increases monotonically, across all sweeps--* At the beginning of each sweep-      tfb_cha  = NoChange-      tfb_lbls = {}--* During each sweep we process each block in turn.  Processing a block-  is done thus:-    1.  Read from tfb_fbase the facts for its entry label (forward)-        or successors labels (backward)-    2.  Transform those facts into new facts for its successors (forward)-        or entry label (backward)-    3.  Augment tfb_fbase with that info-  We call the labels read in step (1) the "in-labels" of the sweep--* The field tfb_lbls is the set of in-labels of all blocks that have-  been processed so far this sweep, including the block that is-  currently being processed.  tfb_lbls is initialised to {}.  It is a-  subset of the Labels of the *original* (not transformed) blocks.--* The tfb_cha field is set to SomeChange iff we decide we need to-  perform another iteration of the fixpoint loop. It is initialsed to NoChange.--  Specifically, we set tfb_cha to SomeChange in step (3) iff-    (a) The fact in tfb_fbase for a block L changes-    (b) L is in tfb_lbls-  Reason: until a label enters the in-labels its accumuated fact in tfb_fbase-  has not been read, hence cannot affect the outcome--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_join 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.--}----------------------------------------------------------------------------------      DG: an internal data type for 'decorated graphs'---          TOTALLY internal to Hoopl; each block is decorated with a fact---------------------------------------------------------------------------------- @ start dg.tex-type Graph = Graph' Block-type DG f  = Graph' (DBlock f)-data DBlock f n e x = DBlock f (Block n e x) -- ^ block decorated with fact--- @ end dg.tex-instance NonLocal n => NonLocal (DBlock f n) where-  entryLabel (DBlock _ b) = entryLabel b-  successors (DBlock _ b) = successors b----- constructors--dgnil  :: DG f n O O-dgnilC :: DG f n C C-dgSplice  :: NonLocal n => DG f n e a -> DG f n a x -> DG f n e x------ observers--type GraphWithFacts n f e x = (Graph n e x, FactBase f)-  -- A Graph together with the facts for that graph-  -- The domains of the two maps should be identical--normalizeGraph :: forall n f e x .-                  NonLocal n => DG f n e x -> GraphWithFacts n f e x--normalizeGraph g = (graphMapBlocks dropFact g, facts g)-    where dropFact (DBlock _ b) = b-          facts :: DG f n e x -> FactBase f-          facts GNil = noFacts-          facts (GUnit _) = noFacts-          facts (GMany _ body exit) = bodyFacts body `mapUnion` exitFacts exit-          exitFacts :: MaybeO x (DBlock f n C O) -> FactBase f-          exitFacts NothingO = noFacts-          exitFacts (JustO (DBlock f b)) = mapSingleton (entryLabel b) f-          bodyFacts :: LabelMap (DBlock f n C C) -> FactBase f-          bodyFacts body = mapFold f noFacts body-            where f (DBlock f b) fb = mapInsert (entryLabel b) f fb----- implementation of the constructors (boring)--dgnil  = GNil-dgnilC = GMany NothingO emptyBody NothingO--dgSplice = U.splice fzCat-  where fzCat (DBlock f b1) (DBlock _ b2) = DBlock f (b1 `U.cat` b2)---------------------------------------------------------------------       Utilities--------------------------------------------------------------------- Lifting based on shape:---  - from nodes to blocks---  - from facts to fact-like things--- Lowering back:---  - from fact-like things to facts--- Note that the latter two functions depend only on the entry shape.--- @ start node.tex-class ShapeLifter e x where- singletonDG   :: f -> n e x -> DG f n e x- fwdEntryFact  :: NonLocal n => n e x -> f -> Fact e f- fwdEntryLabel :: NonLocal n => n e x -> MaybeC e [Label]- ftransfer :: FwdPass m n f -> n e x -> f -> Fact x f- frewrite  :: FwdPass m n f -> n e x -           -> f -> m (Maybe (Graph n e x, FwdRewrite m n f))--- @ end node.tex- bwdEntryFact :: NonLocal n => DataflowLattice f -> n e x -> Fact e f -> f- btransfer    :: BwdPass m n f -> n e x -> Fact x f -> f- brewrite     :: BwdPass m n f -> n e x-              -> Fact x f -> m (Maybe (Graph n e x, BwdRewrite m n f))--instance ShapeLifter C O where-  singletonDG f = gUnitCO . DBlock f . BFirst-  fwdEntryFact     n f  = mapSingleton (entryLabel n) f-  bwdEntryFact lat n fb = getFact lat (entryLabel n) fb-  ftransfer (FwdPass {fp_transfer = FwdTransfer3 (ft, _, _)}) n f = ft n f-  btransfer (BwdPass {bp_transfer = BwdTransfer3 (bt, _, _)}) n f = bt n f-  frewrite  (FwdPass {fp_rewrite  = FwdRewrite3  (fr, _, _)}) n f = fr n f-  brewrite  (BwdPass {bp_rewrite  = BwdRewrite3  (br, _, _)}) n f = br n f-  fwdEntryLabel n = JustC [entryLabel n]--instance ShapeLifter O O where-  singletonDG f = gUnitOO . DBlock f . BMiddle-  fwdEntryFact   _ f = f-  bwdEntryFact _ _ f = f-  ftransfer (FwdPass {fp_transfer = FwdTransfer3 (_, ft, _)}) n f = ft n f-  btransfer (BwdPass {bp_transfer = BwdTransfer3 (_, bt, _)}) n f = bt n f-  frewrite  (FwdPass {fp_rewrite  = FwdRewrite3  (_, fr, _)}) n f = fr n f-  brewrite  (BwdPass {bp_rewrite  = BwdRewrite3  (_, br, _)}) n f = br n f-  fwdEntryLabel _ = NothingC--instance ShapeLifter O C where-  singletonDG f = gUnitOC . DBlock f . BLast-  fwdEntryFact   _ f = f-  bwdEntryFact _ _ f = f-  ftransfer (FwdPass {fp_transfer = FwdTransfer3 (_, _, ft)}) n f = ft n f-  btransfer (BwdPass {bp_transfer = BwdTransfer3 (_, _, bt)}) n f = bt n f-  frewrite  (FwdPass {fp_rewrite  = FwdRewrite3  (_, _, fr)}) n f = fr n f-  brewrite  (BwdPass {bp_rewrite  = BwdRewrite3  (_, _, br)}) n f = br n f-  fwdEntryLabel _ = NothingC---- Fact lookup: the fact `orelse` bottom-getFact  :: DataflowLattice f -> Label -> FactBase f -> f-getFact lat l fb = case lookupFact l fb of Just  f -> f-                                           Nothing -> fact_bot lat----{-  Note [Respects fuel]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--}--- $fuel--- A value of type 'FwdRewrite' or 'BwdRewrite' /respects fuel/ if --- any function contained within the value satisfies the following properties:------   * When fuel is exhausted, it always returns 'Nothing'.------   * When it returns @Just g rw@, it consumes /exactly/ one unit---     of fuel, and new rewrite 'rw' also respects fuel.------ Provided that functions passed to 'mkFRewrite', 'mkFRewrite3', --- 'mkBRewrite', and 'mkBRewrite3' are not aware of the fuel supply,--- the results respect fuel.------ It is an /unchecked/ run-time error for the argument passed to 'wrapFR',--- 'wrapFR2', 'wrapBR', or 'warpBR2' to return a function that does not respect fuel.
− Compiler/Hoopl/Debug.hs
@@ -1,103 +0,0 @@-{-# LANGUAGE RankNTypes, GADTs, ScopedTypeVariables, FlexibleContexts #-}--module Compiler.Hoopl.Debug -  ( TraceFn , debugFwdJoins , debugBwdJoins-  , debugFwdTransfers , debugBwdTransfers-  )-where--import Compiler.Hoopl.Dataflow-import Compiler.Hoopl.Show------------------------------------------------------------------------------------- | 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------ There are two kinds of debugging messages for a join,--- depending on whether the join is higher in the lattice than the old fact:---   1. If the join is higher, we show:---         + Join@L: f1 `join` f2 = f'---      where:---        + indicates a change---        L is the label where the join takes place---        f1 is the old fact at the label---        f2 is the new fact we are joining to f1---        f' is the result of the join---   2. _ Join@L: f2 <= f1---      where:---        _ indicates no change---        L is the label where the join takes place---        f1 is the old fact at the label (which remains unchanged)---        f2 is the new fact we joined with f1------------------------------------------------------------------------------------debugFwdJoins :: forall m n f . Show f => TraceFn -> ChangePred -> FwdPass m n f -> FwdPass m n f-debugBwdJoins :: forall m n f . Show f => TraceFn -> ChangePred -> BwdPass m n f -> BwdPass m 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 showPred l@(DataflowLattice {fact_join = join}) = l {fact_join = join'}-  where-   join' l f1@(OldFact of1) f2@(NewFact nf2) =-     if showPred c then trace output res else res-       where res@(c, f') = join l f1 f2-             output = case c of-                        SomeChange -> "+ Join@" ++ show l ++ ": " ++ show of1 ++ " `join` "-                                                                  ++ 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 ShowN n   = forall e x . n e x ->      String-type FPred n f = forall e x . n e x -> f        -> Bool-type BPred n f = forall e x . n e x -> Fact x f -> Bool-debugFwdTransfers::-  forall m n f . Show f => TraceFn -> ShowN n -> FPred n f -> FwdPass m n f -> FwdPass m n f-debugFwdTransfers trace showN showPred pass = pass { fp_transfer = transfers' }-  where-    (f, m, l) = getFTransfer3 $ fp_transfer pass-    transfers' = mkFTransfer3 (wrap show f) (wrap show m) (wrap showFactBase l)-    wrap :: forall e x . (Fact x f -> String) -> (n e x -> f -> Fact x f) -> n e x -> f -> Fact x f-    wrap showOutF ft n f = if showPred n f then trace output res else res-      where-        res    = ft n f-        output = name ++ " transfer: " ++ show f ++ " -> " ++ showN n ++ " -> " ++ showOutF res-    name = fact_name (fp_lattice pass)-    -debugBwdTransfers::-  forall m n f . Show f => TraceFn -> ShowN n -> BPred n f -> BwdPass m n f -> BwdPass m n f-debugBwdTransfers trace showN showPred pass = pass { bp_transfer = transfers' }-  where-    (f, m, l) = getBTransfer3 $ bp_transfer pass-    transfers' = mkBTransfer3 (wrap show f) (wrap show m) (wrap showFactBase l)-    wrap :: forall e x . (Fact x f -> String) -> (n e x -> Fact x f -> f) -> n e x -> Fact x f -> f-    wrap showInF ft n f = if showPred n f then trace output res else res-      where-        res    = ft n f-        output = name ++ " transfer: " ++ showInF f ++ " -> " ++ showN n ++ " -> " ++ show res-    name = fact_name (bp_lattice pass)-    ---- debugFwdTransfers, debugFwdRewrites, debugFwdAll ::---   forall m n f . Show f => TraceFn -> ShowN n -> FwdPass m n f -> FwdPass m n f--- debugBwdTransfers, debugBwdRewrites, debugBwdAll ::---   forall m n f . Show f => TraceFn -> ShowN n -> BwdPass m n f -> BwdPass m n f-
− Compiler/Hoopl/Fuel.hs
@@ -1,105 +0,0 @@-{-# LANGUAGE TypeFamilies #-}----------------------------------------------------------------------------------		The fuel monad--------------------------------------------------------------------------------module Compiler.Hoopl.Fuel-  ( Fuel, infiniteFuel, fuelRemaining-  , withFuel-  , FuelMonad(..)-  , FuelMonadT(..)-  , CheckingFuelMonad-  , InfiniteFuelMonad-  , SimpleFuelMonad-  )-where--import Compiler.Hoopl.Checkpoint-import Compiler.Hoopl.Unique--class Monad m => FuelMonad m where-  getFuel :: m Fuel-  setFuel :: Fuel -> m ()---- | Find out how much fuel remains after a computation.--- Can be subtracted from initial fuel to get total consumption.-fuelRemaining :: FuelMonad m => m Fuel-fuelRemaining = getFuel--class FuelMonadT fm where-  runWithFuel :: (Monad m, FuelMonad (fm m)) => Fuel -> fm m a -> m a---type Fuel = Int--withFuel :: FuelMonad m => Maybe a -> m (Maybe a)-withFuel Nothing  = return Nothing-withFuel (Just a) = do f <- getFuel-                       if f == 0-                         then return Nothing-                         else setFuel (f-1) >> return (Just a)---------------------------------------------------------------------newtype CheckingFuelMonad m a = FM { unFM :: Fuel -> m (a, Fuel) }--instance Monad m => Monad (CheckingFuelMonad m) where-  return a = FM (\f -> return (a, f))-  fm >>= k = FM (\f -> do { (a, f') <- unFM fm f; unFM (k a) f' })--instance CheckpointMonad m => CheckpointMonad (CheckingFuelMonad m) where-  type Checkpoint (CheckingFuelMonad m) = (Fuel, Checkpoint m)-  checkpoint = FM $ \fuel -> do { s <- checkpoint-                                ; return ((fuel, s), fuel) }-  restart (fuel, s) = FM $ \_ -> do { restart s; return ((), fuel) }--instance UniqueMonad m => UniqueMonad (CheckingFuelMonad m) where-  freshUnique = FM (\f -> do { l <- freshUnique; return (l, f) })--instance Monad m => FuelMonad (CheckingFuelMonad m) where-  getFuel   = FM (\f -> return (f, f))-  setFuel f = FM (\_ -> return ((),f))--instance FuelMonadT CheckingFuelMonad where-  runWithFuel fuel m = do { (a, _) <- unFM m fuel; return a }--------------------------------------------------------------------newtype InfiniteFuelMonad m a = IFM { unIFM :: m a }-instance Monad m => Monad (InfiniteFuelMonad m) where-  return a = IFM $ return a-  m >>= k  = IFM $ do { a <- unIFM m; unIFM (k a) }--instance UniqueMonad m => UniqueMonad (InfiniteFuelMonad m) where-  freshUnique = IFM $ freshUnique--instance Monad m => FuelMonad (InfiniteFuelMonad m) where-  getFuel   = return infiniteFuel-  setFuel _ = return ()--instance CheckpointMonad m => CheckpointMonad (InfiniteFuelMonad m) where-  type Checkpoint (InfiniteFuelMonad m) = Checkpoint m-  checkpoint = IFM checkpoint-  restart s  = IFM $ restart s----instance FuelMonadT InfiniteFuelMonad where-  runWithFuel _ = unIFM--infiniteFuel :: Fuel -- effectively infinite, any, but subtractable-infiniteFuel = maxBound--type SimpleFuelMonad = CheckingFuelMonad SimpleUniqueMonad--{--runWithFuelAndUniques :: Fuel -> [Unique] -> FuelMonad a -> a-runWithFuelAndUniques fuel uniques m = a-  where (a, _, _) = unFM m fuel uniques--freshUnique :: FuelMonad Unique-freshUnique = FM (\f (l:ls) -> (l, f, ls))--}-
− Compiler/Hoopl/GHC.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE GADTs, RankNTypes #-}--{- Exposing some internals to GHC -}-module Compiler.Hoopl.GHC-  ( uniqueToInt-  , uniqueToLbl, lblToUnique-  , getFuel, setFuel-  , bodyToBlockMap, bodyOfBlockMap-  )-where--import Compiler.Hoopl.Fuel-import Compiler.Hoopl.Graph-import Compiler.Hoopl.Label-import Compiler.Hoopl.Unique---- Converts Body to a map of closed/closed blocks.--- It should better be a constant-time operation--- as GHC is counting on it.-bodyToBlockMap :: Body' block n -> LabelMap (block n C C)-bodyToBlockMap (Body bodyMap) = bodyMap--bodyOfBlockMap :: LabelMap (block n C C) -> Body' block n-bodyOfBlockMap = Body
− Compiler/Hoopl/Graph.hs
@@ -1,119 +0,0 @@-{-# LANGUAGE GADTs, EmptyDataDecls, TypeFamilies #-}--module Compiler.Hoopl.Graph -  ( O, C, Block(..), Body, Body'(..), Graph, Graph'(..)-  , MaybeO(..), MaybeC(..), Shape(..), IndexedCO-  , NonLocal(entryLabel, successors)-  , emptyBody, addBlock, bodyList-  )-where--import Compiler.Hoopl.Collections-import Compiler.Hoopl.Label----------------------------------------------------------------------------------		Graphs---------------------------------------------------------------------------------- | Used at the type level to indicate an "open" structure with    --- a unique, unnamed control-flow edge flowing in or out.         --- "Fallthrough" and concatenation are permitted at an open point.-data O -       -       --- | Used at the type level to indicate a "closed" structure which--- supports control transfer only through the use of named--- labels---no "fallthrough" is permitted.  The number of control-flow--- edges is unconstrained.-data C---- | A sequence of nodes.  May be any of four shapes (O/O, O/C, C/O, C/C).--- Open at the entry means single entry, mutatis mutandis for exit.--- A closed/closed block is a /basic/ block and can't be extended further.--- Clients should avoid manipulating blocks and should stick to either nodes--- or graphs.-data Block n e x where-  -- nodes-  BFirst  :: n C O                 -> Block n C O -- x^ block holds a single first node-  BMiddle :: n O O                 -> Block n O O -- x^ block holds a single middle node-  BLast   :: n O C                 -> Block n O C -- x^ block holds a single last node--  -- concatenation operations-  BCat    :: Block n O O -> Block n O O -> Block n O O -- non-list-like-  BHead   :: Block n C O -> n O O       -> Block n C O-  BTail   :: n O O       -> Block n O C -> Block n O C  --  BClosed :: Block n C O -> Block n O C -> Block n C C -- the zipper---- | A (possibly empty) collection of closed/closed blocks-type Body n = LabelMap (Block n C C)-newtype Body' block n = Body (LabelMap (block n C C))---- | A control-flow graph, which may take any of four shapes (O/O, O/C, C/O, C/C).--- A graph open at the entry has a single, distinguished, anonymous entry point;--- if a graph is closed at the entry, its entry point(s) are supplied by a context.-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) -        -> LabelMap (block n C C)-        -> MaybeO x (block n C O)-        -> Graph' block n e x---- | Maybe type indexed by open/closed-data MaybeO ex t where-  JustO    :: t -> MaybeO O t-  NothingO ::      MaybeO C t---- | Maybe type indexed by closed/open-data MaybeC ex t where-  JustC    :: t -> MaybeC C t-  NothingC ::      MaybeC O t---- | Dynamic shape value-data Shape ex where-  Closed :: Shape C-  Open   :: Shape O---- | Either type indexed by closed/open using type families-type family IndexedCO ex a b :: *-type instance IndexedCO C a b = a-type instance IndexedCO O a b = b--instance Functor (MaybeO ex) where-  fmap _ NothingO = NothingO-  fmap f (JustO a) = JustO (f a)--instance Functor (MaybeC ex) where-  fmap _ NothingC = NothingC-  fmap f (JustC a) = JustC (f a)------------------------------------ | Gives access to the anchor points for--- nonlocal edges as well as the edges themselves-class NonLocal thing where -  entryLabel :: thing C x -> Label   -- ^ The label of a first node or block-  successors :: thing e C -> [Label] -- ^ Gives control-flow successors--instance NonLocal n => NonLocal (Block n) where-  entryLabel (BFirst n)    = entryLabel n-  entryLabel (BHead h _)   = entryLabel h-  entryLabel (BClosed h _) = entryLabel h-  successors (BLast n)     = successors n-  successors (BTail _ t)   = successors t-  successors (BClosed _ t) = successors t---------------------------------emptyBody :: LabelMap (thing C C)-emptyBody = mapEmpty--addBlock :: NonLocal thing => thing C C -> LabelMap (thing C C) -> LabelMap (thing C C)-addBlock b body = nodupsInsert (entryLabel b) b body-  where nodupsInsert l b body = if mapMember l body then-                                    error $ "duplicate label " ++ show l ++ " in graph"-                                else-                                    mapInsert l b body--bodyList :: NonLocal (block n) => Body' block n -> [(Label,block n C C)]-bodyList (Body body) = mapToList body
− Compiler/Hoopl/GraphUtil.hs
@@ -1,124 +0,0 @@-{-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables #-}---- N.B. addBasicBlocks won't work on OO without a Node (branch/label) constraint--module Compiler.Hoopl.GraphUtil-  ( splice, gSplice , cat , bodyGraph, bodyUnion-  , frontBiasBlock, backBiasBlock-  )--where--import Compiler.Hoopl.Collections-import Compiler.Hoopl.Graph-import Compiler.Hoopl.Label--bodyGraph :: Body n -> Graph n C C-bodyGraph b = GMany NothingO b NothingO--splice :: forall block n e a x . NonLocal (block n) =>-          (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--        sp GNil g2 = g2-        sp g1 GNil = g1--        sp (GUnit b1) (GUnit b2) = GUnit (b1 `bcat` b2)--        sp (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))--        sp (GMany e1 bs1 (JustO x1)) (GMany (JustO e2) b2 x2)-          = GMany e1 (b1 `bodyUnion` b2) x2-          where b1 = addBlock (x1 `bcat` e2) bs1--        sp (GMany e1 b1 NothingO) (GMany NothingO b2 x2)-          = GMany e1 (b1 `bodyUnion` b2) x2--        sp _ _ = error "bogus GADT match failure"--bodyUnion :: forall a . LabelMap a -> LabelMap a -> LabelMap a-bodyUnion = mapUnionWithKey nodups-  where nodups l _ _ = error $ "duplicate blocks with label " ++ show l--gSplice :: NonLocal n => Graph n e a -> Graph n a x -> Graph n e x-gSplice = splice cat--cat :: Block n e O -> Block n O x -> Block n e x-cat b1@(BFirst {})     (BMiddle n)  = BHead   b1 n-cat b1@(BFirst {})  b2@(BLast{})    = BClosed b1 b2-cat b1@(BFirst {})  b2@(BTail{})    = BClosed b1 b2-cat b1@(BFirst {})     (BCat b2 b3) = (b1 `cat` b2) `cat` b3-cat b1@(BHead {})      (BCat b2 b3) = (b1 `cat` b2) `cat` b3-cat b1@(BHead {})      (BMiddle n)  = BHead   b1 n-cat b1@(BHead {})   b2@(BLast{})    = BClosed b1 b2-cat b1@(BHead {})   b2@(BTail{})    = BClosed b1 b2-cat b1@(BMiddle {}) b2@(BMiddle{})  = BCat    b1 b2-cat    (BMiddle n)  b2@(BLast{})    = BTail    n b2-cat b1@(BMiddle {}) b2@(BCat{})     = BCat    b1 b2-cat    (BMiddle n)  b2@(BTail{})    = BTail    n b2-cat    (BCat b1 b2) b3@(BLast{})    = b1 `cat` (b2 `cat` b3)-cat    (BCat b1 b2) b3@(BTail{})    = b1 `cat` (b2 `cat` b3)-cat b1@(BCat {})    b2@(BCat{})     = BCat    b1 b2-cat b1@(BCat {})    b2@(BMiddle{})  = BCat    b1 b2----------------------------------------------------------------------- | 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 :: Block n e x -> Block n e x-frontBiasBlock b@(BFirst  {}) = b-frontBiasBlock b@(BMiddle {}) = b-frontBiasBlock b@(BLast   {}) = b-frontBiasBlock b@(BCat {}) = rotate b-  where -- rotate and append ensure every left child of ZCat is ZMiddle-        -- provided 2nd argument to append already has this property-    rotate :: Block n O O -> Block n O O-    append :: Block n O O -> Block n O O -> Block n O O-    rotate (BCat h t)     = append h (rotate t)-    rotate b@(BMiddle {}) = b-    append b@(BMiddle {}) t = b `BCat` t-    append (BCat b1 b2) b3 = b1 `append` (b2 `append` b3)-frontBiasBlock b@(BHead {})    = b -- back-biased by nature; cannot fix-frontBiasBlock b@(BTail {})    = b -- statically front-biased-frontBiasBlock   (BClosed h t) = shiftRight h t-    where shiftRight :: Block n C O -> Block n O C -> Block n C C-          shiftRight (BHead b1 b2)  b3 = shiftRight b1 (BTail b2 b3)-          shiftRight b1@(BFirst {}) b2 = BClosed 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 :: Block n e x -> Block n e x-backBiasBlock b@(BFirst  {}) = b-backBiasBlock b@(BMiddle {}) = b-backBiasBlock b@(BLast   {}) = b-backBiasBlock b@(BCat {}) = rotate b-  where -- rotate and append ensure every right child of Cat is Middle-        -- provided 1st argument to append already has this property-    rotate :: Block n O O -> Block n O O-    append :: Block n O O -> Block n O O -> Block n O O-    rotate (BCat h t)     = append (rotate h) t-    rotate b@(BMiddle {}) = b-    append h b@(BMiddle {}) = h `BCat` b-    append b1 (BCat b2 b3) = (b1 `append` b2) `append` b3-backBiasBlock b@(BHead {}) = b -- statically back-biased-backBiasBlock b@(BTail {}) = b -- front-biased by nature; cannot fix-backBiasBlock (BClosed h t) = shiftLeft h t-    where shiftLeft :: Block n C O -> Block n O C -> Block n C C-          shiftLeft b1 (BTail b2 b3) = shiftLeft (BHead b1 b2) b3-          shiftLeft b1 b2@(BLast {}) = BClosed b1 b2
− Compiler/Hoopl/Label.hs
@@ -1,104 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-module Compiler.Hoopl.Label-  ( Label-  , freshLabel-  , LabelSet, LabelMap-  , FactBase, noFacts, lookupFact--  , uniqueToLbl -- MkGraph and GHC use only-  , lblToUnique -- GHC use only-  )--where--import Compiler.Hoopl.Collections-import Compiler.Hoopl.Unique----------------------------------------------------------------------------------		Label--------------------------------------------------------------------------------newtype Label = Label { lblToUnique :: Unique }-  deriving (Eq, Ord)--uniqueToLbl :: Unique -> Label-uniqueToLbl = Label--instance Show Label where-  show (Label n) = "L" ++ show n--freshLabel :: UniqueMonad m => m Label-freshLabel = freshUnique >>= return . uniqueToLbl---------------------------------------------------------------------------------- LabelSet--newtype LabelSet = LS UniqueSet deriving (Eq, Ord, Show)--instance IsSet LabelSet where-  type ElemOf LabelSet = Label--  setNull (LS s) = setNull s-  setSize (LS s) = setSize s-  setMember (Label k) (LS s) = setMember k s--  setEmpty = LS setEmpty-  setSingleton (Label k) = LS (setSingleton k)-  setInsert (Label k) (LS s) = LS (setInsert k s)-  setDelete (Label k) (LS s) = LS (setDelete k s)--  setUnion (LS x) (LS y) = LS (setUnion x y)-  setDifference (LS x) (LS y) = LS (setDifference x y)-  setIntersection (LS x) (LS y) = LS (setIntersection x y)-  setIsSubsetOf (LS x) (LS y) = setIsSubsetOf x y--  setFold k z (LS s) = setFold (k . uniqueToLbl) z s--  setElems (LS s) = map uniqueToLbl (setElems s)-  setFromList ks = LS (setFromList (map lblToUnique ks))---------------------------------------------------------------------------------- LabelMap--newtype LabelMap v = LM (UniqueMap v) deriving (Eq, Ord, Show)--instance IsMap LabelMap where-  type KeyOf LabelMap = Label--  mapNull (LM m) = mapNull m-  mapSize (LM m) = mapSize m-  mapMember (Label k) (LM m) = mapMember k m-  mapLookup (Label k) (LM m) = mapLookup k m-  mapFindWithDefault def (Label k) (LM m) = mapFindWithDefault def k m--  mapEmpty = LM mapEmpty-  mapSingleton (Label k) v = LM (mapSingleton k v)-  mapInsert (Label k) v (LM m) = LM (mapInsert k v m)-  mapDelete (Label k) (LM m) = LM (mapDelete k m)--  mapUnion (LM x) (LM y) = LM (mapUnion x y)-  mapUnionWithKey f (LM x) (LM y) = LM (mapUnionWithKey (f . uniqueToLbl) x y)-  mapDifference (LM x) (LM y) = LM (mapDifference x y)-  mapIntersection (LM x) (LM y) = LM (mapIntersection x y)-  mapIsSubmapOf (LM x) (LM y) = mapIsSubmapOf x y--  mapMap f (LM m) = LM (mapMap f m)-  mapMapWithKey f (LM m) = LM (mapMapWithKey (f . uniqueToLbl) m)-  mapFold k z (LM m) = mapFold k z m-  mapFoldWithKey k z (LM m) = mapFoldWithKey (k . uniqueToLbl) z m--  mapElems (LM m) = mapElems m-  mapKeys (LM m) = map uniqueToLbl (mapKeys m)-  mapToList (LM m) = [(uniqueToLbl k, v) | (k, v) <- mapToList m]-  mapFromList assocs = LM (mapFromList [(lblToUnique k, v) | (k, v) <- assocs])---------------------------------------------------------------------------------- FactBase--type FactBase f = LabelMap f--noFacts :: FactBase f-noFacts = mapEmpty--lookupFact :: Label -> FactBase f -> Maybe f-lookupFact = mapLookup
− Compiler/Hoopl/MkGraph.hs
@@ -1,252 +0,0 @@-{-# LANGUAGE ScopedTypeVariables, GADTs, TypeSynonymInstances, FlexibleInstances, RankNTypes #-}-module Compiler.Hoopl.MkGraph-    ( AGraph, graphOfAGraph, aGraphOfGraph-    , (<*>), (|*><*|), catGraphs, addEntrySeq, addExitSeq, addBlocks, unionBlocks-    , emptyGraph, emptyClosedGraph, withFresh-    , mkFirst, mkMiddle, mkMiddles, mkLast, mkBranch, mkLabel, mkWhileDo-    , IfThenElseable(mkIfThenElse)-    , mkEntry, mkExit-    , HooplNode(mkLabelNode, mkBranchNode)-    )-where--import Compiler.Hoopl.Label (Label, uniqueToLbl)-import Compiler.Hoopl.Graph-import qualified Compiler.Hoopl.GraphUtil as U-import Compiler.Hoopl.Unique-import Control.Monad (liftM2)--{-|-As noted in the paper, we can define a single, polymorphic type of -splicing operation with the very polymorphic type-@-  AGraph n e a -> AGraph n a x -> AGraph n e x-@-However, we feel that this operation is a bit /too/ polymorphic,-and that it's too easy for clients to use it blindly without -thinking.  We therfore split it into two operations, '<*>' and '|*><*|', -which are supplemented by other functions:--  * The '<*>' operator is true concatenation, for connecting open graphs.-    Control flows from the left graph to the right graph.--  * The '|*><*|' operator splices together two graphs at a closed-    point. Nothing is known about control flow. 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.--  * The operator 'addBlocks' adds a set of basic blocks (represented-    as a closed/closed 'AGraph' to an existing graph, without changing-    the shape of the existing graph.  In some cases, it's necessary to-    introduce a branch and a label to 'get around' the blocks added,-    so this operator, and other functions based on it, requires a-    'HooplNode' type-class constraint and is available only on AGraph,-    not Graph.--  * We have discussed a dynamic assertion about dangling outedges and-    unreachable blocks, but nothing is implemented yet.---}----class GraphRep g where-  -- | An empty graph that is open at entry and exit.  -  -- It is the left and right identity of '<*>'.-  emptyGraph       :: g n O O-  -- | An empty graph that is closed at entry and exit.  -  -- It is the left and right identity of '|*><*|'.-  emptyClosedGraph :: g n C C-  -- | Create a graph from a first node-  mkFirst  :: n C O -> g n C O-  -- | Create a graph from a middle node-  mkMiddle :: n O O -> g n O O-  -- | Create a graph from a last node-  mkLast   :: n O C -> g n O C-  mkFirst = mkExit  . BFirst-  mkLast  = mkEntry . BLast-  infixl 3 <*>-  infixl 2 |*><*| -  -- | Concatenate two graphs; control flows from left to right.-  (<*>)    :: NonLocal n => g n e O -> g n O x -> g n e x-  -- | Splice together two graphs at a closed point; nothing is known-  -- about control flow.-  (|*><*|) :: NonLocal n => g n e C -> g n C x -> g n e x-  -- | Conveniently concatenate a sequence of open/open graphs using '<*>'.-  catGraphs :: NonLocal n => [g n O O] -> g n O O-  catGraphs = foldr (<*>) emptyGraph--  -- | Create a graph that defines a label-  mkLabel  :: HooplNode n => Label -> g n C O -- definition of the label-  -- | Create a graph that branches to a label-  mkBranch :: HooplNode n => Label -> g n O C -- unconditional branch to the label--  -- | Conveniently concatenate a sequence of middle nodes to form-  -- an open/open graph.-  mkMiddles :: NonLocal n => [n O O] -> g n O O--  mkLabel  id     = mkFirst $ mkLabelNode id-  mkBranch target = mkLast  $ mkBranchNode target-  mkMiddles ms    = catGraphs $ map mkMiddle ms--  -- | Create a graph containing only an entry sequence-  mkEntry   :: Block n O C -> g n O C-  -- | Create a graph containing only an exit sequence-  mkExit    :: Block n C O -> g n C O--instance GraphRep Graph where-  emptyGraph  = GNil-  emptyClosedGraph = GMany NothingO emptyBody NothingO-  (<*>)       = U.gSplice-  (|*><*|)    = U.gSplice-  mkMiddle    = GUnit . BMiddle-  mkExit   block = GMany NothingO      emptyBody (JustO block)-  mkEntry  block = GMany (JustO block) emptyBody NothingO--instance GraphRep AGraph where-  emptyGraph  = aGraphOfGraph emptyGraph-  emptyClosedGraph = aGraphOfGraph emptyClosedGraph-  (<*>)       = liftA2 (<*>)-  (|*><*|)    = liftA2 (|*><*|)-  mkMiddle    = aGraphOfGraph . mkMiddle-  mkExit  = aGraphOfGraph . mkExit-  mkEntry = aGraphOfGraph . mkEntry----- | The type of abstract graphs.  Offers extra "smart constructors"--- that may consume fresh labels during construction.-newtype AGraph n e x =-  A { graphOfAGraph :: forall m. UniqueMonad m =>-                       m (Graph n e x) -- ^ Take an abstract 'AGraph'-                                       -- and make a concrete (if monadic)-                                       -- 'Graph'.-    }---- | Take a graph and make it abstract.-aGraphOfGraph :: Graph n e x -> AGraph n e x-aGraphOfGraph g = A (return g)----- | The 'Labels' class defines things that can be lambda-bound--- by an argument to 'withFreshLabels'.  Such an argument may--- lambda-bind a single 'Label', or if multiple labels are needed,--- it can bind a tuple.  Tuples can be nested, so arbitrarily many--- fresh labels can be acquired in a single call.--- --- For example usage see implementations of 'mkIfThenElse' and 'mkWhileDo'.-class Uniques u where-  withFresh :: (u -> AGraph n e x) -> AGraph n e x--instance Uniques Unique where-  withFresh f = A $ freshUnique >>= (graphOfAGraph . f)--instance Uniques Label where-  withFresh f = A $ freshUnique >>= (graphOfAGraph . f . uniqueToLbl)---- | Lifts binary 'Graph' functions into 'AGraph' functions.-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)-liftA2 f (A g) (A g') = A (liftM2 f g g')---- | Extend an existing 'AGraph' with extra basic blocks "out of line".--- No control flow is implied.  Simon PJ should give example use case.-addBlocks      :: HooplNode n-               => AGraph n e x -> AGraph n C C -> AGraph n e x-addBlocks (A g) (A blocks) = A $ g >>= \g -> blocks >>= add g-  where add :: (UniqueMonad m, HooplNode n)-            => Graph n e x -> Graph n C C -> m (Graph n e x)-        add (GMany e body x) (GMany NothingO body' NothingO) =-          return $ GMany e (body `U.bodyUnion` body') x-        add g@GNil      blocks = spliceOO g blocks-        add g@(GUnit _) blocks = spliceOO g blocks-        spliceOO :: (HooplNode n, UniqueMonad m)-                 => Graph n O O -> Graph n C C -> m (Graph n O O)-        spliceOO g blocks = graphOfAGraph $ withFresh $ \l ->-          A (return g) <*> mkBranch l |*><*| A (return blocks) |*><*| mkLabel l---- | For some graph-construction operations and some optimizations,--- Hoopl must be able to create control-flow edges using a given node--- type 'n'.-class NonLocal n => HooplNode n where-  -- | Create a branch node, the source of a control-flow edge.-  mkBranchNode :: Label -> n O C-  -- | Create a label node, the target (destination) of a control-flow edge.-  mkLabelNode  :: Label -> n C O-------------------------------------------------------------------                   Shiny Things-----------------------------------------------------------------class IfThenElseable x where-  -- | Translate a high-level if-then-else construct into an 'AGraph'.-  -- The condition takes as arguments labels on the true-false branch-  -- and returns a single-entry, two-exit graph which exits to -  -- the two labels.-  mkIfThenElse :: HooplNode n-               => (Label -> Label -> AGraph n O C) -- ^ branch condition-               -> AGraph n O x   -- ^ code in the "then" branch-               -> AGraph n O x   -- ^ code in the "else" branch -               -> AGraph n O x   -- ^ resulting if-then-else construct--mkWhileDo    :: HooplNode n-             => (Label -> Label -> AGraph n O C) -- ^ loop condition-             -> AGraph n O O -- ^ body of the loop-             -> AGraph n O O -- ^ the final while loop--instance IfThenElseable O where-  mkIfThenElse cbranch tbranch fbranch = withFresh $ \(endif, ltrue, lfalse) ->-    cbranch ltrue lfalse |*><*|-      mkLabel ltrue  <*> tbranch <*> mkBranch endif |*><*|-      mkLabel lfalse <*> fbranch <*> mkBranch endif |*><*|-      mkLabel endif--instance IfThenElseable C where-  mkIfThenElse cbranch tbranch fbranch = withFresh $ \(ltrue, lfalse) ->-    cbranch ltrue lfalse |*><*|-       mkLabel ltrue  <*> tbranch |*><*|-       mkLabel lfalse <*> fbranch--mkWhileDo cbranch body = withFresh $ \(test, head, endwhile) ->-     -- Forrest Baskett's while-loop layout-  mkBranch test |*><*|-    mkLabel head <*> body <*> mkBranch test |*><*|-    mkLabel test <*> cbranch head endwhile  |*><*|-    mkLabel endwhile-------------------------------------------------------------------               Boring instance declarations------------------------------------------------------------------instance (Uniques u1, Uniques u2) => Uniques (u1, u2) where-  withFresh f = withFresh $ \u1 ->-                withFresh $ \u2 ->-                f (u1, u2)--instance (Uniques u1, Uniques u2, Uniques u3) => Uniques (u1, u2, u3) where-  withFresh f = withFresh $ \u1 ->-                withFresh $ \u2 ->-                withFresh $ \u3 ->-                f (u1, u2, u3)--instance (Uniques u1, Uniques u2, Uniques u3, Uniques u4) => Uniques (u1, u2, u3, u4) where-  withFresh f = withFresh $ \u1 ->-                withFresh $ \u2 ->-                withFresh $ \u3 ->-                withFresh $ \u4 ->-                f (u1, u2, u3, u4)-------------------------------------------------- deprecated legacy functions--{-# DEPRECATED addEntrySeq, addExitSeq, unionBlocks "use |*><*| instead" #-}-addEntrySeq :: NonLocal n => AGraph n O C -> AGraph n C x -> AGraph n O x-addExitSeq  :: NonLocal n => AGraph n e C -> AGraph n C O -> AGraph n e O-unionBlocks :: NonLocal n => AGraph n C C -> AGraph n C C -> AGraph n C C--addEntrySeq = (|*><*|)-addExitSeq  = (|*><*|)-unionBlocks = (|*><*|)
− Compiler/Hoopl/Passes/DList.hs
@@ -1,45 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}--module Compiler.Hoopl.Passes.DList-  ( Doms, domEntry, domLattice-  , domPass-  )-where--import Compiler.Hoopl---type Doms = WithBot [Label]--- ^ List of labels, extended with a standard bottom element---- | The fact that goes into the entry of a dominator analysis: the first node--- is dominated only by the entry point, which is represented by the empty list--- of labels.-domEntry :: Doms-domEntry = PElem []--domLattice :: DataflowLattice Doms-domLattice = addPoints "dominators" extend--extend :: JoinFun [Label]-extend _ (OldFact l) (NewFact l') = (changeIf (l `lengthDiffers` j), j)-    where j = lcs l l'-          lcs :: [Label] -> [Label] -> [Label] -- longest common suffix-          lcs l l' | length l > length l' = lcs (drop (length l - length l') l) l'-                   | length l < length l' = lcs l' l-                   | otherwise = dropUnlike l l' l-          dropUnlike [] [] maybe_like = maybe_like-          dropUnlike (x:xs) (y:ys) maybe_like =-              dropUnlike xs ys (if x == y then maybe_like else xs)-          dropUnlike _ _ _ = error "this can't happen"--          lengthDiffers [] [] = False-          lengthDiffers (_:xs) (_:ys) = lengthDiffers xs ys-          lengthDiffers [] (_:_) = True-          lengthDiffers (_:_) [] = True---- | Dominator pass-domPass :: (NonLocal n, Monad m) => FwdPass m n Doms-domPass = FwdPass domLattice (mkFTransfer3 first (const id) distributeFact) noFwdRewrite-  where first n = fmap (entryLabel n:)
− Compiler/Hoopl/Passes/Dominator.hs
@@ -1,130 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}--module Compiler.Hoopl.Passes.Dominator-  ( Doms, DPath(..), domPath, domEntry, domLattice, extendDom-  , DominatorNode(..), DominatorTree(..), tree-  , immediateDominators-  , domPass-  )-where--import Data.Maybe--import Compiler.Hoopl---type Doms = WithBot DPath--- ^ List of labels, extended with a standard bottom element---- | The fact that goes into the entry of a dominator analysis: the first node--- is dominated only by the entry point, which is represented by the empty list--- of labels.-domEntry :: Doms-domEntry = PElem (DPath [])--newtype DPath = DPath [Label]-  -- ^ represents part of the domination relation: each label-  -- in a list is dominated by all its successors.  This is a newtype only so-  -- we can give it a fancy Show instance.--instance Show DPath where-  show (DPath ls) = concat (foldr (\l path -> show l : " -> " : path) ["entry"] ls)--domPath :: Doms -> [Label]-domPath Bot = [] -- lies: an unreachable node appears to be dominated by the entry-domPath (PElem (DPath ls)) = ls--extendDom :: Label -> DPath -> DPath-extendDom l (DPath ls) = DPath (l:ls)--domLattice :: DataflowLattice Doms-domLattice = addPoints "dominators" extend--extend :: JoinFun DPath-extend _ (OldFact (DPath l)) (NewFact (DPath l')) =-                                (changeIf (l `lengthDiffers` j), DPath j)-    where j = lcs l l'-          lcs :: [Label] -> [Label] -> [Label] -- longest common suffix-          lcs l l' | length l > length l' = lcs (drop (length l - length l') l) l'-                   | length l < length l' = lcs l' l-                   | otherwise = dropUnlike l l' l-          dropUnlike [] [] maybe_like = maybe_like-          dropUnlike (x:xs) (y:ys) maybe_like =-              dropUnlike xs ys (if x == y then maybe_like else xs)-          dropUnlike _ _ _ = error "this can't happen"--          lengthDiffers [] [] = False-          lengthDiffers (_:xs) (_:ys) = lengthDiffers xs ys-          lengthDiffers [] (_:_) = True-          lengthDiffers (_:_) [] = True------ | Dominator pass-domPass :: (NonLocal n, Monad m) => FwdPass m n Doms-domPass = FwdPass domLattice (mkFTransfer3 first (const id) distributeFact) noFwdRewrite-  where first n = fmap (extendDom $ entryLabel n)--------------------------------------------------------------------data DominatorNode = Entry | Labelled Label-data DominatorTree = Dominates DominatorNode [DominatorTree]--- ^ This data structure is a *rose tree* in which each node may have---  arbitrarily many children.  Each node dominates all its descendants.---- | Map from a FactBase for dominator lists into a--- dominator tree.  -tree :: [(Label, Doms)] -> DominatorTree-tree facts = Dominates Entry $ merge $ map reverse $ map mkList facts-   -- This code has been lightly tested.  The key insight is this: to-   -- find lists that all have the same head, convert from a list of-   -- lists to a finite map, in 'children'.  Then, to convert from the-   -- finite map to list of dominator trees, use the invariant that-   -- each key dominates all the lists of values.-  where merge lists = mapTree $ children $ filter (not . null) lists-        children = foldl addList noFacts-        addList :: FactBase [[Label]] -> [Label] -> FactBase [[Label]]-        addList map (x:xs) = mapInsert x (xs:existing) map-            where existing = fromMaybe [] $ lookupFact x map-        addList _ [] = error "this can't happen"-        mapTree :: FactBase [[Label]] -> [DominatorTree]-        mapTree map = [Dominates (Labelled x) (merge lists) |-                                                    (x, lists) <- mapToList map]-        mkList (l, doms) = l : domPath doms---instance Show DominatorTree where-  show = tree2dot---- | Given a dominator tree, produce a string representation, in the--- input language of dot, that will enable dot to produce a--- visualization of the tree.  For more info about dot see--- http://www.graphviz.org.--tree2dot :: DominatorTree -> String-tree2dot t = concat $ "digraph {\n" : dot t ["}\n"]-  where-    dot :: DominatorTree -> [String] -> [String]-    dot (Dominates root trees) = -                   (dotnode root :) . outedges trees . flip (foldl subtree) trees-      where outedges [] = id-            outedges (Dominates n _ : ts) =-                \s -> "  " : show root : " -> " : show n : "\n" : outedges ts s-            dotnode Entry = "  entryNode [shape=plaintext, label=\"entry\"]\n"-            dotnode (Labelled l) = "  " ++ show l ++ "\n"-            subtree = flip dot--instance Show DominatorNode where-  show Entry = "entryNode"-  show (Labelled l) = show l---------------------------------------------------------------------- | Takes FactBase from dominator analysis and returns a map from each --- label to its immediate dominator, if any-immediateDominators :: FactBase Doms -> LabelMap Label-immediateDominators = mapFoldWithKey add mapEmpty-    where add l (PElem (DPath (idom:_))) = mapInsert l idom -          add _ _ = id-
− Compiler/Hoopl/Pointed.hs
@@ -1,147 +0,0 @@-{-# LANGUAGE GADTs, ScopedTypeVariables #-}---- | Possibly doubly pointed lattices--module Compiler.Hoopl.Pointed-  ( Pointed(..), addPoints, addPoints', addTop, addTop'-  , liftJoinTop, extendJoinDomain-  , WithTop, WithBot, WithTopAndBot-  )-where--import Compiler.Hoopl.Graph-import Compiler.Hoopl.Label-import Compiler.Hoopl.Dataflow---- | Adds top, bottom, or both to help form a lattice-data Pointed t b a where-   Bot   ::      Pointed t C a-   PElem :: a -> Pointed t b a-   Top   ::      Pointed C b a---- ^ The type parameters 't' and 'b' are used to say whether top--- and bottom elements have been added.  The analogy with 'Block'--- is nearly exact:------  * A 'Block' is closed at the entry if and only if it has a first node;---    a 'Pointed' is closed at the top if and only if it has a top element.------  * A 'Block' is closed at the exit if and only if it has a last node;---    a 'Pointed' is closed at the bottom if and only if it has a bottom element.------ We thus have four possible types, of which three are interesting:------  [@Pointed C C a@] Type @a@ extended with both top and bottom elements.------  [@Pointed C O a@] Type @a@ extended with a top element---  only. (Presumably @a@ comes equipped with a bottom element of its own.)------  [@Pointed O C a@] Type @a@ extended with a bottom element only. ------  [@Pointed O O a@] Isomorphic to @a@, and therefore not interesting.------ The advantage of all this GADT-ishness is that the constructors--- 'Bot', 'Top', and 'PElem' can all be used polymorphically.------ A 'Pointed t b' type is an instance of 'Functor' and 'Show'.----type WithBot a = Pointed O C a--- ^ Type 'a' with a bottom element adjoined--type WithTop a = Pointed C O a--- ^ Type 'a' with a top element adjoined--type WithTopAndBot a = Pointed C C a--- ^ Type 'a' with top and bottom elements adjoined----- | Given a join function and a name, creates a semi lattice by--- adding a bottom element, and possibly a top element also.--- A specialized version of 'addPoints''.-addPoints  :: String -> JoinFun a -> DataflowLattice (Pointed t C a)--- | A more general case for creating a new lattice-addPoints' :: forall a t .-              String-           -> (Label -> OldFact a -> NewFact a -> (ChangeFlag, Pointed t C a))-           -> DataflowLattice (Pointed t C a)--addPoints name join = addPoints' name join'-   where join' l o n = (change, PElem f)-            where (change, f) = join l o n--addPoints' name joinx = DataflowLattice name Bot join-  where -- careful: order of cases matters for ChangeFlag-        join :: JoinFun (Pointed t C a)-        join _ (OldFact f)            (NewFact Bot) = (NoChange, f)-        join _ (OldFact Top)          (NewFact _)   = (NoChange, Top)-        join _ (OldFact Bot)          (NewFact f)   = (SomeChange, f)-        join _ (OldFact _)            (NewFact Top) = (SomeChange, Top)-        join l (OldFact (PElem old)) (NewFact (PElem new))-           = joinx l (OldFact old) (NewFact new)---liftJoinTop :: JoinFun a -> JoinFun (WithTop a)-extendJoinDomain :: forall a-              . (Label -> OldFact a -> NewFact a -> (ChangeFlag, WithTop a))-             -> JoinFun (WithTop a)--extendJoinDomain joinx = join- where join :: JoinFun (WithTop a)-       join _ (OldFact Top)          (NewFact _)   = (NoChange, Top)-       join _ (OldFact _)            (NewFact Top) = (SomeChange, Top)-       join l (OldFact (PElem old)) (NewFact (PElem new))-           = joinx l (OldFact old) (NewFact new)--liftJoinTop joinx = extendJoinDomain (\l old new -> liftPair $ joinx l old new)-  where liftPair (c, a) = (c, PElem a)---- | Given a join function and a name, creates a semi lattice by--- adding a top element but no bottom element.  Caller must supply the bottom --- element.-addTop  :: DataflowLattice a -> DataflowLattice (WithTop a)--- | A more general case for creating a new lattice-addTop' :: forall a .-              String-           -> a-           -> (Label -> OldFact a -> NewFact a -> (ChangeFlag, WithTop a))-           -> DataflowLattice (WithTop a)--addTop lattice = addTop' name' (fact_bot lattice) join'-   where name' = fact_name lattice ++ " + T"-         join' l o n = (change, PElem f)-            where (change, f) = fact_join lattice l o n--addTop' name bot joinx = DataflowLattice name (PElem bot) join-  where -- careful: order of cases matters for ChangeFlag-        join :: JoinFun (WithTop a)-        join _ (OldFact Top)          (NewFact _)   = (NoChange, Top)-        join _ (OldFact _)            (NewFact Top) = (SomeChange, Top)-        join l (OldFact (PElem old)) (NewFact (PElem new))-           = joinx l (OldFact old) (NewFact new)--instance Show a => Show (Pointed t b a) where-  show Bot = "_|_"-  show Top = "T"-  show (PElem a) = show a--instance Functor (Pointed t b) where-  fmap _ Bot = Bot-  fmap _ Top = Top-  fmap f (PElem a) = PElem (f a)--instance Eq a => Eq (Pointed t b a) where-  Bot == Bot = True-  Top == Top = True-  (PElem a) == (PElem a') = a == a'-  _ == _ = False--instance Ord a => Ord (Pointed t b a) where-  Bot     `compare` Bot      = EQ-  Bot     `compare` _        = LT-  _       `compare` Bot      = GT-  PElem a `compare` PElem a' = a `compare` a'-  Top     `compare` Top      = EQ-  Top     `compare` _        = GT-  _       `compare` Top      = LT
− Compiler/Hoopl/Shape.hs
@@ -1,50 +0,0 @@-{-# LANGUAGE GADTs, EmptyDataDecls #-}--module Compiler.Hoopl.Shape {-# DEPRECATED "not ready to migrate to this yet" #-}-where---- | Used at the type level to indicate an "open" structure with    --- a unique, unnamed control-flow edge flowing in or out.         --- "Fallthrough" and concatenation are permitted at an open point.-data O -       -       --- | Used at the type level to indicate a "closed" structure which--- supports control transfer only through the use of named--- labels---no "fallthrough" is permitted.  The number of control-flow--- edges is unconstrained.-data C---data HalfShape s where-  ShapeO :: HalfShape O-  ShapeC :: HalfShape C--data Shape e x where-  ShapeOO :: Shape O O-  ShapeCO :: Shape C O-  ShapeOC :: Shape O C-  ShapeCC :: Shape C C--class Shapely n where-  shape        :: n e x -> Shape e x-  shapeAtEntry :: n e x -> HalfShape e-  shapeAtExit  :: n e x -> HalfShape x--  shapeAtEntry = entryHalfShape . shape-  shapeAtExit  = exitHalfShape  . shape-  --entryHalfShape :: Shape e x -> HalfShape e-exitHalfShape  :: Shape e x -> HalfShape x--entryHalfShape ShapeOO = ShapeO-entryHalfShape ShapeOC = ShapeO-entryHalfShape ShapeCO = ShapeC-entryHalfShape ShapeCC = ShapeC--exitHalfShape ShapeOO = ShapeO-exitHalfShape ShapeOC = ShapeC-exitHalfShape ShapeCO = ShapeO-exitHalfShape ShapeCC = ShapeC-
− Compiler/Hoopl/Show.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE RankNTypes, GADTs, ScopedTypeVariables, FlexibleContexts #-}--module Compiler.Hoopl.Show -  ( showGraph, showFactBase-  )-where--import Compiler.Hoopl.Collections-import Compiler.Hoopl.Graph-import Compiler.Hoopl.Label------------------------------------------------------------------------------------- Prettyprinting-----------------------------------------------------------------------------------type Showing n = forall e x . n e x -> String- --showGraph :: forall n e x . (NonLocal n) => Showing n -> Graph n e x -> String-showGraph node = g-  where g :: (NonLocal 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 (mapElems blocks)-        b :: forall e x . Block n e x -> String-        b (BFirst  n)     = node n-        b (BMiddle n)     = node n-        b (BLast   n)     = node n ++ "\n"-        b (BCat b1 b2)    = b b1   ++ b b2-        b (BHead b1 n)    = b b1   ++ node n ++ "\n"-        b (BTail n b1)    = node n ++ b b1-        b (BClosed b1 b2) = b b1   ++ b b2--open :: (a -> String) -> MaybeO z a -> String-open _ NothingO  = ""-open p (JustO n) = p n--showFactBase :: Show f => FactBase f -> String-showFactBase = show . mapToList
− Compiler/Hoopl/Unique.hs
@@ -1,134 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-module Compiler.Hoopl.Unique-  ( Unique, intToUnique-  , UniqueSet, UniqueMap-  , UniqueMonad(..)-  , SimpleUniqueMonad, runSimpleUniqueMonad-  , UniqueMonadT, runUniqueMonadT--  , uniqueToInt -- exposed through GHC module only!-  )--where--import Compiler.Hoopl.Checkpoint-import Compiler.Hoopl.Collections--import qualified Data.IntMap as M-import qualified Data.IntSet as S----------------------------------------------------------------------------------		Unique--------------------------------------------------------------------------------data Unique = Unique { uniqueToInt ::  {-# UNPACK #-} !Int }-  deriving (Eq, Ord)--intToUnique :: Int -> Unique-intToUnique = Unique--instance Show Unique where-  show (Unique n) = show n---------------------------------------------------------------------------------- UniqueSet--newtype UniqueSet = US S.IntSet deriving (Eq, Ord, Show)--instance IsSet UniqueSet where-  type ElemOf UniqueSet = Unique--  setNull (US s) = S.null s-  setSize (US s) = S.size s-  setMember (Unique k) (US s) = S.member k s--  setEmpty = US S.empty-  setSingleton (Unique k) = US (S.singleton k)-  setInsert (Unique k) (US s) = US (S.insert k s)-  setDelete (Unique k) (US s) = US (S.delete k s)--  setUnion (US x) (US y) = US (S.union x y)-  setDifference (US x) (US y) = US (S.difference x y)-  setIntersection (US x) (US y) = US (S.intersection x y)-  setIsSubsetOf (US x) (US y) = S.isSubsetOf x y--  setFold k z (US s) = S.fold (k . intToUnique) z s--  setElems (US s) = map intToUnique (S.elems s)-  setFromList ks = US (S.fromList (map uniqueToInt ks))---------------------------------------------------------------------------------- UniqueMap--newtype UniqueMap v = UM (M.IntMap v) deriving (Eq, Ord, Show)--instance IsMap UniqueMap where-  type KeyOf UniqueMap = Unique--  mapNull (UM m) = M.null m-  mapSize (UM m) = M.size m-  mapMember (Unique k) (UM m) = M.member k m-  mapLookup (Unique k) (UM m) = M.lookup k m-  mapFindWithDefault def (Unique k) (UM m) = M.findWithDefault def k m--  mapEmpty = UM M.empty-  mapSingleton (Unique k) v = UM (M.singleton k v)-  mapInsert (Unique k) v (UM m) = UM (M.insert k v m)-  mapDelete (Unique k) (UM m) = UM (M.delete k m)--  mapUnion (UM x) (UM y) = UM (M.union x y)-  mapUnionWithKey f (UM x) (UM y) = UM (M.unionWithKey (f . intToUnique) x y)-  mapDifference (UM x) (UM y) = UM (M.difference x y)-  mapIntersection (UM x) (UM y) = UM (M.intersection x y)-  mapIsSubmapOf (UM x) (UM y) = M.isSubmapOf x y--  mapMap f (UM m) = UM (M.map f m)-  mapMapWithKey f (UM m) = UM (M.mapWithKey (f . intToUnique) m)-  mapFold k z (UM m) = M.fold k z m-  mapFoldWithKey k z (UM m) = M.foldWithKey (k . intToUnique) z m--  mapElems (UM m) = M.elems m-  mapKeys (UM m) = map intToUnique (M.keys m)-  mapToList (UM m) = [(intToUnique k, v) | (k, v) <- M.toList m]-  mapFromList assocs = UM (M.fromList [(uniqueToInt k, v) | (k, v) <- assocs])--------------------------------------------------------------------- Monads--class Monad m => UniqueMonad m where-  freshUnique :: m Unique--newtype SimpleUniqueMonad a = SUM { unSUM :: [Unique] -> (a, [Unique]) }--instance Monad SimpleUniqueMonad where-  return a = SUM $ \us -> (a, us)-  m >>= k  = SUM $ \us -> let (a, us') = unSUM m us in-                              unSUM (k a) us'--instance UniqueMonad SimpleUniqueMonad where-  freshUnique = SUM $ \(u:us) -> (u, us)--instance CheckpointMonad SimpleUniqueMonad where-  type Checkpoint SimpleUniqueMonad = [Unique]-  checkpoint = SUM $ \us -> (us, us)-  restart us = SUM $ \_  -> ((), us)--runSimpleUniqueMonad :: SimpleUniqueMonad a -> a-runSimpleUniqueMonad m = fst (unSUM m allUniques)--------------------------------------------------------------------newtype UniqueMonadT m a = UMT { unUMT :: [Unique] -> m (a, [Unique]) }--instance Monad m => Monad (UniqueMonadT m) where-  return a = UMT $ \us -> return (a, us)-  m >>= k  = UMT $ \us -> do { (a, us') <- unUMT m us; unUMT (k a) us' }--instance Monad m => UniqueMonad (UniqueMonadT m) where-  freshUnique = UMT $ \(u:us) -> return (u, us)--runUniqueMonadT :: Monad m => UniqueMonadT m a -> m a-runUniqueMonadT m = do { (a, _) <- unUMT m allUniques; return a }--allUniques :: [Unique]-allUniques = map Unique [1..]
− Compiler/Hoopl/Util.hs
@@ -1,263 +0,0 @@-{-# LANGUAGE GADTs, ScopedTypeVariables, FlexibleInstances, RankNTypes #-}--module Compiler.Hoopl.Util-  ( gUnitOO, gUnitOC, gUnitCO, gUnitCC-  , catGraphNodeOC, catGraphNodeOO-  , catNodeCOGraph, catNodeOOGraph-  , graphMapBlocks-  , blockMapNodes, blockMapNodes3-  , blockGraph-  , 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.Collections-import Compiler.Hoopl.Graph-import Compiler.Hoopl.Label---------------------------------------------------------------------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 :: NonLocal (block n) => block n C C -> Graph' block n C C-gUnitOO b = GUnit b-gUnitOC b = GMany (JustO b) emptyBody  NothingO-gUnitCO b = GMany NothingO  emptyBody (JustO b)-gUnitCC b = GMany NothingO  (addBlock b emptyBody) NothingO---catGraphNodeOO ::            Graph n e O -> n O O -> Graph n e O-catGraphNodeOC :: NonLocal n => Graph n e O -> n O C -> Graph n e C-catNodeOOGraph ::            n O O -> Graph n O x -> Graph n O x-catNodeCOGraph :: NonLocal n => n C O -> Graph n O x -> Graph n C x--catGraphNodeOO GNil                     n = gUnitOO $ BMiddle n-catGraphNodeOO (GUnit b)                n = gUnitOO $ b `BCat` BMiddle n-catGraphNodeOO (GMany e body (JustO x)) n = GMany e body (JustO $ x `BHead` n)--catGraphNodeOC GNil                     n = gUnitOC $ BLast n-catGraphNodeOC (GUnit b)                n = gUnitOC $ addToLeft b $ BLast n-  where addToLeft :: Block n O O -> Block n O C -> Block n O C-        addToLeft (BMiddle m)    g = m `BTail` g-        addToLeft (b1 `BCat` b2) g = addToLeft b1 $ addToLeft b2 g-catGraphNodeOC (GMany e body (JustO x)) n = GMany e body' NothingO-  where body' = addBlock (x `BClosed` BLast n) body--catNodeOOGraph n GNil                     = gUnitOO $ BMiddle n-catNodeOOGraph n (GUnit b)                = gUnitOO $ BMiddle n `BCat` b-catNodeOOGraph n (GMany (JustO e) body x) = GMany (JustO $ n `BTail` e) body x--catNodeCOGraph n GNil                     = gUnitCO $ BFirst n-catNodeCOGraph n (GUnit b)                = gUnitCO $ addToRight (BFirst n) b-  where addToRight :: Block n C O -> Block n O O -> Block n C O-        addToRight g (BMiddle m)    = g `BHead` m-        addToRight g (b1 `BCat` b2) = addToRight (addToRight g b1) b2-catNodeCOGraph n (GMany (JustO e) body x) = GMany NothingO body' x-  where body' = addBlock (BFirst n `BClosed` e) body------blockGraph :: NonLocal n => Block n e x -> Graph n e x-blockGraph b@(BFirst  {}) = gUnitCO b-blockGraph b@(BMiddle {}) = gUnitOO b-blockGraph b@(BLast   {}) = gUnitOC b-blockGraph b@(BCat {})    = gUnitOO b-blockGraph b@(BHead {})   = gUnitCO b-blockGraph b@(BTail {})   = gUnitOC b-blockGraph b@(BClosed {}) = gUnitCC b----- | Function 'graphMapBlocks' enables a change of representation of blocks,--- nodes, or both.  It lifts a polymorphic block transform into a polymorphic--- graph transform.  When the block representation stabilizes, a similar--- function should be provided for blocks.-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)--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) (mapMap f b) (fmap f x)---- | Function 'blockMapNodes' enables a change of nodes in a block.-blockMapNodes3 :: ( n C O -> n' C O-                  , n O O -> n' O O-                  , n O C -> n' O C)-               -> Block n e x -> Block n' e x-blockMapNodes3 (f, _, _) (BFirst n)     = BFirst (f n)-blockMapNodes3 (_, m, _) (BMiddle n)    = BMiddle (m n)-blockMapNodes3 (_, _, l) (BLast n)      = BLast (l n)-blockMapNodes3 fs (BCat x y)            = BCat (blockMapNodes3 fs x) (blockMapNodes3 fs y)-blockMapNodes3 fs@(_, m, _) (BHead x n) = BHead (blockMapNodes3 fs x) (m n)-blockMapNodes3 fs@(_, m, _) (BTail n x) = BTail (m n) (blockMapNodes3 fs x)-blockMapNodes3 fs (BClosed x y)         = BClosed (blockMapNodes3 fs x) (blockMapNodes3 fs y)--blockMapNodes :: (forall e x. n e x -> n' e x)-              -> (Block n e x -> Block n' e x)-blockMapNodes f = blockMapNodes3 (f, f, f)--------------------------------------------------------------------class LabelsPtr l where-  targetLabels :: l -> [Label]--instance NonLocal n => LabelsPtr (n e C) where-  targetLabels n = successors n--instance LabelsPtr Label where-  targetLabels l = [l]--instance LabelsPtr LabelSet where-  targetLabels = setElems--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 :: NonLocal (block n) => Graph' block n O x -> [block n C C]-preorder_dfs  :: NonLocal (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 :: (NonLocal (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 body entry setEmpty--postorder_dfs = graphDfs postorder_dfs_from_except-preorder_dfs  = graphDfs preorder_dfs_from_except--postorder_dfs_from_except :: forall block e . (NonLocal 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 setMember id visited then-            cont acc visited-        else-            let cont' acc visited = cont (block:acc) visited in-            vchildren (get_children block) cont' acc (setInsert id visited)-      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 id blocks of-                      Just b -> b : rst-                      Nothing -> rst--postorder_dfs_from-    :: (NonLocal block, LabelsPtr b) => LabelMap (block C C) -> b -> [block C C]-postorder_dfs_from blocks b = postorder_dfs_from_except blocks b setEmpty---------------------------------------------------------------------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 -> (setMember l v, v)-mark   l = VM $ \v -> ((), setInsert l v)--preorder_dfs_from_except :: forall block e . (NonLocal 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 id blocks 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 . NonLocal (block n) => Graph' block n e x -> LabelSet-labelsDefined GNil      = setEmpty-labelsDefined (GUnit{}) = setEmpty-labelsDefined (GMany _ body x) = mapFoldWithKey addEntry (exitLabel x) body-  where addEntry label _ labels = setInsert label labels-        exitLabel :: MaybeO x (block n C O) -> LabelSet-        exitLabel NothingO  = setEmpty-        exitLabel (JustO b) = setSingleton (entryLabel b)--labelsUsed :: forall block n e x. NonLocal (block n) => Graph' block n e x -> LabelSet-labelsUsed GNil      = setEmpty-labelsUsed (GUnit{}) = setEmpty-labelsUsed (GMany e body _) = mapFold addTargets (entryTargets e) body -  where addTargets block labels = setInsertList (successors block) labels-        entryTargets :: MaybeO e (block n O C) -> LabelSet-        entryTargets NothingO = setEmpty-        entryTargets (JustO b) = addTargets b setEmpty--externalEntryLabels :: forall n .-                       NonLocal n => LabelMap (Block n C C) -> LabelSet-externalEntryLabels body = defined `setDifference` used-  where defined = labelsDefined g-        used = labelsUsed g-        g = GMany NothingO body NothingO
− Compiler/Hoopl/Wrappers.hs
@@ -1,7 +0,0 @@-module Compiler.Hoopl.Wrappers {-# DEPRECATED "Use only if you know what you are doing and can preserve the 'respects fuel' invariant" #-}-  ( wrapFR, wrapFR2, wrapBR, wrapBR2-  )-where--import Compiler.Hoopl.Dataflow-
− Compiler/Hoopl/XUtil.hs
@@ -1,490 +0,0 @@-{-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables, TypeFamilies  #-}---- | Utilities for clients of Hoopl, not used internally.--module Compiler.Hoopl.XUtil-  ( firstXfer, distributeXfer-  , distributeFact, distributeFactBwd-  , successorFacts-  , joinFacts-  , joinOutFacts -- deprecated-  , joinMaps-  , foldGraphNodes-  , foldBlockNodesF, foldBlockNodesB, foldBlockNodesF3, foldBlockNodesB3-  , tfFoldBlock-  , ScottBlock(ScottBlock), scottFoldBlock-  , fbnf3-  , blockToNodeList, blockOfNodeList-  , blockToNodeList'   -- alternate version using fold-  , blockToNodeList''  -- alternate version using scottFoldBlock-  , blockToNodeList''' -- alternate version using tfFoldBlock-  , analyzeAndRewriteFwdBody, analyzeAndRewriteBwdBody-  , analyzeAndRewriteFwdOx, analyzeAndRewriteBwdOx-  , noEntries-  , BlockResult(..), lookupBlock-  )-where--import qualified Data.Map as M-import Data.Maybe--import Compiler.Hoopl.Checkpoint-import Compiler.Hoopl.Collections-import Compiler.Hoopl.Dataflow-import Compiler.Hoopl.Graph-import Compiler.Hoopl.Label-import Compiler.Hoopl.Util----- | Forward dataflow analysis and rewriting for the special case of a Body.--- A set of entry points must be supplied; blocks not reachable from--- the set are thrown away.-analyzeAndRewriteFwdBody-   :: forall m n f entries. (CheckpointMonad m, NonLocal n, LabelsPtr entries)-   => FwdPass m n f-   -> entries -> Body n -> FactBase f-   -> m (Body n, FactBase f)---- | Backward dataflow analysis and rewriting for the special case of a Body.--- A set of entry points must be supplied; blocks not reachable from--- the set are thrown away.-analyzeAndRewriteBwdBody-   :: forall m n f entries. (CheckpointMonad m, NonLocal n, LabelsPtr entries)-   => BwdPass m n f -   -> entries -> Body n -> FactBase f -   -> m (Body n, FactBase f)--analyzeAndRewriteFwdBody pass en = mapBodyFacts (analyzeAndRewriteFwd pass (JustC en))-analyzeAndRewriteBwdBody pass en = mapBodyFacts (analyzeAndRewriteBwd pass (JustC en))--mapBodyFacts :: (Monad m)-    => (Graph n C C -> Fact C f   -> m (Graph n C C, Fact C f, MaybeO C f))-    -> (Body n      -> FactBase f -> m (Body n, FactBase f))--- ^ Internal utility; should not escape-mapBodyFacts anal b f = anal (GMany NothingO b NothingO) f >>= bodyFacts-  where -- the type constraint is needed for the pattern match;-        -- if it were not, we would use do-notation here.-    bodyFacts :: Monad m => (Graph n C C, Fact C f, MaybeO C f) -> m (Body n, Fact C f)-    bodyFacts (GMany NothingO body NothingO, fb, NothingO) = return (body, fb)--{--  Can't write:--     do (GMany NothingO body NothingO, fb, NothingO) <- anal (....) f-        return (body, fb)--  because we need an explicit type signature in order to do the GADT-  pattern matches on NothingO--}------ | Forward dataflow analysis and rewriting for the special case of a --- graph open at the entry.  This special case relieves the client--- from having to specify a type signature for 'NothingO', which beginners--- might find confusing and experts might find annoying.-analyzeAndRewriteFwdOx-   :: forall m n f x. (CheckpointMonad m, NonLocal n)-   => FwdPass m n f -> Graph n O x -> f -> m (Graph n O x, FactBase f, MaybeO x f)---- | Backward dataflow analysis and rewriting for the special case of a --- graph open at the entry.  This special case relieves the client--- from having to specify a type signature for 'NothingO', which beginners--- might find confusing and experts might find annoying.-analyzeAndRewriteBwdOx-   :: forall m n f x. (CheckpointMonad m, NonLocal n)-   => BwdPass m n f -> Graph n O x -> Fact x f -> m (Graph n O x, FactBase f, f)---- | A value that can be used for the entry point of a graph open at the entry.-noEntries :: MaybeC O Label-noEntries = NothingC--analyzeAndRewriteFwdOx pass g f  = analyzeAndRewriteFwd pass noEntries g f-analyzeAndRewriteBwdOx pass g fb = analyzeAndRewriteBwd pass noEntries g fb >>= strip-  where strip :: forall m a b c . Monad m => (a, b, MaybeO O c) -> m (a, b, c)-        strip (a, b, JustO c) = return (a, b, c)-------- | A utility function so that a transfer function for a first--- node can be given just a fact; we handle the lookup.  This--- function is planned to be made obsolete by changes in the dataflow--- interface.--firstXfer :: NonLocal n => (n C O -> f -> f) -> (n C O -> FactBase f -> f)-firstXfer xfer n fb = xfer n $ fromJust $ lookupFact (entryLabel n) fb---- | This utility function handles a common case in which a transfer function--- produces a single fact out of a last node, which is then distributed--- over the outgoing edges.-distributeXfer :: NonLocal n-               => DataflowLattice f -> (n O C -> f -> f) -> (n O C -> f -> FactBase f)-distributeXfer lattice xfer n f =-    mkFactBase lattice [ (l, xfer n f) | l <- successors n ]---- | This utility function handles a common case in which a transfer function--- for a last node takes the incoming fact unchanged and simply distributes--- that fact over the outgoing edges.-distributeFact :: NonLocal n => n O C -> f -> FactBase f-distributeFact n f = mapFromList [ (l, f) | l <- successors n ]-   -- because the same fact goes out on every edge,-   -- there's no need for 'mkFactBase' here.---- | This utility function handles a common case in which a backward transfer--- function takes the incoming fact unchanged and tags it with the node's label.-distributeFactBwd :: NonLocal n => n C O -> f -> FactBase f-distributeFactBwd n f = mapSingleton (entryLabel n) f---- | List of (unlabelled) facts from the successors of a last node-successorFacts :: NonLocal n => n O C -> FactBase f -> [f]-successorFacts n fb = [ f | id <- successors n, let Just f = lookupFact id fb ]---- | Join a list of facts.-joinFacts :: DataflowLattice f -> Label -> [f] -> f-joinFacts lat inBlock = foldr extend (fact_bot lat)-  where extend new old = snd $ fact_join lat inBlock (OldFact old) (NewFact new)--{-# DEPRECATED joinOutFacts-    "should be replaced by 'joinFacts lat l (successorFacts n f)'; as is, it uses the wrong Label" #-}--joinOutFacts :: (NonLocal node) => DataflowLattice f -> node O C -> FactBase f -> f-joinOutFacts lat n f = foldr join (fact_bot lat) facts-  where join (lbl, new) old = snd $ fact_join lat lbl (OldFact old) (NewFact new)-        facts = [(s, fromJust fact) | s <- successors n, let fact = lookupFact s f, isJust fact]----- | It's common to represent dataflow facts as a map from variables--- to some fact about the locations. For these maps, the join--- operation on the map can be expressed in terms of the join on each--- element of the codomain:-joinMaps :: Ord k => JoinFun v -> JoinFun (M.Map k v)-joinMaps eltJoin l (OldFact old) (NewFact new) = M.foldWithKey add (NoChange, old) new-  where -    add k new_v (ch, joinmap) =-      case M.lookup k joinmap of-        Nothing    -> (SomeChange, M.insert k new_v joinmap)-        Just old_v -> case eltJoin l (OldFact old_v) (NewFact new_v) of-                        (SomeChange, v') -> (SomeChange, M.insert k v' joinmap)-                        (NoChange,   _)  -> (ch, joinmap)------ | A fold function that relies on the IndexedCO type function.---   Note that the type parameter e is available to the functions---   that are applied to the middle and last nodes.-tfFoldBlock :: forall n bc bo c e x .-               ( n C O -> bc-               , n O O -> IndexedCO e bc bo -> IndexedCO e bc bo-               , n O C -> IndexedCO e bc bo -> c)-            -> (Block n e x -> bo -> IndexedCO x c (IndexedCO e bc bo))-tfFoldBlock (f, m, l) bl bo = block bl-  where block :: forall x . Block n e x -> IndexedCO x c (IndexedCO e bc bo)-        block (BFirst  n)       = f n-        block (BMiddle n)       = m n bo-        block (BLast   n)       = l n bo-        block (b1 `BCat`    b2) = oblock b2 $ block b1-        block (b1 `BClosed` b2) = oblock b2 $ block b1-        block (b1 `BHead` n)    = m n $ block b1-        block (n `BTail` b2)    = oblock b2 $ m n bo-        oblock :: forall x . Block n O x -> IndexedCO e bc bo -> IndexedCO x c (IndexedCO e bc bo)-        oblock (BMiddle n)       = m n-        oblock (BLast   n)       = l n-        oblock (b1 `BCat`    b2) = oblock b1 `cat` oblock b2-        oblock (n `BTail` b2)    = m n       `cat` oblock b2-        cat f f' = f' . f---type NodeList' e x n = (MaybeC e (n C O), [n O O], MaybeC x (n O C))-blockToNodeList''' ::-  forall n e x. ( IndexedCO e (NodeList' C O n) (NodeList' O O n) ~ NodeList' e O n-                , IndexedCO x (NodeList' e C n) (NodeList' e O n) ~ NodeList' e x n) =>-    Block n e x -> NodeList' e x n-blockToNodeList''' b = (h, reverse ms', t)-  where-    (h, ms', t) = tfFoldBlock (f, m, l) b z-    z :: NodeList' O O n-    z = (NothingC, [], NothingC)-    f :: n C O -> NodeList' C O n-    f n = (JustC n,  [], NothingC)-    m n (h, ms', t) = (h, n : ms', t)-    l n (h, ms', _) = (h, ms', JustC n)---{--data EitherCO' ex a b where-  LeftCO  :: a -> EitherCO' C a b-  RightCO :: b -> EitherCO' O a b--}--  -- should be done with a *backward* fold---- | More general fold--_unused :: Int-_unused = 3-  where _a = foldBlockNodesF3'' (Trips undefined undefined undefined)-        _b = foldBlockNodesF3'--data Trips n a b c = Trips { ff :: forall e . MaybeC e (n C O) -> a -> b-                           , fm :: n O O            -> b -> b-                           , fl :: forall x . MaybeC x (n O C) -> b -> c-                           }--foldBlockNodesF3'' :: forall n a b c .-                      Trips n a b c -> (forall e x . Block n e x -> a -> c)-foldBlockNodesF3'' trips = block-  where block :: Block n e x -> a -> c-        block (b1 `BClosed` b2) = foldCO b1 `cat` foldOC b2-        block (BFirst  node)    = ff trips (JustC node)  `cat` missingLast-        block (b @ BHead {})    = foldCO b `cat` missingLast-        block (BMiddle node)    = missingFirst `cat` fm trips node  `cat` missingLast-        block (b @ BCat {})     = missingFirst `cat` foldOO b `cat` missingLast-        block (BLast   node)    = missingFirst `cat` fl trips (JustC node)-        block (b @ BTail {})    = missingFirst `cat` foldOC b-        missingLast = fl trips NothingC-        missingFirst = ff trips NothingC-        foldCO :: Block n C O -> a -> b-        foldOO :: Block n O O -> b -> b-        foldOC :: Block n O C -> b -> c-        foldCO (BFirst n)   = ff trips (JustC n)-        foldCO (BHead b n)  = foldCO b `cat` fm trips n-        foldOO (BMiddle n)  = fm trips n-        foldOO (BCat b1 b2) = foldOO b1 `cat` foldOO b2-        foldOC (BLast n)    = fl trips (JustC n)-        foldOC (BTail n b)  = fm trips n `cat` foldOC b-        f `cat` g = g . f --data ScottBlock n a = ScottBlock-   { sb_first :: n C O -> a C O-   , sb_mid   :: n O O -> a O O-   , sb_last  :: n O C -> a O C-   , sb_cat   :: forall e x . a e O -> a O x -> a e x-   }--scottFoldBlock :: forall n a e x . ScottBlock n a -> Block n e x -> a e x-scottFoldBlock funs = block-  where block :: forall e x . Block n e x -> a e x-        block (BFirst n)  = sb_first  funs n-        block (BMiddle n) = sb_mid    funs n-        block (BLast   n) = sb_last   funs n-        block (BClosed b1 b2) = block b1 `cat` block b2-        block (BCat    b1 b2) = block b1 `cat` block b2-        block (BHead   b  n)  = block b  `cat` sb_mid funs n-        block (BTail   n  b)  = sb_mid funs n `cat` block b-        cat = sb_cat funs--newtype NodeList n e x-    = NL { unList :: (MaybeC e (n C O), [n O O] -> [n O O], MaybeC x (n O C)) }--fbnf3 :: forall n a b c .-         ( n C O       -> a -> b-         , n O O       -> b -> b-         , n O C       -> b -> c)-      -> (forall e x . Block n e x -> IndexedCO e a b -> IndexedCO x c b)-fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) block-    where f n = FF3 $ ff n-          m n = FF3 $ fm n-          l n = FF3 $ fl n-          FF3 f `cat` FF3 f' = FF3 $ f' . f--newtype FF3 a b c e x = FF3 { unFF3 :: IndexedCO e a b -> IndexedCO x c b }--blockToNodeList'' :: Block n e x -> (MaybeC e (n C O), [n O O], MaybeC x (n O C))-blockToNodeList'' = finish . unList . scottFoldBlock (ScottBlock f m l cat)-    where f n = NL (JustC n, id, NothingC)-          m n = NL (NothingC, (n:), NothingC)-          l n = NL (NothingC, id, JustC n)-          cat :: NodeList n e O -> NodeList n O x -> NodeList n e x-          NL (e, ms, NothingC) `cat` NL (NothingC, ms', x) = NL (e, ms . ms', x)-          finish (e, ms, x) = (e, ms [], x)----blockToNodeList' :: Block n e x -> (MaybeC e (n C O), [n O O], MaybeC x (n O C))-blockToNodeList' b = unFNL $ foldBlockNodesF3''' ff fm fl b ()-  where ff n () = PNL (n, [])-        fm n (PNL (first, mids')) = PNL (first, n : mids')-        fl n (PNL (first, mids')) = FNL (first, reverse mids', n)--   -- newtypes for 'partial node list' and 'final node list'-newtype PNL n e   = PNL (MaybeC e (n C O), [n O O])-newtype FNL n e x = FNL {unFNL :: (MaybeC e (n C O), [n O O], MaybeC x (n O C))}--foldBlockNodesF3''' :: forall n a b c .-                       (forall e   . MaybeC e (n C O) -> a   -> b e)-                    -> (forall e   .           n O O  -> b e -> b e)-                    -> (forall e x . MaybeC x (n O C) -> b e -> c e x)-                    -> (forall e x . Block n e x      -> a   -> c e x)-foldBlockNodesF3''' ff fm fl = block-  where block   :: forall e x . Block n e x -> a   -> c e x-        blockCO ::              Block n C O -> a   -> b C-        blockOO :: forall e .   Block n O O -> b e -> b e-        blockOC :: forall e .   Block n O C -> b e -> c e C-        block (b1 `BClosed` b2) = blockCO b1       `cat` blockOC b2-        block (BFirst  node)    = ff (JustC node)  `cat` fl NothingC-        block (b @ BHead {})    = blockCO b        `cat` fl NothingC-        block (BMiddle node)    = ff NothingC `cat` fm node   `cat` fl NothingC-        block (b @ BCat {})     = ff NothingC `cat` blockOO b `cat` fl NothingC-        block (BLast   node)    = ff NothingC `cat` fl (JustC node)-        block (b @ BTail {})    = ff NothingC `cat` blockOC b-        blockCO (BFirst n)      = ff (JustC n)-        blockCO (BHead b n)     = blockCO b `cat` fm n-        blockOO (BMiddle n)     = fm n-        blockOO (BCat b1 b2)    = blockOO b1 `cat` blockOO b2-        blockOC (BLast n)       = fl (JustC n)-        blockOC (BTail n b)     = fm n `cat` blockOC b-        f `cat` g = g . f ----- | The following function is easy enough to define but maybe not so useful-foldBlockNodesF3' :: forall n a b c .-                   ( n C O -> a -> b-                   , n O O -> b -> b-                   , n O C -> b -> c)-                   -> (a -> b) -- called iff there is no first node-                   -> (b -> c) -- called iff there is no last node-                   -> (forall e x . Block n e x -> a -> c)-foldBlockNodesF3' (ff, fm, fl) missingFirst missingLast = block-  where block   :: forall e x . Block n e x -> a -> c-        blockCO ::              Block n C O -> a -> b-        blockOO ::              Block n O O -> b -> b-        blockOC ::              Block n O C -> b -> c-        block (b1 `BClosed` b2) = blockCO b1 `cat` blockOC b2-        block (BFirst  node)    = ff node  `cat` missingLast-        block (b @ BHead {})    = blockCO b `cat` missingLast-        block (BMiddle node)    = missingFirst `cat` fm node  `cat` missingLast-        block (b @ BCat {})     = missingFirst `cat` blockOO b `cat` missingLast-        block (BLast   node)    = missingFirst `cat` fl node-        block (b @ BTail {})    = missingFirst `cat` blockOC b-        blockCO (BFirst n)   = ff n-        blockCO (BHead b n)  = blockCO b `cat` fm n-        blockOO (BMiddle n)  = fm n-        blockOO (BCat b1 b2) = blockOO b1 `cat` blockOO b2-        blockOC (BLast n)    = fl n-        blockOC (BTail n b)  = fm n `cat` blockOC b-        f `cat` g = g . f ---- | Fold a function over every node in a block, forward or backward.--- The fold function must be polymorphic in the shape of the nodes.-foldBlockNodesF3 :: forall n a b c .-                   ( n C O       -> a -> b-                   , n O O       -> b -> b-                   , n O C       -> b -> c)-                 -> (forall e x . Block n e x -> IndexedCO e a b -> IndexedCO x c b)-foldBlockNodesF  :: forall n a .-                    (forall e x . n e x       -> a -> a)-                 -> (forall e x . Block n e x -> IndexedCO e a a -> IndexedCO x a a)-foldBlockNodesB3 :: forall n a b c .-                   ( n C O       -> b -> c-                   , n O O       -> b -> b-                   , n O C       -> a -> b)-                 -> (forall e x . Block n e x -> IndexedCO x a b -> IndexedCO e c b)-foldBlockNodesB  :: forall n a .-                    (forall e x . n e x       -> a -> a)-                 -> (forall e x . Block n e x -> IndexedCO x a a -> IndexedCO e a a)--- | Fold a function over every node in a graph.--- The fold function must be polymorphic in the shape of the nodes.--foldGraphNodes :: forall n a .-                  (forall e x . n e x       -> a -> a)-               -> (forall e x . Graph n e x -> a -> a)---foldBlockNodesF3 (ff, fm, fl) = block-  where block :: forall e x . Block n e x -> IndexedCO e a b -> IndexedCO x c b-        block (BFirst  node)    = ff node-        block (BMiddle node)    = fm node-        block (BLast   node)    = fl node-        block (b1 `BCat`    b2) = block b1 `cat` block b2-        block (b1 `BClosed` b2) = block b1 `cat` block b2-        block (b1 `BHead` n)    = block b1 `cat` fm n-        block (n `BTail` b2)    = fm n `cat` block b2-        cat f f' = f' . f-foldBlockNodesF f = foldBlockNodesF3 (f, f, f)--foldBlockNodesB3 (ff, fm, fl) = block-  where block :: forall e x . Block n e x -> IndexedCO x a b -> IndexedCO e c b-        block (BFirst  node)    = ff node-        block (BMiddle node)    = fm node-        block (BLast   node)    = fl node-        block (b1 `BCat`    b2) = block b1 `cat` block b2-        block (b1 `BClosed` b2) = block b1 `cat` block b2-        block (b1 `BHead` n)    = block b1 `cat` fm n-        block (n `BTail` b2)    = fm n `cat` block b2-        cat f f' = f . f'-foldBlockNodesB f = foldBlockNodesB3 (f, f, f)---foldGraphNodes f = graph-    where graph :: forall e x . Graph n e x -> a -> a-          lift  :: forall thing ex . (thing -> a -> a) -> (MaybeO ex thing -> a -> a)--          graph GNil              = id-          graph (GUnit b)         = block b-          graph (GMany e b x)     = lift block e . body b . lift block x-          body :: Body n -> a -> a-          body bdy                = \a -> mapFold block a bdy-          lift _ NothingO         = id-          lift f (JustO thing)    = f thing--          block = foldBlockNodesF f--{-# DEPRECATED blockToNodeList, blockOfNodeList -  "What justifies these functions?  Can they be eliminated?  Replaced with folds?" #-}------ | Convert a block to a list of nodes. The entry and exit node--- is or is not present depending on the shape of the block.------ The blockToNodeList function cannot be currently expressed using--- foldBlockNodesB, because it returns IndexedCO e a b, which means--- two different types depending on the shape of the block entry.--- But blockToNodeList returns one of four possible types, depending--- on the shape of the block entry *and* exit.-blockToNodeList :: Block n e x -> (MaybeC e (n C O), [n O O], MaybeC x (n O C))-blockToNodeList block = case block of-  BFirst n    -> (JustC n, [], NothingC)-  BMiddle n   -> (NothingC, [n], NothingC)-  BLast n     -> (NothingC, [], JustC n)-  BCat {}     -> (NothingC, foldOO block [], NothingC)-  BHead x n   -> case foldCO x [n] of (f, m) -> (f, m, NothingC)-  BTail n x   -> case foldOC x of (m, l) -> (NothingC, n : m, l)-  BClosed x y -> case foldOC y of (m, l) -> case foldCO x m of (f, m') -> (f, m', l)-  where foldCO :: Block n C O -> [n O O] -> (MaybeC C (n C O), [n O O])-        foldCO (BFirst n) m  = (JustC n, m)-        foldCO (BHead x n) m = foldCO x (n : m)--        foldOO :: Block n O O -> [n O O] -> [n O O]-        foldOO (BMiddle n) acc = n : acc-        foldOO (BCat x y) acc  = foldOO x $ foldOO y acc--        foldOC :: Block n O C -> ([n O O], MaybeC C (n O C))-        foldOC (BLast n)   = ([], JustC n)-        foldOC (BTail n x) = case foldOC x of (m, l) -> (n : m, l)---- | Convert a list of nodes to a block. The entry and exit node--- must or must not be present depending on the shape of the block.-blockOfNodeList :: (MaybeC e (n C O), [n O O], MaybeC x (n O C)) -> Block n e x-blockOfNodeList (NothingC, [], NothingC) = error "No nodes to created block from in blockOfNodeList"-blockOfNodeList (NothingC, m, NothingC)  = foldr1 BCat (map BMiddle m)-blockOfNodeList (NothingC, m, JustC l)   = foldr BTail (BLast l) m-blockOfNodeList (JustC f, m, NothingC)   = foldl BHead (BFirst f) m-blockOfNodeList (JustC f, m, JustC l)    = BClosed (BFirst f) $ foldr BTail (BLast l) m--data BlockResult n x where-  NoBlock   :: BlockResult n x-  BodyBlock :: Block n C C -> BlockResult n x-  ExitBlock :: Block n C O -> BlockResult n O--lookupBlock :: NonLocal n => Graph n e x -> Label -> BlockResult n x-lookupBlock (GMany _ _ (JustO exit)) lbl-  | entryLabel exit == lbl = ExitBlock exit-lookupBlock (GMany _ body _) lbl =-  case mapLookup lbl body of-    Just b  -> BodyBlock b-    Nothing -> NoBlock-lookupBlock GNil      _ = NoBlock-lookupBlock (GUnit _) _ = NoBlock
README view
@@ -1,35 +1,30 @@-This is Hoopl, a higher-order optimization library.-There are two unpublished papers describing Hoopl:+This repository contains things related to -  Hoopl: Dataflow Optimization Made Simple-  Hoopl: A Modular, Reusable Library for Dataflow Analysis and Transformation+              Hoopl: A Higher-Order OPtimization Library -The second such paper is attached to this package.+** The closest thing we have to a SAMPLE CLIENT is in ./testing ** -The version number is split into four parts:+Directory     Contents -  3.   Third major body plan (phylum)-  7.   Seventh iteration (roughly) of data structures-  2.   Major version; changes when clients must change-  1.   Minor version; changes when clients can stay the same+paper/        A paper about Hoopl+prototypes/   A sampling of prototypes and early designs+src/          The current official sources to the Cabal package+testing/      Tests, including a sample client.  See ./testing/README. +To build the library, change to the src directory and run -Version 3.7.3.3 has fixed known bugs.+  cabal configure --prefix=$HOME --user   # we have no idea what this means+  cabal build+  cabal install --enable-documentation -Version 3.7.8.0 will be the last version uploaded to Hackage for some time.-This library is undergoing *very* rapid development, and we ask that you-get the most recent version from our public git repository:+You'll need a Haskell Platform, which should include appropriate+versions of Cabal and GHC. -  git clone -o tufts git://ghc.cs.tufts.edu/hoopl/hoopl.git+To upload to Hackage, -If you are not familiar with git, we recommend the tutorial 'Git Magic'-by Ben Lynn.  To get some ideas about how to use git effectively,+  cabal sdist+  cabal upload dist/something.tar.gz -  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,6 +1,7 @@ Name:                hoopl-Version:             3.8.6.0+Version:             3.8.7.0 -- version 3.8.6.0 is the version that goes with the camera-ready Haskell'10 paper+-- version 3.8.7.0 works with GHC 7 Description:         Higher-order optimization library License:             BSD3 License-file:        LICENSE@@ -42,6 +43,7 @@                        Compiler.Hoopl.Util                        Compiler.Hoopl.XUtil   ghc-options:       -Wall -fno-warn-name-shadowing+  hs-source-dirs:  src   Source-repository head
hoopl.pdf view

binary file changed (216881 → 279781 bytes)

+ src/Compiler/Hoopl.hs view
@@ -0,0 +1,37 @@+module Compiler.Hoopl+  ( module Compiler.Hoopl.Graph+  , module Compiler.Hoopl.MkGraph+  , module Compiler.Hoopl.XUtil+  , module Compiler.Hoopl.Collections+  , module Compiler.Hoopl.Checkpoint+  , module Compiler.Hoopl.Dataflow+  , module Compiler.Hoopl.Label+  , module Compiler.Hoopl.Pointed+  , module Compiler.Hoopl.Combinators+  , module Compiler.Hoopl.Fuel+  , module Compiler.Hoopl.Unique+  , module Compiler.Hoopl.Util+  , module Compiler.Hoopl.Debug+  , module Compiler.Hoopl.Show+  )+where++import Compiler.Hoopl.Checkpoint+import Compiler.Hoopl.Collections+import Compiler.Hoopl.Combinators+import Compiler.Hoopl.Dataflow hiding ( wrapFR, wrapFR2, wrapBR, wrapBR2+                                      )+import Compiler.Hoopl.Debug+import Compiler.Hoopl.Fuel hiding (withFuel, getFuel, setFuel, FuelMonadT)+import Compiler.Hoopl.Graph hiding +   ( Body+   , BCat, BHead, BTail, BClosed -- OK to expose BFirst, BMiddle, BLast+   )+import Compiler.Hoopl.Graph (Body)+import Compiler.Hoopl.Label hiding (uniqueToLbl, lblToUnique)+import Compiler.Hoopl.MkGraph+import Compiler.Hoopl.Pointed+import Compiler.Hoopl.Show+import Compiler.Hoopl.Util+import Compiler.Hoopl.Unique hiding (uniqueToInt)+import Compiler.Hoopl.XUtil
+ src/Compiler/Hoopl/Checkpoint.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE TypeFamilies #-}++module Compiler.Hoopl.Checkpoint+  ( CheckpointMonad(..)+  )+where++-- | Obeys the following law:+-- for all @m@ +-- @+--    do { s <- checkpoint; m; restart s } == return ()+-- @+class Monad m => CheckpointMonad m where+  type Checkpoint m+  checkpoint :: m (Checkpoint m)+  restart    :: Checkpoint m -> m () +
+ src/Compiler/Hoopl/Collections.hs view
@@ -0,0 +1,85 @@+{- Baseclasses for Map-like and Set-like collections inspired by containers. -}++{-# LANGUAGE TypeFamilies #-}+module Compiler.Hoopl.Collections ( IsSet(..)+                                  , setInsertList, setDeleteList, setUnions+                                  , IsMap(..)+                                  , mapInsertList, mapDeleteList, mapUnions+                                  ) where++import Data.List (foldl', foldl1')++class IsSet set where+  type ElemOf set++  setNull :: set -> Bool+  setSize :: set -> Int+  setMember :: ElemOf set -> set -> Bool++  setEmpty :: set+  setSingleton :: ElemOf set -> set+  setInsert :: ElemOf set -> set -> set+  setDelete :: ElemOf set -> set -> set++  setUnion :: set -> set -> set+  setDifference :: set -> set -> set+  setIntersection :: set -> set -> set+  setIsSubsetOf :: set -> set -> Bool++  setFold :: (ElemOf set -> b -> b) -> b -> set -> b++  setElems :: set -> [ElemOf set]+  setFromList :: [ElemOf set] -> set++-- Helper functions for IsSet class+setInsertList :: IsSet set => [ElemOf set] -> set -> set+setInsertList keys set = foldl' (flip setInsert) set keys++setDeleteList :: IsSet set => [ElemOf set] -> set -> set+setDeleteList keys set = foldl' (flip setDelete) set keys++setUnions :: IsSet set => [set] -> set+setUnions [] = setEmpty+setUnions sets = foldl1' setUnion sets+++class IsMap map where+  type KeyOf map++  mapNull :: map a -> Bool+  mapSize :: map a -> Int+  mapMember :: KeyOf map -> map a -> Bool+  mapLookup :: KeyOf map -> map a -> Maybe a+  mapFindWithDefault :: a -> KeyOf map -> map a -> a++  mapEmpty :: map a+  mapSingleton :: KeyOf map -> a -> map a+  mapInsert :: KeyOf map -> a -> map a -> map a+  mapDelete :: KeyOf map -> map a -> map a++  mapUnion :: map a -> map a -> map a+  mapUnionWithKey :: (KeyOf map -> a -> a -> a) -> map a -> map a -> map a+  mapDifference :: map a -> map a -> map a+  mapIntersection :: map a -> map a -> map a+  mapIsSubmapOf :: Eq a => map a -> map a -> Bool++  mapMap :: (a -> b) -> map a -> map b+  mapMapWithKey :: (KeyOf map -> a -> b) -> map a -> map b+  mapFold :: (a -> b -> b) -> b -> map a -> b+  mapFoldWithKey :: (KeyOf map -> a -> b -> b) -> b -> map a -> b++  mapElems :: map a -> [a]+  mapKeys :: map a -> [KeyOf map]+  mapToList :: map a -> [(KeyOf map, a)]+  mapFromList :: [(KeyOf map, a)] -> map a++-- Helper functions for IsMap class+mapInsertList :: IsMap map => [(KeyOf map, a)] -> map a -> map a+mapInsertList assocs map = foldl' (flip (uncurry mapInsert)) map assocs++mapDeleteList :: IsMap map => [KeyOf map] -> map a -> map a+mapDeleteList keys map = foldl' (flip mapDelete) map keys++mapUnions :: IsMap map => [map a] -> map a+mapUnions [] = mapEmpty+mapUnions maps = foldl1' mapUnion maps
+ src/Compiler/Hoopl/Combinators.hs view
@@ -0,0 +1,232 @@+{-# LANGUAGE RankNTypes, LiberalTypeSynonyms, ScopedTypeVariables, GADTs #-}++module Compiler.Hoopl.Combinators+  ( thenFwdRw+  , deepFwdRw3, deepFwdRw, iterFwdRw+  , thenBwdRw+  , deepBwdRw3, deepBwdRw, iterBwdRw+  , pairFwd, pairBwd, pairLattice+  )++where++import Control.Monad+import Data.Maybe++import Compiler.Hoopl.Collections+import Compiler.Hoopl.Dataflow+import Compiler.Hoopl.Fuel+import Compiler.Hoopl.Graph (Graph, C, O, Shape(..))+import Compiler.Hoopl.Label++----------------------------------------------------------------++deepFwdRw3 :: FuelMonad m+           => (n C O -> f -> m (Maybe (Graph n C O)))+           -> (n O O -> f -> m (Maybe (Graph n O O)))+           -> (n O C -> f -> m (Maybe (Graph n O C)))+           -> (FwdRewrite m n f)+deepFwdRw :: FuelMonad m+          => (forall e x . n e x -> f -> m (Maybe (Graph n e x))) -> FwdRewrite m n f+deepFwdRw3 f m l = iterFwdRw $ mkFRewrite3 f m l+deepFwdRw f = deepFwdRw3 f f f++-- N.B. rw3, rw3', and rw3a are triples of functions.+-- But rw and rw' are single functions.+-- @ start comb1.tex+thenFwdRw :: forall m n f. Monad m +          => FwdRewrite m n f +          -> FwdRewrite m n f +          -> FwdRewrite m n f+-- @ end comb1.tex+thenFwdRw rw3 rw3' = wrapFR2 thenrw rw3 rw3'+ where+  thenrw :: forall m1 e x t t1.+            Monad m1 =>+            (t -> t1 -> m1 (Maybe (Graph n e x, FwdRewrite m n f)))+            -> (t -> t1 -> m1 (Maybe (Graph n e x, FwdRewrite m n f)))+            -> t+            -> t1+            -> m1 (Maybe (Graph n e x, FwdRewrite m n f))+  thenrw rw rw' n f = rw n f >>= fwdRes+     where fwdRes Nothing   = rw' n f+           fwdRes (Just gr) = return $ Just $ fadd_rw rw3' gr++-- @ start iterf.tex+iterFwdRw :: forall m n f. Monad m +          => FwdRewrite m n f +          -> FwdRewrite m n f+-- @ end iterf.tex+iterFwdRw rw3 = wrapFR iter rw3+ where iter :: forall a m1 m2 e x t.+               (Monad m2, Monad m1) =>+               (t -> a -> m1 (m2 (Graph n e x, FwdRewrite m n f)))+               -> t+               -> a+               -> m1 (m2 (Graph n e x, FwdRewrite m n f))+       iter rw n = (liftM $ liftM $ fadd_rw (iterFwdRw rw3)) . rw n++-- | Function inspired by 'rew' in the paper+_frewrite_cps :: Monad m+             => ((Graph n e x, FwdRewrite m n f) -> m a)+             -> m a+             -> (forall e x . n e x -> f -> m (Maybe (Graph n e x, FwdRewrite m n f)))+             -> n e x+             -> f+             -> m a+_frewrite_cps j n rw node f =+    do mg <- rw node f+       case mg of Nothing -> n+                  Just gr -> j gr++++-- | Function inspired by 'add' in the paper+fadd_rw :: Monad m+       => FwdRewrite m n f+       -> (Graph n e x, FwdRewrite m n f)+       -> (Graph n e x, FwdRewrite m n f)+fadd_rw rw2 (g, rw1) = (g, rw1 `thenFwdRw` rw2)++----------------------------------------------------------------++deepBwdRw3 :: FuelMonad m+           => (n C O -> f          -> m (Maybe (Graph n C O)))+           -> (n O O -> f          -> m (Maybe (Graph n O O)))+           -> (n O C -> FactBase f -> m (Maybe (Graph n O C)))+           -> (BwdRewrite m n f)+deepBwdRw  :: FuelMonad m+           => (forall e x . n e x -> Fact x f -> m (Maybe (Graph n e x)))+           -> BwdRewrite m n f+deepBwdRw3 f m l = iterBwdRw $ mkBRewrite3 f m l+deepBwdRw  f = deepBwdRw3 f f f+++thenBwdRw :: forall m n f. Monad m => BwdRewrite m n f -> BwdRewrite m n f -> BwdRewrite m n f+thenBwdRw rw1 rw2 = wrapBR2 f rw1 rw2+  where f :: forall t t1 t2 m1 e x.+             Monad m1 =>+             t+             -> (t1 -> t2 -> m1 (Maybe (Graph n e x, BwdRewrite m n f)))+             -> (t1 -> t2 -> m1 (Maybe (Graph n e x, BwdRewrite m n f)))+             -> t1+             -> t2+             -> m1 (Maybe (Graph n e x, BwdRewrite m n f))+        f _ rw1 rw2' n f = do+          res1 <- rw1 n f+          case res1 of+            Nothing -> rw2' n f+            Just gr -> return $ Just $ badd_rw rw2 gr++iterBwdRw :: forall m n f. Monad m => BwdRewrite m n f -> BwdRewrite m n f+iterBwdRw rw = wrapBR f rw+  where f :: forall t m1 m2 e x t1 t2.+             (Monad m2, Monad m1) =>+             t+             -> (t1 -> t2 -> m1 (m2 (Graph n e x, BwdRewrite m n f)))+             -> t1+             -> t2+             -> m1 (m2 (Graph n e x, BwdRewrite m n f))+        f _ rw' n f = liftM (liftM (badd_rw (iterBwdRw rw))) (rw' n f)++-- | Function inspired by 'add' in the paper+badd_rw :: Monad m+       => BwdRewrite m n f+       -> (Graph n e x, BwdRewrite m n f)+       -> (Graph n e x, BwdRewrite m n f)+badd_rw rw2 (g, rw1) = (g, rw1 `thenBwdRw` rw2)+++-- @ start pairf.tex+pairFwd :: forall m n f f'. Monad m+        => FwdPass m n f+        -> FwdPass m n f' +        -> FwdPass m n (f, f')+-- @ end pairf.tex+pairFwd pass1 pass2 = FwdPass lattice transfer rewrite+  where+    lattice = pairLattice (fp_lattice pass1) (fp_lattice pass2)+    transfer = mkFTransfer3 (tf tf1 tf2) (tf tm1 tm2) (tfb tl1 tl2)+      where+        tf :: forall t t1 t2 t3 t4.+              (t4 -> t -> t2) -> (t4 -> t1 -> t3) -> t4 -> (t, t1) -> (t2, t3)+        tf  t1 t2 n (f1, f2) = (t1 n f1, t2 n f2)+        tfb t1 t2 n (f1, f2) = mapMapWithKey withfb2 fb1+          where fb1 = t1 n f1+                fb2 = t2 n f2+                withfb2 :: forall t. Label -> t -> (t, f')+                withfb2 l f = (f, fromMaybe bot2 $ lookupFact l fb2)+                bot2 = fact_bot (fp_lattice pass2)+        (tf1, tm1, tl1) = getFTransfer3 (fp_transfer pass1)+        (tf2, tm2, tl2) = getFTransfer3 (fp_transfer pass2)+    rewrite = lift fst (fp_rewrite pass1) `thenFwdRw` lift snd (fp_rewrite pass2) +      where+        lift :: forall f m' n' f'.+                Monad m' =>+                (f' -> f) -> FwdRewrite m' n' f -> FwdRewrite m' n' f'+        lift proj = wrapFR project+          where project :: forall m m1 t t1.+                          (Monad m1, Monad m) =>+                          (t1 -> f -> m (m1 (t, FwdRewrite m' n' f)))+                          -> t1+                          -> f'+                          -> m (m1 (t, FwdRewrite m' n' f'))+                project rw = \n pair -> liftM (liftM repair) $ rw n (proj pair)+                repair :: forall t.+                          (t, FwdRewrite m' n' f) -> (t, FwdRewrite m' n' f')+                repair (g, rw') = (g, lift proj rw')++pairBwd :: forall m n f f' . +           Monad m => BwdPass m n f -> BwdPass m n f' -> BwdPass m n (f, f')+pairBwd pass1 pass2 = BwdPass lattice transfer rewrite+  where+    lattice = pairLattice (bp_lattice pass1) (bp_lattice pass2)+    transfer = mkBTransfer3 (tf tf1 tf2) (tf tm1 tm2) (tfb tl1 tl2)+      where+        tf :: (t4 -> t -> t2) -> (t4 -> t1 -> t3) -> t4 -> (t, t1) -> (t2, t3)+        tf  t1 t2 n (f1, f2) = (t1 n f1, t2 n f2)+        tfb :: IsMap map =>+               (t2 -> map a -> t)+               -> (t2 -> map b -> t1)+               -> t2+               -> map (a, b)+               -> (t, t1)+        tfb t1 t2 n fb = (t1 n $ mapMap fst fb, t2 n $ mapMap snd fb)+        (tf1, tm1, tl1) = getBTransfer3 (bp_transfer pass1)+        (tf2, tm2, tl2) = getBTransfer3 (bp_transfer pass2)+    rewrite = lift fst (bp_rewrite pass1) `thenBwdRw` lift snd (bp_rewrite pass2) +      where+       lift :: forall f1 .+                ((f, f') -> f1) -> BwdRewrite m n f1 -> BwdRewrite m n (f, f')+       lift proj = wrapBR project+        where project :: forall e x . Shape x +               -> (n e x ->+                       Fact x f1     -> m (Maybe (Graph n e x, BwdRewrite m n f1)))+               -> (n e x ->+                       Fact x (f,f') -> m (Maybe (Graph n e x, BwdRewrite m n (f,f'))))+              project Open = +                 \rw n pair -> liftM (liftM repair) $ rw n (       proj pair)+              project Closed = +                 \rw n pair -> liftM (liftM repair) $ rw n (mapMap proj pair)+              repair :: forall t.+                        (t, BwdRewrite m n f1) -> (t, BwdRewrite m n (f, f'))+              repair (g, rw') = (g, lift proj rw')+                -- XXX specialize repair so that the cost+                -- of discriminating is one per combinator not one+                -- per rewrite++pairLattice :: forall f f' .+               DataflowLattice f -> DataflowLattice f' -> DataflowLattice (f, f')+pairLattice l1 l2 =+  DataflowLattice+    { fact_name = fact_name l1 ++ " x " ++ fact_name l2+    , fact_bot  = (fact_bot l1, fact_bot l2)+    , fact_join = join+    }+  where+    join lbl (OldFact (o1, o2)) (NewFact (n1, n2)) = (c', (f1, f2))+      where (c1, f1) = fact_join l1 lbl (OldFact o1) (NewFact n1)+            (c2, f2) = fact_join l2 lbl (OldFact o2) (NewFact n2)+            c' = case (c1, c2) of+                   (NoChange, NoChange) -> NoChange+                   _                    -> SomeChange
+ src/Compiler/Hoopl/Dataflow.hs view
@@ -0,0 +1,821 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables, GADTs, EmptyDataDecls, PatternGuards, TypeFamilies, MultiParamTypeClasses #-}++module Compiler.Hoopl.Dataflow+  ( DataflowLattice(..), JoinFun, OldFact(..), NewFact(..), Fact, mkFactBase+  , ChangeFlag(..), changeIf+  , FwdPass(..), FwdTransfer, mkFTransfer, mkFTransfer3, getFTransfer3+  -- * Respecting Fuel++  -- $fuel+  , FwdRewrite,  mkFRewrite,  mkFRewrite3,  getFRewrite3, noFwdRewrite+  , wrapFR, wrapFR2+  , BwdPass(..), BwdTransfer, mkBTransfer, mkBTransfer3, getBTransfer3+  , wrapBR, wrapBR2+  , BwdRewrite,  mkBRewrite,  mkBRewrite3,  getBRewrite3, noBwdRewrite+  , analyzeAndRewriteFwd,  analyzeAndRewriteBwd+  )+where++import Control.Monad+import Data.Maybe++import Compiler.Hoopl.Checkpoint+import Compiler.Hoopl.Collections+import Compiler.Hoopl.Fuel+import Compiler.Hoopl.Graph hiding (Graph) -- hiding so we can redefine+                                           -- and include definition in paper+import qualified Compiler.Hoopl.GraphUtil as U+import Compiler.Hoopl.Label+import Compiler.Hoopl.Util++-----------------------------------------------------------------------------+--              DataflowLattice+-----------------------------------------------------------------------------++data DataflowLattice a = DataflowLattice  + { fact_name       :: String          -- Documentation+ , fact_bot        :: a               -- Lattice bottom element+ , fact_join       :: JoinFun a       -- Lattice join plus change flag+                                      -- (changes iff result > old fact)+ }+-- ^ A transfer function might want to use the logging flag+-- to control debugging, as in for example, it updates just one element+-- in a big finite map.  We don't want Hoopl to show the whole fact,+-- and only the transfer function knows exactly what changed.++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 deriving (Eq, Ord)+changeIf :: Bool -> ChangeFlag+changeIf changed = if changed then SomeChange else NoChange+++-- | 'mkFactBase' creates a 'FactBase' from a list of ('Label', fact)+-- pairs.  If the same label appears more than once, the relevant facts+-- are joined.++mkFactBase :: forall f. DataflowLattice f -> [(Label, f)] -> FactBase f+mkFactBase lattice = foldl add mapEmpty+  where add :: FactBase f -> (Label, f) -> FactBase f+        add map (lbl, f) = mapInsert lbl newFact map+          where newFact = case mapLookup lbl map of+                            Nothing -> f+                            Just f' -> snd $ join lbl (OldFact f') (NewFact f)+                join = fact_join lattice+++-----------------------------------------------------------------------------+--              Analyze and rewrite forward: the interface+-----------------------------------------------------------------------------++data FwdPass m n f+  = FwdPass { fp_lattice  :: DataflowLattice f+            , fp_transfer :: FwdTransfer n f+            , fp_rewrite  :: FwdRewrite m n f }++newtype FwdTransfer n f +  = FwdTransfer3 { getFTransfer3 ::+                     ( n C O -> f -> f+                     , n O O -> f -> f+                     , n O C -> f -> FactBase f+                     ) }++newtype FwdRewrite m n f   -- see Note [Respects Fuel]+  = FwdRewrite3 { getFRewrite3 ::+                    ( n C O -> f -> m (Maybe (Graph n C O, FwdRewrite m n f))+                    , n O O -> f -> m (Maybe (Graph n O O, FwdRewrite m n f))+                    , n O C -> f -> m (Maybe (Graph n O C, FwdRewrite m n f))+                    ) }++wrapFR :: (forall e x. (n  e x -> f  -> m  (Maybe (Graph n  e x, FwdRewrite m  n  f )))+                    -> (n' e x -> f' -> m' (Maybe (Graph n' e x, FwdRewrite m' n' f')))+          )+            -- ^ This argument may assume that any function passed to it+            -- respects fuel, and it must return a result that respects fuel.+       -> FwdRewrite m  n  f +       -> FwdRewrite m' n' f'      -- see Note [Respects Fuel]+wrapFR wrap (FwdRewrite3 (f, m, l)) = FwdRewrite3 (wrap f, wrap m, wrap l)+wrapFR2 +  :: (forall e x . (n1 e x -> f1 -> m1 (Maybe (Graph n1 e x, FwdRewrite m1 n1 f1))) ->+                   (n2 e x -> f2 -> m2 (Maybe (Graph n2 e x, FwdRewrite m2 n2 f2))) ->+                   (n3 e x -> f3 -> m3 (Maybe (Graph n3 e x, FwdRewrite m3 n3 f3)))+     )+            -- ^ This argument may assume that any function passed to it+            -- respects fuel, and it must return a result that respects fuel.+  -> FwdRewrite m1 n1 f1+  -> FwdRewrite m2 n2 f2+  -> FwdRewrite m3 n3 f3      -- see Note [Respects Fuel]+wrapFR2 wrap2 (FwdRewrite3 (f1, m1, l1)) (FwdRewrite3 (f2, m2, l2)) =+    FwdRewrite3 (wrap2 f1 f2, wrap2 m1 m2, wrap2 l1 l2)+++mkFTransfer3 :: (n C O -> f -> f)+             -> (n O O -> f -> f)+             -> (n O C -> f -> FactBase f)+             -> FwdTransfer n f+mkFTransfer3 f m l = FwdTransfer3 (f, m, l)++mkFTransfer :: (forall e x . n e x -> f -> Fact x f) -> FwdTransfer n f+mkFTransfer f = FwdTransfer3 (f, f, f)++-- | Functions passed to 'mkFRewrite3' should not be aware of the fuel supply.+-- The result returned by 'mkFRewrite3' respects fuel.+mkFRewrite3 :: forall m n f. FuelMonad m+            => (n C O -> f -> m (Maybe (Graph n C O)))+            -> (n O O -> f -> m (Maybe (Graph n O O)))+            -> (n O C -> f -> m (Maybe (Graph n O C)))+            -> FwdRewrite m n f+mkFRewrite3 f m l = FwdRewrite3 (lift f, lift m, lift l)+  where lift :: forall t t1 a. (t -> t1 -> m (Maybe a)) -> t -> t1 -> m (Maybe (a, FwdRewrite m n f))+        lift rw node fact = liftM (liftM asRew) (withFuel =<< rw node fact)+        asRew :: forall t. t -> (t, FwdRewrite m n f)+        asRew g = (g, noFwdRewrite)++noFwdRewrite :: Monad m => FwdRewrite m n f+noFwdRewrite = FwdRewrite3 (noRewrite, noRewrite, noRewrite)++noRewrite :: Monad m => a -> b -> m (Maybe c)+noRewrite _ _ = return Nothing++                               ++-- | Functions passed to 'mkFRewrite' should not be aware of the fuel supply.+-- The result returned by 'mkFRewrite' respects fuel.+mkFRewrite :: FuelMonad m => (forall e x . n e x -> f -> m (Maybe (Graph n e x)))+           -> FwdRewrite m n f+mkFRewrite f = mkFRewrite3 f f f+++type family   Fact x f :: *+type instance Fact C f = FactBase f+type instance Fact O f = f++-- | if the graph being analyzed is open at the entry, there must+--   be no other entry point, or all goes horribly wrong...+analyzeAndRewriteFwd+   :: forall m n f e x entries. (CheckpointMonad m, NonLocal n, LabelsPtr entries)+   => FwdPass m n f+   -> MaybeC e entries+   -> Graph n e x -> Fact e f+   -> m (Graph n e x, FactBase f, MaybeO x f)+analyzeAndRewriteFwd pass entries g f =+  do (rg, fout) <- arfGraph pass (fmap targetLabels entries) g f+     let (g', fb) = normalizeGraph 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++----------------------------------------------------------------+--       Forward Implementation+----------------------------------------------------------------++type Entries e = MaybeC e [Label]++arfGraph :: forall m n f e x .+            (NonLocal n, CheckpointMonad m) => FwdPass m n f -> +            Entries e -> Graph n e x -> Fact e f -> m (DG f n e x, Fact x f)+arfGraph pass entries = graph+  where+    {- nested type synonyms would be so lovely here +    type ARF  thing = forall e x . thing e x -> f        -> m (DG f n e x, Fact x f)+    type ARFX thing = forall e x . thing e x -> Fact e f -> m (DG f n e x, Fact x f)+    -}+    graph ::              Graph n e x -> Fact e f -> m (DG f n e x, Fact x f)+-- @ start block.tex -2+    block :: forall e x . +             Block n e x -> f -> m (DG f n e x, Fact x f)+-- @ end block.tex+-- @ start node.tex -4+    node :: forall e x . (ShapeLifter e x) +         => n e x -> f -> m (DG f n e x, Fact x f)+-- @ end node.tex+-- @ start bodyfun.tex+    body  :: [Label] -> LabelMap (Block n C C)+          -> Fact C f -> m (DG f n C C, Fact C f)+-- @ end bodyfun.tex+                    -- Outgoing factbase is restricted to Labels *not* in+                    -- in the Body; the facts for Labels *in*+                    -- the Body are in the 'DG f n C C'+-- @ start cat.tex -2+    cat :: forall e a x f1 f2 f3. +           (f1 -> m (DG f n e a, f2))+        -> (f2 -> m (DG f n a x, f3))+        -> (f1 -> m (DG f n e x, f3))+-- @ end cat.tex++    graph GNil            = \f -> return (dgnil, f)+    graph (GUnit blk)     = block blk+    graph (GMany e bdy x) = (e `ebcat` bdy) `cat` exit x+     where+      ebcat :: MaybeO e (Block n O C) -> Body n -> Fact e f -> m (DG f n e C, Fact C f)+      exit  :: MaybeO x (Block n C O)           -> Fact C f -> m (DG f n C x, Fact x f)+      exit (JustO blk) = arfx block blk+      exit NothingO    = \fb -> return (dgnilC, fb)+      ebcat entry bdy = c entries entry+       where c :: MaybeC e [Label] -> MaybeO e (Block n O C)+                -> Fact e f -> m (DG f n e C, Fact C f)+             c NothingC (JustO entry)   = block entry `cat` body (successors entry) bdy+             c (JustC entries) NothingO = body entries bdy+             c _ _ = error "bogus GADT pattern match failure"++    -- Lift from nodes to blocks+-- @ start block.tex -2+    block (BFirst  n)  = node n+    block (BMiddle n)  = node n+    block (BLast   n)  = node n+    block (BCat b1 b2) = block b1 `cat` block b2+-- @ end block.tex+    block (BHead h n)  = block h  `cat` node n+    block (BTail n t)  = node  n  `cat` block t+    block (BClosed h t)= block h  `cat` block t++-- @ start node.tex -4+    node n f+     = do { grw <- frewrite pass n f+          ; case grw of+              Nothing -> return ( singletonDG f n+                                , ftransfer pass n f )+              Just (g, rw) ->+                  let pass' = pass { fp_rewrite = rw }+                      f'    = fwdEntryFact n f+                  in  arfGraph pass' (fwdEntryLabel n) g f' }++-- @ end node.tex++    -- | Compose fact transformers and concatenate the resulting+    -- rewritten graphs.+    {-# INLINE cat #-} +-- @ start cat.tex -2+    cat ft1 ft2 f = do { (g1,f1) <- ft1 f+                       ; (g2,f2) <- ft2 f1+                       ; return (g1 `dgSplice` g2, f2) }+-- @ end cat.tex+    arfx :: forall thing x .+            NonLocal thing+         => (thing C x ->        f -> m (DG f n C x, Fact x f))+         -> (thing C x -> Fact C f -> m (DG f n C x, Fact x f))+    arfx arf thing fb = +      arf thing $ fromJust $ lookupFact (entryLabel thing) $ joinInFacts lattice fb+     where lattice = fp_lattice pass+     -- joinInFacts adds debugging information+++                    -- Outgoing factbase is restricted to Labels *not* in+                    -- in the Body; the facts for Labels *in*+                    -- the Body are in the 'DG f n C C'+-- @ start bodyfun.tex+    body entries blockmap init_fbase+      = fixpoint Fwd lattice do_block blocks init_fbase+      where+        blocks  = forwardBlockList entries blockmap+        lattice = fp_lattice pass+        do_block :: forall x. Block n C x -> FactBase f -> m (DG f n C x, Fact x f)+        do_block b fb = block b entryFact+          where entryFact = getFact lattice (entryLabel b) fb+-- @ end bodyfun.tex+++-- Join all the incoming facts with bottom.+-- We know the results _shouldn't change_, but the transfer+-- functions might, for example, generate some debugging traces.+joinInFacts :: DataflowLattice f -> FactBase f -> FactBase f+joinInFacts (lattice @ DataflowLattice {fact_bot = bot, fact_join = fj}) fb =+  mkFactBase lattice $ map botJoin $ mapToList fb+    where botJoin (l, f) = (l, snd $ fj l (OldFact bot) (NewFact f))++forwardBlockList :: (NonLocal 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.+forwardBlockList entries blks = postorder_dfs_from blks entries++-----------------------------------------------------------------------------+--              Backward analysis and rewriting: the interface+-----------------------------------------------------------------------------++data BwdPass m n f+  = BwdPass { bp_lattice  :: DataflowLattice f+            , bp_transfer :: BwdTransfer n f+            , bp_rewrite  :: BwdRewrite m n f }++newtype BwdTransfer n f +  = BwdTransfer3 { getBTransfer3 ::+                     ( n C O -> f          -> f+                     , n O O -> f          -> f+                     , n O C -> FactBase f -> f+                     ) }+newtype BwdRewrite m n f +  = BwdRewrite3 { getBRewrite3 ::+                    ( n C O -> f          -> m (Maybe (Graph n C O, BwdRewrite m n f))+                    , n O O -> f          -> m (Maybe (Graph n O O, BwdRewrite m n f))+                    , n O C -> FactBase f -> m (Maybe (Graph n O C, BwdRewrite m n f))+                    ) }++wrapBR :: (forall e x .+                Shape x +             -> (n  e x -> Fact x f  -> m  (Maybe (Graph n  e x, BwdRewrite m  n  f )))+             -> (n' e x -> Fact x f' -> m' (Maybe (Graph n' e x, BwdRewrite m' n' f')))+          )+            -- ^ This argument may assume that any function passed to it+            -- respects fuel, and it must return a result that respects fuel.+       -> BwdRewrite m  n  f +       -> BwdRewrite m' n' f'      -- see Note [Respects Fuel]+wrapBR wrap (BwdRewrite3 (f, m, l)) = +  BwdRewrite3 (wrap Open f, wrap Open m, wrap Closed l)++wrapBR2 :: (forall e x . Shape x+            -> (n1 e x -> Fact x f1 -> m1 (Maybe (Graph n1 e x, BwdRewrite m1 n1 f1)))+            -> (n2 e x -> Fact x f2 -> m2 (Maybe (Graph n2 e x, BwdRewrite m2 n2 f2)))+            -> (n3 e x -> Fact x f3 -> m3 (Maybe (Graph n3 e x, BwdRewrite m3 n3 f3))))+            -- ^ This argument may assume that any function passed to it+            -- respects fuel, and it must return a result that respects fuel.+        -> BwdRewrite m1 n1 f1+        -> BwdRewrite m2 n2 f2+        -> BwdRewrite m3 n3 f3      -- see Note [Respects Fuel]+wrapBR2 wrap2 (BwdRewrite3 (f1, m1, l1)) (BwdRewrite3 (f2, m2, l2)) =+    BwdRewrite3 (wrap2 Open f1 f2, wrap2 Open m1 m2, wrap2 Closed l1 l2)++++mkBTransfer3 :: (n C O -> f -> f) -> (n O O -> f -> f) ->+                (n O C -> FactBase f -> f) -> BwdTransfer n f+mkBTransfer3 f m l = BwdTransfer3 (f, m, l)++mkBTransfer :: (forall e x . n e x -> Fact x f -> f) -> BwdTransfer n f+mkBTransfer f = BwdTransfer3 (f, f, f)++-- | Functions passed to 'mkBRewrite3' should not be aware of the fuel supply.+-- The result returned by 'mkBRewrite3' respects fuel.+mkBRewrite3 :: forall m n f. FuelMonad m+            => (n C O -> f          -> m (Maybe (Graph n C O)))+            -> (n O O -> f          -> m (Maybe (Graph n O O)))+            -> (n O C -> FactBase f -> m (Maybe (Graph n O C)))+            -> BwdRewrite m n f+mkBRewrite3 f m l = BwdRewrite3 (lift f, lift m, lift l)+  where lift :: forall t t1 a. (t -> t1 -> m (Maybe a)) -> t -> t1 -> m (Maybe (a, BwdRewrite m n f))+        lift rw node fact = liftM (liftM asRew) (withFuel =<< rw node fact)+        asRew :: t -> (t, BwdRewrite m n f)+        asRew g = (g, noBwdRewrite)++noBwdRewrite :: Monad m => BwdRewrite m n f+noBwdRewrite = BwdRewrite3 (noRewrite, noRewrite, noRewrite)++-- | Functions passed to 'mkBRewrite' should not be aware of the fuel supply.+-- The result returned by 'mkBRewrite' respects fuel.+mkBRewrite :: FuelMonad m +           => (forall e x . n e x -> Fact x f -> m (Maybe (Graph n e x)))+           -> BwdRewrite m n f+mkBRewrite f = mkBRewrite3 f f f+++-----------------------------------------------------------------------------+--              Backward implementation+-----------------------------------------------------------------------------++arbGraph :: forall m n f e x .+            (NonLocal n, CheckpointMonad m) => BwdPass m n f -> +            Entries e -> Graph n e x -> Fact x f -> m (DG f n e x, Fact e f)+arbGraph pass entries = graph+  where+    {- nested type synonyms would be so lovely here +    type ARB  thing = forall e x . thing e x -> Fact x f -> m (DG f n e x, f)+    type ARBX thing = forall e x . thing e x -> Fact x f -> m (DG f n e x, Fact e f)+    -}+    graph ::              Graph n e x -> Fact x f -> m (DG f n e x, Fact e f)+    block :: forall e x . Block n e x -> Fact x f -> m (DG f n e x, f)+    node  :: forall e x . (ShapeLifter e x) +                       => n e x       -> Fact x f -> m (DG f n e x, f)+    body  :: [Label] -> Body n -> Fact C f -> m (DG f n C C, Fact C f)+    cat :: forall e a x info info' info''.+           (info' -> m (DG f n e a, info''))+        -> (info  -> m (DG f n a x, info'))+        -> (info  -> m (DG f n e x, info''))++    graph GNil            = \f -> return (dgnil, f)+    graph (GUnit blk)     = block blk+    graph (GMany e bdy x) = (e `ebcat` bdy) `cat` exit x+     where+      ebcat :: MaybeO e (Block n O C) -> Body n -> Fact C f -> m (DG f n e C, Fact e f)+      exit  :: MaybeO x (Block n C O)           -> Fact x f -> m (DG f n C x, Fact C f)+      exit (JustO blk) = arbx block blk+      exit NothingO    = \fb -> return (dgnilC, fb)+      ebcat entry bdy = c entries entry+       where c :: MaybeC e [Label] -> MaybeO e (Block n O C)+                -> Fact C f -> m (DG f n e C, Fact e f)+             c NothingC (JustO entry)   = block entry `cat` body (successors entry) bdy+             c (JustC entries) NothingO = body entries bdy+             c _ _ = error "bogus GADT pattern match failure"++    -- Lift from nodes to blocks+    block (BFirst  n)  = node n+    block (BMiddle n)  = node n+    block (BLast   n)  = node n+    block (BCat b1 b2) = block b1 `cat` block b2+    block (BHead h n)  = block h  `cat` node n+    block (BTail n t)  = node  n  `cat` block t+    block (BClosed h t)= block h  `cat` block t++    node n f+      = do { bwdres <- brewrite pass n f+           ; case bwdres of+               Nothing -> return (singletonDG entry_f n, entry_f)+                            where entry_f = btransfer pass n f+               Just (g, rw) ->+                          do { let pass' = pass { bp_rewrite = rw }+                             ; (g, f) <- arbGraph pass' (fwdEntryLabel n) g f+                             ; return (g, bwdEntryFact (bp_lattice pass) n f)} }++    -- | Compose fact transformers and concatenate the resulting+    -- rewritten graphs.+    {-# INLINE cat #-} +    cat ft1 ft2 f = do { (g2,f2) <- ft2 f+                       ; (g1,f1) <- ft1 f2+                       ; return (g1 `dgSplice` g2, f1) }++    arbx :: forall thing x .+            NonLocal thing+         => (thing C x -> Fact x f -> m (DG f n C x, f))+         -> (thing C x -> Fact x f -> m (DG f n C x, Fact C f))++    arbx arb thing f = do { (rg, f) <- arb thing f+                          ; let fb = joinInFacts (bp_lattice pass) $+                                     mapSingleton (entryLabel thing) f+                          ; return (rg, fb) }+     -- joinInFacts adds debugging information++                    -- Outgoing factbase is restricted to Labels *not* in+                    -- in the Body; the facts for Labels *in*+                    -- the Body are in the 'DG f n C C'+    body entries blockmap init_fbase+      = fixpoint Bwd (bp_lattice pass) do_block blocks init_fbase+      where+        blocks = backwardBlockList entries blockmap+        do_block :: forall x. Block n C x -> Fact x f -> m (DG f n C x, LabelMap f)+        do_block b f = do (g, f) <- block b f+                          return (g, mapSingleton (entryLabel b) f)+++backwardBlockList :: (LabelsPtr entries, NonLocal n) => entries -> 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 entries body = reverse $ forwardBlockList entries body++{-++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.)++-}+++-- | if the graph being analyzed is open at the exit, I don't+--   quite understand the implications of possible other exits+analyzeAndRewriteBwd+   :: (CheckpointMonad m, NonLocal n, LabelsPtr entries)+   => BwdPass m n f+   -> MaybeC e entries -> Graph n e x -> Fact x f+   -> m (Graph n e x, FactBase f, MaybeO e f)+analyzeAndRewriteBwd pass entries g f =+  do (rg, fout) <- arbGraph pass (fmap targetLabels entries) g f+     let (g', fb) = normalizeGraph 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+-----------------------------------------------------------------------------+-- @ start txfb.tex+data TxFactBase n f+  = TxFB { tfb_fbase :: FactBase f+         , tfb_rg    :: DG f n C C -- Transformed blocks+         , tfb_cha   :: ChangeFlag+         , tfb_lbls  :: LabelSet }+-- @ end txfb.tex+     -- See Note [TxFactBase invariants]+-- @ start update.tex+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 `setMember` lbls = (SomeChange, new_fbase)+  | otherwise            = (cha,        new_fbase)+  where+    (cha2, res_fact) -- Note [Unreachable blocks]+       = case lookupFact lbl fbase of+           Nothing -> (SomeChange, new_fact_debug)  -- Note [Unreachable blocks]+           Just old_fact -> join old_fact+         where join old_fact = +                 fact_join lat lbl+                   (OldFact old_fact) (NewFact new_fact)+               (_, new_fact_debug) = join (fact_bot lat)+    new_fbase = mapInsert lbl res_fact fbase+-- @ end update.tex+++{-+-- this doesn't work because it can't be implemented+class Monad m => FixpointMonad m where+  observeChangedFactBase :: m (Maybe (FactBase f)) -> Maybe (FactBase f)+-}++-- @ start fptype.tex+data Direction = Fwd | Bwd+fixpoint :: forall m n f. (CheckpointMonad m, NonLocal n)+ => Direction+ -> DataflowLattice f+ -> (Block n C C -> Fact C f -> m (DG f n C C, Fact C f))+ -> [Block n C C]+ -> (Fact C f -> m (DG f n C C, Fact C f))+-- @ end fptype.tex+-- @ start fpimp.tex+fixpoint direction lat do_block blocks init_fbase+  = do { tx_fb <- loop init_fbase+       ; return (tfb_rg tx_fb, +                 map (fst . fst) tagged_blocks +                    `mapDeleteList` tfb_fbase tx_fb ) }+    -- The successors of the Graph are the the Labels +    -- for which we have facts and which are *not* in+    -- the blocks of the graph+  where+    tagged_blocks = map tag blocks+    is_fwd = case direction of { Fwd -> True; +                                 Bwd -> False }+    tag :: NonLocal t => t C C -> ((Label, t C C), [Label])+    tag b = ((entryLabel b, b), +             if is_fwd then [entryLabel b] +                        else successors b)+     -- 'tag' adds the in-labels of the block; +     -- see Note [TxFactBase invairants]++    tx_blocks :: [((Label, Block n C C), [Label])]   -- I do not understand this type+              -> TxFactBase n f -> m (TxFactBase n f)+    tx_blocks []              tx_fb = return tx_fb+    tx_blocks (((lbl,blk), in_lbls):bs) tx_fb +      = tx_block lbl blk in_lbls tx_fb >>= tx_blocks bs+     -- "in_lbls" == Labels the block may +     --                 _depend_ upon for facts++    tx_block :: Label -> Block n C C -> [Label]+             -> TxFactBase n f -> m (TxFactBase n f)+    tx_block lbl blk in_lbls +        tx_fb@(TxFB { tfb_fbase = fbase, tfb_lbls = lbls+                    , tfb_rg = blks, tfb_cha = cha })+      | is_fwd && not (lbl `mapMember` fbase)+      = return (tx_fb {tfb_lbls = lbls'})       -- Note [Unreachable blocks]+      | otherwise+      = do { (rg, out_facts) <- do_block blk fbase+           ; let (cha', fbase') = mapFoldWithKey+                                  (updateFact lat lbls) +                                  (cha,fbase) out_facts+           ; return $+               TxFB { tfb_lbls  = lbls'+                    , tfb_rg    = rg `dgSplice` blks+                    , tfb_fbase = fbase'+                    , tfb_cha = cha' } }+      where+        lbls' = lbls `setUnion` setFromList in_lbls+        ++    loop :: FactBase f -> m (TxFactBase n f)+    loop fbase +      = do { s <- checkpoint+           ; let init_tx :: TxFactBase n f+                 init_tx = TxFB { tfb_fbase = fbase+                                , tfb_cha   = NoChange+                                , tfb_rg    = dgnilC+                                , tfb_lbls  = setEmpty }+           ; tx_fb <- tx_blocks tagged_blocks init_tx+           ; case tfb_cha tx_fb of+               NoChange   -> return tx_fb+               SomeChange +                 -> do { restart s+                       ; loop (tfb_fbase tx_fb) } }+-- @ end fpimp.tex           +++{-  Note [TxFactBase invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The TxFactBase is used only during a fixpoint iteration (or "sweep"),+and accumulates facts (and the transformed code) during the fixpoint+iteration.++* tfb_fbase increases monotonically, across all sweeps++* At the beginning of each sweep+      tfb_cha  = NoChange+      tfb_lbls = {}++* During each sweep we process each block in turn.  Processing a block+  is done thus:+    1.  Read from tfb_fbase the facts for its entry label (forward)+        or successors labels (backward)+    2.  Transform those facts into new facts for its successors (forward)+        or entry label (backward)+    3.  Augment tfb_fbase with that info+  We call the labels read in step (1) the "in-labels" of the sweep++* The field tfb_lbls is the set of in-labels of all blocks that have+  been processed so far this sweep, including the block that is+  currently being processed.  tfb_lbls is initialised to {}.  It is a+  subset of the Labels of the *original* (not transformed) blocks.++* The tfb_cha field is set to SomeChange iff we decide we need to+  perform another iteration of the fixpoint loop. It is initialsed to NoChange.++  Specifically, we set tfb_cha to SomeChange in step (3) iff+    (a) The fact in tfb_fbase for a block L changes+    (b) L is in tfb_lbls+  Reason: until a label enters the in-labels its accumuated fact in tfb_fbase+  has not been read, hence cannot affect the outcome++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_join 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.+-}++-----------------------------------------------------------------------------+--      DG: an internal data type for 'decorated graphs'+--          TOTALLY internal to Hoopl; each block is decorated with a fact+-----------------------------------------------------------------------------++-- @ start dg.tex+type Graph = Graph' Block+type DG f  = Graph' (DBlock f)+data DBlock f n e x = DBlock f (Block n e x) -- ^ block decorated with fact+-- @ end dg.tex+instance NonLocal n => NonLocal (DBlock f n) where+  entryLabel (DBlock _ b) = entryLabel b+  successors (DBlock _ b) = successors b++--- constructors++dgnil  :: DG f n O O+dgnilC :: DG f n C C+dgSplice  :: NonLocal n => DG f n e a -> DG f n a x -> DG f n e x++---- observers++type GraphWithFacts n f e x = (Graph n e x, FactBase f)+  -- A Graph together with the facts for that graph+  -- The domains of the two maps should be identical++normalizeGraph :: forall n f e x .+                  NonLocal n => DG f n e x -> GraphWithFacts n f e x++normalizeGraph g = (graphMapBlocks dropFact g, facts g)+    where dropFact :: DBlock t t1 t2 t3 -> Block t1 t2 t3+          dropFact (DBlock _ b) = b+          facts :: DG f n e x -> FactBase f+          facts GNil = noFacts+          facts (GUnit _) = noFacts+          facts (GMany _ body exit) = bodyFacts body `mapUnion` exitFacts exit+          exitFacts :: MaybeO x (DBlock f n C O) -> FactBase f+          exitFacts NothingO = noFacts+          exitFacts (JustO (DBlock f b)) = mapSingleton (entryLabel b) f+          bodyFacts :: LabelMap (DBlock f n C C) -> FactBase f+          bodyFacts body = mapFold f noFacts body+            where f :: forall t a x. (NonLocal t) => DBlock a t C x -> LabelMap a -> LabelMap a+                  f (DBlock f b) fb = mapInsert (entryLabel b) f fb++--- implementation of the constructors (boring)++dgnil  = GNil+dgnilC = GMany NothingO emptyBody NothingO++dgSplice = U.splice fzCat+  where fzCat :: DBlock f n e O -> DBlock t n O x -> DBlock f n e x+        fzCat (DBlock f b1) (DBlock _ b2) = DBlock f (b1 `U.cat` b2)++----------------------------------------------------------------+--       Utilities+----------------------------------------------------------------++-- Lifting based on shape:+--  - from nodes to blocks+--  - from facts to fact-like things+-- Lowering back:+--  - from fact-like things to facts+-- Note that the latter two functions depend only on the entry shape.+-- @ start node.tex+class ShapeLifter e x where+ singletonDG   :: f -> n e x -> DG f n e x+ fwdEntryFact  :: NonLocal n => n e x -> f -> Fact e f+ fwdEntryLabel :: NonLocal n => n e x -> MaybeC e [Label]+ ftransfer :: FwdPass m n f -> n e x -> f -> Fact x f+ frewrite  :: FwdPass m n f -> n e x +           -> f -> m (Maybe (Graph n e x, FwdRewrite m n f))+-- @ end node.tex+ bwdEntryFact :: NonLocal n => DataflowLattice f -> n e x -> Fact e f -> f+ btransfer    :: BwdPass m n f -> n e x -> Fact x f -> f+ brewrite     :: BwdPass m n f -> n e x+              -> Fact x f -> m (Maybe (Graph n e x, BwdRewrite m n f))++instance ShapeLifter C O where+  singletonDG f = gUnitCO . DBlock f . BFirst+  fwdEntryFact     n f  = mapSingleton (entryLabel n) f+  bwdEntryFact lat n fb = getFact lat (entryLabel n) fb+  ftransfer (FwdPass {fp_transfer = FwdTransfer3 (ft, _, _)}) n f = ft n f+  btransfer (BwdPass {bp_transfer = BwdTransfer3 (bt, _, _)}) n f = bt n f+  frewrite  (FwdPass {fp_rewrite  = FwdRewrite3  (fr, _, _)}) n f = fr n f+  brewrite  (BwdPass {bp_rewrite  = BwdRewrite3  (br, _, _)}) n f = br n f+  fwdEntryLabel n = JustC [entryLabel n]++instance ShapeLifter O O where+  singletonDG f = gUnitOO . DBlock f . BMiddle+  fwdEntryFact   _ f = f+  bwdEntryFact _ _ f = f+  ftransfer (FwdPass {fp_transfer = FwdTransfer3 (_, ft, _)}) n f = ft n f+  btransfer (BwdPass {bp_transfer = BwdTransfer3 (_, bt, _)}) n f = bt n f+  frewrite  (FwdPass {fp_rewrite  = FwdRewrite3  (_, fr, _)}) n f = fr n f+  brewrite  (BwdPass {bp_rewrite  = BwdRewrite3  (_, br, _)}) n f = br n f+  fwdEntryLabel _ = NothingC++instance ShapeLifter O C where+  singletonDG f = gUnitOC . DBlock f . BLast+  fwdEntryFact   _ f = f+  bwdEntryFact _ _ f = f+  ftransfer (FwdPass {fp_transfer = FwdTransfer3 (_, _, ft)}) n f = ft n f+  btransfer (BwdPass {bp_transfer = BwdTransfer3 (_, _, bt)}) n f = bt n f+  frewrite  (FwdPass {fp_rewrite  = FwdRewrite3  (_, _, fr)}) n f = fr n f+  brewrite  (BwdPass {bp_rewrite  = BwdRewrite3  (_, _, br)}) n f = br n f+  fwdEntryLabel _ = NothingC++-- Fact lookup: the fact `orelse` bottom+getFact  :: DataflowLattice f -> Label -> FactBase f -> f+getFact lat l fb = case lookupFact l fb of Just  f -> f+                                           Nothing -> fact_bot lat++++{-  Note [Respects fuel]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-}+-- $fuel+-- A value of type 'FwdRewrite' or 'BwdRewrite' /respects fuel/ if +-- any function contained within the value satisfies the following properties:+--+--   * When fuel is exhausted, it always returns 'Nothing'.+--+--   * When it returns @Just g rw@, it consumes /exactly/ one unit+--     of fuel, and new rewrite 'rw' also respects fuel.+--+-- Provided that functions passed to 'mkFRewrite', 'mkFRewrite3', +-- 'mkBRewrite', and 'mkBRewrite3' are not aware of the fuel supply,+-- the results respect fuel.+--+-- It is an /unchecked/ run-time error for the argument passed to 'wrapFR',+-- 'wrapFR2', 'wrapBR', or 'warpBR2' to return a function that does not respect fuel.
+ src/Compiler/Hoopl/Debug.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE RankNTypes, GADTs, ScopedTypeVariables, FlexibleContexts #-}++module Compiler.Hoopl.Debug +  ( TraceFn , debugFwdJoins , debugBwdJoins+  , debugFwdTransfers , debugBwdTransfers+  )+where++import Compiler.Hoopl.Dataflow+import Compiler.Hoopl.Show++--------------------------------------------------------------------------------+-- | 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+--+-- There are two kinds of debugging messages for a join,+-- depending on whether the join is higher in the lattice than the old fact:+--   1. If the join is higher, we show:+--         + Join@L: f1 `join` f2 = f'+--      where:+--        + indicates a change+--        L is the label where the join takes place+--        f1 is the old fact at the label+--        f2 is the new fact we are joining to f1+--        f' is the result of the join+--   2. _ Join@L: f2 <= f1+--      where:+--        _ indicates no change+--        L is the label where the join takes place+--        f1 is the old fact at the label (which remains unchanged)+--        f2 is the new fact we joined with f1+--------------------------------------------------------------------------------+++debugFwdJoins :: forall m n f . Show f => TraceFn -> ChangePred -> FwdPass m n f -> FwdPass m n f+debugBwdJoins :: forall m n f . Show f => TraceFn -> ChangePred -> BwdPass m n f -> BwdPass m 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 showPred l@(DataflowLattice {fact_join = join}) = l {fact_join = join'}+  where+   join' l f1@(OldFact of1) f2@(NewFact nf2) =+     if showPred c then trace output res else res+       where res@(c, f') = join l f1 f2+             output = case c of+                        SomeChange -> "+ Join@" ++ show l ++ ": " ++ show of1 ++ " `join` "+                                                                  ++ 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 ShowN n   = forall e x . n e x ->      String+type FPred n f = forall e x . n e x -> f        -> Bool+type BPred n f = forall e x . n e x -> Fact x f -> Bool+debugFwdTransfers::+  forall m n f . Show f => TraceFn -> ShowN n -> FPred n f -> FwdPass m n f -> FwdPass m n f+debugFwdTransfers trace showN showPred pass = pass { fp_transfer = transfers' }+  where+    (f, m, l) = getFTransfer3 $ fp_transfer pass+    transfers' = mkFTransfer3 (wrap show f) (wrap show m) (wrap showFactBase l)+    wrap :: forall e x . (Fact x f -> String) -> (n e x -> f -> Fact x f) -> n e x -> f -> Fact x f+    wrap showOutF ft n f = if showPred n f then trace output res else res+      where+        res    = ft n f+        output = name ++ " transfer: " ++ show f ++ " -> " ++ showN n ++ " -> " ++ showOutF res+    name = fact_name (fp_lattice pass)+    +debugBwdTransfers::+  forall m n f . Show f => TraceFn -> ShowN n -> BPred n f -> BwdPass m n f -> BwdPass m n f+debugBwdTransfers trace showN showPred pass = pass { bp_transfer = transfers' }+  where+    (f, m, l) = getBTransfer3 $ bp_transfer pass+    transfers' = mkBTransfer3 (wrap show f) (wrap show m) (wrap showFactBase l)+    wrap :: forall e x . (Fact x f -> String) -> (n e x -> Fact x f -> f) -> n e x -> Fact x f -> f+    wrap showInF ft n f = if showPred n f then trace output res else res+      where+        res    = ft n f+        output = name ++ " transfer: " ++ showInF f ++ " -> " ++ showN n ++ " -> " ++ show res+    name = fact_name (bp_lattice pass)+    ++-- debugFwdTransfers, debugFwdRewrites, debugFwdAll ::+--   forall m n f . Show f => TraceFn -> ShowN n -> FwdPass m n f -> FwdPass m n f+-- debugBwdTransfers, debugBwdRewrites, debugBwdAll ::+--   forall m n f . Show f => TraceFn -> ShowN n -> BwdPass m n f -> BwdPass m n f+
+ src/Compiler/Hoopl/Fuel.hs view
@@ -0,0 +1,105 @@+{-# LANGUAGE TypeFamilies #-}++-----------------------------------------------------------------------------+--		The fuel monad+-----------------------------------------------------------------------------++module Compiler.Hoopl.Fuel+  ( Fuel, infiniteFuel, fuelRemaining+  , withFuel+  , FuelMonad(..)+  , FuelMonadT(..)+  , CheckingFuelMonad+  , InfiniteFuelMonad+  , SimpleFuelMonad+  )+where++import Compiler.Hoopl.Checkpoint+import Compiler.Hoopl.Unique++class Monad m => FuelMonad m where+  getFuel :: m Fuel+  setFuel :: Fuel -> m ()++-- | Find out how much fuel remains after a computation.+-- Can be subtracted from initial fuel to get total consumption.+fuelRemaining :: FuelMonad m => m Fuel+fuelRemaining = getFuel++class FuelMonadT fm where+  runWithFuel :: (Monad m, FuelMonad (fm m)) => Fuel -> fm m a -> m a+++type Fuel = Int++withFuel :: FuelMonad m => Maybe a -> m (Maybe a)+withFuel Nothing  = return Nothing+withFuel (Just a) = do f <- getFuel+                       if f == 0+                         then return Nothing+                         else setFuel (f-1) >> return (Just a)+++----------------------------------------------------------------++newtype CheckingFuelMonad m a = FM { unFM :: Fuel -> m (a, Fuel) }++instance Monad m => Monad (CheckingFuelMonad m) where+  return a = FM (\f -> return (a, f))+  fm >>= k = FM (\f -> do { (a, f') <- unFM fm f; unFM (k a) f' })++instance CheckpointMonad m => CheckpointMonad (CheckingFuelMonad m) where+  type Checkpoint (CheckingFuelMonad m) = (Fuel, Checkpoint m)+  checkpoint = FM $ \fuel -> do { s <- checkpoint+                                ; return ((fuel, s), fuel) }+  restart (fuel, s) = FM $ \_ -> do { restart s; return ((), fuel) }++instance UniqueMonad m => UniqueMonad (CheckingFuelMonad m) where+  freshUnique = FM (\f -> do { l <- freshUnique; return (l, f) })++instance Monad m => FuelMonad (CheckingFuelMonad m) where+  getFuel   = FM (\f -> return (f, f))+  setFuel f = FM (\_ -> return ((),f))++instance FuelMonadT CheckingFuelMonad where+  runWithFuel fuel m = do { (a, _) <- unFM m fuel; return a }++----------------------------------------------------------------++newtype InfiniteFuelMonad m a = IFM { unIFM :: m a }+instance Monad m => Monad (InfiniteFuelMonad m) where+  return a = IFM $ return a+  m >>= k  = IFM $ do { a <- unIFM m; unIFM (k a) }++instance UniqueMonad m => UniqueMonad (InfiniteFuelMonad m) where+  freshUnique = IFM $ freshUnique++instance Monad m => FuelMonad (InfiniteFuelMonad m) where+  getFuel   = return infiniteFuel+  setFuel _ = return ()++instance CheckpointMonad m => CheckpointMonad (InfiniteFuelMonad m) where+  type Checkpoint (InfiniteFuelMonad m) = Checkpoint m+  checkpoint = IFM checkpoint+  restart s  = IFM $ restart s++++instance FuelMonadT InfiniteFuelMonad where+  runWithFuel _ = unIFM++infiniteFuel :: Fuel -- effectively infinite, any, but subtractable+infiniteFuel = maxBound++type SimpleFuelMonad = CheckingFuelMonad SimpleUniqueMonad++{-+runWithFuelAndUniques :: Fuel -> [Unique] -> FuelMonad a -> a+runWithFuelAndUniques fuel uniques m = a+  where (a, _, _) = unFM m fuel uniques++freshUnique :: FuelMonad Unique+freshUnique = FM (\f (l:ls) -> (l, f, ls))+-}+
+ src/Compiler/Hoopl/GHC.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE GADTs, RankNTypes #-}++{- Exposing some internals to GHC -}+module Compiler.Hoopl.GHC+  ( uniqueToInt+  , uniqueToLbl, lblToUnique+  , getFuel, setFuel+  , bodyToBlockMap, bodyOfBlockMap+  )+where++import Compiler.Hoopl.Fuel+import Compiler.Hoopl.Graph+import Compiler.Hoopl.Label+import Compiler.Hoopl.Unique++-- Converts Body to a map of closed/closed blocks.+-- It should better be a constant-time operation+-- as GHC is counting on it.+bodyToBlockMap :: Body' block n -> LabelMap (block n C C)+bodyToBlockMap (Body bodyMap) = bodyMap++bodyOfBlockMap :: LabelMap (block n C C) -> Body' block n+bodyOfBlockMap = Body
+ src/Compiler/Hoopl/Graph.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE GADTs, EmptyDataDecls, TypeFamilies #-}++module Compiler.Hoopl.Graph +  ( O, C, Block(..), Body, Body'(..), Graph, Graph'(..)+  , MaybeO(..), MaybeC(..), Shape(..), IndexedCO+  , NonLocal(entryLabel, successors)+  , emptyBody, addBlock, bodyList+  )+where++import Compiler.Hoopl.Collections+import Compiler.Hoopl.Label++-----------------------------------------------------------------------------+--		Graphs+-----------------------------------------------------------------------------++-- | Used at the type level to indicate an "open" structure with    +-- a unique, unnamed control-flow edge flowing in or out.         +-- "Fallthrough" and concatenation are permitted at an open point.+data O +       +       +-- | Used at the type level to indicate a "closed" structure which+-- supports control transfer only through the use of named+-- labels---no "fallthrough" is permitted.  The number of control-flow+-- edges is unconstrained.+data C++-- | A sequence of nodes.  May be any of four shapes (O/O, O/C, C/O, C/C).+-- Open at the entry means single entry, mutatis mutandis for exit.+-- A closed/closed block is a /basic/ block and can't be extended further.+-- Clients should avoid manipulating blocks and should stick to either nodes+-- or graphs.+data Block n e x where+  -- nodes+  BFirst  :: n C O                 -> Block n C O -- x^ block holds a single first node+  BMiddle :: n O O                 -> Block n O O -- x^ block holds a single middle node+  BLast   :: n O C                 -> Block n O C -- x^ block holds a single last node++  -- concatenation operations+  BCat    :: Block n O O -> Block n O O -> Block n O O -- non-list-like+  BHead   :: Block n C O -> n O O       -> Block n C O+  BTail   :: n O O       -> Block n O C -> Block n O C  ++  BClosed :: Block n C O -> Block n O C -> Block n C C -- the zipper++-- | A (possibly empty) collection of closed/closed blocks+type Body n = LabelMap (Block n C C)+newtype Body' block n = Body (LabelMap (block n C C))++-- | A control-flow graph, which may take any of four shapes (O/O, O/C, C/O, C/C).+-- A graph open at the entry has a single, distinguished, anonymous entry point;+-- if a graph is closed at the entry, its entry point(s) are supplied by a context.+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) +        -> LabelMap (block n C C)+        -> MaybeO x (block n C O)+        -> Graph' block n e x++-- | Maybe type indexed by open/closed+data MaybeO ex t where+  JustO    :: t -> MaybeO O t+  NothingO ::      MaybeO C t++-- | Maybe type indexed by closed/open+data MaybeC ex t where+  JustC    :: t -> MaybeC C t+  NothingC ::      MaybeC O t++-- | Dynamic shape value+data Shape ex where+  Closed :: Shape C+  Open   :: Shape O++-- | Either type indexed by closed/open using type families+type family IndexedCO ex a b :: *+type instance IndexedCO C a b = a+type instance IndexedCO O a b = b++instance Functor (MaybeO ex) where+  fmap _ NothingO = NothingO+  fmap f (JustO a) = JustO (f a)++instance Functor (MaybeC ex) where+  fmap _ NothingC = NothingC+  fmap f (JustC a) = JustC (f a)++-------------------------------+-- | Gives access to the anchor points for+-- nonlocal edges as well as the edges themselves+class NonLocal thing where +  entryLabel :: thing C x -> Label   -- ^ The label of a first node or block+  successors :: thing e C -> [Label] -- ^ Gives control-flow successors++instance NonLocal n => NonLocal (Block n) where+  entryLabel (BFirst n)    = entryLabel n+  entryLabel (BHead h _)   = entryLabel h+  entryLabel (BClosed h _) = entryLabel h+  successors (BLast n)     = successors n+  successors (BTail _ t)   = successors t+  successors (BClosed _ t) = successors t++------------------------------+emptyBody :: LabelMap (thing C C)+emptyBody = mapEmpty++addBlock :: NonLocal thing => thing C C -> LabelMap (thing C C) -> LabelMap (thing C C)+addBlock b body = nodupsInsert (entryLabel b) b body+  where nodupsInsert l b body = if mapMember l body then+                                    error $ "duplicate label " ++ show l ++ " in graph"+                                else+                                    mapInsert l b body++bodyList :: NonLocal (block n) => Body' block n -> [(Label,block n C C)]+bodyList (Body body) = mapToList body
+ src/Compiler/Hoopl/GraphUtil.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables #-}++-- N.B. addBasicBlocks won't work on OO without a Node (branch/label) constraint++module Compiler.Hoopl.GraphUtil+  ( splice, gSplice , cat , bodyGraph, bodyUnion+  , frontBiasBlock, backBiasBlock+  )++where++import Compiler.Hoopl.Collections+import Compiler.Hoopl.Graph+import Compiler.Hoopl.Label++bodyGraph :: Body n -> Graph n C C+bodyGraph b = GMany NothingO b NothingO++splice :: forall block n e a x . NonLocal (block n) =>+          (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++        sp GNil g2 = g2+        sp g1 GNil = g1++        sp (GUnit b1) (GUnit b2) = GUnit (b1 `bcat` b2)++        sp (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))++        sp (GMany e1 bs1 (JustO x1)) (GMany (JustO e2) b2 x2)+          = GMany e1 (b1 `bodyUnion` b2) x2+          where b1 = addBlock (x1 `bcat` e2) bs1++        sp (GMany e1 b1 NothingO) (GMany NothingO b2 x2)+          = GMany e1 (b1 `bodyUnion` b2) x2++        sp _ _ = error "bogus GADT match failure"++bodyUnion :: forall a . LabelMap a -> LabelMap a -> LabelMap a+bodyUnion = mapUnionWithKey nodups+  where nodups l _ _ = error $ "duplicate blocks with label " ++ show l++gSplice :: NonLocal n => Graph n e a -> Graph n a x -> Graph n e x+gSplice = splice cat++cat :: Block n e O -> Block n O x -> Block n e x+cat b1@(BFirst {})     (BMiddle n)  = BHead   b1 n+cat b1@(BFirst {})  b2@(BLast{})    = BClosed b1 b2+cat b1@(BFirst {})  b2@(BTail{})    = BClosed b1 b2+cat b1@(BFirst {})     (BCat b2 b3) = (b1 `cat` b2) `cat` b3+cat b1@(BHead {})      (BCat b2 b3) = (b1 `cat` b2) `cat` b3+cat b1@(BHead {})      (BMiddle n)  = BHead   b1 n+cat b1@(BHead {})   b2@(BLast{})    = BClosed b1 b2+cat b1@(BHead {})   b2@(BTail{})    = BClosed b1 b2+cat b1@(BMiddle {}) b2@(BMiddle{})  = BCat    b1 b2+cat    (BMiddle n)  b2@(BLast{})    = BTail    n b2+cat b1@(BMiddle {}) b2@(BCat{})     = BCat    b1 b2+cat    (BMiddle n)  b2@(BTail{})    = BTail    n b2+cat    (BCat b1 b2) b3@(BLast{})    = b1 `cat` (b2 `cat` b3)+cat    (BCat b1 b2) b3@(BTail{})    = b1 `cat` (b2 `cat` b3)+cat b1@(BCat {})    b2@(BCat{})     = BCat    b1 b2+cat b1@(BCat {})    b2@(BMiddle{})  = BCat    b1 b2+++----------------------------------------------------------------++-- | 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 :: Block n e x -> Block n e x+frontBiasBlock b@(BFirst  {}) = b+frontBiasBlock b@(BMiddle {}) = b+frontBiasBlock b@(BLast   {}) = b+frontBiasBlock b@(BCat {}) = rotate b+  where -- rotate and append ensure every left child of ZCat is ZMiddle+        -- provided 2nd argument to append already has this property+    rotate :: Block n O O -> Block n O O+    append :: Block n O O -> Block n O O -> Block n O O+    rotate (BCat h t)     = append h (rotate t)+    rotate b@(BMiddle {}) = b+    append b@(BMiddle {}) t = b `BCat` t+    append (BCat b1 b2) b3 = b1 `append` (b2 `append` b3)+frontBiasBlock b@(BHead {})    = b -- back-biased by nature; cannot fix+frontBiasBlock b@(BTail {})    = b -- statically front-biased+frontBiasBlock   (BClosed h t) = shiftRight h t+    where shiftRight :: Block n C O -> Block n O C -> Block n C C+          shiftRight (BHead b1 b2)  b3 = shiftRight b1 (BTail b2 b3)+          shiftRight b1@(BFirst {}) b2 = BClosed 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 :: Block n e x -> Block n e x+backBiasBlock b@(BFirst  {}) = b+backBiasBlock b@(BMiddle {}) = b+backBiasBlock b@(BLast   {}) = b+backBiasBlock b@(BCat {}) = rotate b+  where -- rotate and append ensure every right child of Cat is Middle+        -- provided 1st argument to append already has this property+    rotate :: Block n O O -> Block n O O+    append :: Block n O O -> Block n O O -> Block n O O+    rotate (BCat h t)     = append (rotate h) t+    rotate b@(BMiddle {}) = b+    append h b@(BMiddle {}) = h `BCat` b+    append b1 (BCat b2 b3) = (b1 `append` b2) `append` b3+backBiasBlock b@(BHead {}) = b -- statically back-biased+backBiasBlock b@(BTail {}) = b -- front-biased by nature; cannot fix+backBiasBlock (BClosed h t) = shiftLeft h t+    where shiftLeft :: Block n C O -> Block n O C -> Block n C C+          shiftLeft b1 (BTail b2 b3) = shiftLeft (BHead b1 b2) b3+          shiftLeft b1 b2@(BLast {}) = BClosed b1 b2
+ src/Compiler/Hoopl/Label.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE TypeFamilies #-}+module Compiler.Hoopl.Label+  ( Label+  , freshLabel+  , LabelSet, LabelMap+  , FactBase, noFacts, lookupFact++  , uniqueToLbl -- MkGraph and GHC use only+  , lblToUnique -- GHC use only+  )++where++import Compiler.Hoopl.Collections+import Compiler.Hoopl.Unique++-----------------------------------------------------------------------------+--		Label+-----------------------------------------------------------------------------++newtype Label = Label { lblToUnique :: Unique }+  deriving (Eq, Ord)++uniqueToLbl :: Unique -> Label+uniqueToLbl = Label++instance Show Label where+  show (Label n) = "L" ++ show n++freshLabel :: UniqueMonad m => m Label+freshLabel = freshUnique >>= return . uniqueToLbl++-----------------------------------------------------------------------------+-- LabelSet++newtype LabelSet = LS UniqueSet deriving (Eq, Ord, Show)++instance IsSet LabelSet where+  type ElemOf LabelSet = Label++  setNull (LS s) = setNull s+  setSize (LS s) = setSize s+  setMember (Label k) (LS s) = setMember k s++  setEmpty = LS setEmpty+  setSingleton (Label k) = LS (setSingleton k)+  setInsert (Label k) (LS s) = LS (setInsert k s)+  setDelete (Label k) (LS s) = LS (setDelete k s)++  setUnion (LS x) (LS y) = LS (setUnion x y)+  setDifference (LS x) (LS y) = LS (setDifference x y)+  setIntersection (LS x) (LS y) = LS (setIntersection x y)+  setIsSubsetOf (LS x) (LS y) = setIsSubsetOf x y++  setFold k z (LS s) = setFold (k . uniqueToLbl) z s++  setElems (LS s) = map uniqueToLbl (setElems s)+  setFromList ks = LS (setFromList (map lblToUnique ks))++-----------------------------------------------------------------------------+-- LabelMap++newtype LabelMap v = LM (UniqueMap v) deriving (Eq, Ord, Show)++instance IsMap LabelMap where+  type KeyOf LabelMap = Label++  mapNull (LM m) = mapNull m+  mapSize (LM m) = mapSize m+  mapMember (Label k) (LM m) = mapMember k m+  mapLookup (Label k) (LM m) = mapLookup k m+  mapFindWithDefault def (Label k) (LM m) = mapFindWithDefault def k m++  mapEmpty = LM mapEmpty+  mapSingleton (Label k) v = LM (mapSingleton k v)+  mapInsert (Label k) v (LM m) = LM (mapInsert k v m)+  mapDelete (Label k) (LM m) = LM (mapDelete k m)++  mapUnion (LM x) (LM y) = LM (mapUnion x y)+  mapUnionWithKey f (LM x) (LM y) = LM (mapUnionWithKey (f . uniqueToLbl) x y)+  mapDifference (LM x) (LM y) = LM (mapDifference x y)+  mapIntersection (LM x) (LM y) = LM (mapIntersection x y)+  mapIsSubmapOf (LM x) (LM y) = mapIsSubmapOf x y++  mapMap f (LM m) = LM (mapMap f m)+  mapMapWithKey f (LM m) = LM (mapMapWithKey (f . uniqueToLbl) m)+  mapFold k z (LM m) = mapFold k z m+  mapFoldWithKey k z (LM m) = mapFoldWithKey (k . uniqueToLbl) z m++  mapElems (LM m) = mapElems m+  mapKeys (LM m) = map uniqueToLbl (mapKeys m)+  mapToList (LM m) = [(uniqueToLbl k, v) | (k, v) <- mapToList m]+  mapFromList assocs = LM (mapFromList [(lblToUnique k, v) | (k, v) <- assocs])++-----------------------------------------------------------------------------+-- FactBase++type FactBase f = LabelMap f++noFacts :: FactBase f+noFacts = mapEmpty++lookupFact :: Label -> FactBase f -> Maybe f+lookupFact = mapLookup
+ src/Compiler/Hoopl/MkGraph.hs view
@@ -0,0 +1,252 @@+{-# LANGUAGE ScopedTypeVariables, GADTs, TypeSynonymInstances, FlexibleInstances, RankNTypes #-}+module Compiler.Hoopl.MkGraph+    ( AGraph, graphOfAGraph, aGraphOfGraph+    , (<*>), (|*><*|), catGraphs, addEntrySeq, addExitSeq, addBlocks, unionBlocks+    , emptyGraph, emptyClosedGraph, withFresh+    , mkFirst, mkMiddle, mkMiddles, mkLast, mkBranch, mkLabel, mkWhileDo+    , IfThenElseable(mkIfThenElse)+    , mkEntry, mkExit+    , HooplNode(mkLabelNode, mkBranchNode)+    )+where++import Compiler.Hoopl.Label (Label, uniqueToLbl)+import Compiler.Hoopl.Graph+import qualified Compiler.Hoopl.GraphUtil as U+import Compiler.Hoopl.Unique+import Control.Monad (liftM2)++{-|+As noted in the paper, we can define a single, polymorphic type of +splicing operation with the very polymorphic type+@+  AGraph n e a -> AGraph n a x -> AGraph n e x+@+However, we feel that this operation is a bit /too/ polymorphic,+and that it's too easy for clients to use it blindly without +thinking.  We therfore split it into two operations, '<*>' and '|*><*|', +which are supplemented by other functions:++  * The '<*>' operator is true concatenation, for connecting open graphs.+    Control flows from the left graph to the right graph.++  * The '|*><*|' operator splices together two graphs at a closed+    point. Nothing is known about control flow. 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.++  * The operator 'addBlocks' adds a set of basic blocks (represented+    as a closed/closed 'AGraph' to an existing graph, without changing+    the shape of the existing graph.  In some cases, it's necessary to+    introduce a branch and a label to 'get around' the blocks added,+    so this operator, and other functions based on it, requires a+    'HooplNode' type-class constraint and is available only on AGraph,+    not Graph.++  * We have discussed a dynamic assertion about dangling outedges and+    unreachable blocks, but nothing is implemented yet.++-}++++class GraphRep g where+  -- | An empty graph that is open at entry and exit.  +  -- It is the left and right identity of '<*>'.+  emptyGraph       :: g n O O+  -- | An empty graph that is closed at entry and exit.  +  -- It is the left and right identity of '|*><*|'.+  emptyClosedGraph :: g n C C+  -- | Create a graph from a first node+  mkFirst  :: n C O -> g n C O+  -- | Create a graph from a middle node+  mkMiddle :: n O O -> g n O O+  -- | Create a graph from a last node+  mkLast   :: n O C -> g n O C+  mkFirst = mkExit  . BFirst+  mkLast  = mkEntry . BLast+  infixl 3 <*>+  infixl 2 |*><*| +  -- | Concatenate two graphs; control flows from left to right.+  (<*>)    :: NonLocal n => g n e O -> g n O x -> g n e x+  -- | Splice together two graphs at a closed point; nothing is known+  -- about control flow.+  (|*><*|) :: NonLocal n => g n e C -> g n C x -> g n e x+  -- | Conveniently concatenate a sequence of open/open graphs using '<*>'.+  catGraphs :: NonLocal n => [g n O O] -> g n O O+  catGraphs = foldr (<*>) emptyGraph++  -- | Create a graph that defines a label+  mkLabel  :: HooplNode n => Label -> g n C O -- definition of the label+  -- | Create a graph that branches to a label+  mkBranch :: HooplNode n => Label -> g n O C -- unconditional branch to the label++  -- | Conveniently concatenate a sequence of middle nodes to form+  -- an open/open graph.+  mkMiddles :: NonLocal n => [n O O] -> g n O O++  mkLabel  id     = mkFirst $ mkLabelNode id+  mkBranch target = mkLast  $ mkBranchNode target+  mkMiddles ms    = catGraphs $ map mkMiddle ms++  -- | Create a graph containing only an entry sequence+  mkEntry   :: Block n O C -> g n O C+  -- | Create a graph containing only an exit sequence+  mkExit    :: Block n C O -> g n C O++instance GraphRep Graph where+  emptyGraph  = GNil+  emptyClosedGraph = GMany NothingO emptyBody NothingO+  (<*>)       = U.gSplice+  (|*><*|)    = U.gSplice+  mkMiddle    = GUnit . BMiddle+  mkExit   block = GMany NothingO      emptyBody (JustO block)+  mkEntry  block = GMany (JustO block) emptyBody NothingO++instance GraphRep AGraph where+  emptyGraph  = aGraphOfGraph emptyGraph+  emptyClosedGraph = aGraphOfGraph emptyClosedGraph+  (<*>)       = liftA2 (<*>)+  (|*><*|)    = liftA2 (|*><*|)+  mkMiddle    = aGraphOfGraph . mkMiddle+  mkExit  = aGraphOfGraph . mkExit+  mkEntry = aGraphOfGraph . mkEntry+++-- | The type of abstract graphs.  Offers extra "smart constructors"+-- that may consume fresh labels during construction.+newtype AGraph n e x =+  A { graphOfAGraph :: forall m. UniqueMonad m =>+                       m (Graph n e x) -- ^ Take an abstract 'AGraph'+                                       -- and make a concrete (if monadic)+                                       -- 'Graph'.+    }++-- | Take a graph and make it abstract.+aGraphOfGraph :: Graph n e x -> AGraph n e x+aGraphOfGraph g = A (return g)+++-- | The 'Labels' class defines things that can be lambda-bound+-- by an argument to 'withFreshLabels'.  Such an argument may+-- lambda-bind a single 'Label', or if multiple labels are needed,+-- it can bind a tuple.  Tuples can be nested, so arbitrarily many+-- fresh labels can be acquired in a single call.+-- +-- For example usage see implementations of 'mkIfThenElse' and 'mkWhileDo'.+class Uniques u where+  withFresh :: (u -> AGraph n e x) -> AGraph n e x++instance Uniques Unique where+  withFresh f = A $ freshUnique >>= (graphOfAGraph . f)++instance Uniques Label where+  withFresh f = A $ freshUnique >>= (graphOfAGraph . f . uniqueToLbl)++-- | Lifts binary 'Graph' functions into 'AGraph' functions.+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)+liftA2 f (A g) (A g') = A (liftM2 f g g')++-- | Extend an existing 'AGraph' with extra basic blocks "out of line".+-- No control flow is implied.  Simon PJ should give example use case.+addBlocks      :: HooplNode n+               => AGraph n e x -> AGraph n C C -> AGraph n e x+addBlocks (A g) (A blocks) = A $ g >>= \g -> blocks >>= add g+  where add :: (UniqueMonad m, HooplNode n)+            => Graph n e x -> Graph n C C -> m (Graph n e x)+        add (GMany e body x) (GMany NothingO body' NothingO) =+          return $ GMany e (body `U.bodyUnion` body') x+        add g@GNil      blocks = spliceOO g blocks+        add g@(GUnit _) blocks = spliceOO g blocks+        spliceOO :: (HooplNode n, UniqueMonad m)+                 => Graph n O O -> Graph n C C -> m (Graph n O O)+        spliceOO g blocks = graphOfAGraph $ withFresh $ \l ->+          A (return g) <*> mkBranch l |*><*| A (return blocks) |*><*| mkLabel l++-- | For some graph-construction operations and some optimizations,+-- Hoopl must be able to create control-flow edges using a given node+-- type 'n'.+class NonLocal n => HooplNode n where+  -- | Create a branch node, the source of a control-flow edge.+  mkBranchNode :: Label -> n O C+  -- | Create a label node, the target (destination) of a control-flow edge.+  mkLabelNode  :: Label -> n C O++--------------------------------------------------------------+--                   Shiny Things+--------------------------------------------------------------++class IfThenElseable x where+  -- | Translate a high-level if-then-else construct into an 'AGraph'.+  -- The condition takes as arguments labels on the true-false branch+  -- and returns a single-entry, two-exit graph which exits to +  -- the two labels.+  mkIfThenElse :: HooplNode n+               => (Label -> Label -> AGraph n O C) -- ^ branch condition+               -> AGraph n O x   -- ^ code in the "then" branch+               -> AGraph n O x   -- ^ code in the "else" branch +               -> AGraph n O x   -- ^ resulting if-then-else construct++mkWhileDo    :: HooplNode n+             => (Label -> Label -> AGraph n O C) -- ^ loop condition+             -> AGraph n O O -- ^ body of the loop+             -> AGraph n O O -- ^ the final while loop++instance IfThenElseable O where+  mkIfThenElse cbranch tbranch fbranch = withFresh $ \(endif, ltrue, lfalse) ->+    cbranch ltrue lfalse |*><*|+      mkLabel ltrue  <*> tbranch <*> mkBranch endif |*><*|+      mkLabel lfalse <*> fbranch <*> mkBranch endif |*><*|+      mkLabel endif++instance IfThenElseable C where+  mkIfThenElse cbranch tbranch fbranch = withFresh $ \(ltrue, lfalse) ->+    cbranch ltrue lfalse |*><*|+       mkLabel ltrue  <*> tbranch |*><*|+       mkLabel lfalse <*> fbranch++mkWhileDo cbranch body = withFresh $ \(test, head, endwhile) ->+     -- Forrest Baskett's while-loop layout+  mkBranch test |*><*|+    mkLabel head <*> body <*> mkBranch test |*><*|+    mkLabel test <*> cbranch head endwhile  |*><*|+    mkLabel endwhile++--------------------------------------------------------------+--               Boring instance declarations+--------------------------------------------------------------+++instance (Uniques u1, Uniques u2) => Uniques (u1, u2) where+  withFresh f = withFresh $ \u1 ->+                withFresh $ \u2 ->+                f (u1, u2)++instance (Uniques u1, Uniques u2, Uniques u3) => Uniques (u1, u2, u3) where+  withFresh f = withFresh $ \u1 ->+                withFresh $ \u2 ->+                withFresh $ \u3 ->+                f (u1, u2, u3)++instance (Uniques u1, Uniques u2, Uniques u3, Uniques u4) => Uniques (u1, u2, u3, u4) where+  withFresh f = withFresh $ \u1 ->+                withFresh $ \u2 ->+                withFresh $ \u3 ->+                withFresh $ \u4 ->+                f (u1, u2, u3, u4)++---------------------------------------------+-- deprecated legacy functions++{-# DEPRECATED addEntrySeq, addExitSeq, unionBlocks "use |*><*| instead" #-}+addEntrySeq :: NonLocal n => AGraph n O C -> AGraph n C x -> AGraph n O x+addExitSeq  :: NonLocal n => AGraph n e C -> AGraph n C O -> AGraph n e O+unionBlocks :: NonLocal n => AGraph n C C -> AGraph n C C -> AGraph n C C++addEntrySeq = (|*><*|)+addExitSeq  = (|*><*|)+unionBlocks = (|*><*|)
+ src/Compiler/Hoopl/Passes/DList.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE GADTs #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}++module Compiler.Hoopl.Passes.DList+  ( Doms, domEntry, domLattice+  , domPass+  )+where++import Compiler.Hoopl+++type Doms = WithBot [Label]+-- ^ List of labels, extended with a standard bottom element++-- | The fact that goes into the entry of a dominator analysis: the first node+-- is dominated only by the entry point, which is represented by the empty list+-- of labels.+domEntry :: Doms+domEntry = PElem []++domLattice :: DataflowLattice Doms+domLattice = addPoints "dominators" extend++extend :: JoinFun [Label]+extend _ (OldFact l) (NewFact l') = (changeIf (l `lengthDiffers` j), j)+    where j = lcs l l'+          lcs :: [Label] -> [Label] -> [Label] -- longest common suffix+          lcs l l' | length l > length l' = lcs (drop (length l - length l') l) l'+                   | length l < length l' = lcs l' l+                   | otherwise = dropUnlike l l' l+          dropUnlike [] [] maybe_like = maybe_like+          dropUnlike (x:xs) (y:ys) maybe_like =+              dropUnlike xs ys (if x == y then maybe_like else xs)+          dropUnlike _ _ _ = error "this can't happen"++          lengthDiffers [] [] = False+          lengthDiffers (_:xs) (_:ys) = lengthDiffers xs ys+          lengthDiffers [] (_:_) = True+          lengthDiffers (_:_) [] = True++-- | Dominator pass+domPass :: (NonLocal n, Monad m) => FwdPass m n Doms+domPass = FwdPass domLattice (mkFTransfer3 first (const id) distributeFact) noFwdRewrite+  where first n = fmap (entryLabel n:)
+ src/Compiler/Hoopl/Passes/Dominator.hs view
@@ -0,0 +1,130 @@+{-# LANGUAGE GADTs #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}++module Compiler.Hoopl.Passes.Dominator+  ( Doms, DPath(..), domPath, domEntry, domLattice, extendDom+  , DominatorNode(..), DominatorTree(..), tree+  , immediateDominators+  , domPass+  )+where++import Data.Maybe++import Compiler.Hoopl+++type Doms = WithBot DPath+-- ^ List of labels, extended with a standard bottom element++-- | The fact that goes into the entry of a dominator analysis: the first node+-- is dominated only by the entry point, which is represented by the empty list+-- of labels.+domEntry :: Doms+domEntry = PElem (DPath [])++newtype DPath = DPath [Label]+  -- ^ represents part of the domination relation: each label+  -- in a list is dominated by all its successors.  This is a newtype only so+  -- we can give it a fancy Show instance.++instance Show DPath where+  show (DPath ls) = concat (foldr (\l path -> show l : " -> " : path) ["entry"] ls)++domPath :: Doms -> [Label]+domPath Bot = [] -- lies: an unreachable node appears to be dominated by the entry+domPath (PElem (DPath ls)) = ls++extendDom :: Label -> DPath -> DPath+extendDom l (DPath ls) = DPath (l:ls)++domLattice :: DataflowLattice Doms+domLattice = addPoints "dominators" extend++extend :: JoinFun DPath+extend _ (OldFact (DPath l)) (NewFact (DPath l')) =+                                (changeIf (l `lengthDiffers` j), DPath j)+    where j = lcs l l'+          lcs :: [Label] -> [Label] -> [Label] -- longest common suffix+          lcs l l' | length l > length l' = lcs (drop (length l - length l') l) l'+                   | length l < length l' = lcs l' l+                   | otherwise = dropUnlike l l' l+          dropUnlike [] [] maybe_like = maybe_like+          dropUnlike (x:xs) (y:ys) maybe_like =+              dropUnlike xs ys (if x == y then maybe_like else xs)+          dropUnlike _ _ _ = error "this can't happen"++          lengthDiffers [] [] = False+          lengthDiffers (_:xs) (_:ys) = lengthDiffers xs ys+          lengthDiffers [] (_:_) = True+          lengthDiffers (_:_) [] = True++++-- | Dominator pass+domPass :: (NonLocal n, Monad m) => FwdPass m n Doms+domPass = FwdPass domLattice (mkFTransfer3 first (const id) distributeFact) noFwdRewrite+  where first n = fmap (extendDom $ entryLabel n)++----------------------------------------------------------------++data DominatorNode = Entry | Labelled Label+data DominatorTree = Dominates DominatorNode [DominatorTree]+-- ^ This data structure is a *rose tree* in which each node may have+--  arbitrarily many children.  Each node dominates all its descendants.++-- | Map from a FactBase for dominator lists into a+-- dominator tree.  +tree :: [(Label, Doms)] -> DominatorTree+tree facts = Dominates Entry $ merge $ map reverse $ map mkList facts+   -- This code has been lightly tested.  The key insight is this: to+   -- find lists that all have the same head, convert from a list of+   -- lists to a finite map, in 'children'.  Then, to convert from the+   -- finite map to list of dominator trees, use the invariant that+   -- each key dominates all the lists of values.+  where merge lists = mapTree $ children $ filter (not . null) lists+        children = foldl addList noFacts+        addList :: FactBase [[Label]] -> [Label] -> FactBase [[Label]]+        addList map (x:xs) = mapInsert x (xs:existing) map+            where existing = fromMaybe [] $ lookupFact x map+        addList _ [] = error "this can't happen"+        mapTree :: FactBase [[Label]] -> [DominatorTree]+        mapTree map = [Dominates (Labelled x) (merge lists) |+                                                    (x, lists) <- mapToList map]+        mkList (l, doms) = l : domPath doms+++instance Show DominatorTree where+  show = tree2dot++-- | Given a dominator tree, produce a string representation, in the+-- input language of dot, that will enable dot to produce a+-- visualization of the tree.  For more info about dot see+-- http://www.graphviz.org.++tree2dot :: DominatorTree -> String+tree2dot t = concat $ "digraph {\n" : dot t ["}\n"]+  where+    dot :: DominatorTree -> [String] -> [String]+    dot (Dominates root trees) = +                   (dotnode root :) . outedges trees . flip (foldl subtree) trees+      where outedges [] = id+            outedges (Dominates n _ : ts) =+                \s -> "  " : show root : " -> " : show n : "\n" : outedges ts s+            dotnode Entry = "  entryNode [shape=plaintext, label=\"entry\"]\n"+            dotnode (Labelled l) = "  " ++ show l ++ "\n"+            subtree = flip dot++instance Show DominatorNode where+  show Entry = "entryNode"+  show (Labelled l) = show l++----------------------------------------------------------------++-- | Takes FactBase from dominator analysis and returns a map from each +-- label to its immediate dominator, if any+immediateDominators :: FactBase Doms -> LabelMap Label+immediateDominators = mapFoldWithKey add mapEmpty+    where add l (PElem (DPath (idom:_))) = mapInsert l idom +          add _ _ = id+
+ src/Compiler/Hoopl/Pointed.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE GADTs, ScopedTypeVariables #-}++-- | Possibly doubly pointed lattices++module Compiler.Hoopl.Pointed+  ( Pointed(..), addPoints, addPoints', addTop, addTop'+  , liftJoinTop, extendJoinDomain+  , WithTop, WithBot, WithTopAndBot+  )+where++import Compiler.Hoopl.Graph+import Compiler.Hoopl.Label+import Compiler.Hoopl.Dataflow++-- | Adds top, bottom, or both to help form a lattice+data Pointed t b a where+   Bot   ::      Pointed t C a+   PElem :: a -> Pointed t b a+   Top   ::      Pointed C b a++-- ^ The type parameters 't' and 'b' are used to say whether top+-- and bottom elements have been added.  The analogy with 'Block'+-- is nearly exact:+--+--  * A 'Block' is closed at the entry if and only if it has a first node;+--    a 'Pointed' is closed at the top if and only if it has a top element.+--+--  * A 'Block' is closed at the exit if and only if it has a last node;+--    a 'Pointed' is closed at the bottom if and only if it has a bottom element.+--+-- We thus have four possible types, of which three are interesting:+--+--  [@Pointed C C a@] Type @a@ extended with both top and bottom elements.+--+--  [@Pointed C O a@] Type @a@ extended with a top element+--  only. (Presumably @a@ comes equipped with a bottom element of its own.)+--+--  [@Pointed O C a@] Type @a@ extended with a bottom element only. +--+--  [@Pointed O O a@] Isomorphic to @a@, and therefore not interesting.+--+-- The advantage of all this GADT-ishness is that the constructors+-- 'Bot', 'Top', and 'PElem' can all be used polymorphically.+--+-- A 'Pointed t b' type is an instance of 'Functor' and 'Show'.++++type WithBot a = Pointed O C a+-- ^ Type 'a' with a bottom element adjoined++type WithTop a = Pointed C O a+-- ^ Type 'a' with a top element adjoined++type WithTopAndBot a = Pointed C C a+-- ^ Type 'a' with top and bottom elements adjoined+++-- | Given a join function and a name, creates a semi lattice by+-- adding a bottom element, and possibly a top element also.+-- A specialized version of 'addPoints''.+addPoints  :: String -> JoinFun a -> DataflowLattice (Pointed t C a)+-- | A more general case for creating a new lattice+addPoints' :: forall a t .+              String+           -> (Label -> OldFact a -> NewFact a -> (ChangeFlag, Pointed t C a))+           -> DataflowLattice (Pointed t C a)++addPoints name join = addPoints' name join'+   where join' l o n = (change, PElem f)+            where (change, f) = join l o n++addPoints' name joinx = DataflowLattice name Bot join+  where -- careful: order of cases matters for ChangeFlag+        join :: JoinFun (Pointed t C a)+        join _ (OldFact f)            (NewFact Bot) = (NoChange, f)+        join _ (OldFact Top)          (NewFact _)   = (NoChange, Top)+        join _ (OldFact Bot)          (NewFact f)   = (SomeChange, f)+        join _ (OldFact _)            (NewFact Top) = (SomeChange, Top)+        join l (OldFact (PElem old)) (NewFact (PElem new))+           = joinx l (OldFact old) (NewFact new)+++liftJoinTop :: JoinFun a -> JoinFun (WithTop a)+extendJoinDomain :: forall a+              . (Label -> OldFact a -> NewFact a -> (ChangeFlag, WithTop a))+             -> JoinFun (WithTop a)++extendJoinDomain joinx = join+ where join :: JoinFun (WithTop a)+       join _ (OldFact Top)          (NewFact _)   = (NoChange, Top)+       join _ (OldFact _)            (NewFact Top) = (SomeChange, Top)+       join l (OldFact (PElem old)) (NewFact (PElem new))+           = joinx l (OldFact old) (NewFact new)++liftJoinTop joinx = extendJoinDomain (\l old new -> liftPair $ joinx l old new)+  where liftPair (c, a) = (c, PElem a)++-- | Given a join function and a name, creates a semi lattice by+-- adding a top element but no bottom element.  Caller must supply the bottom +-- element.+addTop  :: DataflowLattice a -> DataflowLattice (WithTop a)+-- | A more general case for creating a new lattice+addTop' :: forall a .+              String+           -> a+           -> (Label -> OldFact a -> NewFact a -> (ChangeFlag, WithTop a))+           -> DataflowLattice (WithTop a)++addTop lattice = addTop' name' (fact_bot lattice) join'+   where name' = fact_name lattice ++ " + T"+         join' l o n = (change, PElem f)+            where (change, f) = fact_join lattice l o n++addTop' name bot joinx = DataflowLattice name (PElem bot) join+  where -- careful: order of cases matters for ChangeFlag+        join :: JoinFun (WithTop a)+        join _ (OldFact Top)          (NewFact _)   = (NoChange, Top)+        join _ (OldFact _)            (NewFact Top) = (SomeChange, Top)+        join l (OldFact (PElem old)) (NewFact (PElem new))+           = joinx l (OldFact old) (NewFact new)++instance Show a => Show (Pointed t b a) where+  show Bot = "_|_"+  show Top = "T"+  show (PElem a) = show a++instance Functor (Pointed t b) where+  fmap _ Bot = Bot+  fmap _ Top = Top+  fmap f (PElem a) = PElem (f a)++instance Eq a => Eq (Pointed t b a) where+  Bot == Bot = True+  Top == Top = True+  (PElem a) == (PElem a') = a == a'+  _ == _ = False++instance Ord a => Ord (Pointed t b a) where+  Bot     `compare` Bot      = EQ+  Bot     `compare` _        = LT+  _       `compare` Bot      = GT+  PElem a `compare` PElem a' = a `compare` a'+  Top     `compare` Top      = EQ+  Top     `compare` _        = GT+  _       `compare` Top      = LT
+ src/Compiler/Hoopl/Shape.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE GADTs, EmptyDataDecls #-}++module Compiler.Hoopl.Shape {-# DEPRECATED "not ready to migrate to this yet" #-}+where++-- | Used at the type level to indicate an "open" structure with    +-- a unique, unnamed control-flow edge flowing in or out.         +-- "Fallthrough" and concatenation are permitted at an open point.+data O +       +       +-- | Used at the type level to indicate a "closed" structure which+-- supports control transfer only through the use of named+-- labels---no "fallthrough" is permitted.  The number of control-flow+-- edges is unconstrained.+data C+++data HalfShape s where+  ShapeO :: HalfShape O+  ShapeC :: HalfShape C++data Shape e x where+  ShapeOO :: Shape O O+  ShapeCO :: Shape C O+  ShapeOC :: Shape O C+  ShapeCC :: Shape C C++class Shapely n where+  shape        :: n e x -> Shape e x+  shapeAtEntry :: n e x -> HalfShape e+  shapeAtExit  :: n e x -> HalfShape x++  shapeAtEntry = entryHalfShape . shape+  shapeAtExit  = exitHalfShape  . shape+  ++entryHalfShape :: Shape e x -> HalfShape e+exitHalfShape  :: Shape e x -> HalfShape x++entryHalfShape ShapeOO = ShapeO+entryHalfShape ShapeOC = ShapeO+entryHalfShape ShapeCO = ShapeC+entryHalfShape ShapeCC = ShapeC++exitHalfShape ShapeOO = ShapeO+exitHalfShape ShapeOC = ShapeC+exitHalfShape ShapeCO = ShapeO+exitHalfShape ShapeCC = ShapeC+
+ src/Compiler/Hoopl/Show.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE RankNTypes, GADTs, ScopedTypeVariables, FlexibleContexts #-}++module Compiler.Hoopl.Show +  ( showGraph, showFactBase+  )+where++import Compiler.Hoopl.Collections+import Compiler.Hoopl.Graph+import Compiler.Hoopl.Label++--------------------------------------------------------------------------------+-- Prettyprinting+--------------------------------------------------------------------------------++type Showing n = forall e x . n e x -> String+ ++showGraph :: forall n e x . (NonLocal n) => Showing n -> Graph n e x -> String+showGraph node = g+  where g :: (NonLocal 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 (mapElems blocks)+        b :: forall e x . Block n e x -> String+        b (BFirst  n)     = node n+        b (BMiddle n)     = node n+        b (BLast   n)     = node n ++ "\n"+        b (BCat b1 b2)    = b b1   ++ b b2+        b (BHead b1 n)    = b b1   ++ node n ++ "\n"+        b (BTail n b1)    = node n ++ b b1+        b (BClosed b1 b2) = b b1   ++ b b2++open :: (a -> String) -> MaybeO z a -> String+open _ NothingO  = ""+open p (JustO n) = p n++showFactBase :: Show f => FactBase f -> String+showFactBase = show . mapToList
+ src/Compiler/Hoopl/Unique.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE TypeFamilies #-}+module Compiler.Hoopl.Unique+  ( Unique, intToUnique+  , UniqueSet, UniqueMap+  , UniqueMonad(..)+  , SimpleUniqueMonad, runSimpleUniqueMonad+  , UniqueMonadT, runUniqueMonadT++  , uniqueToInt -- exposed through GHC module only!+  )++where++import Compiler.Hoopl.Checkpoint+import Compiler.Hoopl.Collections++import qualified Data.IntMap as M+import qualified Data.IntSet as S++-----------------------------------------------------------------------------+--		Unique+-----------------------------------------------------------------------------++data Unique = Unique { uniqueToInt ::  {-# UNPACK #-} !Int }+  deriving (Eq, Ord)++intToUnique :: Int -> Unique+intToUnique = Unique++instance Show Unique where+  show (Unique n) = show n++-----------------------------------------------------------------------------+-- UniqueSet++newtype UniqueSet = US S.IntSet deriving (Eq, Ord, Show)++instance IsSet UniqueSet where+  type ElemOf UniqueSet = Unique++  setNull (US s) = S.null s+  setSize (US s) = S.size s+  setMember (Unique k) (US s) = S.member k s++  setEmpty = US S.empty+  setSingleton (Unique k) = US (S.singleton k)+  setInsert (Unique k) (US s) = US (S.insert k s)+  setDelete (Unique k) (US s) = US (S.delete k s)++  setUnion (US x) (US y) = US (S.union x y)+  setDifference (US x) (US y) = US (S.difference x y)+  setIntersection (US x) (US y) = US (S.intersection x y)+  setIsSubsetOf (US x) (US y) = S.isSubsetOf x y++  setFold k z (US s) = S.fold (k . intToUnique) z s++  setElems (US s) = map intToUnique (S.elems s)+  setFromList ks = US (S.fromList (map uniqueToInt ks))++-----------------------------------------------------------------------------+-- UniqueMap++newtype UniqueMap v = UM (M.IntMap v) deriving (Eq, Ord, Show)++instance IsMap UniqueMap where+  type KeyOf UniqueMap = Unique++  mapNull (UM m) = M.null m+  mapSize (UM m) = M.size m+  mapMember (Unique k) (UM m) = M.member k m+  mapLookup (Unique k) (UM m) = M.lookup k m+  mapFindWithDefault def (Unique k) (UM m) = M.findWithDefault def k m++  mapEmpty = UM M.empty+  mapSingleton (Unique k) v = UM (M.singleton k v)+  mapInsert (Unique k) v (UM m) = UM (M.insert k v m)+  mapDelete (Unique k) (UM m) = UM (M.delete k m)++  mapUnion (UM x) (UM y) = UM (M.union x y)+  mapUnionWithKey f (UM x) (UM y) = UM (M.unionWithKey (f . intToUnique) x y)+  mapDifference (UM x) (UM y) = UM (M.difference x y)+  mapIntersection (UM x) (UM y) = UM (M.intersection x y)+  mapIsSubmapOf (UM x) (UM y) = M.isSubmapOf x y++  mapMap f (UM m) = UM (M.map f m)+  mapMapWithKey f (UM m) = UM (M.mapWithKey (f . intToUnique) m)+  mapFold k z (UM m) = M.fold k z m+  mapFoldWithKey k z (UM m) = M.foldWithKey (k . intToUnique) z m++  mapElems (UM m) = M.elems m+  mapKeys (UM m) = map intToUnique (M.keys m)+  mapToList (UM m) = [(intToUnique k, v) | (k, v) <- M.toList m]+  mapFromList assocs = UM (M.fromList [(uniqueToInt k, v) | (k, v) <- assocs])++----------------------------------------------------------------+-- Monads++class Monad m => UniqueMonad m where+  freshUnique :: m Unique++newtype SimpleUniqueMonad a = SUM { unSUM :: [Unique] -> (a, [Unique]) }++instance Monad SimpleUniqueMonad where+  return a = SUM $ \us -> (a, us)+  m >>= k  = SUM $ \us -> let (a, us') = unSUM m us in+                              unSUM (k a) us'++instance UniqueMonad SimpleUniqueMonad where+  freshUnique = SUM $ f+    where f (u:us) = (u, us)+          f _ = error "Unique.freshUnique(SimpleUniqueMonad): empty list"++instance CheckpointMonad SimpleUniqueMonad where+  type Checkpoint SimpleUniqueMonad = [Unique]+  checkpoint = SUM $ \us -> (us, us)+  restart us = SUM $ \_  -> ((), us)++runSimpleUniqueMonad :: SimpleUniqueMonad a -> a+runSimpleUniqueMonad m = fst (unSUM m allUniques)++----------------------------------------------------------------++newtype UniqueMonadT m a = UMT { unUMT :: [Unique] -> m (a, [Unique]) }++instance Monad m => Monad (UniqueMonadT m) where+  return a = UMT $ \us -> return (a, us)+  m >>= k  = UMT $ \us -> do { (a, us') <- unUMT m us; unUMT (k a) us' }++instance Monad m => UniqueMonad (UniqueMonadT m) where+  freshUnique = UMT $ f+    where f (u:us) = return (u, us)+          f _ = error "Unique.freshUnique(UniqueMonadT): empty list"++runUniqueMonadT :: Monad m => UniqueMonadT m a -> m a+runUniqueMonadT m = do { (a, _) <- unUMT m allUniques; return a }++allUniques :: [Unique]+allUniques = map Unique [1..]
+ src/Compiler/Hoopl/Util.hs view
@@ -0,0 +1,268 @@+{-# LANGUAGE GADTs, ScopedTypeVariables, FlexibleInstances, RankNTypes, TypeFamilies #-}++module Compiler.Hoopl.Util+  ( gUnitOO, gUnitOC, gUnitCO, gUnitCC+  , catGraphNodeOC, catGraphNodeOO+  , catNodeCOGraph, catNodeOOGraph+  , graphMapBlocks+  , blockMapNodes, blockMapNodes3+  , blockGraph+  , 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.Collections+import Compiler.Hoopl.Graph+import Compiler.Hoopl.Label+++----------------------------------------------------------------++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 :: NonLocal (block n) => block n C C -> Graph' block n C C+gUnitOO b = GUnit b+gUnitOC b = GMany (JustO b) emptyBody  NothingO+gUnitCO b = GMany NothingO  emptyBody (JustO b)+gUnitCC b = GMany NothingO  (addBlock b emptyBody) NothingO+++catGraphNodeOO ::            Graph n e O -> n O O -> Graph n e O+catGraphNodeOC :: NonLocal n => Graph n e O -> n O C -> Graph n e C+catNodeOOGraph ::            n O O -> Graph n O x -> Graph n O x+catNodeCOGraph :: NonLocal n => n C O -> Graph n O x -> Graph n C x++catGraphNodeOO GNil                     n = gUnitOO $ BMiddle n+catGraphNodeOO (GUnit b)                n = gUnitOO $ b `BCat` BMiddle n+catGraphNodeOO (GMany e body (JustO x)) n = GMany e body (JustO $ x `BHead` n)++catGraphNodeOC GNil                     n = gUnitOC $ BLast n+catGraphNodeOC (GUnit b)                n = gUnitOC $ addToLeft b $ BLast n+  where addToLeft :: Block n O O -> Block n O C -> Block n O C+        addToLeft (BMiddle m)    g = m `BTail` g+        addToLeft (b1 `BCat` b2) g = addToLeft b1 $ addToLeft b2 g+catGraphNodeOC (GMany e body (JustO x)) n = GMany e body' NothingO+  where body' = addBlock (x `BClosed` BLast n) body++catNodeOOGraph n GNil                     = gUnitOO $ BMiddle n+catNodeOOGraph n (GUnit b)                = gUnitOO $ BMiddle n `BCat` b+catNodeOOGraph n (GMany (JustO e) body x) = GMany (JustO $ n `BTail` e) body x++catNodeCOGraph n GNil                     = gUnitCO $ BFirst n+catNodeCOGraph n (GUnit b)                = gUnitCO $ addToRight (BFirst n) b+  where addToRight :: Block n C O -> Block n O O -> Block n C O+        addToRight g (BMiddle m)    = g `BHead` m+        addToRight g (b1 `BCat` b2) = addToRight (addToRight g b1) b2+catNodeCOGraph n (GMany (JustO e) body x) = GMany NothingO body' x+  where body' = addBlock (BFirst n `BClosed` e) body++++++blockGraph :: NonLocal n => Block n e x -> Graph n e x+blockGraph b@(BFirst  {}) = gUnitCO b+blockGraph b@(BMiddle {}) = gUnitOO b+blockGraph b@(BLast   {}) = gUnitOC b+blockGraph b@(BCat {})    = gUnitOO b+blockGraph b@(BHead {})   = gUnitCO b+blockGraph b@(BTail {})   = gUnitOC b+blockGraph b@(BClosed {}) = gUnitCC b+++-- | Function 'graphMapBlocks' enables a change of representation of blocks,+-- nodes, or both.  It lifts a polymorphic block transform into a polymorphic+-- graph transform.  When the block representation stabilizes, a similar+-- function should be provided for blocks.+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)++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) (mapMap f b) (fmap f x)++-- | Function 'blockMapNodes' enables a change of nodes in a block.+blockMapNodes3 :: ( n C O -> n' C O+                  , n O O -> n' O O+                  , n O C -> n' O C)+               -> Block n e x -> Block n' e x+blockMapNodes3 (f, _, _) (BFirst n)     = BFirst (f n)+blockMapNodes3 (_, m, _) (BMiddle n)    = BMiddle (m n)+blockMapNodes3 (_, _, l) (BLast n)      = BLast (l n)+blockMapNodes3 fs (BCat x y)            = BCat (blockMapNodes3 fs x) (blockMapNodes3 fs y)+blockMapNodes3 fs@(_, m, _) (BHead x n) = BHead (blockMapNodes3 fs x) (m n)+blockMapNodes3 fs@(_, m, _) (BTail n x) = BTail (m n) (blockMapNodes3 fs x)+blockMapNodes3 fs (BClosed x y)         = BClosed (blockMapNodes3 fs x) (blockMapNodes3 fs y)++blockMapNodes :: (forall e x. n e x -> n' e x)+              -> (Block n e x -> Block n' e x)+blockMapNodes f = blockMapNodes3 (f, f, f)++----------------------------------------------------------------++class LabelsPtr l where+  targetLabels :: l -> [Label]++instance NonLocal n => LabelsPtr (n e C) where+  targetLabels n = successors n++instance LabelsPtr Label where+  targetLabels l = [l]++instance LabelsPtr LabelSet where+  targetLabels = setElems++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 :: NonLocal (block n) => Graph' block n O x -> [block n C C]+preorder_dfs  :: NonLocal (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 :: (NonLocal (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 body entry setEmpty++postorder_dfs = graphDfs postorder_dfs_from_except+preorder_dfs  = graphDfs preorder_dfs_from_except++postorder_dfs_from_except :: forall block e . (NonLocal 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 setMember id visited then+            cont acc visited+        else+            let cont' acc visited = cont (block:acc) visited in+            vchildren (get_children block) cont' acc (setInsert id visited)+      where id = entryLabel block+   vchildren :: forall a. [block C C] -> ([block C C] -> LabelSet -> a) -> [block C C] -> LabelSet -> a+   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 :: forall l. LabelsPtr l => l -> [block C C]+   get_children block = foldr add_id [] $ targetLabels block+   add_id id rst = case lookupFact id blocks of+                      Just b -> b : rst+                      Nothing -> rst++postorder_dfs_from+    :: (NonLocal block, LabelsPtr b) => LabelMap (block C C) -> b -> [block C C]+postorder_dfs_from blocks b = postorder_dfs_from_except blocks b setEmpty+++----------------------------------------------------------------++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 -> (setMember l v, v)+mark   l = VM $ \v -> ((), setInsert l v)++preorder_dfs_from_except :: forall block e . (NonLocal 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 :: forall l. LabelsPtr l => l -> [block C C]+        get_children block = foldr add_id [] $ targetLabels block+        add_id id rst = case lookupFact id blocks 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 . NonLocal (block n) => Graph' block n e x -> LabelSet+labelsDefined GNil      = setEmpty+labelsDefined (GUnit{}) = setEmpty+labelsDefined (GMany _ body x) = mapFoldWithKey addEntry (exitLabel x) body+  where addEntry :: forall a. ElemOf LabelSet -> a -> LabelSet -> LabelSet+        addEntry label _ labels = setInsert label labels+        exitLabel :: MaybeO x (block n C O) -> LabelSet+        exitLabel NothingO  = setEmpty+        exitLabel (JustO b) = setSingleton (entryLabel b)++labelsUsed :: forall block n e x. NonLocal (block n) => Graph' block n e x -> LabelSet+labelsUsed GNil      = setEmpty+labelsUsed (GUnit{}) = setEmpty+labelsUsed (GMany e body _) = mapFold addTargets (entryTargets e) body +  where addTargets :: forall e. block n e C -> LabelSet -> LabelSet+        addTargets block labels = setInsertList (successors block) labels+        entryTargets :: MaybeO e (block n O C) -> LabelSet+        entryTargets NothingO = setEmpty+        entryTargets (JustO b) = addTargets b setEmpty++externalEntryLabels :: forall n .+                       NonLocal n => LabelMap (Block n C C) -> LabelSet+externalEntryLabels body = defined `setDifference` used+  where defined = labelsDefined g+        used = labelsUsed g+        g = GMany NothingO body NothingO
+ src/Compiler/Hoopl/Wrappers.hs view
@@ -0,0 +1,7 @@+module Compiler.Hoopl.Wrappers {-# DEPRECATED "Use only if you know what you are doing and can preserve the 'respects fuel' invariant" #-}+  ( wrapFR, wrapFR2, wrapBR, wrapBR2+  )+where++import Compiler.Hoopl.Dataflow+
+ src/Compiler/Hoopl/XUtil.hs view
@@ -0,0 +1,508 @@+{-# LANGUAGE GADTs, RankNTypes, ScopedTypeVariables, TypeFamilies  #-}++-- | Utilities for clients of Hoopl, not used internally.++module Compiler.Hoopl.XUtil+  ( firstXfer, distributeXfer+  , distributeFact, distributeFactBwd+  , successorFacts+  , joinFacts+  , joinOutFacts -- deprecated+  , joinMaps+  , foldGraphNodes+  , foldBlockNodesF, foldBlockNodesB, foldBlockNodesF3, foldBlockNodesB3+  , tfFoldBlock+  , ScottBlock(ScottBlock), scottFoldBlock+  , fbnf3+  , blockToNodeList, blockOfNodeList+  , blockToNodeList'   -- alternate version using fold+  , blockToNodeList''  -- alternate version using scottFoldBlock+  , blockToNodeList''' -- alternate version using tfFoldBlock+  , analyzeAndRewriteFwdBody, analyzeAndRewriteBwdBody+  , analyzeAndRewriteFwdOx, analyzeAndRewriteBwdOx+  , noEntries+  , BlockResult(..), lookupBlock+  )+where++import qualified Data.Map as M+import Data.Maybe++import Compiler.Hoopl.Checkpoint+import Compiler.Hoopl.Collections+import Compiler.Hoopl.Dataflow+import Compiler.Hoopl.Graph+import Compiler.Hoopl.Label+import Compiler.Hoopl.Util+++-- | Forward dataflow analysis and rewriting for the special case of a Body.+-- A set of entry points must be supplied; blocks not reachable from+-- the set are thrown away.+analyzeAndRewriteFwdBody+   :: forall m n f entries. (CheckpointMonad m, NonLocal n, LabelsPtr entries)+   => FwdPass m n f+   -> entries -> Body n -> FactBase f+   -> m (Body n, FactBase f)++-- | Backward dataflow analysis and rewriting for the special case of a Body.+-- A set of entry points must be supplied; blocks not reachable from+-- the set are thrown away.+analyzeAndRewriteBwdBody+   :: forall m n f entries. (CheckpointMonad m, NonLocal n, LabelsPtr entries)+   => BwdPass m n f +   -> entries -> Body n -> FactBase f +   -> m (Body n, FactBase f)++analyzeAndRewriteFwdBody pass en = mapBodyFacts (analyzeAndRewriteFwd pass (JustC en))+analyzeAndRewriteBwdBody pass en = mapBodyFacts (analyzeAndRewriteBwd pass (JustC en))++mapBodyFacts :: (Monad m)+    => (Graph n C C -> Fact C f   -> m (Graph n C C, Fact C f, MaybeO C f))+    -> (Body n      -> FactBase f -> m (Body n, FactBase f))+-- ^ Internal utility; should not escape+mapBodyFacts anal b f = anal (GMany NothingO b NothingO) f >>= bodyFacts+  where -- the type constraint is needed for the pattern match;+        -- if it were not, we would use do-notation here.+    bodyFacts :: Monad m => (Graph n C C, Fact C f, MaybeO C f) -> m (Body n, Fact C f)+    bodyFacts (GMany NothingO body NothingO, fb, NothingO) = return (body, fb)++{-+  Can't write:++     do (GMany NothingO body NothingO, fb, NothingO) <- anal (....) f+        return (body, fb)++  because we need an explicit type signature in order to do the GADT+  pattern matches on NothingO+-}++++-- | Forward dataflow analysis and rewriting for the special case of a +-- graph open at the entry.  This special case relieves the client+-- from having to specify a type signature for 'NothingO', which beginners+-- might find confusing and experts might find annoying.+analyzeAndRewriteFwdOx+   :: forall m n f x. (CheckpointMonad m, NonLocal n)+   => FwdPass m n f -> Graph n O x -> f -> m (Graph n O x, FactBase f, MaybeO x f)++-- | Backward dataflow analysis and rewriting for the special case of a +-- graph open at the entry.  This special case relieves the client+-- from having to specify a type signature for 'NothingO', which beginners+-- might find confusing and experts might find annoying.+analyzeAndRewriteBwdOx+   :: forall m n f x. (CheckpointMonad m, NonLocal n)+   => BwdPass m n f -> Graph n O x -> Fact x f -> m (Graph n O x, FactBase f, f)++-- | A value that can be used for the entry point of a graph open at the entry.+noEntries :: MaybeC O Label+noEntries = NothingC++analyzeAndRewriteFwdOx pass g f  = analyzeAndRewriteFwd pass noEntries g f+analyzeAndRewriteBwdOx pass g fb = analyzeAndRewriteBwd pass noEntries g fb >>= strip+  where strip :: forall m a b c . Monad m => (a, b, MaybeO O c) -> m (a, b, c)+        strip (a, b, JustO c) = return (a, b, c)++++++-- | A utility function so that a transfer function for a first+-- node can be given just a fact; we handle the lookup.  This+-- function is planned to be made obsolete by changes in the dataflow+-- interface.++firstXfer :: NonLocal n => (n C O -> f -> f) -> (n C O -> FactBase f -> f)+firstXfer xfer n fb = xfer n $ fromJust $ lookupFact (entryLabel n) fb++-- | This utility function handles a common case in which a transfer function+-- produces a single fact out of a last node, which is then distributed+-- over the outgoing edges.+distributeXfer :: NonLocal n+               => DataflowLattice f -> (n O C -> f -> f) -> (n O C -> f -> FactBase f)+distributeXfer lattice xfer n f =+    mkFactBase lattice [ (l, xfer n f) | l <- successors n ]++-- | This utility function handles a common case in which a transfer function+-- for a last node takes the incoming fact unchanged and simply distributes+-- that fact over the outgoing edges.+distributeFact :: NonLocal n => n O C -> f -> FactBase f+distributeFact n f = mapFromList [ (l, f) | l <- successors n ]+   -- because the same fact goes out on every edge,+   -- there's no need for 'mkFactBase' here.++-- | This utility function handles a common case in which a backward transfer+-- function takes the incoming fact unchanged and tags it with the node's label.+distributeFactBwd :: NonLocal n => n C O -> f -> FactBase f+distributeFactBwd n f = mapSingleton (entryLabel n) f++-- | List of (unlabelled) facts from the successors of a last node+successorFacts :: NonLocal n => n O C -> FactBase f -> [f]+successorFacts n fb = [ f | id <- successors n, let Just f = lookupFact id fb ]++-- | Join a list of facts.+joinFacts :: DataflowLattice f -> Label -> [f] -> f+joinFacts lat inBlock = foldr extend (fact_bot lat)+  where extend new old = snd $ fact_join lat inBlock (OldFact old) (NewFact new)++{-# DEPRECATED joinOutFacts+    "should be replaced by 'joinFacts lat l (successorFacts n f)'; as is, it uses the wrong Label" #-}++joinOutFacts :: (NonLocal node) => DataflowLattice f -> node O C -> FactBase f -> f+joinOutFacts lat n f = foldr join (fact_bot lat) facts+  where join (lbl, new) old = snd $ fact_join lat lbl (OldFact old) (NewFact new)+        facts = [(s, fromJust fact) | s <- successors n, let fact = lookupFact s f, isJust fact]+++-- | It's common to represent dataflow facts as a map from variables+-- to some fact about the locations. For these maps, the join+-- operation on the map can be expressed in terms of the join on each+-- element of the codomain:+joinMaps :: Ord k => JoinFun v -> JoinFun (M.Map k v)+joinMaps eltJoin l (OldFact old) (NewFact new) = M.foldrWithKey add (NoChange, old) new+  where +    add k new_v (ch, joinmap) =+      case M.lookup k joinmap of+        Nothing    -> (SomeChange, M.insert k new_v joinmap)+        Just old_v -> case eltJoin l (OldFact old_v) (NewFact new_v) of+                        (SomeChange, v') -> (SomeChange, M.insert k v' joinmap)+                        (NoChange,   _)  -> (ch, joinmap)++++-- | A fold function that relies on the IndexedCO type function.+--   Note that the type parameter e is available to the functions+--   that are applied to the middle and last nodes.+tfFoldBlock :: forall n bc bo c e x .+               ( n C O -> bc+               , n O O -> IndexedCO e bc bo -> IndexedCO e bc bo+               , n O C -> IndexedCO e bc bo -> c)+            -> (Block n e x -> bo -> IndexedCO x c (IndexedCO e bc bo))+tfFoldBlock (f, m, l) bl bo = block bl+  where block :: forall x . Block n e x -> IndexedCO x c (IndexedCO e bc bo)+        block (BFirst  n)       = f n+        block (BMiddle n)       = m n bo+        block (BLast   n)       = l n bo+        block (b1 `BCat`    b2) = oblock b2 $ block b1+        block (b1 `BClosed` b2) = oblock b2 $ block b1+        block (b1 `BHead` n)    = m n $ block b1+        block (n `BTail` b2)    = oblock b2 $ m n bo+        oblock :: forall x . Block n O x -> IndexedCO e bc bo -> IndexedCO x c (IndexedCO e bc bo)+        oblock (BMiddle n)       = m n+        oblock (BLast   n)       = l n+        oblock (b1 `BCat`    b2) = oblock b1 `cat` oblock b2+        oblock (n `BTail` b2)    = m n       `cat` oblock b2+        cat :: forall b c a. (a -> b) -> (b -> c) -> a -> c+        cat f f' = f' . f+++type NodeList' e x n = (MaybeC e (n C O), [n O O], MaybeC x (n O C))+blockToNodeList''' ::+  forall n e x. ( IndexedCO e (NodeList' C O n) (NodeList' O O n) ~ NodeList' e O n+                , IndexedCO x (NodeList' e C n) (NodeList' e O n) ~ NodeList' e x n) =>+    Block n e x -> NodeList' e x n+blockToNodeList''' b = (h, reverse ms', t)+  where+    (h, ms', t) = tfFoldBlock (f, m, l) b z+    z :: NodeList' O O n+    z = (NothingC, [], NothingC)+    f :: n C O -> NodeList' C O n+    f n = (JustC n,  [], NothingC)+    m n (h, ms', t) = (h, n : ms', t)+    l n (h, ms', _) = (h, ms', JustC n)+++{-+data EitherCO' ex a b where+  LeftCO  :: a -> EitherCO' C a b+  RightCO :: b -> EitherCO' O a b+-}++  -- should be done with a *backward* fold++-- | More general fold++_unused :: Int+_unused = 3+  where _a = foldBlockNodesF3'' (Trips undefined undefined undefined)+        _b = foldBlockNodesF3'++data Trips n a b c = Trips { ff :: forall e . MaybeC e (n C O) -> a -> b+                           , fm :: n O O            -> b -> b+                           , fl :: forall x . MaybeC x (n O C) -> b -> c+                           }++foldBlockNodesF3'' :: forall n a b c .+                      Trips n a b c -> (forall e x . Block n e x -> a -> c)+foldBlockNodesF3'' trips = block+  where block :: Block n e x -> a -> c+        block (b1 `BClosed` b2) = foldCO b1 `cat` foldOC b2+        block (BFirst  node)    = ff trips (JustC node)  `cat` missingLast+        block (b @ BHead {})    = foldCO b `cat` missingLast+        block (BMiddle node)    = missingFirst `cat` fm trips node  `cat` missingLast+        block (b @ BCat {})     = missingFirst `cat` foldOO b `cat` missingLast+        block (BLast   node)    = missingFirst `cat` fl trips (JustC node)+        block (b @ BTail {})    = missingFirst `cat` foldOC b+        missingLast = fl trips NothingC+        missingFirst = ff trips NothingC+        foldCO :: Block n C O -> a -> b+        foldOO :: Block n O O -> b -> b+        foldOC :: Block n O C -> b -> c+        foldCO (BFirst n)   = ff trips (JustC n)+        foldCO (BHead b n)  = foldCO b `cat` fm trips n+        foldOO (BMiddle n)  = fm trips n+        foldOO (BCat b1 b2) = foldOO b1 `cat` foldOO b2+        foldOC (BLast n)    = fl trips (JustC n)+        foldOC (BTail n b)  = fm trips n `cat` foldOC b+        cat :: forall b c a. (a -> b) -> (b -> c) -> a -> c+        f `cat` g = g . f ++data ScottBlock n a = ScottBlock+   { sb_first :: n C O -> a C O+   , sb_mid   :: n O O -> a O O+   , sb_last  :: n O C -> a O C+   , sb_cat   :: forall e x . a e O -> a O x -> a e x+   }++scottFoldBlock :: forall n a e x . ScottBlock n a -> Block n e x -> a e x+scottFoldBlock funs = block+  where block :: forall e x . Block n e x -> a e x+        block (BFirst n)  = sb_first  funs n+        block (BMiddle n) = sb_mid    funs n+        block (BLast   n) = sb_last   funs n+        block (BClosed b1 b2) = block b1 `cat` block b2+        block (BCat    b1 b2) = block b1 `cat` block b2+        block (BHead   b  n)  = block b  `cat` sb_mid funs n+        block (BTail   n  b)  = sb_mid funs n `cat` block b+        cat :: forall e x. a e O -> a O x -> a e x+        cat = sb_cat funs++newtype NodeList n e x+    = NL { unList :: (MaybeC e (n C O), [n O O] -> [n O O], MaybeC x (n O C)) }++fbnf3 :: forall n a b c .+         ( n C O       -> a -> b+         , n O O       -> b -> b+         , n O C       -> b -> c)+      -> (forall e x . Block n e x -> IndexedCO e a b -> IndexedCO x c b)+fbnf3 (ff, fm, fl) block = unFF3 $ scottFoldBlock (ScottBlock f m l cat) block+    where f n = FF3 $ ff n+          m n = FF3 $ fm n+          l n = FF3 $ fl n+          -- XXX Ew.+          cat :: forall t t1 t2 t3 t4 t5 t6 t7 t8 t9 a b c e x.+                 (IndexedCO x c b ~ IndexedCO t9 t7 t6,+                  IndexedCO t8 t5 t6 ~ IndexedCO t4 t2 t1,+                  IndexedCO t3 t t1 ~ IndexedCO e a b) =>+                 FF3 t t1 t2 t3 t4 -> FF3 t5 t6 t7 t8 t9 -> FF3 a b c e x+          FF3 f `cat` FF3 f' = FF3 $ f' . f++newtype FF3 a b c e x = FF3 { unFF3 :: IndexedCO e a b -> IndexedCO x c b }++blockToNodeList'' :: Block n e x -> (MaybeC e (n C O), [n O O], MaybeC x (n O C))+blockToNodeList'' = finish . unList . scottFoldBlock (ScottBlock f m l cat)+    where f n = NL (JustC n, id, NothingC)+          m n = NL (NothingC, (n:), NothingC)+          l n = NL (NothingC, id, JustC n)+          cat :: forall n t1 t2 t3. NodeList n t1 t2 -> NodeList n t2 t3 -> NodeList n t1 t3+          NL (e, ms, NothingC) `cat` NL (NothingC, ms', x) = NL (e, ms . ms', x)+          finish :: forall t t1 t2 a. (t, [a] -> t1, t2) -> (t, t1, t2)+          finish (e, ms, x) = (e, ms [], x)++++blockToNodeList' :: Block n e x -> (MaybeC e (n C O), [n O O], MaybeC x (n O C))+blockToNodeList' b = unFNL $ foldBlockNodesF3''' ff fm fl b ()+  where ff :: forall n e. MaybeC e (n C O) -> () -> PNL n e+        fm :: forall n e. n O O -> PNL n e -> PNL n e+        fl :: forall n e x. MaybeC x (n O C) -> PNL n e -> FNL n e x+        ff n () = PNL (n, [])+        fm n (PNL (first, mids')) = PNL (first, n : mids')+        fl n (PNL (first, mids')) = FNL (first, reverse mids', n)++   -- newtypes for 'partial node list' and 'final node list'+newtype PNL n e   = PNL (MaybeC e (n C O), [n O O])+newtype FNL n e x = FNL {unFNL :: (MaybeC e (n C O), [n O O], MaybeC x (n O C))}++foldBlockNodesF3''' :: forall n a b c .+                       (forall e   . MaybeC e (n C O) -> a   -> b e)+                    -> (forall e   .           n O O  -> b e -> b e)+                    -> (forall e x . MaybeC x (n O C) -> b e -> c e x)+                    -> (forall e x . Block n e x      -> a   -> c e x)+foldBlockNodesF3''' ff fm fl = block+  where block   :: forall e x . Block n e x -> a   -> c e x+        blockCO ::              Block n C O -> a   -> b C+        blockOO :: forall e .   Block n O O -> b e -> b e+        blockOC :: forall e .   Block n O C -> b e -> c e C+        block (b1 `BClosed` b2) = blockCO b1       `cat` blockOC b2+        block (BFirst  node)    = ff (JustC node)  `cat` fl NothingC+        block (b @ BHead {})    = blockCO b        `cat` fl NothingC+        block (BMiddle node)    = ff NothingC `cat` fm node   `cat` fl NothingC+        block (b @ BCat {})     = ff NothingC `cat` blockOO b `cat` fl NothingC+        block (BLast   node)    = ff NothingC `cat` fl (JustC node)+        block (b @ BTail {})    = ff NothingC `cat` blockOC b+        blockCO (BFirst n)      = ff (JustC n)+        blockCO (BHead b n)     = blockCO b `cat` fm n+        blockOO (BMiddle n)     = fm n+        blockOO (BCat b1 b2)    = blockOO b1 `cat` blockOO b2+        blockOC (BLast n)       = fl (JustC n)+        blockOC (BTail n b)     = fm n `cat` blockOC b+        cat :: forall a b c. (a -> b) -> (b -> c) -> a -> c+        f `cat` g = g . f +++-- | The following function is easy enough to define but maybe not so useful+foldBlockNodesF3' :: forall n a b c .+                   ( n C O -> a -> b+                   , n O O -> b -> b+                   , n O C -> b -> c)+                   -> (a -> b) -- called iff there is no first node+                   -> (b -> c) -- called iff there is no last node+                   -> (forall e x . Block n e x -> a -> c)+foldBlockNodesF3' (ff, fm, fl) missingFirst missingLast = block+  where block   :: forall e x . Block n e x -> a -> c+        blockCO ::              Block n C O -> a -> b+        blockOO ::              Block n O O -> b -> b+        blockOC ::              Block n O C -> b -> c+        block (b1 `BClosed` b2) = blockCO b1 `cat` blockOC b2+        block (BFirst  node)    = ff node  `cat` missingLast+        block (b @ BHead {})    = blockCO b `cat` missingLast+        block (BMiddle node)    = missingFirst `cat` fm node  `cat` missingLast+        block (b @ BCat {})     = missingFirst `cat` blockOO b `cat` missingLast+        block (BLast   node)    = missingFirst `cat` fl node+        block (b @ BTail {})    = missingFirst `cat` blockOC b+        blockCO (BFirst n)   = ff n+        blockCO (BHead b n)  = blockCO b `cat` fm n+        blockOO (BMiddle n)  = fm n+        blockOO (BCat b1 b2) = blockOO b1 `cat` blockOO b2+        blockOC (BLast n)    = fl n+        blockOC (BTail n b)  = fm n `cat` blockOC b+        cat :: forall a b c. (a -> b) -> (b -> c) -> a -> c+        f `cat` g = g . f ++-- | Fold a function over every node in a block, forward or backward.+-- The fold function must be polymorphic in the shape of the nodes.+foldBlockNodesF3 :: forall n a b c .+                   ( n C O       -> a -> b+                   , n O O       -> b -> b+                   , n O C       -> b -> c)+                 -> (forall e x . Block n e x -> IndexedCO e a b -> IndexedCO x c b)+foldBlockNodesF  :: forall n a .+                    (forall e x . n e x       -> a -> a)+                 -> (forall e x . Block n e x -> IndexedCO e a a -> IndexedCO x a a)+foldBlockNodesB3 :: forall n a b c .+                   ( n C O       -> b -> c+                   , n O O       -> b -> b+                   , n O C       -> a -> b)+                 -> (forall e x . Block n e x -> IndexedCO x a b -> IndexedCO e c b)+foldBlockNodesB  :: forall n a .+                    (forall e x . n e x       -> a -> a)+                 -> (forall e x . Block n e x -> IndexedCO x a a -> IndexedCO e a a)+-- | Fold a function over every node in a graph.+-- The fold function must be polymorphic in the shape of the nodes.++foldGraphNodes :: forall n a .+                  (forall e x . n e x       -> a -> a)+               -> (forall e x . Graph n e x -> a -> a)+++foldBlockNodesF3 (ff, fm, fl) = block+  where block :: forall e x . Block n e x -> IndexedCO e a b -> IndexedCO x c b+        block (BFirst  node)    = ff node+        block (BMiddle node)    = fm node+        block (BLast   node)    = fl node+        block (b1 `BCat`    b2) = block b1 `cat` block b2+        block (b1 `BClosed` b2) = block b1 `cat` block b2+        block (b1 `BHead` n)    = block b1 `cat` fm n+        block (n `BTail` b2)    = fm n `cat` block b2+        cat :: forall a b c. (a -> b) -> (b -> c) -> a -> c+        cat f f' = f' . f+foldBlockNodesF f = foldBlockNodesF3 (f, f, f)++foldBlockNodesB3 (ff, fm, fl) = block+  where block :: forall e x . Block n e x -> IndexedCO x a b -> IndexedCO e c b+        block (BFirst  node)    = ff node+        block (BMiddle node)    = fm node+        block (BLast   node)    = fl node+        block (b1 `BCat`    b2) = block b1 `cat` block b2+        block (b1 `BClosed` b2) = block b1 `cat` block b2+        block (b1 `BHead` n)    = block b1 `cat` fm n+        block (n `BTail` b2)    = fm n `cat` block b2+        cat :: forall a b c. (b -> c) -> (a -> b) -> a -> c+        cat f f' = f . f'+foldBlockNodesB f = foldBlockNodesB3 (f, f, f)+++foldGraphNodes f = graph+    where graph :: forall e x . Graph n e x -> a -> a+          lift  :: forall thing ex . (thing -> a -> a) -> (MaybeO ex thing -> a -> a)++          graph GNil              = id+          graph (GUnit b)         = block b+          graph (GMany e b x)     = lift block e . body b . lift block x+          body :: Body n -> a -> a+          body bdy                = \a -> mapFold block a bdy+          lift _ NothingO         = id+          lift f (JustO thing)    = f thing++          block :: Block n e x -> IndexedCO e a a -> IndexedCO x a a+          block = foldBlockNodesF f++{-# DEPRECATED blockToNodeList, blockOfNodeList +  "What justifies these functions?  Can they be eliminated?  Replaced with folds?" #-}++++-- | Convert a block to a list of nodes. The entry and exit node+-- is or is not present depending on the shape of the block.+--+-- The blockToNodeList function cannot be currently expressed using+-- foldBlockNodesB, because it returns IndexedCO e a b, which means+-- two different types depending on the shape of the block entry.+-- But blockToNodeList returns one of four possible types, depending+-- on the shape of the block entry *and* exit.+blockToNodeList :: Block n e x -> (MaybeC e (n C O), [n O O], MaybeC x (n O C))+blockToNodeList block = case block of+  BFirst n    -> (JustC n, [], NothingC)+  BMiddle n   -> (NothingC, [n], NothingC)+  BLast n     -> (NothingC, [], JustC n)+  BCat {}     -> (NothingC, foldOO block [], NothingC)+  BHead x n   -> case foldCO x [n] of (f, m) -> (f, m, NothingC)+  BTail n x   -> case foldOC x of (m, l) -> (NothingC, n : m, l)+  BClosed x y -> case foldOC y of (m, l) -> case foldCO x m of (f, m') -> (f, m', l)+  where foldCO :: Block n C O -> [n O O] -> (MaybeC C (n C O), [n O O])+        foldCO (BFirst n) m  = (JustC n, m)+        foldCO (BHead x n) m = foldCO x (n : m)++        foldOO :: Block n O O -> [n O O] -> [n O O]+        foldOO (BMiddle n) acc = n : acc+        foldOO (BCat x y) acc  = foldOO x $ foldOO y acc++        foldOC :: Block n O C -> ([n O O], MaybeC C (n O C))+        foldOC (BLast n)   = ([], JustC n)+        foldOC (BTail n x) = case foldOC x of (m, l) -> (n : m, l)++-- | Convert a list of nodes to a block. The entry and exit node+-- must or must not be present depending on the shape of the block.+blockOfNodeList :: (MaybeC e (n C O), [n O O], MaybeC x (n O C)) -> Block n e x+blockOfNodeList (NothingC, [], NothingC) = error "No nodes to created block from in blockOfNodeList"+blockOfNodeList (NothingC, m, NothingC)  = foldr1 BCat (map BMiddle m)+blockOfNodeList (NothingC, m, JustC l)   = foldr BTail (BLast l) m+blockOfNodeList (JustC f, m, NothingC)   = foldl BHead (BFirst f) m+blockOfNodeList (JustC f, m, JustC l)    = BClosed (BFirst f) $ foldr BTail (BLast l) m++data BlockResult n x where+  NoBlock   :: BlockResult n x+  BodyBlock :: Block n C C -> BlockResult n x+  ExitBlock :: Block n C O -> BlockResult n O++lookupBlock :: NonLocal n => Graph n e x -> Label -> BlockResult n x+lookupBlock (GMany _ _ (JustO exit)) lbl+  | entryLabel exit == lbl = ExitBlock exit+lookupBlock (GMany _ body _) lbl =+  case mapLookup lbl body of+    Just b  -> BodyBlock b+    Nothing -> NoBlock+lookupBlock GNil      _ = NoBlock+lookupBlock (GUnit _) _ = NoBlock