%
% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 19921998
%
Utility functions on @Core@ syntax
\begin{code}
module CoreUtils (
mkInlineMe, mkSCC, mkCoerce, mkCoerceI,
bindNonRec, needsCaseBinding,
mkAltExpr, mkPiType, mkPiTypes,
findDefault, findAlt, isDefaultAlt, mergeAlts, trimConArgs,
exprType, coreAltType, coreAltsType,
exprIsDupable, exprIsTrivial, exprIsCheap, exprIsExpandable,
exprIsHNF,exprOkForSpeculation, exprIsBig,
exprIsConApp_maybe, exprIsBottom,
rhsIsStatic,
coreBindsSize, exprSize,
hashExpr,
cheapEqExpr,
applyTypeToArgs, applyTypeToArg,
dataConOrigInstPat, dataConRepInstPat, dataConRepFSInstPat
) where
#include "HsVersions.h"
import CoreSyn
import PprCore
import Var
import SrcLoc
import VarEnv
import VarSet
import Name
import Module
#if mingw32_TARGET_OS
import Packages
#endif
import Literal
import DataCon
import PrimOp
import Id
import IdInfo
import NewDemand
import Type
import Coercion
import TyCon
import CostCentre
import Unique
import Outputable
import TysPrim
import FastString
import Maybes
import Util
import Data.Word
import Data.Bits
\end{code}
%************************************************************************
%* *
\subsection{Find the type of a Core atom/expression}
%* *
%************************************************************************
\begin{code}
exprType :: CoreExpr -> Type
exprType (Var var) = idType var
exprType (Lit lit) = literalType lit
exprType (Let _ body) = exprType body
exprType (Case _ _ ty _) = ty
exprType (Cast _ co) = snd (coercionKind co)
exprType (Note _ e) = exprType e
exprType (Lam binder expr) = mkPiType binder (exprType expr)
exprType e@(App _ _)
= case collectArgs e of
(fun, args) -> applyTypeToArgs e (exprType fun) args
exprType other = pprTrace "exprType" (pprCoreExpr other) alphaTy
coreAltType :: CoreAlt -> Type
coreAltType (_,bs,rhs)
| any bad_binder bs = expandTypeSynonyms ty
| otherwise = ty
where
ty = exprType rhs
free_tvs = tyVarsOfType ty
bad_binder b = isTyVar b && b `elemVarSet` free_tvs
coreAltsType :: [CoreAlt] -> Type
coreAltsType (alt:_) = coreAltType alt
coreAltsType [] = panic "corAltsType"
\end{code}
Note [Existential variables and silly type synonyms]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider
data T = forall a. T (Funny a)
type Funny a = Bool
f :: T -> Bool
f (T x) = x
Now, the type of 'x' is (Funny a), where 'a' is existentially quantified.
That means that 'exprType' and 'coreAltsType' may give a result that *appears*
to mention an outofscope type variable. See Trac #3409 for a more realworld
example.
Various possibilities suggest themselves:
Ignore the problem, and make Lint not complain about such variables
Expand all type synonyms (or at least all those that discard arguments)
This is tricky, because at least for toplevel things we want to
retain the type the user originally specified.
Expand synonyms on the fly, when the problem arises. That is what
we are doing here. It's not too expensive, I think.
\begin{code}
mkPiType :: Var -> Type -> Type
mkPiTypes :: [Var] -> Type -> Type
mkPiType v ty
| isId v = mkFunTy (idType v) ty
| otherwise = mkForAllTy v ty
mkPiTypes vs ty = foldr mkPiType ty vs
\end{code}
\begin{code}
applyTypeToArg :: Type -> CoreExpr -> Type
applyTypeToArg fun_ty (Type arg_ty) = applyTy fun_ty arg_ty
applyTypeToArg fun_ty _ = funResultTy fun_ty
applyTypeToArgs :: CoreExpr -> Type -> [CoreExpr] -> Type
applyTypeToArgs _ op_ty [] = op_ty
applyTypeToArgs e op_ty (Type ty : args)
=
go [ty] args
where
go rev_tys (Type ty : args) = go (ty:rev_tys) args
go rev_tys rest_args = applyTypeToArgs e op_ty' rest_args
where
op_ty' = applyTysD msg op_ty (reverse rev_tys)
msg = ptext (sLit "applyTypeToArgs") <+>
panic_msg e op_ty
applyTypeToArgs e op_ty (_ : args)
= case (splitFunTy_maybe op_ty) of
Just (_, res_ty) -> applyTypeToArgs e res_ty args
Nothing -> pprPanic "applyTypeToArgs" (panic_msg e op_ty)
panic_msg :: CoreExpr -> Type -> SDoc
panic_msg e op_ty = pprCoreExpr e $$ ppr op_ty
\end{code}
%************************************************************************
%* *
\subsection{Attaching notes}
%* *
%************************************************************************
mkNote removes redundant coercions, and SCCs where possible
\begin{code}
#ifdef UNUSED
mkNote :: Note -> CoreExpr -> CoreExpr
mkNote (SCC cc) expr = mkSCC cc expr
mkNote InlineMe expr = mkInlineMe expr
mkNote note expr = Note note expr
#endif
\end{code}
Drop trivial InlineMe's. This is somewhat important, because if we have an unfolding
that looks like (Note InlineMe (Var v)), the InlineMe doesn't go away because it may
not be *applied* to anything.
We don't use exprIsTrivial here, though, because we sometimes generate worker/wrapper
bindings like
fw = ...
f = inline_me (coerce t fw)
As usual, the inline_me prevents the worker from getting inlined back into the wrapper.
We want the split, so that the coerces can cancel at the call site.
However, we can get left with tiresome type applications. Notably, consider
f = /\ a -> let t = e in (t, w)
Then lifting the let out of the big lambda gives
t' = /\a -> e
f = /\ a -> let t = inline_me (t' a) in (t, w)
The inline_me is to stop the simplifier inlining t' right back
into t's RHS. In the next phase we'll substitute for t (since
its rhs is trivial) and *then* we could get rid of the inline_me.
But it hardly seems worth it, so I don't bother.
\begin{code}
mkInlineMe :: CoreExpr -> CoreExpr
mkInlineMe e@(Var _) = e
mkInlineMe e@(Note InlineMe _) = e
mkInlineMe e = Note InlineMe e
\end{code}
\begin{code}
mkCoerceI :: CoercionI -> CoreExpr -> CoreExpr
mkCoerceI IdCo e = e
mkCoerceI (ACo co) e = mkCoerce co e
mkCoerce :: Coercion -> CoreExpr -> CoreExpr
mkCoerce co (Cast expr co2)
= ASSERT(let { (from_ty, _to_ty) = coercionKind co;
(_from_ty2, to_ty2) = coercionKind co2} in
from_ty `coreEqType` to_ty2 )
mkCoerce (mkTransCoercion co2 co) expr
mkCoerce co expr
= let (from_ty, _to_ty) = coercionKind co in
ASSERT2(from_ty `coreEqType` (exprType expr), text "Trying to coerce" <+> text "(" <> ppr expr $$ text "::" <+> ppr (exprType expr) <> text ")" $$ ppr co $$ ppr (coercionKindPredTy co))
(Cast expr co)
\end{code}
\begin{code}
mkSCC :: CostCentre -> Expr b -> Expr b
mkSCC _ (Lit lit) = Lit lit
mkSCC cc (Lam x e) = Lam x (mkSCC cc e)
mkSCC cc (Note (SCC cc') e) = Note (SCC cc) (Note (SCC cc') e)
mkSCC cc (Note n e) = Note n (mkSCC cc e)
mkSCC cc (Cast e co) = Cast (mkSCC cc e) co
mkSCC cc expr = Note (SCC cc) expr
\end{code}
%************************************************************************
%* *
\subsection{Other expression construction}
%* *
%************************************************************************
\begin{code}
bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr
bindNonRec bndr rhs body
| needsCaseBinding (idType bndr) rhs = Case rhs bndr (exprType body) [(DEFAULT, [], body)]
| otherwise = Let (NonRec bndr rhs) body
needsCaseBinding :: Type -> CoreExpr -> Bool
needsCaseBinding ty rhs = isUnLiftedType ty && not (exprOkForSpeculation rhs)
\end{code}
\begin{code}
mkAltExpr :: AltCon
-> [CoreBndr]
-> [Type]
-> CoreExpr
mkAltExpr (DataAlt con) args inst_tys
= mkConApp con (map Type inst_tys ++ varsToCoreExprs args)
mkAltExpr (LitAlt lit) [] []
= Lit lit
mkAltExpr (LitAlt _) _ _ = panic "mkAltExpr LitAlt"
mkAltExpr DEFAULT _ _ = panic "mkAltExpr DEFAULT"
\end{code}
%************************************************************************
%* *
\subsection{Taking expressions apart}
%* *
%************************************************************************
The default alternative must be first, if it exists at all.
This makes it easy to find, though it makes matching marginally harder.
\begin{code}
findDefault :: [CoreAlt] -> ([CoreAlt], Maybe CoreExpr)
findDefault ((DEFAULT,args,rhs) : alts) = ASSERT( null args ) (alts, Just rhs)
findDefault alts = (alts, Nothing)
isDefaultAlt :: CoreAlt -> Bool
isDefaultAlt (DEFAULT, _, _) = True
isDefaultAlt _ = False
findAlt :: AltCon -> [CoreAlt] -> Maybe CoreAlt
findAlt con alts
= case alts of
(deflt@(DEFAULT,_,_):alts) -> go alts (Just deflt)
_ -> go alts Nothing
where
go [] deflt = deflt
go (alt@(con1,_,_) : alts) deflt
= case con `cmpAltCon` con1 of
LT -> deflt
EQ -> Just alt
GT -> ASSERT( not (con1 == DEFAULT) ) go alts deflt
mergeAlts :: [CoreAlt] -> [CoreAlt] -> [CoreAlt]
mergeAlts [] as2 = as2
mergeAlts as1 [] = as1
mergeAlts (a1:as1) (a2:as2)
= case a1 `cmpAlt` a2 of
LT -> a1 : mergeAlts as1 (a2:as2)
EQ -> a1 : mergeAlts as1 as2
GT -> a2 : mergeAlts (a1:as1) as2
trimConArgs :: AltCon -> [CoreArg] -> [CoreArg]
trimConArgs DEFAULT args = ASSERT( null args ) []
trimConArgs (LitAlt _) args = ASSERT( null args ) []
trimConArgs (DataAlt dc) args = dropList (dataConUnivTyVars dc) args
\end{code}
Note [Unreachable code]
~~~~~~~~~~~~~~~~~~~~~~~
It is possible (although unusual) for GHC to find a case expression
that cannot match. For example:
data Col = Red | Green | Blue
x = Red
f v = case x of
Red -> ...
_ -> ...(case x of { Green -> e1; Blue -> e2 })...
Suppose that for some silly reason, x isn't substituted in the case
expression. (Perhaps there's a NOINLINE on it, or profiling SCC stuff
gets in the way; cf Trac #3118.) Then the fulllazines pass might produce
this
x = Red
lvl = case x of { Green -> e1; Blue -> e2 })
f v = case x of
Red -> ...
_ -> ...lvl...
Now if x gets inlined, we won't be able to find a matching alternative
for 'Red'. That's because 'lvl' is unreachable. So rather than crashing
we generate (error "Inaccessible alternative").
Similar things can happen (augmented by GADTs) when the Simplifier
filters down the matching alternatives in Simplify.rebuildCase.
%************************************************************************
%* *
\subsection{Figuring out things about expressions}
%* *
%************************************************************************
@exprIsTrivial@ is true of expressions we are unconditionally happy to
duplicate; simple variables and constants, and type
applications. Note that primop Ids aren't considered
trivial unless
Note [Variable are trivial]
~~~~~~~~~~~~~~~~~~~~~~~~~~~
There used to be a gruesome test for (hasNoBinding v) in the
Var case:
exprIsTrivial (Var v) | hasNoBinding v = idArity v == 0
The idea here is that a constructor worker, like \$wJust, is
really short for (\x -> \$wJust x), becuase \$wJust has no binding.
So it should be treated like a lambda. Ditto unsaturated primops.
But now constructor workers are not "have-no-binding" Ids. And
completely unapplied primops and foreigncall Ids are sufficiently
rare that I plan to allow them to be duplicated and put up with
saturating them.
Note [SCCs are trivial]
~~~~~~~~~~~~~~~~~~~~~~~
We used not to treat (_scc_ "foo" x) as trivial, because it really
generates code, (and a heap object when it's a function arg) to
capture the cost centre. However, the profiling system discounts the
allocation costs for such "boxing thunks" whereas the extra costs of
*not* inlining otherwisetrivial bindings can be high, and are hard to
discount.
\begin{code}
exprIsTrivial :: CoreExpr -> Bool
exprIsTrivial (Var _) = True
exprIsTrivial (Type _) = True
exprIsTrivial (Lit lit) = litIsTrivial lit
exprIsTrivial (App e arg) = not (isRuntimeArg arg) && exprIsTrivial e
exprIsTrivial (Note _ e) = exprIsTrivial e
exprIsTrivial (Cast e _) = exprIsTrivial e
exprIsTrivial (Lam b body) = not (isRuntimeVar b) && exprIsTrivial body
exprIsTrivial _ = False
\end{code}
@exprIsDupable@ is true of expressions that can be duplicated at a modest
cost in code size. This will only happen in different case
branches, so there's no issue about duplicating work.
That is, exprIsDupable returns True of (f x) even if
f is very very expensive to call.
Its only purpose is to avoid fruitless letbinding
and then inlining of case join points
\begin{code}
exprIsDupable :: CoreExpr -> Bool
exprIsDupable (Type _) = True
exprIsDupable (Var _) = True
exprIsDupable (Lit lit) = litIsDupable lit
exprIsDupable (Note InlineMe _) = True
exprIsDupable (Note _ e) = exprIsDupable e
exprIsDupable (Cast e _) = exprIsDupable e
exprIsDupable expr
= go expr 0
where
go (Var _) _ = True
go (App f a) n_args = n_args < dupAppSize
&& exprIsDupable a
&& go f (n_args+1)
go _ _ = False
dupAppSize :: Int
dupAppSize = 4
\end{code}
@exprIsCheap@ looks at a Core expression and returns \tr{True} if
it is obviously in weak head normal form, or is cheap to get to WHNF.
[Note that that's not the same as exprIsDupable; an expression might be
big, and hence not dupable, but still cheap.]
By ``cheap'' we mean a computation we're willing to:
push inside a lambda, or
inline at more than one place
That might mean it gets evaluated more than once, instead of being
shared. The main examples of things which aren't WHNF but are
``cheap'' are:
* case e of
pi -> ei
(where e, and all the ei are cheap)
* let x = e in b
(where e and b are cheap)
* op x1 ... xn
(where op is a cheap primitive operator)
* error "foo"
(because we are happy to substitute it inside a lambda)
Notice that a variable is considered 'cheap': we can push it inside a lambda,
because sharing will make sure it is only evaluated once.
\begin{code}
exprIsCheap' :: (Id -> Bool) -> CoreExpr -> Bool
exprIsCheap' _ (Lit _) = True
exprIsCheap' _ (Type _) = True
exprIsCheap' _ (Var _) = True
exprIsCheap' _ (Note InlineMe _) = True
exprIsCheap' is_conlike (Note _ e) = exprIsCheap' is_conlike e
exprIsCheap' is_conlike (Cast e _) = exprIsCheap' is_conlike e
exprIsCheap' is_conlike (Lam x e) = isRuntimeVar x
|| exprIsCheap' is_conlike e
exprIsCheap' is_conlike (Case e _ _ alts) = exprIsCheap' is_conlike e &&
and [exprIsCheap' is_conlike rhs | (_,_,rhs) <- alts]
exprIsCheap' is_conlike (Let (NonRec x _) e)
| isUnLiftedType (idType x) = exprIsCheap' is_conlike e
| otherwise = False
exprIsCheap' is_conlike other_expr
= go other_expr []
where
go (App f a) val_args | isRuntimeArg a = go f (a:val_args)
| otherwise = go f val_args
go (Var _) [] = True
go (Var f) args
= case idDetails f of
RecSelId {} -> go_sel args
ClassOpId _ -> go_sel args
PrimOpId op -> go_primop op args
_ | is_conlike f -> go_pap args
| length args < idArity f -> go_pap args
_ -> isBottomingId f
go _ _ = False
go_pap args = all exprIsTrivial args
go_primop op args = primOpIsCheap op && all (exprIsCheap' is_conlike) args
go_sel [arg] = exprIsCheap' is_conlike arg
go_sel _ = False
exprIsCheap :: CoreExpr -> Bool
exprIsCheap = exprIsCheap' isDataConWorkId
exprIsExpandable :: CoreExpr -> Bool
exprIsExpandable = exprIsCheap' isConLikeId
\end{code}
\begin{code}
exprOkForSpeculation :: CoreExpr -> Bool
exprOkForSpeculation (Lit _) = True
exprOkForSpeculation (Type _) = True
exprOkForSpeculation (Var v) = isUnLiftedType (idType v)
&& not (isTickBoxOp v)
exprOkForSpeculation (Note _ e) = exprOkForSpeculation e
exprOkForSpeculation (Cast e _) = exprOkForSpeculation e
exprOkForSpeculation other_expr
= case collectArgs other_expr of
(Var f, args) -> spec_ok (idDetails f) args
_ -> False
where
spec_ok (DataConWorkId _) _
= True
spec_ok (PrimOpId op) args
| isDivOp op,
[arg1, Lit lit] <- args
= not (isZeroLit lit) && exprOkForSpeculation arg1
| otherwise
= primOpOkForSpeculation op &&
all exprOkForSpeculation args
spec_ok _ _ = False
isDivOp :: PrimOp -> Bool
isDivOp IntQuotOp = True
isDivOp IntRemOp = True
isDivOp WordQuotOp = True
isDivOp WordRemOp = True
isDivOp FloatDivOp = True
isDivOp DoubleDivOp = True
isDivOp _ = False
\end{code}
\begin{code}
exprIsBottom :: CoreExpr -> Bool
exprIsBottom e = go 0 e
where
go n (Note _ e) = go n e
go n (Cast e _) = go n e
go n (Let _ e) = go n e
go _ (Case e _ _ _) = go 0 e
go n (App e _) = go (n+1) e
go n (Var v) = idAppIsBottom v n
go _ (Lit _) = False
go _ (Lam _ _) = False
go _ (Type _) = False
idAppIsBottom :: Id -> Int -> Bool
idAppIsBottom id n_val_args = appIsBottom (idNewStrictness id) n_val_args
\end{code}
\begin{code}
exprIsHNF :: CoreExpr -> Bool
exprIsHNF (Var v)
= isDataConWorkId v
|| idArity v > 0
|| isEvaldUnfolding (idUnfolding v)
exprIsHNF (Lit _) = True
exprIsHNF (Type _) = True
exprIsHNF (Lam b e) = isRuntimeVar b || exprIsHNF e
exprIsHNF (Note _ e) = exprIsHNF e
exprIsHNF (Cast e _) = exprIsHNF e
exprIsHNF (App e (Type _)) = exprIsHNF e
exprIsHNF (App e a) = app_is_value e [a]
exprIsHNF _ = False
app_is_value :: CoreExpr -> [CoreArg] -> Bool
app_is_value (Var fun) args
= idArity fun > valArgCount args
|| isDataConWorkId fun
app_is_value (Note _ f) as = app_is_value f as
app_is_value (Cast f _) as = app_is_value f as
app_is_value (App f a) as = app_is_value f (a:as)
app_is_value _ _ = False
\end{code}
These InstPat functions go here to avoid circularity between DataCon and Id
\begin{code}
dataConRepInstPat, dataConOrigInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [CoVar], [Id])
dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [CoVar], [Id])
dataConRepInstPat = dataConInstPat dataConRepArgTys (repeat ((fsLit "ipv")))
dataConRepFSInstPat = dataConInstPat dataConRepArgTys
dataConOrigInstPat = dataConInstPat dc_arg_tys (repeat ((fsLit "ipv")))
where
dc_arg_tys dc = map mkPredTy (dataConEqTheta dc) ++ map mkPredTy (dataConDictTheta dc) ++ dataConOrigArgTys dc
dataConInstPat :: (DataCon -> [Type])
-> [FastString]
-> [Unique]
-> DataCon
-> [Type]
-> ([TyVar], [CoVar], [Id])
dataConInstPat arg_fun fss uniqs con inst_tys
= (ex_bndrs, co_bndrs, arg_ids)
where
univ_tvs = dataConUnivTyVars con
ex_tvs = dataConExTyVars con
arg_tys = arg_fun con
eq_spec = dataConEqSpec con
eq_theta = dataConEqTheta con
eq_preds = eqSpecPreds eq_spec ++ eq_theta
n_ex = length ex_tvs
n_co = length eq_preds
(ex_uniqs, uniqs') = splitAt n_ex uniqs
(co_uniqs, id_uniqs) = splitAt n_co uniqs'
(ex_fss, fss') = splitAt n_ex fss
(co_fss, id_fss) = splitAt n_co fss'
ex_bndrs = zipWith3 mk_ex_var ex_uniqs ex_fss ex_tvs
mk_ex_var uniq fs var = mkTyVar new_name kind
where
new_name = mkSysTvName uniq fs
kind = tyVarKind var
subst = zipOpenTvSubst (univ_tvs ++ ex_tvs) (inst_tys ++ map mkTyVarTy ex_bndrs)
co_bndrs = zipWith3 mk_co_var co_uniqs co_fss eq_preds
mk_co_var uniq fs eq_pred = mkCoVar new_name co_kind
where
new_name = mkSysTvName uniq fs
co_kind = substTy subst (mkPredTy eq_pred)
mk_id_var uniq fs ty = mkUserLocal (mkVarOccFS fs) uniq (substTy subst ty) noSrcSpan
arg_ids = zipWith3 mk_id_var id_uniqs id_fss arg_tys
exprIsConApp_maybe :: CoreExpr -> Maybe (DataCon, [CoreExpr])
exprIsConApp_maybe (Cast expr co)
=
case exprIsConApp_maybe expr of {
Nothing -> Nothing ;
Just (dc, dc_args) ->
let (from_ty, to_ty) = coercionKind co
(from_tc, from_tc_arg_tys) = splitTyConApp from_ty
in
case splitTyConApp_maybe to_ty of {
Nothing -> Nothing ;
Just (to_tc, to_tc_arg_tys)
| from_tc /= to_tc -> Nothing
| otherwise ->
let
tc_arity = tyConArity from_tc
(univ_args, rest1) = splitAt tc_arity dc_args
(ex_args, rest2) = splitAt n_ex_tvs rest1
(co_args_spec, rest3) = splitAt n_cos_spec rest2
(co_args_theta, val_args) = splitAt n_cos_theta rest3
arg_tys = dataConRepArgTys dc
dc_univ_tyvars = dataConUnivTyVars dc
dc_ex_tyvars = dataConExTyVars dc
dc_eq_spec = dataConEqSpec dc
dc_eq_theta = dataConEqTheta dc
dc_tyvars = dc_univ_tyvars ++ dc_ex_tyvars
n_ex_tvs = length dc_ex_tyvars
n_cos_spec = length dc_eq_spec
n_cos_theta = length dc_eq_theta
gammas = decomposeCo tc_arity co
new_tys = gammas ++ map (\ (Type t) -> t) ex_args
theta = zipOpenTvSubst dc_tyvars new_tys
cast_co_spec (tv, ty) co
= cast_co_theta (mkEqPred (mkTyVarTy tv, ty)) co
cast_co_theta eqPred (Type co)
| (ty1, ty2) <- getEqPredTys eqPred
= Type $ mkSymCoercion (substTy theta ty1)
`mkTransCoercion` co
`mkTransCoercion` (substTy theta ty2)
new_co_args = zipWith cast_co_spec dc_eq_spec co_args_spec ++
zipWith cast_co_theta dc_eq_theta co_args_theta
new_val_args = zipWith cast_arg arg_tys val_args
cast_arg arg_ty arg = mkCoerce (substTy theta arg_ty) arg
in
ASSERT( length univ_args == tc_arity )
ASSERT2( from_tc == dataConTyCon dc, ppr expr $$ ppr co $$ ppr from_tc $$ ppr dc $$ ppr (dataConTyCon dc) )
ASSERT( and (zipWith coreEqType [t | Type t <- univ_args] from_tc_arg_tys) )
ASSERT( all isTypeArg (univ_args ++ ex_args) )
ASSERT2( equalLength val_args arg_tys, ppr dc $$ ppr dc_tyvars $$ ppr dc_ex_tyvars $$ ppr arg_tys $$ ppr dc_args $$ ppr univ_args $$ ppr ex_args $$ ppr val_args $$ ppr arg_tys )
Just (dc, map Type to_tc_arg_tys ++ ex_args ++ new_co_args ++ new_val_args)
}}
exprIsConApp_maybe (Note _ expr)
= exprIsConApp_maybe expr
exprIsConApp_maybe expr = analyse (collectArgs expr)
where
analyse (Var fun, args)
| Just con <- isDataConWorkId_maybe fun,
count isValArg args == dataConRepArity con
= Just (con,args)
analyse (Var fun, [])
| let unf = idUnfolding fun,
isExpandableUnfolding unf
= exprIsConApp_maybe (unfoldingTemplate unf)
analyse _ = Nothing
\end{code}
%************************************************************************
%* *
\subsection{Equality}
%* *
%************************************************************************
\begin{code}
cheapEqExpr :: Expr b -> Expr b -> Bool
cheapEqExpr (Var v1) (Var v2) = v1==v2
cheapEqExpr (Lit lit1) (Lit lit2) = lit1 == lit2
cheapEqExpr (Type t1) (Type t2) = t1 `coreEqType` t2
cheapEqExpr (App f1 a1) (App f2 a2)
= f1 `cheapEqExpr` f2 && a1 `cheapEqExpr` a2
cheapEqExpr (Cast e1 t1) (Cast e2 t2)
= e1 `cheapEqExpr` e2 && t1 `coreEqCoercion` t2
cheapEqExpr _ _ = False
exprIsBig :: Expr b -> Bool
exprIsBig (Lit _) = False
exprIsBig (Var _) = False
exprIsBig (Type _) = False
exprIsBig (App f a) = exprIsBig f || exprIsBig a
exprIsBig (Cast e _) = exprIsBig e
exprIsBig _ = True
\end{code}
%************************************************************************
%* *
\subsection{The size of an expression}
%* *
%************************************************************************
\begin{code}
coreBindsSize :: [CoreBind] -> Int
coreBindsSize bs = foldr ((+) . bindSize) 0 bs
exprSize :: CoreExpr -> Int
exprSize (Var v) = v `seq` 1
exprSize (Lit lit) = lit `seq` 1
exprSize (App f a) = exprSize f + exprSize a
exprSize (Lam b e) = varSize b + exprSize e
exprSize (Let b e) = bindSize b + exprSize e
exprSize (Case e b t as) = seqType t `seq` exprSize e + varSize b + 1 + foldr ((+) . altSize) 0 as
exprSize (Cast e co) = (seqType co `seq` 1) + exprSize e
exprSize (Note n e) = noteSize n + exprSize e
exprSize (Type t) = seqType t `seq` 1
noteSize :: Note -> Int
noteSize (SCC cc) = cc `seq` 1
noteSize InlineMe = 1
noteSize (CoreNote s) = s `seq` 1
varSize :: Var -> Int
varSize b | isTyVar b = 1
| otherwise = seqType (idType b) `seq`
megaSeqIdInfo (idInfo b) `seq`
1
varsSize :: [Var] -> Int
varsSize = sum . map varSize
bindSize :: CoreBind -> Int
bindSize (NonRec b e) = varSize b + exprSize e
bindSize (Rec prs) = foldr ((+) . pairSize) 0 prs
pairSize :: (Var, CoreExpr) -> Int
pairSize (b,e) = varSize b + exprSize e
altSize :: CoreAlt -> Int
altSize (c,bs,e) = c `seq` varsSize bs + exprSize e
\end{code}
%************************************************************************
%* *
\subsection{Hashing}
%* *
%************************************************************************
\begin{code}
hashExpr :: CoreExpr -> Int
hashExpr e = fromIntegral (hash_expr (1,emptyVarEnv) e .&. 0x7fffffff)
type HashEnv = (Int, VarEnv Int)
hash_expr :: HashEnv -> CoreExpr -> Word32
hash_expr env (Note _ e) = hash_expr env e
hash_expr env (Cast e _) = hash_expr env e
hash_expr env (Var v) = hashVar env v
hash_expr _ (Lit lit) = fromIntegral (hashLiteral lit)
hash_expr env (App f e) = hash_expr env f * fast_hash_expr env e
hash_expr env (Let (NonRec b r) e) = hash_expr (extend_env env b) e * fast_hash_expr env r
hash_expr env (Let (Rec ((b,_):_)) e) = hash_expr (extend_env env b) e
hash_expr env (Case e _ _ _) = hash_expr env e
hash_expr env (Lam b e) = hash_expr (extend_env env b) e
hash_expr _ (Type _) = WARN(True, text "hash_expr: type") 1
fast_hash_expr :: HashEnv -> CoreExpr -> Word32
fast_hash_expr env (Var v) = hashVar env v
fast_hash_expr env (Type t) = fast_hash_type env t
fast_hash_expr _ (Lit lit) = fromIntegral (hashLiteral lit)
fast_hash_expr env (Cast e _) = fast_hash_expr env e
fast_hash_expr env (Note _ e) = fast_hash_expr env e
fast_hash_expr env (App _ a) = fast_hash_expr env a
fast_hash_expr _ _ = 1
fast_hash_type :: HashEnv -> Type -> Word32
fast_hash_type env ty
| Just tv <- getTyVar_maybe ty = hashVar env tv
| Just (tc,tys) <- splitTyConApp_maybe ty = let hash_tc = fromIntegral (hashName (tyConName tc))
in foldr (\t n -> fast_hash_type env t + n) hash_tc tys
| otherwise = 1
extend_env :: HashEnv -> Var -> (Int, VarEnv Int)
extend_env (n,env) b = (n+1, extendVarEnv env b n)
hashVar :: HashEnv -> Var -> Word32
hashVar (_,env) v
= fromIntegral (lookupVarEnv env v `orElse` hashName (idName v))
\end{code}
%************************************************************************
%* *
\subsection{Determining nonupdatable righthandsides}
%* *
%************************************************************************
Toplevel constructor applications can usually be allocated
statically, but they can't if the constructor, or any of the
arguments, come from another DLL (because we can't refer to static
labels in other DLLs).
If this happens we simply make the RHS into an updatable thunk,
and 'execute' it rather than allocating it statically.
\begin{code}
rhsIsStatic :: PackageId -> CoreExpr -> Bool
rhsIsStatic _this_pkg rhs = is_static False rhs
where
is_static :: Bool
-> CoreExpr -> Bool
is_static False (Lam b e) = isRuntimeVar b || is_static False e
is_static _ (Note (SCC _) _) = False
is_static in_arg (Note _ e) = is_static in_arg e
is_static in_arg (Cast e _) = is_static in_arg e
is_static _ (Lit lit)
= case lit of
MachLabel _ _ _ -> False
_ -> True
is_static in_arg other_expr = go other_expr 0
where
go (Var f) n_val_args
#if mingw32_TARGET_OS
| not (isDllName _this_pkg (idName f))
#endif
= saturated_data_con f n_val_args
|| (in_arg && n_val_args == 0)
go (App f a) n_val_args
| isTypeArg a = go f n_val_args
| not in_arg && is_static True a = go f (n_val_args + 1)
go (Note (SCC _) _) _ = False
go (Note _ f) n_val_args = go f n_val_args
go (Cast e _) n_val_args = go e n_val_args
go _ _ = False
saturated_data_con f n_val_args
= case isDataConWorkId_maybe f of
Just dc -> n_val_args == dataConRepArity dc
Nothing -> False
\end{code}