-- Inlining,
preInlineUnconditionally, postInlineUnconditionally,
- activeInline, activeRule, inlineMode,
+ activeInline, activeRule,
-- The continuation type
SimplCont(..), DupFlag(..), ArgInfo(..),
contIsDupable, contResultType, contIsTrivial, contArgs, dropArgs,
- countValArgs, countArgs, splitInlineCont,
+ countValArgs, countArgs,
mkBoringStop, mkLazyArgStop, contIsRhsOrArg,
interestingCallContext, interestingArgContext,
dropArgs 0 cont = cont
dropArgs n (ApplyTo _ _ _ cont) = dropArgs (n-1) cont
dropArgs n other = pprPanic "dropArgs" (ppr n <+> ppr other)
-
---------------------
-splitInlineCont :: SimplCont -> Maybe (SimplCont, SimplCont)
--- Returns Nothing if the continuation should dissolve an InlineMe Note
--- Return Just (c1,c2) otherwise,
--- where c1 is the continuation to put inside the InlineMe
--- and c2 outside
-
--- Example: (__inline_me__ (/\a. e)) ty
--- Here we want to do the beta-redex without dissolving the InlineMe
--- See test simpl017 (and Trac #1627) for a good example of why this is important
-
-splitInlineCont (ApplyTo dup (Type ty) se c)
- | Just (c1, c2) <- splitInlineCont c = Just (ApplyTo dup (Type ty) se c1, c2)
-splitInlineCont cont@(Stop {}) = Just (mkBoringStop, cont)
-splitInlineCont cont@(StrictBind {}) = Just (mkBoringStop, cont)
-splitInlineCont cont@(StrictArg {}) = Just (mkBoringStop, cont)
-splitInlineCont _ = Nothing
\end{code}
interestingCallContext cont
= interesting cont
where
- interestingCtxt = ArgCtxt False 2 -- Give *some* incentive!
-
interesting (Select _ bndr _ _ _)
- | isDeadBinder bndr = CaseCtxt
- | otherwise = interestingCtxt
+ | isDeadBinder bndr = CaseCtxt
+ | otherwise = ArgCtxt False 2 -- If the binder is used, this
+ -- is like a strict let
- interesting (ApplyTo {}) = interestingCtxt
- -- Can happen if we have (coerce t (f x)) y
- -- Perhaps interestingCtxt is a bit over-keen, but I've
- -- seen (coerce f) x, where f has an INLINE prag,
- -- So we have to give some motivation for inlining it
+ interesting (ApplyTo _ arg _ cont)
+ | isTypeArg arg = interesting cont
+ | otherwise = ValAppCtxt -- Can happen if we have (f Int |> co) y
+ -- If f has an INLINE prag we need to give it some
+ -- motivation to inline. See Note [Cast then apply]
+ -- in CoreUnfold
interesting (StrictArg _ cci _ _) = cci
interesting (StrictBind {}) = BoringCtxt
vanilla_discounts, arg_discounts :: [Int]
vanilla_discounts = repeat 0
arg_discounts = case idUnfolding fun of
- CoreUnfolding _ _ _ _ (UnfoldIfGoodArgs _ discounts _ _)
+ CoreUnfolding {uf_guidance = UnfoldIfGoodArgs {ug_args = discounts}}
-> discounts ++ vanilla_discounts
_ -> vanilla_discounts
INLINE pragmas
~~~~~~~~~~~~~~
-SimplGently is also used as the mode to simplify inside an InlineMe note.
-
-\begin{code}
-inlineMode :: SimplifierMode
-inlineMode = SimplGently
-\end{code}
-
+We don't simplify inside InlineRules (which come from INLINE pragmas).
It really is important to switch off inlinings inside such
expressions. Consider the following example
activeRule :: DynFlags -> SimplEnv -> Maybe (Activation -> Bool)
-- Nothing => No rules at all
activeRule dflags env
- | not (dopt Opt_RewriteRules dflags)
+ | not (dopt Opt_EnableRewriteRules dflags)
= Nothing -- Rewriting is off
| otherwise
= case getMode env of
So it's important to to the right thing.
-* 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. Instead, look at the unfolding.
+* 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.
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.
tryEtaReduce bndrs body
= go (reverse bndrs) body
where
+ incoming_arity = count isId bndrs
+
go (b : bs) (App fun arg) | ok_arg b arg = go bs fun -- Loop round
go [] fun | ok_fun fun = Just fun -- Success!
go _ _ = Nothing -- Failure!
&& (ok_fun_id fun_id || all ok_lam bndrs)
ok_fun _fun = False
- ok_fun_id fun
- | isLocalId fun = isEvaldUnfolding (idUnfolding fun)
- | isDataConWorkId fun = True
- | isGlobalId fun = idArity fun > 0
- | otherwise = panic "tryEtaReduce/ok_fun_id"
+ ok_fun_id fun = fun_arity fun >= incoming_arity
+
+ fun_arity fun -- See Note [Arity care]
+ | isLocalId fun && isLoopBreaker (idOccInfo fun) = 0
+ | otherwise = idArity fun
ok_lam v = isTyVar v || isDictId v
_ -> return [(DEFAULT, [], deflt_rhs)]
- | debugIsOn, isAlgTyCon tycon, [] <- tyConDataCons tycon
+ | debugIsOn, isAlgTyCon tycon, not (isOpenTyCon tycon), null (tyConDataCons tycon)
+ -- This can legitimately happen for type families, so don't report that
= pprTrace "prepareDefault" (ppr case_bndr <+> ppr tycon)
- -- This can legitimately happen for type families
$ return [(DEFAULT, [], deflt_rhs)]
--------- Catch-all cases -----------