OutId, OutTyVar, OutBind, OutExpr, OutAlt, OutArg, OutType, OutBndr,
InCoercion, OutCoercion,
- isStrictBndr,
-
-- The simplifier mode
setMode, getMode,
setEnclosingCC, getEnclosingCC,
-- Environments
- SimplEnv(..), -- Temp not abstract
+ SimplEnv(..), pprSimplEnv, -- Temp not abstract
mkSimplEnv, extendIdSubst, SimplEnv.extendTvSubst,
zapSubstEnv, setSubstEnv,
getInScope, setInScope, setInScopeSet, modifyInScope, addNewInScopeIds,
substExpr, substTy,
-- Floats
- Floats, emptyFloats, isEmptyFloats, addNonRec, addFloats,
- wrapFloats, floatBinds, setFloats, canFloat, zapFloats, addRecFloats,
- getFloats
+ Floats, emptyFloats, isEmptyFloats, addNonRec, addFloats, extendFloats,
+ wrapFloats, floatBinds, setFloats, zapFloats, addRecFloats,
+ doFloatFromRhs, getFloats
) where
#include "HsVersions.h"
import CoreSyn
import Rules
import CoreUtils
-import CoreFVs
import CostCentre
import Var
import VarEnv
import VarSet
import OrdList
import Id
-import NewDemand
import qualified CoreSubst ( Subst, mkSubst, substExpr, substSpec, substWorker )
import qualified Type ( substTy, substTyVarBndr )
import Type hiding ( substTy, substTyVarBndr )
import BasicTypes
import DynFlags
import Util
-import UniqFM
import Outputable
+
+import Data.List
\end{code}
%************************************************************************
type OutArg = CoreArg
\end{code}
-\begin{code}
-isStrictBndr :: Id -> Bool
-isStrictBndr bndr
- = ASSERT2( isId bndr, ppr bndr )
- isStrictDmd (idNewDemandInfo bndr) || isStrictType (idType bndr)
-\end{code}
-
%************************************************************************
%* *
\subsubsection{The @SimplEnv@ type}
seChkr :: SwitchChecker,
seCC :: CostCentreStack, -- The enclosing CCS (when profiling)
- -- Rules from other modules
- seExtRules :: RuleBase,
-
-- The current set of in-scope variables
-- They are all OutVars, and all bound in this module
seInScope :: InScopeSet, -- OutVars only
}
+pprSimplEnv :: SimplEnv -> SDoc
+-- Used for debugging; selective
+pprSimplEnv env
+ = vcat [ptext SLIT("TvSubst:") <+> ppr (seTvSubst env),
+ ptext SLIT("IdSubst:") <+> ppr (seIdSubst env) ]
+
type SimplIdSubst = IdEnv SimplSR -- IdId |--> OutExpr
+ -- See Note [Extending the Subst] in CoreSubst
data SimplSR
= DoneEx OutExpr -- Completed term
| ContEx TvSubstEnv -- A suspended substitution
SimplIdSubst
InExpr
+
instance Outputable SimplSR where
ppr (DoneEx e) = ptext SLIT("DoneEx") <+> ppr e
ppr (DoneId v) = ptext SLIT("DoneId") <+> ppr v
ppr (ContEx tv id e) = vcat [ptext SLIT("ContEx") <+> ppr e {-,
ppr (filter_env tv), ppr (filter_env id) -}]
- where
- fvs = exprFreeVars e
- filter_env env = filterVarEnv_Directly keep env
- keep uniq _ = uniq `elemUFM_Directly` fvs
+ -- where
+ -- fvs = exprFreeVars e
+ -- filter_env env = filterVarEnv_Directly keep env
+ -- keep uniq _ = uniq `elemUFM_Directly` fvs
\end{code}
\begin{code}
-mkSimplEnv :: SimplifierMode -> SwitchChecker -> RuleBase -> SimplEnv
-mkSimplEnv mode switches rules
+mkSimplEnv :: SimplifierMode -> SwitchChecker -> SimplEnv
+mkSimplEnv mode switches
= SimplEnv { seChkr = switches, seCC = subsumedCCS,
seMode = mode, seInScope = emptyInScopeSet,
- seExtRules = rules, seFloats = emptyFloats,
+ seFloats = emptyFloats,
seTvSubst = emptyVarEnv, seIdSubst = emptyVarEnv }
-- The top level "enclosing CC" is "SUBSUMED".
isEmptySimplSubst :: SimplEnv -> Bool
isEmptySimplSubst (SimplEnv { seTvSubst = tvs, seIdSubst = ids })
= isEmptyVarEnv tvs && isEmptyVarEnv ids
-
----------------------
-getRules :: SimplEnv -> RuleBase
-getRules = seExtRules
\end{code}
NonRec x (y:ys) FltLifted
Rec [(x,rhs)] FltLifted
- NonRec x# (y +# 3) FltOkSpec
+
+ NonRec x# (y +# 3) FltOkSpec -- Unboxed, but ok-for-spec'n
+
NonRec x# (a /# b) FltCareful
- NonRec x* (f y) FltCareful -- Might fail or diverge
- NonRec x# (f y) FltCareful -- Might fail or diverge
- (where f :: Int -> Int#)
+ NonRec x* (f y) FltCareful -- Strict binding; might fail or diverge
+ NonRec x# (f y) FltCareful -- Unboxed binding: might fail or diverge
+ -- (where f :: Int -> Int#)
\begin{code}
data Floats = Floats (OrdList OutBind) FloatFlag
classifyFF :: CoreBind -> FloatFlag
classifyFF (Rec _) = FltLifted
classifyFF (NonRec bndr rhs)
- | not (isStrictBndr bndr) = FltLifted
+ | not (isStrictId bndr) = FltLifted
| exprOkForSpeculation rhs = FltOkSpec
| otherwise = FltCareful
-canFloat :: TopLevelFlag -> RecFlag -> Bool -> SimplEnv -> Bool
-canFloat lvl rec str (SimplEnv {seFloats = Floats _ ff})
- = canFloatFlt lvl rec str ff
-
-canFloatFlt :: TopLevelFlag -> RecFlag -> Bool -> FloatFlag -> Bool
-canFloatFlt lvl rec str FltLifted = True
-canFloatFlt lvl rec str FltOkSpec = isNotTopLevel lvl && isNonRec rec
-canFloatFlt lvl rec str FltCareful = str && isNotTopLevel lvl && isNonRec rec
+doFloatFromRhs :: TopLevelFlag -> RecFlag -> Bool -> OutExpr -> SimplEnv -> Bool
+doFloatFromRhs lvl rec str rhs (SimplEnv {seFloats = Floats fs ff})
+ = not (isNilOL fs) && want_to_float && can_float
+ where
+ want_to_float = isTopLevel lvl || exprIsCheap rhs
+ can_float = case ff of
+ FltLifted -> True
+ FltOkSpec -> isNotTopLevel lvl && isNonRec rec
+ FltCareful -> isNotTopLevel lvl && isNonRec rec && str
\end{code}
= env { seFloats = seFloats env `addFlts` unitFloat (NonRec id rhs),
seInScope = extendInScopeSet (seInScope env) id }
+extendFloats :: SimplEnv -> [OutBind] -> SimplEnv
+-- Add these bindings to the floats, and extend the in-scope env too
+extendFloats env binds
+ = env { seFloats = seFloats env `addFlts` new_floats,
+ seInScope = extendInScopeSetList (seInScope env) bndrs }
+ where
+ bndrs = bindersOfBinds binds
+ new_floats = Floats (toOL binds)
+ (foldr (andFF . classifyFF) FltLifted binds)
+
addFloats :: SimplEnv -> SimplEnv -> SimplEnv
-- Add the floats for env2 to env1;
-- *plus* the in-scope set for env2, which is bigger
-- * The substitution extended with a DoneId if unique changed
-- In this case, the var in the DoneId is the same as the
-- var returned
+--
+-- Exactly like CoreSubst.substIdBndr, except that the type of id_subst differs
substIdBndr env@(SimplEnv { seInScope = in_scope, seIdSubst = id_subst})
old_id
-- Extend the substitution if the unique has changed
-- See the notes with substTyVarBndr for the delSubstEnv
+ -- Also see Note [Extending the Subst] in CoreSubst
new_subst | new_id /= old_id
= extendVarEnv id_subst old_id (DoneId new_id)
| otherwise
-> (SimplEnv, OutBndr)
-- C.f. substIdBndr above
-- Clone Id if necessary, substitute its type
--- Return an Id with completely zapped IdInfo
+-- Return an Id with its fragile info zapped
+-- namely, any info that depends on free variables
-- [addLetIdInfo, below, will restore its IdInfo]
+-- We want to retain robust info, especially arity and demand info,
+-- so that they are available to occurrences that occur in an
+-- earlier binding of a letrec
-- Augment the subtitution
-- if the unique changed, *or*
-- if there's interesting occurrence info
where
id1 = uniqAway in_scope old_id
id2 = substIdType env id1
- new_id = setIdInfo id2 vanillaIdInfo
+
+ -- We want to get rid of any info that's dependent on free variables,
+ -- but keep other info (like the arity).
+ new_id = zapFragileIdInfo id2
-- Extend the substitution if the unique has changed,
-- or there's some useful occurrence information
= delVarEnv id_subst old_id
\end{code}
-Add IdInfo back onto a let-bound Id
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Note [Add IdInfo back onto a let-bound Id]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We must transfer the IdInfo of the original binder to the new binder.
This is crucial, to preserve
strictness