Commit 30b5ebe4 authored by simonpj's avatar simonpj

[project @ 1999-11-01 17:09:54 by simonpj]

A regrettably-gigantic commit that puts in place what Simon PJ
has been up to for the last month or so, on and off.

The basic idea was to restore unfoldings to *occurrences* of
variables without introducing a space leak.  I wanted to make
sure things improved relative to 4.04, and that proved depressingly
hard.  On the way I discovered several quite serious bugs in the
simplifier.

Here's a summary of what's gone on.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* No commas between for-alls in RULES.  This makes the for-alls have
  the same syntax as in types.

* Arrange that simplConArgs works in one less pass than before.
  This exposed a bug: a bogus call to completeBeta.

* Add a top-level flag in CoreUnfolding, used in callSiteInline

* Extend w/w to use etaExpandArity, so it does eta/coerce expansion

* Implement inline phases.   The meaning of the inline pragmas is
  described in CoreUnfold.lhs.  You can say things like
	{#- INLINE 2 build #-}
  to mean "inline build in phase 2"

* Don't float anything out of an INLINE.
  Don't float things to top level unless they also escape a value lambda.
	[see comments with SetLevels.lvlMFE
  Without at least one of these changes, I found that
	{-# INLINE concat #-}
	concat = __inline (/\a -> foldr (++) [])
  was getting floated to
	concat = __inline( /\a -> lvl a )
	lvl = ...inlined version of foldr...

  Subsequently I found that not floating constants out of an INLINE
  gave really bad code like
	__inline (let x = e in \y -> ...)
  so I now let things float out of INLINE

* Implement the "reverse-mapping" idea for CSE; actually it turned out to be easier
  to implement it in SetLevels, and may benefit full laziness too.

* It's a good idea to inline inRange. Consider

	index (l,h) i = case inRange (l,h) i of
		  	  True ->  l+i
			  False -> error
  inRange itself isn't strict in h, but if it't inlined then 'index'
  *does* become strict in h.  Interesting!

* Big change to the way unfoldings and occurrence info is propagated in the simplifier
  The plan is described in Subst.lhs with the Subst type
  Occurrence info is now in a separate IdInfo field than user pragmas

* I found that
	(coerce T (coerce S (\x.e))) y
  didn't simplify in one round. First we get to
	(\x.e) y
  and only then do the beta. Solution: cancel the coerces in the continuation

* Amazingly, CoreUnfold wasn't counting the cost of a function an application.

* Disable rules in initial simplifier run.  Otherwise full laziness
  doesn't get a chance to lift out a MFE before a rule (e.g. fusion)
  zaps it.  queens is a case in point

* Improve float-out stuff significantly.  The big change is that if we have

	\x -> ... /\a -> ...let p = ..a.. in let q = ...p...

  where p's rhs doesn't x, we abstract a from p, so that we can get p past x.
  (We did that before.)  But we also substitute (p a) for p in q, and then
  we can do the same thing for q.  (We didn't do that, so q got stuck.)
  This is much better.  It involves doing a substitution "as we go" in SetLevels,
  though.
parent ddddb042
_interface_ DataCon 1
_exports_
DataCon DataCon dataConType ;
DataCon DataCon dataConType isExistentialDataCon ;
_declarations_
1 data DataCon ;
1 dataConType _:_ DataCon -> TypeRep.Type ;;
1 isExistentialDataCon _:_ DataCon -> PrelBase.Bool ;;
__interface DataCon 1 0 where
__export DataCon DataCon dataConType ;
__export DataCon DataCon dataConType isExistentialDataCon ;
1 data DataCon ;
1 dataConType :: DataCon -> TypeRep.Type ;
1 isExistentialDataCon :: DataCon -> PrelBase.Bool ;
......@@ -378,8 +378,7 @@ splitProductType_maybe
splitProductType_maybe ty
= case splitAlgTyConApp_maybe ty of
Just (tycon,ty_args,[data_con])
| isProductTyCon tycon && -- Checks for non-recursive
not (isExistentialDataCon data_con)
| isProductTyCon tycon -- Checks for non-recursive, non-existential
-> Just (tycon, ty_args, data_con, data_con_arg_tys)
where
data_con_arg_tys = map (substTy (mkTyVarSubst (dcTyVars data_con) ty_args))
......
......@@ -19,6 +19,7 @@ module Id (
-- Modifying an Id
setIdName, setIdUnique, setIdType, setIdNoDiscard,
setIdInfo, lazySetIdInfo, modifyIdInfo, maybeModifyIdInfo,
zapFragileIdInfo, zapLamIdInfo,
-- Predicates
omitIfaceSigForId,
......@@ -28,12 +29,12 @@ module Id (
-- Inline pragma stuff
getInlinePragma, setInlinePragma, modifyInlinePragma,
idMustBeINLINEd, idMustNotBeINLINEd,
isSpecPragmaId, isRecordSelector,
isPrimitiveId_maybe, isDataConId_maybe,
isConstantId, isBottomingId, idAppIsBottom,
isExportedId, isUserExportedId,
mayHaveNoBinding,
-- One shot lambda stuff
isOneShotLambda, setOneShotLambda, clearOneShotLambda,
......@@ -48,6 +49,7 @@ module Id (
setIdUpdateInfo,
setIdCafInfo,
setIdCprInfo,
setIdOccInfo,
getIdArity,
getIdDemandInfo,
......@@ -57,7 +59,8 @@ module Id (
getIdSpecialisation,
getIdUpdateInfo,
getIdCafInfo,
getIdCprInfo
getIdCprInfo,
getIdOccInfo
) where
......@@ -74,17 +77,20 @@ import Var ( Id, DictId,
externallyVisibleId
)
import VarSet
import Type ( Type, tyVarsOfType, typePrimRep, addFreeTyVars, seqType )
import IdInfo
import Type ( Type, tyVarsOfType, typePrimRep, addFreeTyVars, seqType, splitTyConApp_maybe )
import IdInfo
import Demand ( Demand, isStrict, wwLazy )
import Name ( Name, OccName,
mkSysLocalName, mkLocalName,
isWiredInName, isUserExportedName
)
import OccName ( UserFS )
import Const ( Con(..) )
import PrimRep ( PrimRep )
import PrimOp ( PrimOp )
import TysPrim ( realWorldStatePrimTy )
import TysPrim ( statePrimTyCon )
import FieldLabel ( FieldLabel(..) )
import SrcLoc ( SrcLoc )
import Unique ( Unique, mkBuiltinUnique, getBuiltinUniques )
......@@ -131,8 +137,8 @@ mkVanillaId name ty = mkId name ty vanillaIdInfo
-- SysLocal: for an Id being created by the compiler out of thin air...
-- UserLocal: an Id with a name the user might recognize...
mkUserLocal :: OccName -> Unique -> Type -> SrcLoc -> Id
mkSysLocal :: FAST_STRING -> Unique -> Type -> Id
mkUserLocal :: OccName -> Unique -> Type -> SrcLoc -> Id
mkSysLocal :: UserFS -> Unique -> Type -> Id
mkSysLocal fs uniq ty = mkVanillaId (mkSysLocalName uniq fs) ty
mkUserLocal occ uniq ty loc = mkVanillaId (mkLocalName uniq occ loc) ty
......@@ -215,6 +221,14 @@ isSpecPragmaId id = case idFlavour id of
SpecPragmaId -> True
other -> False
mayHaveNoBinding id = isConstantId id
-- mayHaveNoBinding returns True of an Id which may not have a
-- binding, even though it is defined in this module. Notably,
-- the constructors of a dictionary are in this situation.
--
-- mayHaveNoBinding returns True of some things that *do* have a local binding,
-- so it's only an approximation. That's ok... it's only use for assertions.
-- Don't drop a binding for an exported Id,
-- if it otherwise looks dead.
isExportedId :: Id -> Bool
......@@ -344,6 +358,14 @@ getIdCprInfo id = cprInfo (idInfo id)
setIdCprInfo :: Id -> CprInfo -> Id
setIdCprInfo id cpr_info = modifyIdInfo (`setCprInfo` cpr_info) id
---------------------------------
-- Occcurrence INFO
getIdOccInfo :: Id -> OccInfo
getIdOccInfo id = occInfo (idInfo id)
setIdOccInfo :: Id -> OccInfo -> Id
setIdOccInfo id occ_info = modifyIdInfo (`setOccInfo` occ_info) id
\end{code}
......@@ -361,15 +383,6 @@ setInlinePragma id prag = modifyIdInfo (`setInlinePragInfo` prag) id
modifyInlinePragma :: Id -> (InlinePragInfo -> InlinePragInfo) -> Id
modifyInlinePragma id fn = modifyIdInfo (\info -> info `setInlinePragInfo` (fn (inlinePragInfo info))) id
idMustNotBeINLINEd id = case getInlinePragma id of
IMustNotBeINLINEd -> True
IAmALoopBreaker -> True
other -> False
idMustBeINLINEd id = case getInlinePragma id of
IMustBeINLINEd -> True
other -> False
\end{code}
......@@ -379,7 +392,9 @@ idMustBeINLINEd id = case getInlinePragma id of
isOneShotLambda :: Id -> Bool
isOneShotLambda id = case lbvarInfo (idInfo id) of
IsOneShotLambda -> True
NoLBVarInfo -> idType id == realWorldStatePrimTy
NoLBVarInfo -> case splitTyConApp_maybe (idType id) of
Just (tycon,_) -> tycon == statePrimTyCon
other -> False
-- The last clause is a gross hack. It claims that
-- every function over realWorldStatePrimTy is a one-shot
-- function. This is pretty true in practice, and makes a big
......@@ -391,9 +406,12 @@ isOneShotLambda id = case lbvarInfo (idInfo id) of
-- When `thenST` gets inlined, we end up with
-- let lvl = E in \s -> case a s of (r, s') -> ...lvl...
-- and we don't re-inline E.
--
--
-- It would be better to spot that r was one-shot to start with, but
-- I don't want to rely on that.
--
-- Another good example is in fill_in in PrelPack.lhs. We should be able to
-- spot that fill_in has arity 2 (and when Keith is done, we will) but we can't yet.
setOneShotLambda :: Id -> Id
setOneShotLambda id = modifyIdInfo (`setLBVarInfo` IsOneShotLambda) id
......@@ -407,3 +425,12 @@ clearOneShotLambda id
-- f = \x -> e
-- If we change the one-shot-ness of x, f's type changes
\end{code}
\begin{code}
zapFragileIdInfo :: Id -> Id
zapFragileIdInfo id = maybeModifyIdInfo zapFragileInfo id
zapLamIdInfo :: Id -> Id
zapLamIdInfo id = maybeModifyIdInfo zapLamInfo id
\end{code}
_interface_ IdInfo 1
_exports_
IdInfo IdInfo seqIdInfo ;
IdInfo IdInfo seqIdInfo vanillaIdInfo;
_declarations_
1 data IdInfo ;
1 seqIdInfo _:_ IdInfo -> PrelBase.() ;;
1 vanillaIdInfo _:_ IdInfo ;;
__interface IdInfo 1 0 where
__export IdInfo IdInfo seqIdInfo ;
__export IdInfo IdInfo seqIdInfo vanillaIdInfo ;
1 data IdInfo ;
1 seqIdInfo :: IdInfo -> PrelBase.Z0T ;
1 vanillaIdInfo :: IdInfo ;
......@@ -12,9 +12,12 @@ module IdInfo (
vanillaIdInfo, mkIdInfo, seqIdInfo, megaSeqIdInfo,
-- Zapping
zapFragileInfo, zapLamInfo, zapSpecPragInfo, copyIdInfo,
-- Flavour
IdFlavour(..), flavourInfo,
setNoDiscardInfo, zapSpecPragInfo, copyIdInfo,
setNoDiscardInfo,
ppFlavourInfo,
-- Arity
......@@ -40,8 +43,12 @@ module IdInfo (
demandInfo, setDemandInfo,
-- Inline prags
InlinePragInfo(..), OccInfo(..),
inlinePragInfo, setInlinePragInfo, notInsideLambda,
InlinePragInfo(..),
inlinePragInfo, setInlinePragInfo, pprInlinePragInfo,
-- Occurrence info
OccInfo(..), InsideLam, OneBranch, insideLam, notInsideLam, oneBranch, notOneBranch,
occInfo, setOccInfo, isFragileOccInfo,
-- Specialisation
specInfo, setSpecInfo,
......@@ -56,9 +63,6 @@ module IdInfo (
-- Constructed Product Result Info
CprInfo(..), cprInfo, setCprInfo, ppCprInfo, noCprInfo,
-- Zapping
zapLamIdInfo, zapFragileIdInfo, zapIdInfoForStg,
-- Lambda-bound variable info
LBVarInfo(..), lbvarInfo, setLBVarInfo, noLBVarInfo
) where
......@@ -71,9 +75,9 @@ import {-# SOURCE #-} CoreSyn ( CoreExpr, CoreRules, emptyCoreRules, isEmptyCor
import {-# SOURCE #-} Const ( Con )
import Var ( Id )
import VarSet ( IdOrTyVarSet )
import FieldLabel ( FieldLabel )
import Demand ( Demand, isStrict, isLazy, wwLazy, pprDemands, seqDemand, seqDemands )
import Type ( UsageAnn )
import Outputable
import Maybe ( isJust )
......@@ -86,7 +90,8 @@ infixl 1 `setUpdateInfo`,
`setUnfoldingInfo`,
`setCprInfo`,
`setWorkerInfo`,
`setCafInfo`
`setCafInfo`,
`setOccInfo`
-- infixl so you can say (id `set` a `set` b)
\end{code}
......@@ -121,7 +126,8 @@ data IdInfo
cafInfo :: CafInfo,
cprInfo :: CprInfo, -- Function always constructs a product result
lbvarInfo :: LBVarInfo, -- Info about a lambda-bound variable
inlinePragInfo :: InlinePragInfo -- Inline pragmas
inlinePragInfo :: InlinePragInfo, -- Inline pragma
occInfo :: OccInfo -- How it occurs
}
seqIdInfo :: IdInfo -> ()
......@@ -143,7 +149,7 @@ megaSeqIdInfo info
seqCaf (cafInfo info) `seq`
seqCpr (cprInfo info) `seq`
seqLBVar (lbvarInfo info) `seq`
seqInlinePrag (inlinePragInfo info)
seqOccInfo (occInfo info)
\end{code}
Setters
......@@ -152,6 +158,7 @@ Setters
setWorkerInfo info wk = wk `seq` info { workerInfo = wk }
setSpecInfo info sp = PSEQ sp (info { specInfo = sp })
setInlinePragInfo info pr = pr `seq` info { inlinePragInfo = pr }
setOccInfo info oc = oc `seq` info { occInfo = oc }
setStrictnessInfo info st = st `seq` info { strictnessInfo = st }
-- Try to avoid spack leaks by seq'ing
......@@ -173,33 +180,6 @@ zapSpecPragInfo info = case flavourInfo info of
SpecPragmaId -> info { flavourInfo = VanillaId }
other -> info
copyIdInfo :: IdInfo -- From
-> IdInfo -- To
-> IdInfo -- To, updated with stuff from From; except flavour unchanged
-- copyIdInfo is used when shorting out a top-level binding
-- f_local = BIG
-- f = f_local
-- where f is exported. We are going to swizzle it around to
-- f = BIG
-- f_local = f
-- but we must be careful to combine their IdInfos right.
-- The fact that things can go wrong here is a bad sign, but I can't see
-- how to make it 'patently right', so copyIdInfo is derived (pretty much) by trial and error
--
-- Here 'from' is f_local, 'to' is f, and the result is attached to f
copyIdInfo from to = from { flavourInfo = flavourInfo to,
specInfo = specInfo to,
inlinePragInfo = inlinePragInfo to
}
-- It's important to preserve the inline pragma on 'f'; e.g. consider
-- {-# NOINLINE f #-}
-- f = local
--
-- similarly, transformation rules may be attached to f
-- and we want to preserve them.
--
-- On the other hand, we want the strictness info from f_local.
\end{code}
......@@ -220,7 +200,8 @@ mkIdInfo flv = IdInfo {
cafInfo = MayHaveCafRefs,
cprInfo = NoCPRInfo,
lbvarInfo = NoLBVarInfo,
inlinePragInfo = NoInlinePragInfo
inlinePragInfo = NoInlinePragInfo,
occInfo = NoOccInfo
}
\end{code}
......@@ -314,66 +295,78 @@ ppArityInfo (ArityAtLeast arity) = hsep [ptext SLIT("__AL"), int arity]
\begin{code}
data InlinePragInfo
= NoInlinePragInfo
| IMustNotBeINLINEd Bool -- True <=> came from an INLINE prag, False <=> came from a NOINLINE prag
(Maybe Int) -- Phase number from pragma, if any
-- The True, Nothing case doesn't need to be recorded
| IMustNotBeINLINEd -- User NOINLINE pragma
| IAmALoopBreaker -- Used by the occurrence analyser to mark loop-breakers
-- in a group of recursive definitions
instance Outputable InlinePragInfo where
-- This is now parsed in interface files
ppr NoInlinePragInfo = empty
ppr other_prag = ptext SLIT("__U") <> pprInlinePragInfo other_prag
pprInlinePragInfo NoInlinePragInfo = empty
pprInlinePragInfo (IMustNotBeINLINEd True Nothing) = empty
pprInlinePragInfo (IMustNotBeINLINEd True (Just n)) = brackets (int n)
pprInlinePragInfo (IMustNotBeINLINEd False Nothing) = brackets (char '!')
pprInlinePragInfo (IMustNotBeINLINEd False (Just n)) = brackets (char '!' <> int n)
instance Show InlinePragInfo where
showsPrec p prag = showsPrecSDoc p (ppr prag)
\end{code}
| ICanSafelyBeINLINEd -- Used by the occurrence analyser to mark things
-- that manifesly occur once, not inside SCCs,
-- not in constructor arguments
OccInfo -- Says whether the occurrence is inside a lambda
-- If so, must only substitute WHNFs
%************************************************************************
%* *
\subsection{Occurrence information}
%* *
%************************************************************************
Bool -- False <=> occurs in more than one case branch
-- If so, there's a code-duplication issue
\begin{code}
data OccInfo
= NoOccInfo
| IAmDead -- Marks unused variables. Sometimes useful for
-- lambda and case-bound variables.
| IMustBeINLINEd -- Absolutely must inline; used for PrimOps and
-- constructors only.
| OneOcc InsideLam
seqInlinePrag :: InlinePragInfo -> ()
seqInlinePrag (ICanSafelyBeINLINEd occ alts)
= occ `seq` alts `seq` ()
seqInlinePrag other
= ()
OneBranch
instance Outputable InlinePragInfo where
-- only used for debugging; never parsed. KSW 1999-07
ppr NoInlinePragInfo = empty
ppr IMustBeINLINEd = ptext SLIT("__UU")
ppr IMustNotBeINLINEd = ptext SLIT("__Unot")
ppr IAmALoopBreaker = ptext SLIT("__Ux")
ppr IAmDead = ptext SLIT("__Ud")
ppr (ICanSafelyBeINLINEd InsideLam _) = ptext SLIT("__Ul")
ppr (ICanSafelyBeINLINEd NotInsideLam True) = ptext SLIT("__Us")
ppr (ICanSafelyBeINLINEd NotInsideLam False) = ptext SLIT("__Us*")
instance Show InlinePragInfo where
showsPrec p prag = showsPrecSDoc p (ppr prag)
\end{code}
| IAmALoopBreaker -- Used by the occurrence analyser to mark loop-breakers
-- in a group of recursive definitions
\begin{code}
data OccInfo
= NotInsideLam
seqOccInfo :: OccInfo -> ()
seqOccInfo (OneOcc in_lam once) = in_lam `seq` once `seq` ()
seqOccInfo occ = ()
| InsideLam -- Inside a non-linear lambda (that is, a lambda which
-- is sure to be instantiated only once).
type InsideLam = Bool -- True <=> Occurs inside a non-linear lambda
-- Substituting a redex for this occurrence is
-- dangerous because it might duplicate work.
insideLam = True
notInsideLam = False
instance Outputable OccInfo where
ppr NotInsideLam = empty
ppr InsideLam = text "l"
type OneBranch = Bool -- True <=> Occurs in only one case branch
-- so no code-duplication issue to worry about
oneBranch = True
notOneBranch = False
isFragileOccInfo :: OccInfo -> Bool
isFragileOccInfo (OneOcc _ _) = True
isFragileOccInfo other = False
\end{code}
notInsideLambda :: OccInfo -> Bool
notInsideLambda NotInsideLam = True
notInsideLambda InsideLam = False
\begin{code}
instance Outputable OccInfo where
-- only used for debugging; never parsed. KSW 1999-07
ppr NoOccInfo = empty
ppr IAmALoopBreaker = ptext SLIT("_Kx")
ppr IAmDead = ptext SLIT("_Kd")
ppr (OneOcc inside_lam one_branch) | inside_lam = ptext SLIT("_Kl")
| one_branch = ptext SLIT("_Ks")
| otherwise = ptext SLIT("_Ks*")
instance Show OccInfo where
showsPrec p occ = showsPrecSDoc p (ppr occ)
\end{code}
%************************************************************************
......@@ -533,98 +526,6 @@ ppCafInfo MayHaveCafRefs = empty
\end{code}
%************************************************************************
%* *
\subsection[CAF-IdInfo]{CAF-related information}
%* *
%************************************************************************
zapFragileIdInfo is used when cloning binders, mainly in the
simplifier. We must forget about used-once information because that
isn't necessarily correct in the transformed program.
Also forget specialisations and unfoldings because they would need
substitution to be correct. (They get pinned back on separately.)
\begin{code}
zapFragileIdInfo :: IdInfo -> Maybe IdInfo
zapFragileIdInfo info@(IdInfo {inlinePragInfo = inline_prag,
workerInfo = wrkr,
specInfo = rules,
unfoldingInfo = unfolding})
| not is_fragile_inline_prag
-- We must forget about whether it was marked safe-to-inline,
-- because that isn't necessarily true in the simplified expression.
-- This is important because expressions may be re-simplified
&& isEmptyCoreRules rules
-- Specialisations would need substituting. They get pinned
-- back on separately.
&& not (workerExists wrkr)
&& not (hasUnfolding unfolding)
-- This is very important; occasionally a let-bound binder is used
-- as a binder in some lambda, in which case its unfolding is utterly
-- bogus. Also the unfolding uses old binders so if we left it we'd
-- have to substitute it. Much better simply to give the Id a new
-- unfolding each time, which is what the simplifier does.
= Nothing
| otherwise
= Just (info {inlinePragInfo = safe_inline_prag,
workerInfo = noWorkerInfo,
specInfo = emptyCoreRules,
unfoldingInfo = noUnfolding})
where
is_fragile_inline_prag = case inline_prag of
ICanSafelyBeINLINEd _ _ -> True
-- We used to say the dead-ness was fragile, but I don't
-- see why it is. Furthermore, deadness is a pain to lose;
-- see Simplify.mkDupableCont (Select ...)
-- IAmDead -> True
other -> False
-- Be careful not to destroy real 'pragma' info
safe_inline_prag | is_fragile_inline_prag = NoInlinePragInfo
| otherwise = inline_prag
\end{code}
@zapLamIdInfo@ is used for lambda binders that turn out to to be
part of an unsaturated lambda
\begin{code}
zapLamIdInfo :: IdInfo -> Maybe IdInfo
zapLamIdInfo info@(IdInfo {inlinePragInfo = inline_prag, demandInfo = demand})
| is_safe_inline_prag && not (isStrict demand)
= Nothing
| otherwise
= Just (info {inlinePragInfo = safe_inline_prag,
demandInfo = wwLazy})
where
-- The "unsafe" prags are the ones that say I'm not in a lambda
-- because that might not be true for an unsaturated lambda
is_safe_inline_prag = case inline_prag of
ICanSafelyBeINLINEd NotInsideLam nalts -> False
other -> True
safe_inline_prag = case inline_prag of
ICanSafelyBeINLINEd _ nalts
-> ICanSafelyBeINLINEd InsideLam nalts
other -> inline_prag
\end{code}
\begin{code}
zapIdInfoForStg :: IdInfo -> IdInfo
-- Return only the info needed for STG stuff
-- Namely, nothing, I think
zapIdInfoForStg info = vanillaIdInfo
\end{code}
%************************************************************************
%* *
\subsection[cpr-IdInfo]{Constructed Product Result info about an @Id@}
......@@ -740,3 +641,112 @@ instance Outputable LBVarInfo where
instance Show LBVarInfo where
showsPrec p c = showsPrecSDoc p (ppr c)
\end{code}
%************************************************************************
%* *
\subsection{Bulk operations on IdInfo}
%* *
%************************************************************************
zapFragileInfo is used when cloning binders, mainly in the
simplifier. We must forget about used-once information because that
isn't necessarily correct in the transformed program.
Also forget specialisations and unfoldings because they would need
substitution to be correct. (They get pinned back on separately.)
\begin{code}
zapFragileInfo :: IdInfo -> Maybe IdInfo
zapFragileInfo info@(IdInfo {occInfo = occ,
workerInfo = wrkr,
specInfo = rules,
unfoldingInfo = unfolding})
| not (isFragileOccInfo occ)
-- We must forget about whether it was marked safe-to-inline,
-- because that isn't necessarily true in the simplified expression.
-- This is important because expressions may be re-simplified
-- We don't zap deadness or loop-breaker-ness.
-- The latter is important because it tells MkIface not to
-- spit out an inlining for the thing. The former doesn't
-- seem so important, but there's no harm.
&& isEmptyCoreRules rules
-- Specialisations would need substituting. They get pinned
-- back on separately.
&& not (workerExists wrkr)
&& not (hasUnfolding unfolding)
-- This is very important; occasionally a let-bound binder is used
-- as a binder in some lambda, in which case its unfolding is utterly
-- bogus. Also the unfolding uses old binders so if we left it we'd
-- have to substitute it. Much better simply to give the Id a new
-- unfolding each time, which is what the simplifier does.
= Nothing
| otherwise
= Just (info {occInfo = robust_occ_info,
workerInfo = noWorkerInfo,
specInfo = emptyCoreRules,
unfoldingInfo = noUnfolding})
where
-- It's important to keep the loop-breaker info,
-- because the substitution doesn't remember it.
robust_occ_info = case occ of
OneOcc _ _ -> NoOccInfo
other -> occ
\end{code}
@zapLamInfo@ is used for lambda binders that turn out to to be
part of an unsaturated lambda
\begin{code}
zapLamInfo :: IdInfo -> Maybe IdInfo
zapLamInfo info@(IdInfo {occInfo = occ, demandInfo = demand})
| is_safe_occ && not (isStrict demand)
= Nothing
| otherwise
= Just (info {occInfo = safe_occ,
demandInfo = wwLazy})
where
-- The "unsafe" occ info is the ones that say I'm not in a lambda
-- because that might not be true for an unsaturated lambda
is_safe_occ = case occ of
OneOcc in_lam once -> in_lam
other -> True
safe_occ = case occ of
OneOcc _ once -> OneOcc insideLam once
other -> occ
\end{code}
copyIdInfo is used when shorting out a top-level binding
f_local = BIG
f = f_local
where f is exported. We are going to swizzle it around to
f = BIG
f_local = f
but we must be careful to combine their IdInfos right.
The fact that things can go wrong here is a bad sign, but I can't see
how to make it 'patently right', so copyIdInfo is derived (pretty much) by trial and error
Here 'from' is f_local, 'to' is f, and the result is attached to f
\begin{code}
copyIdInfo :: IdInfo -- From
-> IdInfo -- To
-> IdInfo -- To, updated with stuff from From; except flavour unchanged
copyIdInfo from to = from { flavourInfo = flavourInfo to,
specInfo = specInfo to,
inlinePragInfo = inlinePragInfo to
}