floatExposesHNF,
- mkTyLamTryingEta, mkValLamTryingEta,
+ etaCoreExpr,
etaExpandCount,
type_ok_for_let_to_case
) where
-import Ubiq{-uitous-}
+IMP_Ubiq(){-uitous-}
+IMPORT_DELOOPER(SmplLoop) -- paranoia checking
import BinderInfo
-import CmdLineOpts ( SimplifierSwitch(..) )
+import CmdLineOpts ( opt_DoEtaReduction, SimplifierSwitch(..) )
import CoreSyn
-import CoreUtils ( manifestlyWHNF )
+import CoreUnfold ( SimpleUnfolding, mkFormSummary, FormSummary(..) )
import Id ( idType, isBottomingId, idWantsToBeINLINEd, dataConArgTys,
getIdArity, GenId{-instance Eq-}
)
-import IdInfo ( arityMaybe )
+import IdInfo ( ArityInfo(..) )
import Maybes ( maybeToBool )
import PrelVals ( augmentId, buildId )
import PrimOp ( primOpIsCheap )
import SimplEnv
import SimplMonad
-import Type ( eqTy, isPrimType, maybeAppDataTyConExpandingDicts, getTyVar_maybe )
+import Type ( tyVarsOfType, isPrimType, maybeAppDataTyConExpandingDicts )
import TysWiredIn ( realWorldStateTy )
-import TyVar ( GenTyVar{-instance Eq-} )
+import TyVar ( elementOfTyVarSet,
+ GenTyVar{-instance Eq-} )
import Util ( isIn, panic )
\end{code}
try (App (App (Var bld) _) _) | bld == buildId = True
try (App (App (App (Var aug) _) _) _) | aug == augmentId = True
- try other = manifestlyWHNF other
- {- but *not* necessarily "manifestlyBottom other"...
+ try other = case mkFormSummary other of
+ VarForm -> True
+ ValueForm -> True
+ other -> False
+ {- but *not* necessarily "BottomForm"...
We may want to float a let out of a let to expose WHNFs,
but to do that to expose a "bottom" is a Bad Idea:
try_deflt (BindDefault _ rhs) = try rhs
\end{code}
+Eta reduction
+~~~~~~~~~~~~~
+@etaCoreExpr@ trys an eta reduction at the top level of a Core Expr.
-Eta reduction on ordinary lambdas
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We have a go at doing
+e.g. \ x y -> f x y ===> f
- \ x y -> f x y ===> f
+It is used
+ a) Before constructing an Unfolding, to
+ try to make the unfolding smaller;
+ b) In tidyCoreExpr, which is done just before converting to STG.
But we only do this if it gets rid of a whole lambda, not part.
The idea is that lambdas are often quite helpful: they indicate
gives rise to a recursive function for the list comprehension, and
f turns out to be just a single call to this recursive function.
-\begin{code}
-mkValLamTryingEta :: [Id] -- Args to the lambda
- -> CoreExpr -- Lambda body
- -> CoreExpr
+Doing eta on type lambdas is useful too:
-mkValLamTryingEta [] body = body
+ /\a -> <expr> a ===> <expr>
-mkValLamTryingEta orig_ids body
- = reduce_it (reverse orig_ids) body
- where
- bale_out = mkValLam orig_ids body
+where <expr> doesn't mention a.
+This is sometimes quite useful, because we can get the sequence:
+
+ f ab d = let d1 = ...d... in
+ letrec f' b x = ...d...(f' b)... in
+ f' b
+specialise ==>
+
+ f.Int b = letrec f' b x = ...dInt...(f' b)... in
+ f' b
+
+float ==>
+
+ f' b x = ...dInt...(f' b)...
+ f.Int b = f' b
+
+Now we really want to simplify to
+
+ f.Int = f'
+
+and then replace all the f's with f.Ints.
+
+N.B. We are careful not to partially eta-reduce a sequence of type
+applications since this breaks the specialiser:
- reduce_it [] residual
- | residual_ok residual = residual
- | otherwise = bale_out
+ /\ a -> f Char# a =NO=> f Char#
- reduce_it (id:ids) (App fun (VarArg arg))
- | id == arg
- && not (idType id `eqTy` realWorldStateTy)
- -- *never* eta-reduce away a PrimIO state token! (WDP 94/11)
- = reduce_it ids fun
+\begin{code}
+etaCoreExpr :: CoreExpr -> CoreExpr
- reduce_it ids other = bale_out
- is_elem = isIn "mkValLamTryingEta"
+etaCoreExpr expr@(Lam bndr body)
+ | opt_DoEtaReduction
+ = case etaCoreExpr body of
+ App fun arg | eta_match bndr arg &&
+ residual_ok fun
+ -> fun -- Eta
+ other -> expr -- Can't eliminate it, so do nothing at all
+ where
+ eta_match (ValBinder v) (VarArg v') = v == v'
+ eta_match (TyBinder tv) (TyArg ty) = tv `elementOfTyVarSet` tyVarsOfType ty
+ eta_match bndr arg = False
- -----------
residual_ok :: CoreExpr -> Bool -- Checks for type application
-- and function not one of the
-- bound vars
- residual_ok (Var v) = not (v `is_elem` orig_ids)
- -- Fun mustn't be one of the bound ids
+ residual_ok (Var v)
+ = not (eta_match bndr (VarArg v))
residual_ok (App fun arg)
- | notValArg arg = residual_ok fun
- residual_ok other = False
+ | eta_match bndr arg = False
+ | otherwise = residual_ok fun
+ residual_ok (Coerce coercion ty body)
+ | eta_match bndr (TyArg ty) = False
+ | otherwise = residual_ok body
+
+ residual_ok other = False -- Safe answer
+ -- This last clause may seem conservative, but consider:
+ -- primops, constructors, and literals, are impossible here
+ -- let and case are unlikely (the argument would have been floated inside)
+ -- SCCs we probably want to be conservative about (not sure, but it's safe to be)
+
+etaCoreExpr expr = expr -- The common case
\end{code}
+
Eta expansion
~~~~~~~~~~~~~
| isBottomingId v -- Bottoming ids have "infinite arity"
= 10000 -- Blargh. Infinite enough!
-eta_fun expr@(Var v)
- | maybeToBool arity_maybe -- We know the arity
- = arity
- where
- arity_maybe = arityMaybe (getIdArity v)
- arity = case arity_maybe of { Just arity -> arity }
+eta_fun expr@(Var v) = idMinArity v
eta_fun other = 0 -- Give up
\end{code}
num_val_args == 0 || -- Just a type application of
-- a variable (f t1 t2 t3)
-- counts as WHNF
- case (arityMaybe (getIdArity f)) of
- Nothing -> False
- Just arity -> num_val_args < arity
+ num_val_args < idMinArity f
_ -> False
}
-\end{code}
-
-Eta reduction on type lambdas
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We have a go at doing
-
- /\a -> <expr> a ===> <expr>
-
-where <expr> doesn't mention a.
-This is sometimes quite useful, because we can get the sequence:
-
- f ab d = let d1 = ...d... in
- letrec f' b x = ...d...(f' b)... in
- f' b
-specialise ==>
-
- f.Int b = letrec f' b x = ...dInt...(f' b)... in
- f' b
-
-float ==>
-
- f' b x = ...dInt...(f' b)...
- f.Int b = f' b
-
-Now we really want to simplify to
-
- f.Int = f'
-
-and then replace all the f's with f.Ints.
-
-N.B. We are careful not to partially eta-reduce a sequence of type
-applications since this breaks the specialiser:
-
- /\ a -> f Char# a =NO=> f Char#
-
-\begin{code}
-mkTyLamTryingEta :: [TyVar] -> CoreExpr -> CoreExpr
-
-mkTyLamTryingEta tyvars tylam_body
- = if
- tyvars == tyvar_args && -- Same args in same order
- check_fun fun -- Function left is ok
- then
- -- Eta reduction worked
- fun
- else
- -- The vastly common case
- mkTyLam tyvars tylam_body
- where
- (tyvar_args, fun) = strip_tyvar_args [] tylam_body
-
- strip_tyvar_args args_so_far tyapp@(App fun (TyArg ty))
- = case getTyVar_maybe ty of
- Just tyvar_arg -> strip_tyvar_args (tyvar_arg:args_so_far) fun
- Nothing -> (args_so_far, tyapp)
- strip_tyvar_args args_so_far (App _ (UsageArg _))
- = panic "SimplUtils.mkTyLamTryingEta: strip_tyvar_args UsageArg"
-
- strip_tyvar_args args_so_far fun
- = (args_so_far, fun)
-
- check_fun (Var f) = True -- Claim: tyvars not mentioned by type of f
- check_fun other = False
\end{code}
+
Let to case
~~~~~~~~~~~
then False
else idWantsToBeINLINEd id
+idMinArity id = case getIdArity id of
+ UnknownArity -> 0
+ ArityAtLeast n -> n
+ ArityExactly n -> n
+
type_ok_for_let_to_case :: Type -> Bool
type_ok_for_let_to_case ty