module IdInfo (
IdInfo, -- Abstract
- noIdInfo,
+ vanillaIdInfo, mkIdInfo, seqIdInfo, megaSeqIdInfo,
+
+ -- Flavour
+ IdFlavour(..), flavourInfo,
+ setNoDiscardInfo, zapSpecPragInfo, copyIdInfo,
+ ppFlavourInfo,
-- Arity
ArityInfo(..),
- exactArity, atLeastArity, unknownArity,
+ exactArity, atLeastArity, unknownArity, hasArity,
arityInfo, setArityInfo, ppArityInfo, arityLowerBound,
-- Strictness
StrictnessInfo(..), -- Non-abstract
- workerExists, mkStrictnessInfo,
+ mkStrictnessInfo,
noStrictnessInfo, strictnessInfo,
ppStrictnessInfo, setStrictnessInfo,
isBottomingStrictness, appIsBottom,
+ -- Worker
+ WorkerInfo, workerExists,
+ workerInfo, setWorkerInfo, ppWorkerInfo,
+
-- Unfolding
unfoldingInfo, setUnfoldingInfo,
inlinePragInfo, setInlinePragInfo, notInsideLambda,
-- Specialisation
- IdSpecEnv, specInfo, setSpecInfo,
+ specInfo, setSpecInfo,
-- Update
UpdateInfo, UpdateSpec,
-- CAF info
CafInfo(..), cafInfo, setCafInfo, ppCafInfo,
+
+ -- Constructed Product Result Info
+ CprInfo(..), cprInfo, setCprInfo, ppCprInfo, noCprInfo,
+
+ -- Zapping
+ zapLamIdInfo, zapFragileIdInfo, zapIdInfoForStg,
+
+ -- Lambda-bound variable info
+ LBVarInfo(..), lbvarInfo, setLBVarInfo, noLBVarInfo
) where
#include "HsVersions.h"
-import {-# SOURCE #-} CoreUnfold ( Unfolding, noUnfolding )
-import {-# SOURCE #-} CoreSyn ( CoreExpr )
+import {-# SOURCE #-} CoreUnfold ( Unfolding, noUnfolding, hasUnfolding, seqUnfolding )
+import {-# SOURCE #-} CoreSyn ( CoreExpr, CoreRules, emptyCoreRules, isEmptyCoreRules, seqRules )
+import {-# SOURCE #-} Const ( Con )
-import SpecEnv ( SpecEnv, emptySpecEnv )
-import Demand ( Demand, isLazy, wwLazy, pprDemands )
+import Var ( Id )
+import FieldLabel ( FieldLabel )
+import Demand ( Demand, isStrict, isLazy, wwLazy, pprDemands, seqDemand, seqDemands )
+import Type ( UsageAnn )
import Outputable
+import Maybe ( isJust )
+
+infixl 1 `setUpdateInfo`,
+ `setDemandInfo`,
+ `setStrictnessInfo`,
+ `setSpecInfo`,
+ `setArityInfo`,
+ `setInlinePragInfo`,
+ `setUnfoldingInfo`,
+ `setCprInfo`,
+ `setWorkerInfo`,
+ `setCafInfo`
+ -- infixl so you can say (id `set` a `set` b)
\end{code}
An @IdInfo@ gives {\em optional} information about an @Id@. If
present it never lies, but it may not be present, in which case there
is always a conservative assumption which can be made.
+ There is one exception: the 'flavour' is *not* optional.
+ You must not discard it.
+ It used to be in Var.lhs, but that seems unclean.
+
Two @Id@s may have different info even though they have the same
@Unique@ (and are hence the same @Id@); for example, one might lack
the properties attached to the other.
The @IdInfo@ gives information about the value, or definition, of the
@Id@. It does {\em not} contain information about the @Id@'s usage
-(except for @DemandInfo@? ToDo).
+(except for @DemandInfo@? ToDo). (@lbvarInfo@ is also a marginal
+case. KSW 1999-04).
\begin{code}
data IdInfo
= IdInfo {
- arityInfo :: ArityInfo, -- Its arity
- demandInfo :: Demand, -- Whether or not it is definitely demanded
- specInfo :: IdSpecEnv, -- Specialisations of this function which exist
- strictnessInfo :: StrictnessInfo, -- Strictness properties
- unfoldingInfo :: Unfolding, -- Its unfolding
- updateInfo :: UpdateInfo, -- Which args should be updated
- cafInfo :: CafInfo,
- inlinePragInfo :: !InlinePragInfo -- Inline pragmas
+ flavourInfo :: IdFlavour, -- NOT OPTIONAL
+ arityInfo :: ArityInfo, -- Its arity
+ demandInfo :: Demand, -- Whether or not it is definitely demanded
+ specInfo :: CoreRules, -- Specialisations of this function which exist
+ strictnessInfo :: StrictnessInfo, -- Strictness properties
+ workerInfo :: WorkerInfo, -- Pointer to Worker Function
+ unfoldingInfo :: Unfolding, -- Its unfolding
+ updateInfo :: UpdateInfo, -- Which args should be updated
+ cafInfo :: CafInfo,
+ cprInfo :: CprInfo, -- Function always constructs a product result
+ lbvarInfo :: LBVarInfo, -- Info about a lambda-bound variable
+ inlinePragInfo :: InlinePragInfo -- Inline pragmas
}
+
+seqIdInfo :: IdInfo -> ()
+seqIdInfo (IdInfo {}) = ()
+
+megaSeqIdInfo :: IdInfo -> ()
+megaSeqIdInfo info
+ = seqFlavour (flavourInfo info) `seq`
+ seqArity (arityInfo info) `seq`
+ seqDemand (demandInfo info) `seq`
+ seqRules (specInfo info) `seq`
+ seqStrictness (strictnessInfo info) `seq`
+ seqWorker (workerInfo info) `seq`
+
+-- seqUnfolding (unfoldingInfo info) `seq`
+-- Omitting this improves runtimes a little, presumably because
+-- some unfoldings are not calculated at all
+
+ seqCaf (cafInfo info) `seq`
+ seqCpr (cprInfo info) `seq`
+ seqLBVar (lbvarInfo info) `seq`
+ seqInlinePrag (inlinePragInfo info)
\end{code}
Setters
\begin{code}
-setUpdateInfo ud info = info { updateInfo = ud }
-setDemandInfo dd info = info { demandInfo = dd }
-setStrictnessInfo st info = info { strictnessInfo = st }
-setSpecInfo sp info = info { specInfo = sp }
-setArityInfo ar info = info { arityInfo = ar }
-setInlinePragInfo pr info = info { inlinePragInfo = pr }
-setUnfoldingInfo uf info = info { unfoldingInfo = uf }
-setCafInfo cf info = info { cafInfo = cf }
+setWorkerInfo info wk = wk `seq` info { workerInfo = wk }
+setSpecInfo info sp = sp `seq` info { specInfo = sp }
+setInlinePragInfo info pr = pr `seq` info { inlinePragInfo = pr }
+setStrictnessInfo info st = st `seq` info { strictnessInfo = st }
+ -- Try to avoid spack leaks by seq'ing
+
+setUnfoldingInfo info uf = info { unfoldingInfo = uf }
+ -- We do *not* seq on the unfolding info, For some reason, doing so
+ -- actually increases residency significantly.
+
+setUpdateInfo info ud = info { updateInfo = ud }
+setDemandInfo info dd = info { demandInfo = dd }
+setArityInfo info ar = info { arityInfo = ar }
+setCafInfo info cf = info { cafInfo = cf }
+setCprInfo info cp = info { cprInfo = cp }
+setLBVarInfo info lb = info { lbvarInfo = lb }
+
+setNoDiscardInfo info = case flavourInfo info of
+ VanillaId -> info { flavourInfo = NoDiscardId }
+ other -> info
+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.
+
+copyIdInfo from to = from { flavourInfo = flavourInfo to,
+ specInfo = specInfo to
+ }
+ -- It's important to propagate the inline pragmas from bndr
+ -- to exportd_id. Ditto strictness etc. This "bites" when we use an INLNE pragma:
+ -- {-# INLINE f #-}
+ -- f x = (x,x)
+ --
+ -- This becomes (where the "*" means INLINE prag)
+ --
+ -- M.f = /\a -> let mf* = \x -> (x,x) in mf
+ --
+ -- Now the mf floats out and we end up with the trivial binding
+ --
+ -- mf* = /\a -> \x -> (x,x)
+ -- M.f = mf
+ --
+ -- Now, when we short out the M.f = mf binding we must preserve the inline
+ -- pragma on the mf binding.
+ --
+ -- On the other hand, transformation rules may be attached to the
+ -- 'to' Id, and we want to preserve them.
\end{code}
\begin{code}
-noIdInfo = IdInfo {
- arityInfo = UnknownArity,
- demandInfo = wwLazy,
- specInfo = emptySpecEnv,
- strictnessInfo = NoStrictnessInfo,
- unfoldingInfo = noUnfolding,
- updateInfo = NoUpdateInfo,
- cafInfo = MayHaveCafRefs,
- inlinePragInfo = NoInlinePragInfo
+vanillaIdInfo :: IdInfo
+vanillaIdInfo = mkIdInfo VanillaId
+
+mkIdInfo :: IdFlavour -> IdInfo
+mkIdInfo flv = IdInfo {
+ flavourInfo = flv,
+ arityInfo = UnknownArity,
+ demandInfo = wwLazy,
+ specInfo = emptyCoreRules,
+ workerInfo = Nothing,
+ strictnessInfo = NoStrictnessInfo,
+ unfoldingInfo = noUnfolding,
+ updateInfo = NoUpdateInfo,
+ cafInfo = MayHaveCafRefs,
+ cprInfo = NoCPRInfo,
+ lbvarInfo = NoLBVarInfo,
+ inlinePragInfo = NoInlinePragInfo
}
\end{code}
+
+%************************************************************************
+%* *
+\subsection{Flavour}
+%* *
+%************************************************************************
+
+\begin{code}
+data IdFlavour
+ = VanillaId -- Most Ids are like this
+ | ConstantId Con -- The Id for a constant (data constructor or primop)
+ | RecordSelId FieldLabel -- The Id for a record selector
+ | SpecPragmaId -- Don't discard these
+ | NoDiscardId -- Don't discard these either
+
+ppFlavourInfo :: IdFlavour -> SDoc
+ppFlavourInfo VanillaId = empty
+ppFlavourInfo (ConstantId _) = ptext SLIT("[Constr]")
+ppFlavourInfo (RecordSelId _) = ptext SLIT("[RecSel]")
+ppFlavourInfo SpecPragmaId = ptext SLIT("[SpecPrag]")
+ppFlavourInfo NoDiscardId = ptext SLIT("[NoDiscard]")
+
+seqFlavour :: IdFlavour -> ()
+seqFlavour f = f `seq` ()
+\end{code}
+
+The @SpecPragmaId@ exists only to make Ids that are
+on the *LHS* of bindings created by SPECIALISE pragmas;
+eg: s = f Int d
+The SpecPragmaId is never itself mentioned; it
+exists solely so that the specialiser will find
+the call to f, and make specialised version of it.
+The SpecPragmaId binding is discarded by the specialiser
+when it gathers up overloaded calls.
+Meanwhile, it is not discarded as dead code.
+
+
%************************************************************************
%* *
\subsection[arity-IdInfo]{Arity info about an @Id@}
| ArityExactly Int -- Arity is exactly this
| ArityAtLeast Int -- Arity is this or greater
+seqArity :: ArityInfo -> ()
+seqArity a = arityLowerBound a `seq` ()
+
exactArity = ArityExactly
atLeastArity = ArityAtLeast
unknownArity = UnknownArity
arityLowerBound (ArityAtLeast n) = n
arityLowerBound (ArityExactly n) = n
+hasArity :: ArityInfo -> Bool
+hasArity UnknownArity = False
+hasArity other = True
ppArityInfo UnknownArity = empty
ppArityInfo (ArityExactly arity) = hsep [ptext SLIT("__A"), int arity]
data InlinePragInfo
= NoInlinePragInfo
- | IAmASpecPragmaId -- Used for spec-pragma Ids; don't discard or inline
-
- | IWantToBeINLINEd -- User INLINE pragma
| IMustNotBeINLINEd -- User NOINLINE pragma
| IAmALoopBreaker -- Used by the occurrence analyser to mark loop-breakers
| IMustBeINLINEd -- Absolutely must inline; used for PrimOps and
-- constructors only.
+seqInlinePrag :: InlinePragInfo -> ()
+seqInlinePrag (ICanSafelyBeINLINEd occ alts)
+ = occ `seq` alts `seq` ()
+seqInlinePrag other
+ = ()
+
instance Outputable InlinePragInfo where
ppr NoInlinePragInfo = empty
ppr IMustBeINLINEd = ptext SLIT("__UU")
- ppr IWantToBeINLINEd = ptext SLIT("__U")
ppr IMustNotBeINLINEd = ptext SLIT("__Unot")
ppr IAmALoopBreaker = ptext SLIT("__Ux")
ppr IAmDead = ptext SLIT("__Ud")
ppr (ICanSafelyBeINLINEd InsideLam _) = ptext SLIT("__Ul")
ppr (ICanSafelyBeINLINEd _ _) = ptext SLIT("__Us")
- ppr IAmASpecPragmaId = ptext SLIT("__US")
instance Show InlinePragInfo where
showsPrec p prag = showsPrecSDoc p (ppr prag)
\end{code}
-The @IMustNotBeDiscarded@ exists only to make Ids that are
-on the *LHS* of bindings created by SPECIALISE pragmas;
-eg: s = f Int d
-The SpecPragmaId is never itself mentioned; it
-exists solely so that the specialiser will find
-the call to f, and make specialised version of it.
-The SpecPragmaId binding is discarded by the specialiser
-when it gathers up overloaded calls.
-Meanwhile, it is not discarded as dead code.
-
\begin{code}
data OccInfo
- = StrictOcc -- Occurs syntactically strictly;
- -- i.e. in a function position or case scrutinee
-
- | LazyOcc -- Not syntactically strict (*even* that of a strict function)
- -- or in a case branch where there's more than one alternative
+ = NotInsideLam
| InsideLam -- Inside a non-linear lambda (that is, a lambda which
-- is sure to be instantiated only once).
-- dangerous because it might duplicate work.
instance Outputable OccInfo where
- ppr StrictOcc = text "s"
- ppr LazyOcc = empty
- ppr InsideLam = text "l"
+ ppr NotInsideLam = empty
+ ppr InsideLam = text "l"
notInsideLambda :: OccInfo -> Bool
-notInsideLambda StrictOcc = True
-notInsideLambda LazyOcc = True
-notInsideLambda InsideLam = False
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[specialisation-IdInfo]{Specialisation info about an @Id@}
-%* *
-%************************************************************************
-
-A @IdSpecEnv@ holds details of an @Id@'s specialisations.
-
-\begin{code}
-type IdSpecEnv = SpecEnv CoreExpr
+notInsideLambda NotInsideLam = True
+notInsideLambda InsideLam = False
\end{code}
-For example, if \tr{f}'s @SpecEnv@ contains the mapping:
-\begin{verbatim}
- [List a, b] ===> (\d -> f' a b)
-\end{verbatim}
-then when we find an application of f to matching types, we simply replace
-it by the matching RHS:
-\begin{verbatim}
- f (List Int) Bool ===> (\d -> f' Int Bool)
-\end{verbatim}
-All the stuff about how many dictionaries to discard, and what types
-to apply the specialised function to, are handled by the fact that the
-SpecEnv contains a template for the result of the specialisation.
-
-There is one more exciting case, which is dealt with in exactly the same
-way. If the specialised value is unboxed then it is lifted at its
-definition site and unlifted at its uses. For example:
-
- pi :: forall a. Num a => a
-
-might have a specialisation
-
- [Int#] ===> (case pi' of Lift pi# -> pi#)
-
-where pi' :: Lift Int# is the specialised version of pi.
-
-
%************************************************************************
%* *
\subsection[strictness-IdInfo]{Strictness info about an @Id@}
worker/wrapper-style transformations in the PJ/Launchbury paper on
unboxed types).
-The list of @Demands@ specifies: (a)~the strictness properties
-of a function's arguments; (b)~the {\em existence} of a ``worker''
-version of the function; and (c)~the type signature of that worker (if
-it exists); i.e. its calling convention.
+The list of @Demands@ specifies: (a)~the strictness properties of a
+function's arguments; and (b)~the type signature of that worker (if it
+exists); i.e. its calling convention.
+
+Note that the existence of a worker function is now denoted by the Id's
+workerInfo field.
\begin{code}
data StrictnessInfo
-- will have info SI [SS] True
-- but still (f) and (f 2) are not bot; only (f 3 2) is bot
- Bool -- True <=> there is a worker. There might not be, even for a
- -- strict function, because:
- -- (a) the function might be small enough to inline,
- -- so no need for w/w split
- -- (b) the strictness info might be "SSS" or something, so no w/w split.
+seqStrictness :: StrictnessInfo -> ()
+seqStrictness (StrictnessInfo ds b) = b `seq` seqDemands ds
+seqStrictness other = ()
\end{code}
\begin{code}
-mkStrictnessInfo :: ([Demand], Bool) -> Bool -> StrictnessInfo
+mkStrictnessInfo :: ([Demand], Bool) -> StrictnessInfo
-mkStrictnessInfo (xs, is_bot) has_wrkr
+mkStrictnessInfo (xs, is_bot)
| all isLazy xs && not is_bot = NoStrictnessInfo -- Uninteresting
- | otherwise = StrictnessInfo xs is_bot has_wrkr
+ | otherwise = StrictnessInfo xs is_bot
noStrictnessInfo = NoStrictnessInfo
-isBottomingStrictness (StrictnessInfo _ bot _) = bot
-isBottomingStrictness NoStrictnessInfo = False
+isBottomingStrictness (StrictnessInfo _ bot) = bot
+isBottomingStrictness NoStrictnessInfo = False
-- appIsBottom returns true if an application to n args would diverge
-appIsBottom (StrictnessInfo ds bot _) n = bot && (n >= length ds)
+appIsBottom (StrictnessInfo ds bot) n = bot && (n >= length ds)
appIsBottom NoStrictnessInfo n = False
ppStrictnessInfo NoStrictnessInfo = empty
-ppStrictnessInfo (StrictnessInfo wrapper_args bot wrkr_maybe)
+ppStrictnessInfo (StrictnessInfo wrapper_args bot)
= hsep [ptext SLIT("__S"), pprDemands wrapper_args bot]
\end{code}
+%************************************************************************
+%* *
+\subsection[worker-IdInfo]{Worker info about an @Id@}
+%* *
+%************************************************************************
+
+If this Id has a worker then we store a reference to it. Worker
+functions are generated by the worker/wrapper pass. This uses
+information from the strictness and CPR analyses.
+
+There might not be a worker, even for a strict function, because:
+(a) the function might be small enough to inline, so no need
+ for w/w split
+(b) the strictness info might be "SSS" or something, so no w/w split.
\begin{code}
-workerExists :: StrictnessInfo -> Bool
-workerExists (StrictnessInfo _ _ worker_exists) = worker_exists
-workerExists other = False
+
+type WorkerInfo = Maybe Id
+
+{- UNUSED:
+mkWorkerInfo :: Id -> WorkerInfo
+mkWorkerInfo wk_id = Just wk_id
+-}
+
+seqWorker :: WorkerInfo -> ()
+seqWorker (Just id) = id `seq` ()
+seqWorker Nothing = ()
+
+ppWorkerInfo Nothing = empty
+ppWorkerInfo (Just wk_id) = ptext SLIT("__P") <+> ppr wk_id
+
+noWorkerInfo = Nothing
+
+workerExists :: Maybe Id -> Bool
+workerExists = isJust
\end{code}
-- | OneCafRef Id
+seqCaf c = c `seq` ()
+
ppCafInfo NoCafRefs = ptext SLIT("__C")
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@}
+%* *
+%************************************************************************
+
+If the @Id@ is a function then it may have CPR info. A CPR analysis
+phase detects whether:
+
+\begin{enumerate}
+\item
+The function's return value has a product type, i.e. an algebraic type
+with a single constructor. Examples of such types are tuples and boxed
+primitive values.
+\item
+The function always 'constructs' the value that it is returning. It
+must do this on every path through, and it's OK if it calls another
+function which constructs the result.
+\end{enumerate}
+
+If this is the case then we store a template which tells us the
+function has the CPR property and which components of the result are
+also CPRs.
+
+\begin{code}
+data CprInfo
+ = NoCPRInfo
+
+ | CPRInfo [CprInfo]
+
+-- e.g. const 5 == CPRInfo [NoCPRInfo]
+-- == __M(-)
+-- \x -> (5,
+-- (x,
+-- 5,
+-- x)
+-- )
+-- CPRInfo [CPRInfo [NoCPRInfo],
+-- CPRInfo [NoCprInfo,
+-- CPRInfo [NoCPRInfo],
+-- NoCPRInfo]
+-- ]
+-- __M((-)(-(-)-)-)
+\end{code}
+
+\begin{code}
+seqCpr :: CprInfo -> ()
+seqCpr (CPRInfo cs) = seqCprs cs
+seqCpr NoCPRInfo = ()
+
+seqCprs [] = ()
+seqCprs (c:cs) = seqCpr c `seq` seqCprs cs
+
+
+noCprInfo = NoCPRInfo
+
+ppCprInfo NoCPRInfo = empty
+ppCprInfo c@(CPRInfo _)
+ = hsep [ptext SLIT("__M"), ppCprInfo' c]
+ where
+ ppCprInfo' NoCPRInfo = char '-'
+ ppCprInfo' (CPRInfo args) = parens (hcat (map ppCprInfo' args))
+
+instance Outputable CprInfo where
+ ppr = ppCprInfo
+
+instance Show CprInfo where
+ showsPrec p c = showsPrecSDoc p (ppr c)
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[lbvar-IdInfo]{Lambda-bound var info about an @Id@}
+%* *
+%************************************************************************
+
+If the @Id@ is a lambda-bound variable then it may have lambda-bound
+var info. The usage analysis (UsageSP) detects whether the lambda
+binding this var is a ``one-shot'' lambda; that is, whether it is
+applied at most once.
+
+This information may be useful in optimisation, as computations may
+safely be floated inside such a lambda without risk of duplicating
+work.
+
+\begin{code}
+data LBVarInfo
+ = NoLBVarInfo
+
+ | IsOneShotLambda -- The lambda that binds this Id is applied
+ -- at most once
+ -- HACK ALERT! placing this info here is a short-term hack,
+ -- but it minimises changes to the rest of the compiler.
+ -- Hack agreed by SLPJ/KSW 1999-04.
+
+seqLBVar l = l `seq` ()
+\end{code}
+
+\begin{code}
+noLBVarInfo = NoLBVarInfo
+
+-- not safe to print or parse LBVarInfo because it is not really a
+-- property of the definition, but a property of the context.
+pprLBVarInfo NoLBVarInfo = empty
+pprLBVarInfo IsOneShotLambda = getPprStyle $ \ sty ->
+ if ifaceStyle sty then empty
+ else ptext SLIT("OneShot")
+
+instance Outputable LBVarInfo where
+ ppr = pprLBVarInfo
+
+instance Show LBVarInfo where
+ showsPrec p c = showsPrecSDoc p (ppr c)
+\end{code}