summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Wilson <douglas.wilson@gmail.com>2022-05-09 17:17:11 +0100
committerDouglas Wilson <douglas.wilson@gmail.com>2022-05-10 12:40:20 +0100
commitd59ab9450f5f179dee32c8bb6d60572bdddd5386 (patch)
treef86bd7493c5589c8f2868d5cb13ede85140d681a
parent5604ab11b4059a9ca27710303627f40d22a4fa36 (diff)
downloadhaskell-d59ab9450f5f179dee32c8bb6d60572bdddd5386.tar.gz
wip
-rw-r--r--compiler/GHC/Core/Opt/Pipeline.hs2
-rw-r--r--compiler/GHC/Core/Opt/Simplify.hs204
-rw-r--r--compiler/GHC/Core/Opt/Simplify/Env.hs5
-rw-r--r--compiler/GHC/Core/Opt/Simplify/Monad.hs2
-rw-r--r--compiler/GHC/Core/SimpleOpt.hs2
-rw-r--r--compiler/GHC/Core/Subst.hs30
6 files changed, 138 insertions, 107 deletions
diff --git a/compiler/GHC/Core/Opt/Pipeline.hs b/compiler/GHC/Core/Opt/Pipeline.hs
index 1ef5f09945..eb70b4740d 100644
--- a/compiler/GHC/Core/Opt/Pipeline.hs
+++ b/compiler/GHC/Core/Opt/Pipeline.hs
@@ -789,7 +789,7 @@ simplifyPgmIO pass@(CoreDoSimplify max_iterations mode)
((binds1, rules1), counts1) <-
initSmpl logger dflags (mkRuleEnv rule_base2 vis_orphs) fam_envs sz $
do { (floats, env1) <- {-# SCC "SimplTopBinds" #-}
- simplTopBinds simpl_env tagged_binds
+ simplTopBinds (dopt Opt_D_dump_simpl dflags) simpl_env tagged_binds
-- Apply the substitution to rules defined in this module
-- for imported Ids. Eg RULE map my_f = blah
diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs
index 791478a546..8462b5a84a 100644
--- a/compiler/GHC/Core/Opt/Simplify.hs
+++ b/compiler/GHC/Core/Opt/Simplify.hs
@@ -80,16 +80,22 @@ import GHC.Types.Var.Env
import GHC.Types.Unique.FM
import Control.Concurrent.QSem
import Control.Exception
-import GHC.Core.Subst (Subst, substRecBndrs, substBind, mkEmptySubst, substInScope, extendSubstWithVar)
+import GHC.Core.Subst (Subst, substRecBndrs, substBind, mkEmptySubst, substInScope, extendSubstWithVar, substExpr, extendInScope, substIdOcc, isInScope, clone_id_hack, substIdInfo)
import Data.Foldable
import Data.Traversable
import GHC.Data.OrdList (toOL)
-import GHC.Types.Var.Set (IdSet, mkVarSet, dVarSetElems)
+import GHC.Types.Var.Set (IdSet, mkVarSet, dVarSetElems, partitionVarSet, elemVarSet)
import qualified Data.IntMap.Strict as IntMap
-import GHC.Types.Unique.Set (getUniqSet, isEmptyUniqSet, nonDetEltsUniqSet)
+import GHC.Types.Unique.Set (getUniqSet, isEmptyUniqSet, nonDetEltsUniqSet, addListToUniqSet, elementOfUniqSet, emptyUniqSet, addOneToUniqSet, UniqSet, mkUniqSet)
import qualified Data.IntSet as IntSet
import GHC.Types.Unique (Unique)
-import GHC.Types.Unique.Supply (uniqFromMask)
+import GHC.Types.Unique.Supply (uniqFromMask, initUs_)
+import GHC.Types.Unique (getUnique)
+import qualified Data.Monoid as Mon
+import Control.Applicative
+import GHC.Cmm.Dataflow.Collections (UniqueSet)
+import System.IO (fixIO)
+import Control.Monad.Fix
{-
The guts of the simplifier is in this module, but the driver loop for
@@ -225,58 +231,69 @@ too small to show up in benchmarks.
************************************************************************
-}
-substSimplFloats :: Subst -> SimplFloats -> (Subst, SimplFloats)
-substSimplFloats subst sf@SimplFloats{sfJoinFloats, sfLetFloats = LetFloats bind_ol ff} = let
- (new_subst, new_binds) = ASSERT (null sfJoinFloats)
- mapAccumL substBind subst (toList bind_ol)
- in (new_subst, sf { sfLetFloats = LetFloats (toOL new_binds) ff
- , sfInScope = sfInScope sf `unionInScope` substInScope new_subst
- })
-
-
-simplEnvInscopeLocals :: SimplEnv -> IdSet
-simplEnvInscopeLocals env = let
- inscope_intmap = ufmToSet_Directly . getUniqSet . getInScopeVars . seInScope $ env
- (_,xs0) = IntSet.split (getKey minLocalUnique) inscope_intmap
- (xs, _) = IntSet.split (getKey maxLocalUnique) xs0
- in mkVarSet
- [ x
- | y :: Unique <- [minLocalUnique,maxLocalUnique] ++
- [ mkUniqueGrimily x | x <- IntSet.toList xs]
- , Just x <- [lookupInScope_Directly (seInScope env) y]
- ]
-
-simplSubstLocals :: SimplEnv -> (SimplFloats, SimplEnv) -> IO (SimplFloats, SimplEnv)
-simplSubstLocals env0 (this_float,this_env) = do
- let
- inscope_locals_acc = simplEnvInscopeLocals env0
- ASSERT (isEmptyUniqSet inscope_locals_acc) pure ()
- let
- inscope_locals = simplEnvInscopeLocals this_env
- new_ids <- for (nonDetEltsUniqSet inscope_locals) $ \x -> (x,) . setVarUnique x <$> uniqFromMask 'z'
- let subst = foldr (\(old, new) acc -> extendSubstWithVar acc old new)
- (mkEmptySubst $ seInScope env0) new_ids
- (_, new_floats) = substSimplFloats subst this_float
- pure (new_floats, setInScopeFromF this_env new_floats)
-
--- simplCombineEnvs :: MonadUnique m => SimplEnv -> [(SimplEnv, SimplFloats)] -> m (SimplFloats, SimplEnv)
--- simplCombineEnvs env0 envs = foldlM go (emptyFloats env0, env0) envs where
--- go (acc_floats, acc_env) (this_float, this_env) = do
--- let
--- inscope_locals_acc = simplEnvInscopeLocals acc_env
--- ASSERT (null inscope_locals_acc) pure ()
--- let
--- inscope_locals = simplEnvInscopeLocals this_env
--- new_ids <- for inscope_locals $ \x -> (x,) . setVarUnique x <$> getUniqueM
--- let subst = foldr (\(old, new) acc -> extendSubstWithVar acc old new)
--- (mkEmptySubst $ seInScope acc_env) new_ids
--- (_, new_floats) = substSimplFloats subst this_float
--- floats = acc_floats `unionFloats` new_floats
--- pure (setInScopeFromF acc_env floats, floats)
-
-simplTopBinds :: SimplEnv -> ([(Int, InBind)], M.Map Int [Int]) -> SimplM (SimplFloats, SimplEnv)
+-- TODO rename
+simplScc :: ResimplEnv -> [SimplR] -> InBind -> SimplM SimplR
+simplScc (should_trace, env0, our_binders) deps b = do
+ let traceM | should_trace = pprTraceM
+ | otherwise = \_ _ -> pure ()
+ let (_floats0, envs0) = unzip $ deps
+
+ traceM "simplScc:start:(#deps,binders)" $ ppr (length deps, bindersOf b)
+ -- when (any (> 1) check) $ pprPanic "simplScc" $ ppr (floats0, b)
+ let
+ !inscope = foldr unionInScope (seInScope env0) (seInScope <$> envs0)
+ these_binds = bindersOfBinds [b]
+ inscope_less_ours = foldl' delInScopeSet inscope these_binds
+ no_collisions x y = plusUFM_C arrrrrg x y where
+ arrrrrg = pprPanic "collision" $ ppr (x,y)
+ env1 = env0 { seInScope = inscope, seIdSubst = foldr no_collisions emptyUFM (seIdSubst <$> envs0)
+ }
+
+ traceM "simplScc:env1:" $ ppr env1
+ (floats1, env2) <- simpl_bind env1 b
+ traceM "simplScc:simpl_bind:(floats1,env1)" $ ppr (floats1,env2)
+ -- pprTraceM "simplScc2" $ ppr b
+
+
+
+ -- construct
+ (subst, new_binds) <- getUniqueSupplyM >>= \x -> pure . initUs_ x $ mfix $ \ ~(subst0,_) -> let
+ go_id s i = do
+ u <- getUniqueM
+ pure $ case () of
+ _ | i `elemVarSet` our_binders -> let
+ j = maybeModifyIdInfo (substIdInfo True subst0 i (idInfo i)) i
+ in (extendInScope s j, j)
+ -- | is_local bndr = subst_id_bndr acc_env bndr (flip setVarUnique u)
+ | isLocalId i -> let
+ (new_subst, new_bndr) = clone_id_hack True subst0 s (i, u)
+ in (extendSubstWithVar new_subst i new_bndr, new_bndr)
+ | otherwise -> (extendInScope s i, i)
+ go acc_subst bind = case bind of
+ NonRec i rhs -> do
+ (new_subst, new_id) <- go_id acc_subst i
+ pure (new_subst, NonRec new_id $ substExpr subst0 rhs)
+ Rec bs -> do
+ let f s (i,rhs) = do
+ (ns,ni) <- go_id s i
+ pure (ns, (ni, substExpr subst0 rhs))
+ (new_subst, bs1) <- mapAccumLM f acc_subst bs
+ pure (new_subst, Rec bs1)
+ in mapAccumLM go (mkEmptySubst inscope_less_ours) $ getTopFloatBinds $ floats1
+
+ let !floats2 = case sfLetFloats floats1 of
+ LetFloats _ ff -> let
+ lf = LetFloats (toOL new_binds) ff
+ in SimplFloats lf (sfJoinFloats floats1) (substInScope subst)
+
+ traceM "simplScc:substSimplFloats:(subst0,subst1,floats2)" $ ppr (subst,floats2)
+
+ pure (floats2, setInScopeFromF env2 floats2)
+
+
+simplTopBinds :: Bool -> SimplEnv -> ([(Int, InBind)], M.Map Int [Int]) -> SimplM (SimplFloats, SimplEnv)
-- See Note [The big picture]
-simplTopBinds env0 (binds0, g)
+simplTopBinds should_trace env0 (binds0, g)
= do { -- Put all the top-level binders into scope at the start
-- so that if a rewrite rule has unexpectedly brought
-- anything into scope, then we don't get a complaint about that.
@@ -284,14 +301,15 @@ simplTopBinds env0 (binds0, g)
-- See note [Glomming] in "GHC.Core.Opt.OccurAnal".
-- See Note [Bangs in the Simplifier]
; !env1 <- {-#SCC "simplTopBinds-simplRecBndrs" #-} simplRecBndrs env0 (bindersOfBinds (map snd binds0))
+ ; let my_binds = mkUniqSet [lookupRecBndr env1 x | x <- bindersOfBinds (map snd binds0)]
--- ; env_m_vars :: M.Map Int (MVar (SimplFloats, SimplEnv))
+-- ; env_m_vars :: M.Map Int (MVar (SimplFloats, SimplEnv, UniqSet Var))
; env_m_vars <- liftIO $ M.fromList <$> (sequence [(k,) <$> newEmptyMVar | (k,_) <- binds0])
; sem <- liftIO $ newQSem 8
- ; SM' $ \te sc -> do
- mapM_ (do_one sem env1 env_m_vars te sc) binds0
+ ; SM $ \te sc -> do
+ mapM_ (do_one sem (should_trace, env1, my_binds) env_m_vars te sc) binds0
return ((), sc)
; let res_vars = M.elems env_m_vars
@@ -303,11 +321,22 @@ simplTopBinds env0 (binds0, g)
; _old_res <- {-#SCC "simplTopBinds-simpl_binds" #-} simpl_binds env1 (map snd binds0)
; let
- env = combine_envs env1 envs
- final_floats = foldl' addFloats (emptyFloats env1) floats
+ !env = combine_envs env1 envs
+ !(final_floats, _) = foldl' go_sfs (emptyFloats env, emptyUniqSet) floats where
+ go_sfs acc sf = foldl' go_bind acc $ getTopFloatBinds sf where
+ go_bind bind_acc@(floats_acc, seen_set_acc) b = let
+ bob = bindersOfBinds [b]
+ is_seen = (`elementOfUniqSet` seen_set_acc)
+ f = liftA2 (,) Mon.All Mon.Any . is_seen
+ (Mon.All all_seen, Mon.Any any_seen) = foldMap f bob
+ in case () of
+ _ | all_seen -> bind_acc
+ | any_seen -> pprPanic "simplTopBinds:seenSome" $ ppr b
+ | otherwise -> (floats_acc `extendFloats` b, seen_set_acc `addListToUniqSet` bob)
+
; freeTick SimplifierDone
- ; return (final_floats, setInScopeFromF env final_floats) }
+ ; return (final_floats, env ) }
where
combine_envs env0 envs =
env0 { seInScope = foldr unionInScope (seInScope env0) (map seInScope envs)
@@ -316,41 +345,37 @@ simplTopBinds env0 (binds0, g)
do_one sem env1 deps te sc (k, b) = do
---pprTraceM "forking" (ppr k)
forkIO $ do
- let ds = (filter (/= k) $ fromJust $ M.lookup k g)
- --print (k, ds)
- (_, envs) <- unzip <$> mapM readMVar (mapMaybe (\di -> M.lookup di deps) ds)
- let my_var = fromJust (M.lookup k deps)
- let env' = combine_envs env1 envs
+ rs <- for [x | di <- g M.! k, di /= k, Just x <- [M.lookup di deps]] readMVar
bracket_ (waitQSem sem) (signalQSem sem) $ do
- ((floats, env''), _) <- unSM (simpl_bind env' b) te sc
- simplSubstLocals env' (floats,env'') >>= putMVar my_var
-
+ let my_mv = deps M.! k
+ (fst <$> unSM (simplScc env1 rs b) te sc) >>= putMVar my_mv
--- go :: M.Map Int (MVar SimplEnv) -> [Int] -> IO (MVar SimplEnv)
--- go m deps = let deps = map (\k -> M.lookup k m) deps
--- in _
+-- TODO we need to be threading SimplCount through as well
+type SimplR = (SimplFloats, SimplEnv)
+type ResimplEnv = (Bool, SimplEnv, UniqSet Var)
+ -- We need to track the zapped top-level binders, because
+ -- they should have their fragile IdInfo zapped (notably occurrence info)
+ -- That's why we run down binds and bndrs' simultaneously.
+ --
+simpl_binds :: SimplEnv -> [InBind] -> SimplM (SimplFloats, SimplEnv)
+simpl_binds env [] = return (emptyFloats env, env)
+simpl_binds env (bind:binds) = do { (float, env1) <- simpl_bind env bind
+ ; (floats, env2) <- simpl_binds env1 binds
+ -- See Note [Bangs in the Simplifier]
+ ; let !floats1 = float `addFloats` floats
+ ; -- TODO ^^^ should this be unionFloats?
+ ; return (floats1, env2) }
- -- We need to track the zapped top-level binders, because
- -- they should have their fragile IdInfo zapped (notably occurrence info)
- -- That's why we run down binds and bndrs' simultaneously.
- --
- simpl_binds :: SimplEnv -> [InBind] -> SimplM (SimplFloats, SimplEnv)
- simpl_binds env [] = return (emptyFloats env, env)
- simpl_binds env (bind:binds) = do { (float, env1) <- simpl_bind env bind
- ; (floats, env2) <- simpl_binds env1 binds
- -- See Note [Bangs in the Simplifier]
- ; let !floats1 = float `addFloats` floats
- ; -- TODO ^^^ should this be unionFloats?
- ; return (floats1, env2) }
+simpl_bind :: SimplEnv -> InBind -> SimplM (SimplFloats, SimplEnv)
+simpl_bind env (Rec pairs)
+ = simplRecBind env TopLevel Nothing pairs
+simpl_bind env (NonRec b r)
+ = do { (env', b') <- addBndrRules env b (lookupRecBndr env b) Nothing
+ ; simplRecOrTopPair env' TopLevel NonRecursive Nothing b b' r }
- simpl_bind env (Rec pairs)
- = simplRecBind env TopLevel Nothing pairs
- simpl_bind env (NonRec b r)
- = do { (env', b') <- addBndrRules env b (lookupRecBndr env b) Nothing
- ; simplRecOrTopPair env' TopLevel NonRecursive Nothing b b' r }
{-
************************************************************************
@@ -4291,4 +4316,3 @@ for the RHS as well as the LHS, but that seems more conservative
than necesary. Allowing some inlining might, for example, eliminate
a binding.
-}
-
diff --git a/compiler/GHC/Core/Opt/Simplify/Env.hs b/compiler/GHC/Core/Opt/Simplify/Env.hs
index 68678b6d16..a17b7ac7fc 100644
--- a/compiler/GHC/Core/Opt/Simplify/Env.hs
+++ b/compiler/GHC/Core/Opt/Simplify/Env.hs
@@ -40,7 +40,9 @@ module GHC.Core.Opt.Simplify.Env (
-- * JoinFloats
JoinFloat, JoinFloats, emptyJoinFloats,
- wrapJoinFloats, wrapJoinFloatsX, unitJoinFloat, addJoinFlts
+ wrapJoinFloats, wrapJoinFloatsX, unitJoinFloat, addJoinFlts,
+
+ subst_id_bndr, extendInScopeSetBind
) where
#include "HsVersions.h"
@@ -847,6 +849,7 @@ subst_id_bndr env@(SimplEnv { seInScope = in_scope, seIdSubst = id_subst })
old_id adjust_type
= ASSERT2( not (isCoVar old_id), ppr old_id )
(env { seInScope = new_in_scope,
+
seIdSubst = new_subst }, new_id)
-- It's important that both seInScope and seIdSubst are updated with
-- the new_id, /after/ applying adjust_type. That's why adjust_type
diff --git a/compiler/GHC/Core/Opt/Simplify/Monad.hs b/compiler/GHC/Core/Opt/Simplify/Monad.hs
index 4ad12c3aab..bee0c3607e 100644
--- a/compiler/GHC/Core/Opt/Simplify/Monad.hs
+++ b/compiler/GHC/Core/Opt/Simplify/Monad.hs
@@ -7,7 +7,7 @@
module GHC.Core.Opt.Simplify.Monad (
-- The monad
- SimplM(unSM, SM'),
+ SimplM(unSM, SM),
initSmpl, traceSmpl,
getSimplRules, getFamEnvs, getOptCoercionOpts,
diff --git a/compiler/GHC/Core/SimpleOpt.hs b/compiler/GHC/Core/SimpleOpt.hs
index 6353dcda6f..6a4db0e4cf 100644
--- a/compiler/GHC/Core/SimpleOpt.hs
+++ b/compiler/GHC/Core/SimpleOpt.hs
@@ -670,7 +670,7 @@ add_info env old_bndr top_level new_rhs new_bndr
old_unfolding = unfoldingInfo old_info
new_unfolding | isStableUnfolding old_unfolding
- = substUnfolding subst old_unfolding
+ = substUnfolding False subst old_unfolding
| otherwise
= unfolding_from_rhs
diff --git a/compiler/GHC/Core/Subst.hs b/compiler/GHC/Core/Subst.hs
index 1c7d138574..c50841b7d2 100644
--- a/compiler/GHC/Core/Subst.hs
+++ b/compiler/GHC/Core/Subst.hs
@@ -31,6 +31,7 @@ module GHC.Core.Subst (
-- ** Substituting and cloning binders
substBndr, substBndrs, substRecBndrs, substTyVarBndr, substCoVarBndr,
cloneBndr, cloneBndrs, cloneIdBndr, cloneIdBndrs, cloneRecIdBndrs,
+ clone_id_hack
) where
@@ -485,7 +486,7 @@ substIdBndr _doc rec_subst subst@(Subst in_scope env tvs cvs) old_id
-- The lazy-set is because we're in a loop here, with
-- rec_subst, when dealing with a mutually-recursive group
new_id = maybeModifyIdInfo mb_new_info id2
- mb_new_info = substIdInfo rec_subst id2 (idInfo id2)
+ mb_new_info = substIdInfo False rec_subst id2 (idInfo id2)
-- NB: unfolding info may be zapped
-- Extend the substitution if the unique has changed
@@ -535,19 +536,21 @@ cloneRecIdBndrs subst us ids
-- Just like substIdBndr, except that it always makes a new unique
-- It is given the unique to use
-clone_id :: Subst -- Substitution for the IdInfo
+clone_id_hack :: Bool -> Subst -- Substitution for the IdInfo
-> Subst -> (Id, Unique) -- Substitution and Id to transform
-> (Subst, Id) -- Transformed pair
-clone_id rec_subst subst@(Subst in_scope idvs tvs cvs) (old_id, uniq)
+clone_id_hack hack rec_subst subst@(Subst in_scope idvs tvs cvs) (old_id, uniq)
= (Subst (in_scope `extendInScopeSet` new_id) new_idvs tvs new_cvs, new_id)
where
id1 = setVarUnique old_id uniq
id2 = substIdType subst id1
- new_id = maybeModifyIdInfo (substIdInfo rec_subst id2 (idInfo old_id)) id2
+ new_id = maybeModifyIdInfo (substIdInfo hack rec_subst id2 (idInfo old_id)) id2
(new_idvs, new_cvs) | isCoVar old_id = (idvs, extendVarEnv cvs old_id (mkCoVarCo new_id))
| otherwise = (extendVarEnv idvs old_id (Var new_id), cvs)
+
+clone_id = clone_id_hack False
{-
************************************************************************
* *
@@ -612,11 +615,11 @@ substIdType subst@(Subst _ _ tv_env cv_env) id
------------------
-- | Substitute into some 'IdInfo' with regard to the supplied new 'Id'.
-substIdInfo :: Subst -> Id -> IdInfo -> Maybe IdInfo
-substIdInfo subst new_id info
+substIdInfo :: Bool -> Subst -> Id -> IdInfo -> Maybe IdInfo
+substIdInfo hack subst new_id info
| nothing_to_do = Nothing
| otherwise = Just (info `setRuleInfo` substRuleInfo subst new_id old_rules
- `setUnfoldingInfo` substUnfolding subst old_unf)
+ `setUnfoldingInfo` substUnfolding hack subst old_unf)
where
old_rules = ruleInfo info
old_unf = unfoldingInfo info
@@ -627,23 +630,24 @@ substIdInfo subst new_id info
-- NB: substUnfolding /discards/ any unfolding without
-- without a Stable source. This is usually what we want,
-- but it may be a bit unexpected
-substUnfolding, substUnfoldingSC :: Subst -> Unfolding -> Unfolding
+substUnfolding, substUnfoldingSC :: Bool -> Subst -> Unfolding -> Unfolding
-- Seq'ing on the returned Unfolding is enough to cause
-- all the substitutions to happen completely
-substUnfoldingSC subst unf -- Short-cut version
+substUnfoldingSC hack subst unf -- Short-cut version
| isEmptySubst subst = unf
- | otherwise = substUnfolding subst unf
+ | otherwise = substUnfolding hack subst unf
-substUnfolding subst df@(DFunUnfolding { df_bndrs = bndrs, df_args = args })
+substUnfolding _hack subst df@(DFunUnfolding { df_bndrs = bndrs, df_args = args })
= df { df_bndrs = bndrs', df_args = args' }
where
(subst',bndrs') = substBndrs subst bndrs
args' = map (substExpr subst') args
-substUnfolding subst unf@(CoreUnfolding { uf_tmpl = tmpl, uf_src = src })
+substUnfolding hack subst unf@(CoreUnfolding { uf_tmpl = tmpl, uf_src = src })
-- Retain an InlineRule!
| not (isStableSource src) -- Zap an unstable unfolding, to save substitution work
+ && not hack
= NoUnfolding
| otherwise -- But keep a stable one!
= seqExpr new_tmpl `seq`
@@ -651,7 +655,7 @@ substUnfolding subst unf@(CoreUnfolding { uf_tmpl = tmpl, uf_src = src })
where
new_tmpl = substExpr subst tmpl
-substUnfolding _ unf = unf -- NoUnfolding, OtherCon
+substUnfolding _ _ unf = unf -- NoUnfolding, OtherCon
------------------
substIdOcc :: Subst -> Id -> Id