%
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
%
\section[IdInfo]{@IdInfos@: Non-essential information about @Ids@}
noIdInfo,
ppIdInfo,
+ -- Arity
ArityInfo(..),
exactArity, atLeastArity, unknownArity,
- arityInfo, addArityInfo, ppArityInfo,
-
- DemandInfo,
- noDemandInfo, mkDemandInfo, demandInfo, ppDemandInfo, addDemandInfo, willBeDemanded,
+ arityInfo, setArityInfo, ppArityInfo, arityLowerBound,
+ -- Strictness
StrictnessInfo(..), -- Non-abstract
- Demand(..), NewOrData, -- Non-abstract
+ workerExists, mkStrictnessInfo,
+ noStrictnessInfo, strictnessInfo,
+ ppStrictnessInfo, setStrictnessInfo,
+ isBottomingStrictness, appIsBottom,
+
+ -- Unfolding
+ unfoldingInfo, setUnfoldingInfo,
- workerExists,
- mkStrictnessInfo, mkBottomStrictnessInfo, noStrictnessInfo, bottomIsGuaranteed,
- strictnessInfo, ppStrictnessInfo, addStrictnessInfo,
+ -- DemandInfo
+ demandInfo, setDemandInfo,
- unfoldInfo, addUnfoldInfo,
+ -- Inline prags
+ InlinePragInfo(..), OccInfo(..),
+ inlinePragInfo, setInlinePragInfo, notInsideLambda,
+ -- Specialisation
IdSpecEnv, specInfo, setSpecInfo,
+ -- Update
UpdateInfo, UpdateSpec,
- mkUpdateInfo, updateInfo, updateInfoMaybe, ppUpdateInfo, addUpdateInfo,
-
- ArgUsageInfo, ArgUsage(..), ArgUsageType,
- mkArgUsageInfo, argUsageInfo, addArgUsageInfo, getArgUsage,
+ mkUpdateInfo, updateInfo, updateInfoMaybe, ppUpdateInfo, setUpdateInfo,
- FBTypeInfo, FBType(..), FBConsum(..), FBProd(..),
- fbTypeInfo, ppFBTypeInfo, addFBTypeInfo, mkFBTypeInfo, getFBType
+ -- CAF info
+ CafInfo(..), cafInfo, setCafInfo, ppCafInfo,
) where
#include "HsVersions.h"
import {-# SOURCE #-} CoreUnfold ( Unfolding, noUnfolding )
-import {-# SOURCE #-} CoreSyn ( SimplifiableCoreExpr )
-
--- for mkdependHS, CoreSyn.hi-boot refers to it:
-import BinderInfo ( BinderInfo )
+import {-# SOURCE #-} CoreSyn ( CoreExpr )
import SpecEnv ( SpecEnv, emptySpecEnv )
-import BasicTypes ( NewOrData )
-
-import Demand
+import Demand ( Demand, isLazy, wwLazy, pprDemands )
import Outputable
-
-import Char ( ord )
\end{code}
An @IdInfo@ gives {\em optional} information about an @Id@. If
\begin{code}
data IdInfo
- = IdInfo
- ArityInfo -- Its arity
-
- DemandInfo -- Whether or not it is definitely
- -- demanded
-
- IdSpecEnv -- Specialisations of this function which exist
-
- StrictnessInfo -- Strictness properties
-
- Unfolding -- Its unfolding; for locally-defined
- -- things, this can *only* be NoUnfolding
-
- UpdateInfo -- Which args should be updated
+ = 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
+ }
+\end{code}
- ArgUsageInfo -- how this Id uses its arguments
+Setters
- FBTypeInfo -- the Foldr/Build W/W property of this function.
+\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 }
\end{code}
+
\begin{code}
-noIdInfo = IdInfo UnknownArity UnknownDemand emptySpecEnv NoStrictnessInfo noUnfolding
- NoUpdateInfo NoArgUsageInfo NoFBTypeInfo
+noIdInfo = IdInfo {
+ arityInfo = UnknownArity,
+ demandInfo = wwLazy,
+ specInfo = emptySpecEnv,
+ strictnessInfo = NoStrictnessInfo,
+ unfoldingInfo = noUnfolding,
+ updateInfo = NoUpdateInfo,
+ cafInfo = MayHaveCafRefs,
+ inlinePragInfo = NoInlinePragInfo
+ }
\end{code}
\begin{code}
-ppIdInfo :: Bool -- True <=> print specialisations, please
- -> IdInfo
- -> SDoc
-
-ppIdInfo specs_please
- (IdInfo arity demand specenv strictness unfold update arg_usage fbtype)
+ppIdInfo :: IdInfo -> SDoc
+ppIdInfo (IdInfo {arityInfo,
+ demandInfo,
+ specInfo,
+ strictnessInfo,
+ unfoldingInfo,
+ updateInfo,
+ cafInfo,
+ inlinePragInfo})
= hsep [
- -- order is important!:
- ppArityInfo arity,
- ppUpdateInfo update,
-
- ppStrictnessInfo strictness,
-
- if specs_please
- then empty -- ToDo -- sty (not (isDataCon for_this_id))
- -- better_id_fn inline_env (mEnvToList specenv)
- else empty,
-
- -- DemandInfo needn't be printed since it has no effect on interfaces
- ppDemandInfo demand,
- ppFBTypeInfo fbtype
+ ppArityInfo arityInfo,
+ ppUpdateInfo updateInfo,
+ ppStrictnessInfo strictnessInfo,
+ ppr demandInfo,
+ ppCafInfo cafInfo
+ -- Inline pragma printed out with all binders; see PprCore.pprIdBndr
]
\end{code}
%* *
%************************************************************************
+For locally-defined Ids, the code generator maintains its own notion
+of their arities; so it should not be asking... (but other things
+besides the code-generator need arity info!)
+
\begin{code}
data ArityInfo
= UnknownArity -- No idea
| ArityExactly Int -- Arity is exactly this
| ArityAtLeast Int -- Arity is this or greater
-\end{code}
-\begin{code}
exactArity = ArityExactly
atLeastArity = ArityAtLeast
unknownArity = UnknownArity
-arityInfo (IdInfo arity _ _ _ _ _ _ _) = arity
+arityLowerBound :: ArityInfo -> Int
+arityLowerBound UnknownArity = 0
+arityLowerBound (ArityAtLeast n) = n
+arityLowerBound (ArityExactly n) = n
-addArityInfo (IdInfo _ a b c d e f g) arity = IdInfo arity a b c d e f g
-ppArityInfo UnknownArity = empty
-ppArityInfo (ArityExactly arity) = hsep [ptext SLIT("_A_"), int arity]
-ppArityInfo (ArityAtLeast arity) = hsep [ptext SLIT("_A>_"), int arity]
+ppArityInfo UnknownArity = empty
+ppArityInfo (ArityExactly arity) = hsep [ptext SLIT("__A"), int arity]
+ppArityInfo (ArityAtLeast arity) = hsep [ptext SLIT("__AL"), int arity]
\end{code}
%************************************************************************
%* *
-\subsection[demand-IdInfo]{Demand info about an @Id@}
+\subsection{Inline-pragma information}
%* *
%************************************************************************
-Whether a value is certain to be demanded or not. (This is the
-information that is computed by the ``front-end'' of the strictness
-analyser.)
+\begin{code}
+data InlinePragInfo
+ = NoInlinePragInfo
-This information is only used within a module, it is not exported
-(obviously).
+ | IAmASpecPragmaId -- Used for spec-pragma Ids; don't discard or inline
-\begin{code}
-data DemandInfo
- = UnknownDemand
- | DemandedAsPer Demand
-\end{code}
+ | IWantToBeINLINEd -- User INLINE pragma
+ | IMustNotBeINLINEd -- User NOINLINE pragma
-\begin{code}
-noDemandInfo = UnknownDemand
+ | IAmALoopBreaker -- Used by the occurrence analyser to mark loop-breakers
+ -- in a group of recursive definitions
+
+ | 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
+
+ Bool -- False <=> occurs in more than one case branch
+ -- If so, there's a code-duplication issue
+
+ | IAmDead -- Marks unused variables. Sometimes useful for
+ -- lambda and case-bound variables.
+
+ | IMustBeINLINEd -- Absolutely must inline; used for PrimOps and
+ -- constructors only.
-mkDemandInfo :: Demand -> DemandInfo
-mkDemandInfo demand = DemandedAsPer demand
+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 _ _) = ptext SLIT("__Us")
+ ppr IAmASpecPragmaId = ptext SLIT("__US")
-willBeDemanded :: DemandInfo -> Bool
-willBeDemanded (DemandedAsPer demand) = isStrict demand
-willBeDemanded _ = False
+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}
-demandInfo (IdInfo _ demand _ _ _ _ _ _) = demand
+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
+
+ | InsideLam -- Inside a non-linear lambda (that is, a lambda which
+ -- is sure to be instantiated only once).
+ -- Substituting a redex for this occurrence is
+ -- dangerous because it might duplicate work.
-addDemandInfo (IdInfo a _ c d e f g h) demand = IdInfo a demand c d e f g h
+instance Outputable OccInfo where
+ ppr StrictOcc = text "s"
+ ppr LazyOcc = empty
+ ppr InsideLam = text "l"
-ppDemandInfo UnknownDemand = text "{-# L #-}"
-ppDemandInfo (DemandedAsPer info) = hsep [text "{-#", text (showList [info] ""), text "#-}"]
+
+notInsideLambda :: OccInfo -> Bool
+notInsideLambda StrictOcc = True
+notInsideLambda LazyOcc = True
+notInsideLambda InsideLam = False
\end{code}
%************************************************************************
A @IdSpecEnv@ holds details of an @Id@'s specialisations.
\begin{code}
-type IdSpecEnv = SpecEnv SimplifiableCoreExpr
+type IdSpecEnv = SpecEnv CoreExpr
\end{code}
For example, if \tr{f}'s @SpecEnv@ contains the mapping:
where pi' :: Lift Int# is the specialised version of pi.
-\begin{code}
-specInfo :: IdInfo -> IdSpecEnv
-specInfo (IdInfo _ _ spec _ _ _ _ _) = spec
-
-setSpecInfo (IdInfo a b _ d e f g h) spec = IdInfo a b spec d e f g h
-\end{code}
-
%************************************************************************
%* *
data StrictnessInfo
= NoStrictnessInfo
- | BottomGuaranteed -- This Id guarantees never to return;
- -- it is bottom regardless of its arguments.
- -- Useful for "error" and other disguised
- -- variants thereof.
-
| StrictnessInfo [Demand]
+ Bool -- True <=> the function diverges regardless of its arguments
+ -- Useful for "error" and other disguised variants thereof.
+ -- BUT NB: f = \x y. error "urk"
+ -- 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.
-
- -- Worker's Id, if applicable, and a list of the constructors
- -- mentioned by the wrapper. This is necessary so that the
- -- renamer can slurp them in. Without this info, the renamer doesn't
- -- know which data types to slurp in concretely. Remember, for
- -- strict things we don't put the unfolding in the interface file, to save space.
- -- This constructor list allows the renamer to behave much as if the
- -- unfolding *was* in the interface file.
\end{code}
\begin{code}
-mkStrictnessInfo :: [Demand] -> Bool -> StrictnessInfo
+mkStrictnessInfo :: ([Demand], Bool) -> Bool -> StrictnessInfo
-mkStrictnessInfo xs has_wrkr
- | all is_lazy xs = NoStrictnessInfo -- Uninteresting
- | otherwise = StrictnessInfo xs has_wrkr
- where
- is_lazy (WwLazy False) = True -- NB "Absent" args do *not* count!
- is_lazy _ = False -- (as they imply a worker)
+mkStrictnessInfo (xs, is_bot) has_wrkr
+ | all isLazy xs && not is_bot = NoStrictnessInfo -- Uninteresting
+ | otherwise = StrictnessInfo xs is_bot has_wrkr
noStrictnessInfo = NoStrictnessInfo
-mkBottomStrictnessInfo = BottomGuaranteed
-
-bottomIsGuaranteed BottomGuaranteed = True
-bottomIsGuaranteed other = False
-strictnessInfo (IdInfo _ _ _ strict _ _ _ _) = strict
+isBottomingStrictness (StrictnessInfo _ bot _) = bot
+isBottomingStrictness NoStrictnessInfo = False
-addStrictnessInfo id_info NoStrictnessInfo = id_info
-addStrictnessInfo (IdInfo a b d _ e f g h) strict = IdInfo a b d strict e f g h
+-- appIsBottom returns true if an application to n args would diverge
+appIsBottom (StrictnessInfo ds bot _) n = bot && (n >= length ds)
+appIsBottom NoStrictnessInfo n = False
ppStrictnessInfo NoStrictnessInfo = empty
-ppStrictnessInfo BottomGuaranteed = ptext SLIT("_bot_")
-
-ppStrictnessInfo (StrictnessInfo wrapper_args wrkr_maybe)
- = hsep [ptext SLIT("_S_"), text (showList wrapper_args "")]
+ppStrictnessInfo (StrictnessInfo wrapper_args bot wrkr_maybe)
+ = hsep [ptext SLIT("__S"), pprDemands wrapper_args bot]
\end{code}
\begin{code}
workerExists :: StrictnessInfo -> Bool
-workerExists (StrictnessInfo _ worker_exists) = worker_exists
-workerExists other = False
+workerExists (StrictnessInfo _ _ worker_exists) = worker_exists
+workerExists other = False
\end{code}
%************************************************************************
%* *
-\subsection[unfolding-IdInfo]{Unfolding info about an @Id@}
-%* *
-%************************************************************************
-
-\begin{code}
-unfoldInfo (IdInfo _ _ _ _ unfolding _ _ _) = unfolding
-
-addUnfoldInfo (IdInfo a b d e _ f g h) uf = IdInfo a b d e uf f g h
-\end{code}
-
-%************************************************************************
-%* *
\subsection[update-IdInfo]{Update-analysis info about an @Id@}
%* *
%************************************************************************
Text instance so that the update annotations can be read in.
\begin{code}
-instance Read UpdateInfo where
- readsPrec p s | null s = panic "IdInfo: empty update pragma?!"
- | otherwise = [(SomeUpdateInfo (map ok_digit s),"")]
- where
- ok_digit c | c >= '0' && c <= '2' = ord c - ord '0'
- | otherwise = panic "IdInfo: not a digit while reading update pragma"
-
-updateInfo (IdInfo _ _ _ _ _ update _ _) = update
-
-addUpdateInfo id_info NoUpdateInfo = id_info
-addUpdateInfo (IdInfo a b d e f _ g h) upd_info = IdInfo a b d e f upd_info g h
-
-ppUpdateInfo NoUpdateInfo = empty
+ppUpdateInfo NoUpdateInfo = empty
ppUpdateInfo (SomeUpdateInfo []) = empty
-ppUpdateInfo (SomeUpdateInfo spec) = (<>) (ptext SLIT("_U_ ")) (hcat (map int spec))
+ppUpdateInfo (SomeUpdateInfo spec) = (<>) (ptext SLIT("__U ")) (hcat (map int spec))
\end{code}
%************************************************************************
%* *
-\subsection[argUsage-IdInfo]{Argument Usage info about an @Id@}
+\subsection[CAF-IdInfo]{CAF-related information}
%* *
%************************************************************************
-\begin{code}
-data ArgUsageInfo
- = NoArgUsageInfo
- | SomeArgUsageInfo ArgUsageType
- -- ??? deriving (Eq, Ord)
-
-data ArgUsage = ArgUsage Int -- number of arguments (is linear!)
- | UnknownArgUsage
-type ArgUsageType = [ArgUsage] -- c_1 -> ... -> BLOB
-\end{code}
+This information is used to build Static Reference Tables (see
+simplStg/ComputeSRT.lhs).
\begin{code}
-mkArgUsageInfo [] = NoArgUsageInfo
-mkArgUsageInfo au = SomeArgUsageInfo au
+data CafInfo
+ = MayHaveCafRefs -- either:
+ -- (1) A function or static constructor
+ -- that refers to one or more CAFs,
+ -- (2) A real live CAF
-getArgUsage :: ArgUsageInfo -> ArgUsageType
-getArgUsage NoArgUsageInfo = []
-getArgUsage (SomeArgUsageInfo u) = u
-\end{code}
+ | NoCafRefs -- A function or static constructor
+ -- that refers to no CAFs.
-\begin{code}
-argUsageInfo (IdInfo _ _ _ _ _ _ au _) = au
+-- LATER: not sure how easy this is...
+-- | OneCafRef Id
-addArgUsageInfo id_info NoArgUsageInfo = id_info
-addArgUsageInfo (IdInfo a b d e f g _ h) au_info = IdInfo a b d e f g au_info h
-{- UNUSED:
-ppArgUsageInfo NoArgUsageInfo = empty
-ppArgUsageInfo (SomeArgUsageInfo aut) = (<>) (ptext SLIT("_L_ ")) (ppArgUsageType aut)
--}
-
-ppArgUsage (ArgUsage n) = int n
-ppArgUsage (UnknownArgUsage) = char '-'
-
-ppArgUsageType aut = hcat
- [ char '"' ,
- hcat (punctuate comma (map ppArgUsage aut)),
- char '"' ]
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[FBType-IdInfo]{Type of an expression through Foldr/build's eyes}
-%* *
-%************************************************************************
-
-\begin{code}
-data FBTypeInfo
- = NoFBTypeInfo
- | SomeFBTypeInfo FBType
-
-data FBType = FBType [FBConsum] FBProd deriving (Eq)
-
-data FBConsum = FBGoodConsum | FBBadConsum deriving(Eq)
-data FBProd = FBGoodProd | FBBadProd deriving(Eq)
-\end{code}
-
-\begin{code}
-mkFBTypeInfo = SomeFBTypeInfo
-
-getFBType :: FBTypeInfo -> Maybe FBType
-getFBType NoFBTypeInfo = Nothing
-getFBType (SomeFBTypeInfo u) = Just u
-\end{code}
-
-\begin{code}
-fbTypeInfo (IdInfo _ _ _ _ _ _ _ fb) = fb
-
-addFBTypeInfo id_info NoFBTypeInfo = id_info
-addFBTypeInfo (IdInfo a b d e f g h _) fb_info = IdInfo a b d e f g h fb_info
-
-ppFBTypeInfo NoFBTypeInfo = empty
-ppFBTypeInfo (SomeFBTypeInfo (FBType cons prod))
- = (<>) (ptext SLIT("_F_ ")) (ppFBType cons prod)
-
-ppFBType cons prod = hcat
- ([ char '"' ] ++ map ppCons cons ++ [ char '-', ppProd prod, char '"' ])
- where
- ppCons FBGoodConsum = char 'G'
- ppCons FBBadConsum = char 'B'
- ppProd FBGoodProd = char 'G'
- ppProd FBBadProd = char 'B'
+ppCafInfo NoCafRefs = ptext SLIT("__C")
+ppCafInfo MayHaveCafRefs = empty
\end{code}