Commit 42eee6ea authored by Michal Terepeta's avatar Michal Terepeta Committed by Ben Gamari

Hoopl: remove dependency on Hoopl package

This copies the subset of Hoopl's functionality needed by GHC to
`cmm/Hoopl` and removes the dependency on the Hoopl package.

The main motivation for this change is the confusing/noisy interface
between GHC and Hoopl:
- Hoopl has `Label` which is GHC's `BlockId` but different than
  GHC's `CLabel`
- Hoopl has `Unique` which is different than GHC's `Unique`
- Hoopl has `Unique{Map,Set}` which are different than GHC's
  `Uniq{FM,Set}`
- GHC has its own specialized copy of `Dataflow`, so `cmm/Hoopl` is
  needed just to filter the exposed functions (filter out some of the
  Hoopl's and add the GHC ones)
With this change, we'll be able to simplify this significantly.
It'll also be much easier to do invasive changes (Hoopl is a public
package on Hackage with users that depend on the current behavior)

This should introduce no changes in functionality - it merely
copies the relevant code.
Signed-off-by: Michal Terepeta's avatarMichal Terepeta <michal.terepeta@gmail.com>

Test Plan: ./validate

Reviewers: austin, bgamari, simonmar

Reviewed By: bgamari, simonmar

Subscribers: simonpj, kavon, rwbarton, thomie

Differential Revision: https://phabricator.haskell.org/D3616
parent 90771209
......@@ -11,12 +11,11 @@ module BlockId
import CLabel
import IdInfo
import Name
import Outputable
import Unique
import UniqSupply
import Compiler.Hoopl as Hoopl hiding (Unique)
import Compiler.Hoopl.Internals (uniqueToLbl, lblToUnique)
import Hoopl.Label (Label, uniqueToLbl)
import Hoopl.Unique (intToUnique)
----------------------------------------------------------------
--- Block Ids, their environments, and their sets
......@@ -30,13 +29,7 @@ most assembly languages allow, a label is visible throughout the entire
compilation unit in which it appears.
-}
type BlockId = Hoopl.Label
instance Uniquable BlockId where
getUnique label = getUnique (lblToUnique label)
instance Outputable BlockId where
ppr label = ppr (getUnique label)
type BlockId = Label
mkBlockId :: Unique -> BlockId
mkBlockId unique = uniqueToLbl $ intToUnique $ getKey unique
......
......@@ -31,7 +31,10 @@ import BlockId
import CmmNode
import SMRep
import CmmExpr
import Compiler.Hoopl
import Hoopl.Block
import Hoopl.Collections
import Hoopl.Graph
import Hoopl.Label
import Outputable
import Data.Word ( Word8 )
......
......@@ -7,7 +7,11 @@ where
#include "HsVersions.h"
import Hoopl
import Hoopl.Block
import Hoopl.Graph
import Hoopl.Label
import Hoopl.Collections
import Hoopl.Dataflow
import Digraph
import Bitmap
import CLabel
......
......@@ -13,7 +13,10 @@ import CmmContFlowOpt
-- import PprCmm ()
import Prelude hiding (iterate, succ, unzip, zip)
import Hoopl hiding (ChangeFlag)
import Hoopl.Block
import Hoopl.Graph
import Hoopl.Label
import Hoopl.Collections
import Data.Bits
import Data.Maybe (mapMaybe)
import qualified Data.List as List
......
......@@ -8,7 +8,10 @@ module CmmContFlowOpt
)
where
import Hoopl
import Hoopl.Block
import Hoopl.Collections
import Hoopl.Graph
import Hoopl.Label
import BlockId
import Cmm
import CmmUtils
......
......@@ -4,7 +4,7 @@ module CmmImplementSwitchPlans
)
where
import Hoopl
import Hoopl.Block
import BlockId
import Cmm
import CmmUtils
......
......@@ -41,7 +41,7 @@ import SMRep
import Bitmap
import Stream (Stream)
import qualified Stream
import Hoopl
import Hoopl.Collections
import Maybes
import DynFlags
......
......@@ -17,7 +17,11 @@ import ForeignCall
import CmmLive
import CmmProcPoint
import SMRep
import Hoopl
import Hoopl.Block
import Hoopl.Collections
import Hoopl.Dataflow
import Hoopl.Graph
import Hoopl.Label
import UniqSupply
import StgCmmUtils ( newTemp )
import Maybes
......
......@@ -10,7 +10,10 @@ module CmmLint (
cmmLint, cmmLintGraph
) where
import Hoopl
import Hoopl.Block
import Hoopl.Collections
import Hoopl.Graph
import Hoopl.Label
import Cmm
import CmmUtils
import CmmLive
......
......@@ -16,7 +16,10 @@ import DynFlags
import BlockId
import Cmm
import PprCmmExpr ()
import Hoopl
import Hoopl.Block
import Hoopl.Collections
import Hoopl.Dataflow
import Hoopl.Label
import Maybes
import Outputable
......
......@@ -33,7 +33,9 @@ import SMRep
import CoreSyn (Tickish)
import qualified Unique as U
import Compiler.Hoopl
import Hoopl.Block
import Hoopl.Graph
import Hoopl.Label
import Data.Maybe
import Data.List (tails,sortBy)
import Prelude hiding (succ)
......
......@@ -16,7 +16,7 @@ import CmmProcPoint
import CmmContFlowOpt
import CmmLayoutStack
import CmmSink
import Hoopl
import Hoopl.Collections
import UniqSupply
import DynFlags
......
......@@ -25,7 +25,11 @@ import Control.Monad
import Outputable
import Platform
import UniqSupply
import Hoopl
import Hoopl.Block
import Hoopl.Collections
import Hoopl.Dataflow
import Hoopl.Graph
import Hoopl.Label
-- Compute a minimal set of proc points for a control-flow graph.
......
......@@ -7,7 +7,10 @@ import Cmm
import CmmOpt
import CmmLive
import CmmUtils
import Hoopl
import Hoopl.Block
import Hoopl.Label
import Hoopl.Collections
import Hoopl.Graph
import CodeGen.Platform
import Platform (isARM, platformArch)
......
......@@ -13,7 +13,7 @@ module CmmSwitch (
import Outputable
import DynFlags
import Compiler.Hoopl (Label)
import Hoopl.Label (Label)
import Data.Maybe
import Data.List (groupBy)
......
......@@ -79,7 +79,10 @@ import CodeGen.Platform
import Data.Word
import Data.Maybe
import Data.Bits
import Hoopl
import Hoopl.Graph
import Hoopl.Label
import Hoopl.Block
import Hoopl.Collections
---------------------------------------------------
--
......
......@@ -35,7 +35,10 @@ import PprCmmExpr ( pprExpr )
import SrcLoc
import Util
import Compiler.Hoopl
import Hoopl.Block
import Hoopl.Collections
import Hoopl.Graph
import Hoopl.Label
import Data.Maybe
import Data.List ( minimumBy, nubBy )
......
{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Hoopl (
module Compiler.Hoopl,
module Hoopl.Dataflow,
) where
import Compiler.Hoopl hiding
( (<*>), mkLabel, mkBranch, mkMiddle, mkLast, -- clashes with our MkGraph
DataflowLattice, OldFact, NewFact, JoinFun,
fact_bot, fact_join, joinOutFacts, mkFactBase,
Unique,
FwdTransfer(..), FwdRewrite(..), FwdPass(..),
BwdTransfer(..), BwdRewrite(..), BwdPass(..),
mkFactBase, Fact,
mkBRewrite3, mkBTransfer3,
mkFRewrite3, mkFTransfer3,
)
import Hoopl.Dataflow
import Outputable
instance Outputable LabelSet where
ppr = ppr . setElems
instance Outputable a => Outputable (LabelMap a) where
ppr = ppr . mapToList
This diff is collapsed.
{-# LANGUAGE TypeFamilies #-}
module 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
mapInsertWith :: (a -> a -> a) -> 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
mapFilter :: (a -> Bool) -> map a -> map a
mapElems :: map a -> [a]
mapKeys :: map a -> [KeyOf map]
mapToList :: map a -> [(KeyOf map, a)]
mapFromList :: [(KeyOf map, a)] -> map a
mapFromListWith :: (a -> a -> a) -> [(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
......@@ -42,10 +42,14 @@ import Data.Maybe
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
-- Hide definitions from Hoopl's Dataflow module.
import Compiler.Hoopl hiding ( DataflowLattice, OldFact, NewFact, JoinFun
, fact_bot, fact_join, joinOutFacts, mkFactBase
)
import Hoopl.Block
import Hoopl.Graph
import Hoopl.Collections
import Hoopl.Label
type family Fact x f :: *
type instance Fact C f = FactBase f
type instance Fact O f = f
newtype OldFact a = OldFact a
......
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Hoopl.Graph
( Body
, Graph
, Graph'(..)
, NonLocal(..)
, addBlock
, bodyList
, emptyBody
, labelsDefined
, mapGraph
, mapGraphBlocks
, postorder_dfs_from
) where
import Hoopl.Label
import Hoopl.Block
import Hoopl.Collections
-- | A (possibly empty) collection of closed/closed blocks
type Body n = LabelMap (Block n C C)
-- | @Body@ abstracted over @block@
type Body' block (n :: * -> * -> *) = LabelMap (block n C C)
-------------------------------
-- | 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 (BlockCO f _) = entryLabel f
entryLabel (BlockCC f _ _) = entryLabel f
successors (BlockOC _ n) = successors n
successors (BlockCC _ _ n) = successors n
emptyBody :: Body' block n
emptyBody = mapEmpty
bodyList :: Body' block n -> [(Label,block n C C)]
bodyList body = mapToList body
addBlock :: NonLocal thing
=> thing C C -> LabelMap (thing C C)
-> LabelMap (thing C C)
addBlock b body
| mapMember lbl body = error $ "duplicate label " ++ show lbl ++ " in graph"
| otherwise = mapInsert lbl b body
where lbl = entryLabel b
-- ---------------------------------------------------------------------------
-- Graph
-- | 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
-- | @Graph'@ is abstracted over the block type, so that we can build
-- graphs of annotated blocks for example (Compiler.Hoopl.Dataflow
-- needs this).
data Graph' block (n :: * -> * -> *) e x where
GNil :: Graph' block n O O
GUnit :: block n O O -> Graph' block n O O
GMany :: MaybeO e (block n O C)
-> Body' block n
-> MaybeO x (block n C O)
-> Graph' block n e x
-- -----------------------------------------------------------------------------
-- Mapping over graphs
-- | Maps over all nodes in a graph.
mapGraph :: (forall e x. n e x -> n' e x) -> Graph n e x -> Graph n' e x
mapGraph f = mapGraphBlocks (mapBlock f)
-- | Function 'mapGraphBlocks' 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.
mapGraphBlocks :: 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)
mapGraphBlocks 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)
-- -----------------------------------------------------------------------------
-- Extracting Labels from graphs
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)
----------------------------------------------------------------
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
-- | 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]
-- | 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_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
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE TypeFamilies #-}
module Hoopl.Label
( Label
, LabelMap
, LabelSet
, FactBase
, lookupFact
, uniqueToLbl
) where
import Outputable
import Hoopl.Collections
-- TODO: This should really just use GHC's Unique and Uniq{Set,FM}
import Hoopl.Unique
import Unique (Uniquable(..))
-----------------------------------------------------------------------------
-- Label
-----------------------------------------------------------------------------
newtype Label = Label { lblToUnique :: Unique }
deriving (Eq, Ord)
uniqueToLbl :: Unique -> Label
uniqueToLbl = Label
instance Show Label where
show (Label n) = "L" ++ show n
instance Uniquable Label where
getUnique label = getUnique (lblToUnique label)
instance Outputable Label where
ppr label = ppr (getUnique label)
-----------------------------------------------------------------------------
-- 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, Functor, Foldable, Traversable)
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)
mapInsertWith f (Label k) v (LM m) = LM (mapInsertWith f 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
mapFilter f (LM m) = LM (mapFilter f 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])
mapFromListWith f assocs = LM (mapFromListWith f [(lblToUnique k, v) | (k, v) <- assocs])
-----------------------------------------------------------------------------
-- Instances
instance Outputable LabelSet where
ppr = ppr . setElems
instance Outputable a => Outputable (LabelMap a) where
ppr = ppr . mapToList
-----------------------------------------------------------------------------
-- FactBase
type FactBase f = LabelMap f
lookupFact :: Label -> FactBase f -> Maybe f
lookupFact = mapLookup
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE TypeFamilies #-}
module Hoopl.Unique
( Unique
, UniqueMap
, UniqueSet
, intToUnique
) where
import qualified Data.IntMap as M
import qualified Data.IntSet as S
import Hoopl.Collections
-----------------------------------------------------------------------------