%
% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
Utility functions on @Core@ syntax
\begin{code}
module CoreUtils (
mkSCC, mkCoerce,
bindNonRec, needsCaseBinding,
mkAltExpr, mkPiType, mkPiTypes,
findDefault, findAlt, isDefaultAlt, mergeAlts, trimConArgs,
exprType, coreAltType, coreAltsType,
exprIsDupable, exprIsTrivial, exprIsBottom,
exprIsCheap, exprIsExpandable, exprIsCheap', CheapAppFun,
exprIsHNF, exprOkForSpeculation, exprIsBig, exprIsConLike,
rhsIsStatic, isCheapApp, isExpandableApp,
coreBindsSize, exprSize,
CoreStats(..), coreBindsStats,
hashExpr,
cheapEqExpr, eqExpr, eqExprX,
tryEtaReduce,
applyTypeToArgs, applyTypeToArg,
dataConRepInstPat, dataConRepFSInstPat
) where
#include "HsVersions.h"
import CoreSyn
import PprCore
import Var
import SrcLoc
import VarEnv
import VarSet
import Name
import Literal
import DataCon
import PrimOp
import Id
import IdInfo
import Type
import Coercion
import TyCon
import CostCentre
import Unique
import Outputable
import TysPrim
import FastString
import Maybes
import Util
import Pair
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 (Coercion co) = coercionType co
exprType (Let _ body) = exprType body
exprType (Case _ _ ty _) = ty
exprType (Cast _ co) = pSnd (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 out-of-scope type variable. See Trac #3409 for a more real-world
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 top-level 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}
%* *
%************************************************************************
\begin{code}
mkCoerce :: Coercion -> CoreExpr -> CoreExpr
mkCoerce co e | isReflCo co = e
mkCoerce co (Cast expr co2)
= ASSERT(let { Pair from_ty _to_ty = coercionKind co;
Pair _from_ty2 to_ty2 = coercionKind co2} in
from_ty `eqType` to_ty2 )
mkCoerce (mkTransCo co2 co) expr
mkCoerce co expr
= let Pair from_ty _to_ty = coercionKind co in
WARN(not (from_ty `eqType` exprType expr), text "Trying to coerce" <+> text "(" <> ppr expr $$ text "::" <+> ppr (exprType expr) <> text ")" $$ ppr co $$ pprEqPred (coercionKind 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 full-lazines 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.
%************************************************************************
%* *
exprIsTrivial
%* *
%************************************************************************
Note [exprIsTrivial]
~~~~~~~~~~~~~~~~~~~~
@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 un-applied primops and foreign-call 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 otherwise-trivial bindings can be high, and are hard to
discount.
\begin{code}
exprIsTrivial :: CoreExpr -> Bool
exprIsTrivial (Var _) = True
exprIsTrivial (Type _) = True
exprIsTrivial (Coercion _) = 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}
exprIsBottom is a very cheap and cheerful function; it may return
False for bottoming expressions, but it never costs much to ask.
See also CoreArity.exprBotStrictness_maybe, but that's a bit more
expensive.
\begin{code}
exprIsBottom :: CoreExpr -> Bool
exprIsBottom e
= go 0 e
where
go n (Var v) = isBottomingId v && n >= idArity v
go n (App e a) | isTypeArg a = go n e
| otherwise = go (n+1) e
go n (Note _ e) = go n e
go n (Cast e _) = go n e
go n (Let _ e) = go n e
go _ _ = False
\end{code}
%************************************************************************
%* *
exprIsDupable
%* *
%************************************************************************
Note [exprIsDupable]
~~~~~~~~~~~~~~~~~~~~
@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 let-binding
and then inlining of case join points
\begin{code}
exprIsDupable :: CoreExpr -> Bool
exprIsDupable e
= isJust (go dupAppSize e)
where
go :: Int -> CoreExpr -> Maybe Int
go n (Type {}) = Just n
go n (Coercion {}) = Just n
go n (Var {}) = decrement n
go n (Note _ e) = go n e
go n (Cast e _) = go n e
go n (App f a) | Just n' <- go n a = go n' f
go n (Lit lit) | litIsDupable lit = decrement n
go _ _ = Nothing
decrement :: Int -> Maybe Int
decrement 0 = Nothing
decrement n = Just (n1)
dupAppSize :: Int
dupAppSize = 8
\end{code}
%************************************************************************
%* *
exprIsCheap, exprIsExpandable
%* *
%************************************************************************
Note [exprIsCheap] See also Note [Interaction of exprIsCheap and lone variables]
~~~~~~~~~~~~~~~~~~ in CoreUnfold.lhs
@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.
Note [exprIsCheap and exprIsHNF]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note that exprIsHNF does not imply exprIsCheap. Eg
let x = fac 20 in Just x
This responds True to exprIsHNF (you can discard a seq), but
False to exprIsCheap.
\begin{code}
exprIsCheap :: CoreExpr -> Bool
exprIsCheap = exprIsCheap' isCheapApp
exprIsExpandable :: CoreExpr -> Bool
exprIsExpandable = exprIsCheap' isExpandableApp
type CheapAppFun = Id -> Int -> Bool
exprIsCheap' :: CheapAppFun -> CoreExpr -> Bool
exprIsCheap' _ (Lit _) = True
exprIsCheap' _ (Type _) = True
exprIsCheap' _ (Coercion _) = True
exprIsCheap' _ (Var _) = True
exprIsCheap' good_app (Note _ e) = exprIsCheap' good_app e
exprIsCheap' good_app (Cast e _) = exprIsCheap' good_app e
exprIsCheap' good_app (Lam x e) = isRuntimeVar x
|| exprIsCheap' good_app e
exprIsCheap' good_app (Case e _ _ alts) = exprIsCheap' good_app e &&
and [exprIsCheap' good_app rhs | (_,_,rhs) <- alts]
exprIsCheap' good_app (Let (NonRec x _) e)
| isUnLiftedType (idType x) = exprIsCheap' good_app e
| otherwise = False
exprIsCheap' good_app other_expr
= go other_expr []
where
go (Cast e _) val_args = go e val_args
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
_ | good_app f (length args) -> go_pap args
| isBottomingId f -> True
| otherwise -> False
go _ _ = False
go_pap args = all (exprIsCheap' good_app) args
go_primop op args = primOpIsCheap op && all (exprIsCheap' good_app) args
go_sel [arg] = exprIsCheap' good_app arg
go_sel _ = False
isCheapApp :: CheapAppFun
isCheapApp fn n_val_args
= isDataConWorkId fn
|| n_val_args < idArity fn
isExpandableApp :: CheapAppFun
isExpandableApp fn n_val_args
= isConLikeId fn
|| n_val_args < idArity fn
|| go n_val_args (idType fn)
where
go 0 _ = True
go n_val_args ty
| Just (_, ty) <- splitForAllTy_maybe ty = go n_val_args ty
| Just (arg, ty) <- splitFunTy_maybe ty
, isPredTy arg = go (n_val_args1) ty
| otherwise = False
\end{code}
Note [Expandable overloadings]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Suppose the user wrote this
{-# RULE forall x. foo (negate x) = h x #-}
f x = ....(foo (negate x))....
He'd expect the rule to fire. But since negate is overloaded, we might
get this:
f = \d -> let n = negate d in \x -> ...foo (n x)...
So we treat the application of a function (negate in this case) to a
*dictionary* as expandable. In effect, every function is CONLIKE when
it's applied only to dictionaries.
%************************************************************************
%* *
exprOkForSpeculation
%* *
%************************************************************************
\begin{code}
exprOkForSpeculation :: CoreExpr -> Bool
exprOkForSpeculation (Lit _) = True
exprOkForSpeculation (Type _) = True
exprOkForSpeculation (Coercion _) = True
exprOkForSpeculation (Var v)
| isTickBoxOp v = False
| otherwise = isUnLiftedType (idType v)
|| isDataConWorkId v
|| idArity v > 0
|| isEvaldUnfolding (idUnfolding v)
exprOkForSpeculation (Note _ e) = exprOkForSpeculation e
exprOkForSpeculation (Cast e _) = exprOkForSpeculation e
exprOkForSpeculation (Case e _ _ alts)
= exprOkForSpeculation e
&& all (\(_,_,rhs) -> exprOkForSpeculation rhs) alts
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
| DataToTagOp <- op
= True
| otherwise
= primOpOkForSpeculation op &&
all exprOkForSpeculation args
spec_ok (DFunId new_type) _ = not new_type
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}
Note [exprOkForSpeculation: case expressions]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's always sound for exprOkForSpeculation to return False, and we
don't want it to take too long, so it bales out on complicated-looking
terms. Notably lets, which can be stacked very deeply; and in any
case the argument of exprOkForSpeculation is usually in a strict context,
so any lets will have been floated away.
However, we keep going on case-expressions. An example like this one
showed up in DPH code (Trac #3717):
foo :: Int -> Int
foo 0 = 0
foo n = (if n < 5 then 1 else 2) `seq` foo (n-1)
If exprOkForSpeculation doesn't look through case expressions, you get this:
T.$wfoo =
\ (ww :: GHC.Prim.Int#) ->
case ww of ds {
__DEFAULT -> case (case <# ds 5 of _ {
GHC.Types.False -> lvl1;
GHC.Types.True -> lvl})
of _ { __DEFAULT ->
T.$wfoo (GHC.Prim.-# ds_XkE 1) };
0 -> 0
}
The inner case is redundant, and should be nuked.
Note [dataToTag speculation]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is this OK?
f x = let v::Int# = dataToTag# x
in ...
We say "yes", even though 'x' may not be evaluated. Reasons
* dataToTag#'s strictness means that its argument often will be
evaluated, but FloatOut makes that temporarily untrue
case x of y -> let v = dataToTag# y in ...
-->
case x of y -> let v = dataToTag# x in ...
Note that we look at 'x' instead of 'y' (this is to improve
floating in FloatOut). So Lint complains.
Moreover, it really *might* improve floating to let the
v-binding float out
* CorePrep makes sure dataToTag#'s argument is evaluated, just
before code gen. Until then, it's not guaranteed
%************************************************************************
%* *
exprIsHNF, exprIsConLike
%* *
%************************************************************************
\begin{code}
exprIsHNF :: CoreExpr -> Bool
exprIsHNF = exprIsHNFlike isDataConWorkId isEvaldUnfolding
\end{code}
\begin{code}
exprIsConLike :: CoreExpr -> Bool
exprIsConLike = exprIsHNFlike isConLikeId isConLikeUnfolding
exprIsHNFlike :: (Var -> Bool) -> (Unfolding -> Bool) -> CoreExpr -> Bool
exprIsHNFlike is_con is_con_unf = is_hnf_like
where
is_hnf_like (Var v)
= is_con v
|| idArity v > 0
|| is_con_unf (idUnfolding v)
is_hnf_like (Lit _) = True
is_hnf_like (Type _) = True
is_hnf_like (Coercion _) = True
is_hnf_like (Lam b e) = isRuntimeVar b || is_hnf_like e
is_hnf_like (Note _ e) = is_hnf_like e
is_hnf_like (Cast e _) = is_hnf_like e
is_hnf_like (App e (Type _)) = is_hnf_like e
is_hnf_like (App e (Coercion _)) = is_hnf_like e
is_hnf_like (App e a) = app_is_value e [a]
is_hnf_like (Let _ e) = is_hnf_like e
is_hnf_like _ = False
app_is_value :: CoreExpr -> [CoreArg] -> Bool
app_is_value (Var fun) args
= idArity fun > valArgCount args
|| is_con 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}
%************************************************************************
%* *
Instantiating data constructors
%* *
%************************************************************************
These InstPat functions go here to avoid circularity between DataCon and Id
\begin{code}
dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
dataConRepInstPat = dataConInstPat (repeat ((fsLit "ipv")))
dataConRepFSInstPat = dataConInstPat
dataConInstPat :: [FastString]
-> [Unique]
-> DataCon
-> [Type]
-> ([TyVar], [Id])
dataConInstPat fss uniqs con inst_tys
= (ex_bndrs, arg_ids)
where
univ_tvs = dataConUnivTyVars con
ex_tvs = dataConExTyVars con
arg_tys = dataConRepArgTys con
n_ex = length ex_tvs
(ex_uniqs, id_uniqs) = splitAt n_ex uniqs
(ex_fss, id_fss) = splitAt n_ex 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)
mk_id_var uniq fs ty = mkUserLocal (mkVarOccFS fs) uniq (Type.substTy subst ty) noSrcSpan
arg_ids = zipWith3 mk_id_var id_uniqs id_fss arg_tys
\end{code}
%************************************************************************
%* *
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 `eqType` t2
cheapEqExpr (Coercion c1) (Coercion c2) = c1 `coreEqCoercion` c2
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
\end{code}
\begin{code}
exprIsBig :: Expr b -> Bool
exprIsBig (Lit _) = False
exprIsBig (Var _) = False
exprIsBig (Type _) = False
exprIsBig (Coercion _) = False
exprIsBig (Lam _ e) = exprIsBig e
exprIsBig (App f a) = exprIsBig f || exprIsBig a
exprIsBig (Cast e _) = exprIsBig e
exprIsBig _ = True
\end{code}
\begin{code}
eqExpr :: InScopeSet -> CoreExpr -> CoreExpr -> Bool
eqExpr in_scope e1 e2
= eqExprX id_unf (mkRnEnv2 in_scope) e1 e2
where
id_unf _ = noUnfolding
\end{code}
\begin{code}
eqExprX :: IdUnfoldingFun -> RnEnv2 -> CoreExpr -> CoreExpr -> Bool
eqExprX id_unfolding_fun env e1 e2
= go env e1 e2
where
go env (Var v1) (Var v2)
| rnOccL env v1 == rnOccR env v2
= True
go env (Var v1) e2
| not (locallyBoundL env v1)
, Just e1' <- expandUnfolding_maybe (id_unfolding_fun (lookupRnInScope env v1))
= go (nukeRnEnvL env) e1' e2
go env e1 (Var v2)
| not (locallyBoundR env v2)
, Just e2' <- expandUnfolding_maybe (id_unfolding_fun (lookupRnInScope env v2))
= go (nukeRnEnvR env) e1 e2'
go _ (Lit lit1) (Lit lit2) = lit1 == lit2
go env (Type t1) (Type t2) = eqTypeX env t1 t2
go env (Coercion co1) (Coercion co2) = coreEqCoercion2 env co1 co2
go env (Cast e1 co1) (Cast e2 co2) = coreEqCoercion2 env co1 co2 && go env e1 e2
go env (App f1 a1) (App f2 a2) = go env f1 f2 && go env a1 a2
go env (Note n1 e1) (Note n2 e2) = go_note n1 n2 && go env e1 e2
go env (Lam b1 e1) (Lam b2 e2)
= eqTypeX env (varType b1) (varType b2)
&& go (rnBndr2 env b1 b2) e1 e2
go env (Let (NonRec v1 r1) e1) (Let (NonRec v2 r2) e2)
= go env r1 r2
&& go (rnBndr2 env v1 v2) e1 e2
go env (Let (Rec ps1) e1) (Let (Rec ps2) e2)
= all2 (go env') rs1 rs2 && go env' e1 e2
where
(bs1,rs1) = unzip ps1
(bs2,rs2) = unzip ps2
env' = rnBndrs2 env bs1 bs2
go env (Case e1 b1 _ a1) (Case e2 b2 _ a2)
= go env e1 e2
&& eqTypeX env (idType b1) (idType b2)
&& all2 (go_alt (rnBndr2 env b1 b2)) a1 a2
go _ _ _ = False
go_alt env (c1, bs1, e1) (c2, bs2, e2)
= c1 == c2 && go (rnBndrs2 env bs1 bs2) e1 e2
go_note (SCC cc1) (SCC cc2) = cc1 == cc2
go_note (CoreNote s1) (CoreNote s2) = s1 == s2
go_note _ _ = False
\end{code}
Auxiliary functions
\begin{code}
locallyBoundL, locallyBoundR :: RnEnv2 -> Var -> Bool
locallyBoundL rn_env v = inRnEnvL rn_env v
locallyBoundR rn_env v = inRnEnvR rn_env v
\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) = (seqCo co `seq` 1) + exprSize e
exprSize (Note n e) = noteSize n + exprSize e
exprSize (Type t) = seqType t `seq` 1
exprSize (Coercion co) = seqCo co `seq` 1
noteSize :: Note -> Int
noteSize (SCC cc) = cc `seq` 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}
\begin{code}
data CoreStats = CS { cs_tm, cs_ty, cs_co :: Int }
plusCS :: CoreStats -> CoreStats -> CoreStats
plusCS (CS { cs_tm = p1, cs_ty = q1, cs_co = r1 })
(CS { cs_tm = p2, cs_ty = q2, cs_co = r2 })
= CS { cs_tm = p1+p2, cs_ty = q1+q2, cs_co = r1+r2 }
zeroCS, oneTM :: CoreStats
zeroCS = CS { cs_tm = 0, cs_ty = 0, cs_co = 0 }
oneTM = zeroCS { cs_tm = 1 }
sumCS :: (a -> CoreStats) -> [a] -> CoreStats
sumCS f = foldr (plusCS . f) zeroCS
coreBindsStats :: [CoreBind] -> CoreStats
coreBindsStats = sumCS bindStats
bindStats :: CoreBind -> CoreStats
bindStats (NonRec v r) = bindingStats v r
bindStats (Rec prs) = sumCS (\(v,r) -> bindingStats v r) prs
bindingStats :: Var -> CoreExpr -> CoreStats
bindingStats v r = bndrStats v `plusCS` exprStats r
bndrStats :: Var -> CoreStats
bndrStats v = oneTM `plusCS` tyStats (varType v)
exprStats :: CoreExpr -> CoreStats
exprStats (Var {}) = oneTM
exprStats (Lit {}) = oneTM
exprStats (Type t) = tyStats t
exprStats (Coercion c) = coStats c
exprStats (App f a) = exprStats f `plusCS` exprStats a
exprStats (Lam b e) = bndrStats b `plusCS` exprStats e
exprStats (Let b e) = bindStats b `plusCS` exprStats e
exprStats (Case e b _ as) = exprStats e `plusCS` bndrStats b `plusCS` sumCS altStats as
exprStats (Cast e co) = coStats co `plusCS` exprStats e
exprStats (Note _ e) = exprStats e
altStats :: CoreAlt -> CoreStats
altStats (_, bs, r) = sumCS bndrStats bs `plusCS` exprStats r
tyStats :: Type -> CoreStats
tyStats ty = zeroCS { cs_ty = typeSize ty }
coStats :: Coercion -> CoreStats
coStats co = zeroCS { cs_co = coercionSize co }
\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
hash_expr _ (Coercion _) = WARN(True, text "hash_expr: coercion") 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 env (Coercion co) = fast_hash_co env co
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
fast_hash_co :: HashEnv -> Coercion -> Word32
fast_hash_co env co
| Just cv <- getCoVar_maybe co = hashVar env cv
| Just (tc,cos) <- splitTyConAppCo_maybe co = let hash_tc = fromIntegral (hashName (tyConName tc))
in foldr (\c n -> fast_hash_co env c + n) hash_tc cos
| 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}
%************************************************************************
%* *
Eta reduction
%* *
%************************************************************************
Note [Eta reduction conditions]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We try for eta reduction here, but *only* if we get all the way to an
trivial expression. We don't want to remove extra lambdas unless we
are going to avoid allocating this thing altogether.
There are some particularly delicate points here:
* Eta reduction is not valid in general:
\x. bot /= bot
This matters, partly for old-fashioned correctness reasons but,
worse, getting it wrong can yield a seg fault. Consider
f = \x.f x
h y = case (case y of { True -> f `seq` True; False -> False }) of
True -> ...; False -> ...
If we (unsoundly) eta-reduce f to get f=f, the strictness analyser
says f=bottom, and replaces the (f `seq` True) with just
(f `cast` unsafe-co). BUT, as thing stand, 'f' got arity 1, and it
*keeps* arity 1 (perhaps also wrongly). So CorePrep eta-expands
the definition again, so that it does not termninate after all.
Result: seg-fault because the boolean case actually gets a function value.
See Trac #1947.
So it's important to to the right thing.
* Note [Arity care]: we need to be careful if we just look at f's
arity. Currently (Dec07), f's arity is visible in its own RHS (see
Note [Arity robustness] in SimplEnv) so we must *not* trust the
arity when checking that 'f' is a value. Otherwise we will
eta-reduce
f = \x. f x
to
f = f
Which might change a terminiating program (think (f `seq` e)) to a
non-terminating one. So we check for being a loop breaker first.
However for GlobalIds we can look at the arity; and for primops we
must, since they have no unfolding.
* Regardless of whether 'f' is a value, we always want to
reduce (/\a -> f a) to f
This came up in a RULE: foldr (build (/\a -> g a))
did not match foldr (build (/\b -> ...something complex...))
The type checker can insert these eta-expanded versions,
with both type and dictionary lambdas; hence the slightly
ad-hoc isDictId
* Never *reduce* arity. For example
f = \xy. g x y
Then if h has arity 1 we don't want to eta-reduce because then
f's arity would decrease, and that is bad
These delicacies are why we don't use exprIsTrivial and exprIsHNF here.
Alas.
Note [Eta reduction with casted arguments]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider
(\(x:t3). f (x |> g)) :: t3 -> t2
where
f :: t1 -> t2
g :: t3 ~ t1
This should be eta-reduced to
f |> (sym g -> t2)
So we need to accumulate a coercion, pushing it inward (past
variable arguments only) thus:
f (x |> co_arg) |> co --> (f |> (sym co_arg -> co)) x
f (x:t) |> co --> (f |> (t -> co)) x
f @ a |> co --> (f |> (forall a.co)) @ a
f @ (g:t1~t2) |> co --> (f |> (t1~t2 => co)) @ (g:t1~t2)
These are the equations for ok_arg.
It's true that we could also hope to eta reduce these:
(\xy. (f x |> g) y)
(\xy. (f x y) |> g)
But the simplifier pushes those casts outwards, so we don't
need to address that here.
\begin{code}
tryEtaReduce :: [Var] -> CoreExpr -> Maybe CoreExpr
tryEtaReduce bndrs body
= go (reverse bndrs) body (mkReflCo (exprType body))
where
incoming_arity = count isId bndrs
go :: [Var]
-> CoreExpr
-> Coercion
-> Maybe CoreExpr
go [] fun co
| ok_fun fun = Just (mkCoerce co fun)
go (b : bs) (App fun arg) co
| Just co' <- ok_arg b arg co
= go bs fun co'
go _ _ _ = Nothing
ok_fun (App fun (Type ty))
| not (any (`elemVarSet` tyVarsOfType ty) bndrs)
= ok_fun fun
ok_fun (Var fun_id)
= not (fun_id `elem` bndrs)
&& (ok_fun_id fun_id || all ok_lam bndrs)
ok_fun _fun = False
ok_fun_id fun = fun_arity fun >= incoming_arity
fun_arity fun
| isLocalId fun && isStrongLoopBreaker (idOccInfo fun) = 0
| otherwise = idArity fun
ok_lam v = isTyVar v || isEvVar v
ok_arg :: Var
-> CoreExpr
-> Coercion
-> Maybe Coercion
ok_arg bndr (Type ty) co
| Just tv <- getTyVar_maybe ty
, bndr == tv = Just (mkForAllCo tv co)
ok_arg bndr (Var v) co
| bndr == v = Just (mkFunCo (mkReflCo (idType bndr)) co)
ok_arg bndr (Cast (Var v) co_arg) co
| bndr == v = Just (mkFunCo (mkSymCo co_arg) co)
ok_arg _ _ _ = Nothing
\end{code}
%************************************************************************
%* *
\subsection{Determining non-updatable right-hand-sides}
%* *
%************************************************************************
Top-level 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 :: (Name -> Bool) -> CoreExpr -> Bool
rhsIsStatic _is_dynamic_name 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 in_arg (Note n e) = notSccNote n && is_static in_arg e
is_static in_arg (Cast e _) = is_static in_arg e
is_static _ (Coercion {}) = True
is_static _ (Lit (MachLabel {})) = False
is_static _ (Lit _) = True
is_static in_arg other_expr = go other_expr 0
where
go (Var f) n_val_args
#if mingw32_TARGET_OS
| not (_is_dynamic_name (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 n f) n_val_args = notSccNote n && 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}