-preInlineUnconditionally bndr
- = case getInlinePragma bndr of
- ICanSafelyBeINLINEd InsideLam _ -> False
- ICanSafelyBeINLINEd not_in_lam True -> True -- Not inside a lambda,
- -- one occurrence ==> safe!
- other -> False
-
-
-postInlineUnconditionally :: InId -> OutExpr -> Bool
- -- Examines a (bndr = rhs) binding, AFTER the rhs has been simplified
- -- It returns True if it's ok to discard the binding and inline the
- -- RHS at every use site.
-
- -- NOTE: This isn't our last opportunity to inline.
- -- We're at the binding site right now, and
- -- we'll get another opportunity when we get to the ocurrence(s)
-
-postInlineUnconditionally bndr rhs
- | isExported bndr
- = False
- | otherwise
- = case getInlinePragma bndr of
- IAmALoopBreaker -> False
- IMustNotBeINLINEd -> False
- IAmASpecPragmaId -> False -- Don't discard SpecPrag Ids
-
- ICanSafelyBeINLINEd InsideLam one_branch -> exprIsTrivial rhs
- -- Don't inline even WHNFs inside lambdas; this
- -- isn't the last chance; see NOTE above.
-
- ICanSafelyBeINLINEd not_in_lam one_branch -> one_branch || exprIsDupable rhs
-
- other -> exprIsTrivial rhs -- Duplicating is *free*
- -- NB: Even IWantToBeINLINEd and IMustBeINLINEd are ignored here
- -- Why? Because we don't even want to inline them into the
- -- RHS of constructor arguments. See NOTE above
-
-inlineCase bndr scrut
- = case getInlinePragma bndr of
- -- Not expecting IAmALoopBreaker etc; this is a case binder!
-
- ICanSafelyBeINLINEd StrictOcc one_branch
- -> one_branch || exprIsDupable scrut
- -- This case is the entire reason we distinguish StrictOcc from LazyOcc
- -- We want eliminate the "case" only if we aren't going to
- -- build a thunk instead, and that's what StrictOcc finds
- -- For example:
- -- case (f x) of y { DEFAULT -> g y }
- -- Here we DO NOT WANT:
- -- g (f x)
- -- *even* if g is strict. We want to avoid constructing the
- -- thunk for (f x)! So y gets a LazyOcc.
-
- other -> exprIsTrivial scrut -- Duplication is free
- && ( isUnLiftedType (idType bndr)
- || scrut_is_evald_var -- So dropping the case won't change termination
- || isStrict (getIdDemandInfo bndr)) -- It's going to get evaluated later, so again
- -- termination doesn't change
- where
- -- Check whether or not scrut is known to be evaluted
- -- It's not going to be a visible value (else the previous
- -- blob would apply) so we just check the variable case
- scrut_is_evald_var = case scrut of
- Var v -> isEvaldUnfolding (getIdUnfolding v)
- other -> False
-\end{code}
-
-okToInline is used at call sites, so it is a bit more generous.
-It's a very important function that embodies lots of heuristics.
-
-\begin{code}
-okToInline :: SwitchChecker
- -> InScopeEnv
- -> Id -- The Id
- -> FormSummary -- The thing is WHNF or bottom;
- -> UnfoldingGuidance
- -> SimplCont
- -> Bool -- True <=> inline it
-
--- A non-WHNF can be inlined if it doesn't occur inside a lambda,
--- and occurs exactly once or
--- occurs once in each branch of a case and is small
---
--- If the thing is in WHNF, there's no danger of duplicating work,
--- so we can inline if it occurs once, or is small
-
-okToInline sw_chkr in_scope id form guidance cont
- =
-#ifdef DEBUG
- if opt_D_dump_inlinings then
- pprTrace "Considering inlining"
- (ppr id <+> vcat [text "inline prag:" <+> ppr inline_prag,
- text "whnf" <+> ppr whnf,
- text "small enough" <+> ppr small_enough,
- text "some benefit" <+> ppr some_benefit,
- text "arg evals" <+> ppr arg_evals,
- text "result scrut" <+> ppr result_scrut,
- text "ANSWER =" <+> if result then text "YES" else text "NO"])
- result
- else
-#endif
- result
- where
- result =
- case inline_prag of
- IAmDead -> pprTrace "okToInline: dead" (ppr id) False
- IAmASpecPragmaId -> False
- IMustNotBeINLINEd -> False
- IAmALoopBreaker -> False
- IMustBeINLINEd -> True -- If "essential_unfoldings_only" is true we do no inlinings at all,
- -- EXCEPT for things that absolutely have to be done
- -- (see comments with idMustBeINLINEd)
- IWantToBeINLINEd -> inlinings_enabled
- ICanSafelyBeINLINEd inside_lam one_branch
- -> inlinings_enabled && (unfold_always || consider_single inside_lam one_branch)
- NoInlinePragInfo -> inlinings_enabled && (unfold_always || consider_multi)
-
- inlinings_enabled = not (switchIsOn sw_chkr EssentialUnfoldingsOnly)
- unfold_always = unfoldAlways guidance
-
- -- Consider benefit for ICanSafelyBeINLINEd
- consider_single inside_lam one_branch
- = (small_enough || one_branch) && some_benefit && (whnf || not_inside_lam)
- where
- not_inside_lam = case inside_lam of {InsideLam -> False; other -> True}
-
- -- Consider benefit for NoInlinePragInfo
- consider_multi = whnf && small_enough && some_benefit
- -- We could consider using exprIsCheap here,
- -- as in postInlineUnconditionally, but unlike the latter we wouldn't
- -- necessarily eliminate a thunk; and the "form" doesn't tell
- -- us that.
-
- inline_prag = getInlinePragma id
- whnf = whnfOrBottom form
- small_enough = smallEnoughToInline id arg_evals result_scrut guidance
- (arg_evals, result_scrut) = get_evals cont
-
- -- some_benefit checks that *something* interesting happens to
- -- the variable after it's inlined.
- some_benefit = contIsInteresting cont
-
- -- Finding out whether the args are evaluated. This isn't completely easy
- -- because the args are not yet simplified, so we have to peek into them.
- get_evals (ApplyTo _ arg (te,ve) cont)
- | isValArg arg = case get_evals cont of
- (args, res) -> (get_arg_eval arg ve : args, res)
- | otherwise = get_evals cont
-
- get_evals (Select _ _ _ _ _) = ([], True)
- get_evals other = ([], False)
-
- get_arg_eval (Con con _) ve = isWHNFCon con
- get_arg_eval (Var v) ve = case lookupVarEnv ve v of
- Just (SubstMe e' _ ve') -> get_arg_eval e' ve'
- Just (Done (Con con _)) -> isWHNFCon con
- Just (Done (Var v')) -> get_var_eval v'
- Just (Done other) -> False
- Nothing -> get_var_eval v
- get_arg_eval other ve = False
-
- get_var_eval v = case lookupVarSet in_scope v of
- Just v' -> isEvaldUnfolding (getIdUnfolding v')
- Nothing -> isEvaldUnfolding (getIdUnfolding v)
-
-
-contIsInteresting :: SimplCont -> Bool
-contIsInteresting Stop = False
-contIsInteresting (ArgOf _ _ _) = False
-contIsInteresting (ApplyTo _ (Type _) _ cont) = contIsInteresting cont
-contIsInteresting (CoerceIt _ _ _ cont) = contIsInteresting cont
-
--- See notes below on why a case with only a DEFAULT case is not intersting
--- contIsInteresting (Select _ _ [(DEFAULT,_,_)] _ _) = False
-
-contIsInteresting _ = True