%
% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 19931998
%
\section[IdInfo]{@IdInfos@: Nonessential information about @Ids@}
(And a pretty good illustration of quite a few things wrong with
Haskell. [WDP 94/11])
\begin{code}
module IdInfo (
IdDetails(..), pprIdDetails,
IdInfo,
vanillaIdInfo, noCafIdInfo,
seqIdInfo, megaSeqIdInfo,
zapLamInfo, zapDemandInfo, zapFragileInfo,
ArityInfo,
unknownArity,
arityInfo, setArityInfo, ppArityInfo,
newStrictnessInfo, setNewStrictnessInfo,
newDemandInfo, setNewDemandInfo, pprNewStrictness,
setAllStrictnessInfo,
#ifdef OLD_STRICTNESS
StrictnessInfo(..),
mkStrictnessInfo, noStrictnessInfo,
ppStrictnessInfo, isBottomingStrictness,
strictnessInfo, setStrictnessInfo,
oldStrictnessFromNew, newStrictnessFromOld,
demandInfo, setDemandInfo,
oldDemand, newDemand,
CprInfo(..),
cprInfo, setCprInfo, ppCprInfo, noCprInfo,
cprInfoFromNewStrictness,
#endif
WorkerInfo(..),
workerExists, wrapperArity, workerId,
workerInfo, setWorkerInfo, ppWorkerInfo,
unfoldingInfo, setUnfoldingInfo, setUnfoldingInfoLazily,
InlinePragInfo,
inlinePragInfo, setInlinePragInfo,
OccInfo(..),
isFragileOcc, isDeadOcc, isLoopBreaker,
occInfo, setOccInfo,
InsideLam, OneBranch,
insideLam, notInsideLam, oneBranch, notOneBranch,
SpecInfo(..),
isEmptySpecInfo, specInfoFreeVars,
specInfoRules, seqSpecInfo, setSpecInfoHead,
specInfo, setSpecInfo,
CafInfo(..),
ppCafInfo, mayHaveCafRefs,
cafInfo, setCafInfo,
LBVarInfo(..),
noLBVarInfo, hasNoLBVarInfo,
lbvarInfo, setLBVarInfo,
TickBoxOp(..), TickBoxId,
) where
import CoreSyn ( CoreRule, setRuleIdName, seqRules, Unfolding, noUnfolding )
import Class
import PrimOp
import Name
import Var
import VarSet
import BasicTypes
import DataCon
import TyCon
import ForeignCall
import NewDemand
import Outputable
import Module
import FastString
import Data.Maybe
#ifdef OLD_STRICTNESS
import Demand
import qualified Demand
import Util
import Data.List
#endif
infixl 1 `setSpecInfo`,
`setArityInfo`,
`setInlinePragInfo`,
`setUnfoldingInfo`,
`setWorkerInfo`,
`setLBVarInfo`,
`setOccInfo`,
`setCafInfo`,
`setNewStrictnessInfo`,
`setAllStrictnessInfo`,
`setNewDemandInfo`
#ifdef OLD_STRICTNESS
, `setCprInfo`
, `setDemandInfo`
, `setStrictnessInfo`
#endif
\end{code}
%************************************************************************
%* *
\subsection{New strictness info}
%* *
%************************************************************************
To be removed later
\begin{code}
setAllStrictnessInfo :: IdInfo -> Maybe StrictSig -> IdInfo
setAllStrictnessInfo info Nothing
= info { newStrictnessInfo = Nothing
#ifdef OLD_STRICTNESS
, strictnessInfo = NoStrictnessInfo
, cprInfo = NoCPRInfo
#endif
}
setAllStrictnessInfo info (Just sig)
= info { newStrictnessInfo = Just sig
#ifdef OLD_STRICTNESS
, strictnessInfo = oldStrictnessFromNew sig
, cprInfo = cprInfoFromNewStrictness sig
#endif
}
seqNewStrictnessInfo :: Maybe StrictSig -> ()
seqNewStrictnessInfo Nothing = ()
seqNewStrictnessInfo (Just ty) = seqStrictSig ty
pprNewStrictness :: Maybe StrictSig -> SDoc
pprNewStrictness Nothing = empty
pprNewStrictness (Just sig) = ftext (fsLit "Str:") <+> ppr sig
#ifdef OLD_STRICTNESS
oldStrictnessFromNew :: StrictSig -> Demand.StrictnessInfo
oldStrictnessFromNew sig = mkStrictnessInfo (map oldDemand dmds, isBotRes res_info)
where
(dmds, res_info) = splitStrictSig sig
cprInfoFromNewStrictness :: StrictSig -> CprInfo
cprInfoFromNewStrictness sig = case strictSigResInfo sig of
RetCPR -> ReturnsCPR
other -> NoCPRInfo
newStrictnessFromOld :: Name -> Arity -> Demand.StrictnessInfo -> CprInfo -> StrictSig
newStrictnessFromOld name arity (Demand.StrictnessInfo ds res) cpr
| listLengthCmp ds arity /= GT
= mk_strict_sig name arity $
mkTopDmdType (map newDemand ds) (newRes res cpr)
newStrictnessFromOld name arity other cpr
=
mk_strict_sig name arity $
mkTopDmdType (replicate arity lazyDmd) (newRes False cpr)
mk_strict_sig name arity dmd_ty
= WARN( arity /= dmdTypeDepth dmd_ty, ppr name <+> (ppr arity $$ ppr dmd_ty) )
mkStrictSig dmd_ty
newRes True _ = BotRes
newRes False ReturnsCPR = retCPR
newRes False NoCPRInfo = TopRes
newDemand :: Demand.Demand -> NewDemand.Demand
newDemand (WwLazy True) = Abs
newDemand (WwLazy False) = lazyDmd
newDemand WwStrict = evalDmd
newDemand (WwUnpack unpk ds) = Eval (Prod (map newDemand ds))
newDemand WwPrim = lazyDmd
newDemand WwEnum = evalDmd
oldDemand :: NewDemand.Demand -> Demand.Demand
oldDemand Abs = WwLazy True
oldDemand Top = WwLazy False
oldDemand Bot = WwStrict
oldDemand (Box Bot) = WwStrict
oldDemand (Box Abs) = WwLazy False
oldDemand (Box (Eval _)) = WwStrict
oldDemand (Defer d) = WwLazy False
oldDemand (Eval (Prod ds)) = WwUnpack True (map oldDemand ds)
oldDemand (Eval (Poly _)) = WwStrict
oldDemand (Call _) = WwStrict
#endif /* OLD_STRICTNESS */
\end{code}
\begin{code}
seqNewDemandInfo :: Maybe Demand -> ()
seqNewDemandInfo Nothing = ()
seqNewDemandInfo (Just dmd) = seqDemand dmd
\end{code}
%************************************************************************
%* *
IdDetails
%* *
%************************************************************************
\begin{code}
data IdDetails
= VanillaId
| RecSelId
{ sel_tycon :: TyCon
, sel_naughty :: Bool
}
| DataConWorkId DataCon
| DataConWrapId DataCon
| ClassOpId Class
| PrimOpId PrimOp
| FCallId ForeignCall
| TickBoxOpId TickBoxOp
| DFunId
instance Outputable IdDetails where
ppr = pprIdDetails
pprIdDetails :: IdDetails -> SDoc
pprIdDetails VanillaId = empty
pprIdDetails (DataConWorkId _) = ptext (sLit "[DataCon]")
pprIdDetails (DataConWrapId _) = ptext (sLit "[DataConWrapper]")
pprIdDetails (ClassOpId _) = ptext (sLit "[ClassOp]")
pprIdDetails (PrimOpId _) = ptext (sLit "[PrimOp]")
pprIdDetails (FCallId _) = ptext (sLit "[ForeignCall]")
pprIdDetails (TickBoxOpId _) = ptext (sLit "[TickBoxOp]")
pprIdDetails DFunId = ptext (sLit "[DFunId]")
pprIdDetails (RecSelId { sel_naughty = is_naughty })
= brackets $ ptext (sLit "RecSel") <> pp_naughty
where
pp_naughty | is_naughty = ptext (sLit "(naughty)")
| otherwise = empty
\end{code}
%************************************************************************
%* *
\subsection{The main IdInfo type}
%* *
%************************************************************************
\begin{code}
data IdInfo
= IdInfo {
arityInfo :: !ArityInfo,
specInfo :: SpecInfo,
#ifdef OLD_STRICTNESS
cprInfo :: CprInfo,
demandInfo :: Demand.Demand,
strictnessInfo :: StrictnessInfo,
#endif
workerInfo :: WorkerInfo,
unfoldingInfo :: Unfolding,
cafInfo :: CafInfo,
lbvarInfo :: LBVarInfo,
inlinePragInfo :: InlinePragma,
occInfo :: OccInfo,
newStrictnessInfo :: Maybe StrictSig,
newDemandInfo :: Maybe Demand
}
seqIdInfo :: IdInfo -> ()
seqIdInfo (IdInfo {}) = ()
megaSeqIdInfo :: IdInfo -> ()
megaSeqIdInfo info
= seqSpecInfo (specInfo info) `seq`
seqWorker (workerInfo info) `seq`
seqNewDemandInfo (newDemandInfo info) `seq`
seqNewStrictnessInfo (newStrictnessInfo info) `seq`
#ifdef OLD_STRICTNESS
Demand.seqDemand (demandInfo info) `seq`
seqStrictnessInfo (strictnessInfo info) `seq`
seqCpr (cprInfo info) `seq`
#endif
seqCaf (cafInfo info) `seq`
seqLBVar (lbvarInfo info) `seq`
seqOccInfo (occInfo info)
\end{code}
Setters
\begin{code}
setWorkerInfo :: IdInfo -> WorkerInfo -> IdInfo
setWorkerInfo info wk = wk `seq` info { workerInfo = wk }
setSpecInfo :: IdInfo -> SpecInfo -> IdInfo
setSpecInfo info sp = sp `seq` info { specInfo = sp }
setInlinePragInfo :: IdInfo -> InlinePragma -> IdInfo
setInlinePragInfo info pr = pr `seq` info { inlinePragInfo = pr }
setOccInfo :: IdInfo -> OccInfo -> IdInfo
setOccInfo info oc = oc `seq` info { occInfo = oc }
#ifdef OLD_STRICTNESS
setStrictnessInfo info st = st `seq` info { strictnessInfo = st }
#endif
setUnfoldingInfoLazily :: IdInfo -> Unfolding -> IdInfo
setUnfoldingInfoLazily info uf
=
info { unfoldingInfo = uf }
setUnfoldingInfo :: IdInfo -> Unfolding -> IdInfo
setUnfoldingInfo info uf
= info { unfoldingInfo = uf }
#ifdef OLD_STRICTNESS
setDemandInfo info dd = info { demandInfo = dd }
setCprInfo info cp = info { cprInfo = cp }
#endif
setArityInfo :: IdInfo -> ArityInfo -> IdInfo
setArityInfo info ar = info { arityInfo = ar }
setCafInfo :: IdInfo -> CafInfo -> IdInfo
setCafInfo info caf = info { cafInfo = caf }
setLBVarInfo :: IdInfo -> LBVarInfo -> IdInfo
setLBVarInfo info lb = info { lbvarInfo = lb }
setNewDemandInfo :: IdInfo -> Maybe Demand -> IdInfo
setNewDemandInfo info dd = dd `seq` info { newDemandInfo = dd }
setNewStrictnessInfo :: IdInfo -> Maybe StrictSig -> IdInfo
setNewStrictnessInfo info dd = dd `seq` info { newStrictnessInfo = dd }
\end{code}
\begin{code}
vanillaIdInfo :: IdInfo
vanillaIdInfo
= IdInfo {
cafInfo = vanillaCafInfo,
arityInfo = unknownArity,
#ifdef OLD_STRICTNESS
cprInfo = NoCPRInfo,
demandInfo = wwLazy,
strictnessInfo = NoStrictnessInfo,
#endif
specInfo = emptySpecInfo,
workerInfo = NoWorker,
unfoldingInfo = noUnfolding,
lbvarInfo = NoLBVarInfo,
inlinePragInfo = defaultInlinePragma,
occInfo = NoOccInfo,
newDemandInfo = Nothing,
newStrictnessInfo = Nothing
}
noCafIdInfo :: IdInfo
noCafIdInfo = vanillaIdInfo `setCafInfo` NoCafRefs
\end{code}
%************************************************************************
%* *
\subsection[arityIdInfo]{Arity info about an @Id@}
%* *
%************************************************************************
For locallydefined Ids, the code generator maintains its own notion
of their arities; so it should not be asking... (but other things
besides the codegenerator need arity info!)
\begin{code}
type ArityInfo = Arity
unknownArity :: Arity
unknownArity = 0 :: Arity
ppArityInfo :: Int -> SDoc
ppArityInfo 0 = empty
ppArityInfo n = hsep [ptext (sLit "Arity"), int n]
\end{code}
%************************************************************************
%* *
\subsection{Inlinepragma information}
%* *
%************************************************************************
\begin{code}
type InlinePragInfo = InlinePragma
\end{code}
%************************************************************************
%* *
SpecInfo
%* *
%************************************************************************
\begin{code}
data SpecInfo
= SpecInfo
[CoreRule]
VarSet
emptySpecInfo :: SpecInfo
emptySpecInfo = SpecInfo [] emptyVarSet
isEmptySpecInfo :: SpecInfo -> Bool
isEmptySpecInfo (SpecInfo rs _) = null rs
specInfoFreeVars :: SpecInfo -> VarSet
specInfoFreeVars (SpecInfo _ fvs) = fvs
specInfoRules :: SpecInfo -> [CoreRule]
specInfoRules (SpecInfo rules _) = rules
setSpecInfoHead :: Name -> SpecInfo -> SpecInfo
setSpecInfoHead fn (SpecInfo rules fvs)
= SpecInfo (map (setRuleIdName fn) rules) fvs
seqSpecInfo :: SpecInfo -> ()
seqSpecInfo (SpecInfo rules fvs) = seqRules rules `seq` seqVarSet fvs
\end{code}
%************************************************************************
%* *
\subsection[workerIdInfo]{Worker info about an @Id@}
%* *
%************************************************************************
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.
Sometimes the arity of a wrapper changes from the original arity from
which it was generated, so we always emit the "original" arity into
the interface file, as part of the worker info.
How can this happen? Sometimes we get
f = coerce t (\x y -> $wf x y)
at the moment of w/w split; but the eta reducer turns it into
f = coerce t $wf
which is perfectly fine except that the exposed arity so far as
the code generator is concerned (zero) differs from the arity
when we did the split (2).
All this arises because we use 'arity' to mean "exactly how many
top level lambdas are there" in interface files; but during the
compilation of this module it means "how many things can I apply
this to".
\begin{code}
data WorkerInfo = NoWorker
| HasWorker Id Arity
seqWorker :: WorkerInfo -> ()
seqWorker (HasWorker id a) = id `seq` a `seq` ()
seqWorker NoWorker = ()
ppWorkerInfo :: WorkerInfo -> SDoc
ppWorkerInfo NoWorker = empty
ppWorkerInfo (HasWorker wk_id _) = ptext (sLit "Worker") <+> ppr wk_id
workerExists :: WorkerInfo -> Bool
workerExists NoWorker = False
workerExists (HasWorker _ _) = True
workerId :: WorkerInfo -> Id
workerId (HasWorker id _) = id
workerId NoWorker = panic "workerId: NoWorker"
wrapperArity :: WorkerInfo -> Arity
wrapperArity (HasWorker _ a) = a
wrapperArity NoWorker = panic "wrapperArity: NoWorker"
\end{code}
%************************************************************************
%* *
\subsection[CGIdInfo]{Code generatorrelated information}
%* *
%************************************************************************
\begin{code}
data CafInfo
= MayHaveCafRefs
| NoCafRefs
deriving (Eq, Ord)
vanillaCafInfo :: CafInfo
vanillaCafInfo = MayHaveCafRefs
mayHaveCafRefs :: CafInfo -> Bool
mayHaveCafRefs MayHaveCafRefs = True
mayHaveCafRefs _ = False
seqCaf :: CafInfo -> ()
seqCaf c = c `seq` ()
ppCafInfo :: CafInfo -> SDoc
ppCafInfo NoCafRefs = ptext (sLit "NoCafRefs")
ppCafInfo MayHaveCafRefs = empty
\end{code}
%************************************************************************
%* *
\subsection[cprIdInfo]{Constructed Product Result info about an @Id@}
%* *
%************************************************************************
\begin{code}
#ifdef OLD_STRICTNESS
data CprInfo
= NoCPRInfo
| ReturnsCPR
noCprInfo :: CprInt
noCprInfo = NoCPRInfo
seqCpr :: CprInfo -> ()
seqCpr ReturnsCPR = ()
seqCpr NoCPRInfo = ()
ppCprInfo NoCPRInfo = empty
ppCprInfo ReturnsCPR = ptext (sLit "__M")
instance Outputable CprInfo where
ppr = ppCprInfo
instance Show CprInfo where
showsPrec p c = showsPrecSDoc p (ppr c)
#endif
\end{code}
%************************************************************************
%* *
\subsection[lbvarIdInfo]{Lambdabound var info about an @Id@}
%* *
%************************************************************************
\begin{code}
data LBVarInfo = NoLBVarInfo
| IsOneShotLambda
noLBVarInfo :: LBVarInfo
noLBVarInfo = NoLBVarInfo
hasNoLBVarInfo :: LBVarInfo -> Bool
hasNoLBVarInfo NoLBVarInfo = True
hasNoLBVarInfo IsOneShotLambda = False
seqLBVar :: LBVarInfo -> ()
seqLBVar l = l `seq` ()
pprLBVarInfo :: LBVarInfo -> SDoc
pprLBVarInfo NoLBVarInfo = empty
pprLBVarInfo IsOneShotLambda = ptext (sLit "OneShot")
instance Outputable LBVarInfo where
ppr = pprLBVarInfo
instance Show LBVarInfo where
showsPrec p c = showsPrecSDoc p (ppr c)
\end{code}
%************************************************************************
%* *
\subsection{Bulk operations on IdInfo}
%* *
%************************************************************************
\begin{code}
zapLamInfo :: IdInfo -> Maybe IdInfo
zapLamInfo info@(IdInfo {occInfo = occ, newDemandInfo = demand})
| is_safe_occ occ && is_safe_dmd demand
= Nothing
| otherwise
= Just (info {occInfo = safe_occ, newDemandInfo = Nothing})
where
is_safe_occ (OneOcc in_lam _ _) = in_lam
is_safe_occ _other = True
safe_occ = case occ of
OneOcc _ once int_cxt -> OneOcc insideLam once int_cxt
_other -> occ
is_safe_dmd Nothing = True
is_safe_dmd (Just dmd) = not (isStrictDmd dmd)
\end{code}
\begin{code}
zapDemandInfo :: IdInfo -> Maybe IdInfo
zapDemandInfo info@(IdInfo {newDemandInfo = dmd})
| isJust dmd = Just (info {newDemandInfo = Nothing})
| otherwise = Nothing
\end{code}
\begin{code}
zapFragileInfo :: IdInfo -> Maybe IdInfo
zapFragileInfo info
= Just (info `setSpecInfo` emptySpecInfo
`setWorkerInfo` NoWorker
`setUnfoldingInfo` noUnfolding
`setOccInfo` if isFragileOcc occ then NoOccInfo else occ)
where
occ = occInfo info
\end{code}
%************************************************************************
%* *
\subsection{TickBoxOp}
%* *
%************************************************************************
\begin{code}
type TickBoxId = Int
data TickBoxOp
= TickBox Module !TickBoxId
instance Outputable TickBoxOp where
ppr (TickBox mod n) = ptext (sLit "tick") <+> ppr (mod,n)
\end{code}