Note [inlineBoringOk]
See Note [INLINE for small functions] The function `inlineBoringOk` returns True (boringCxtOk) if the supplied unfolding, which looks like (\x y z. body), is such that the result of inlining a saturated call is no bigger than `body`. Some wrinkles: (IB1) An important case is - \x. (x `cast` co) (IB2) If `body` looks like a data constructor worker, we become keener to inline, by ignoring the number of arguments; we just insist they are all trivial. Reason: in a call like `f (g x y)`, if `g` unfolds to a data construtor, we can allocate a data constructor instead of a thunk (g x y). A case in point where a GADT data constructor failed to inline (#25713) $WK = /\a \x. K @a <co> x We really want to inline a boring call to $WK so that we allocate a data constructor not a thunk ($WK @ty x). But not for nullary constructors! We don't want to turn f ($WRefl @ty) into f (Refl @ty <co>) because the latter might allocate, whereas the former shares. (You might wonder if (Refl @ty <co>) should allocate, but I think that currently it does.) So for nullary constructors, `inlineBoringOk` returns False. (IB3) Types and coercions do not count towards the expression size. They are ultimately erased. (IB4) If there are no value arguments, `inlineBoringOk` we have to be careful (#17182). If we have let y = x @Int in f y y there’s no reason not to inline y at both use sites — no work is actually duplicated. But not so for coercion arguments! Unlike type arguments, which have no runtime representation, coercion arguments *do* have a runtime representation (albeit the zero-width VoidRep, see Note [Coercion tokens] in "GHC.CoreToStg"). For example: let y = g @Int <co> in g y y Here `co` is a value argument, and calling it twice might duplicate work. Even if `g` is a data constructor, so no work is duplicated, inlining `y` might duplicate allocation of a data constructor object (#17787). See also (IB2). TL;DR: if `is_fun` is False, so we have no value arguments, we /do/ count coercion arguments, despite (IB3). (IB5) You might wonder about an unfolding like (\x y z -> x (y z)), whose body is, in some sense, just as small as (g x y z). But `inlineBoringOk` doesn't attempt anything fancy; it just looks for a function call with trivial arguments, Keep it simple. (IB6) If we have an unfolding (K op) where K is a unary-class data constructor, we want to inline it! So that we get calls (f op), which in turn can see (in STG land) that `op` is already evaluated and properly tagged. (If `op` isn't trivial we will have baled out before we get to the Var case.) This made a big difference in benchmarks for the `effectful` library; details in !10479. See Note [Unary class magic] in GHC/Core/TyCon.
References 1
- INLINE for small functions GHC.Core.Unfold
Referenced by 3
- notWorthFloating GHC.Core.Opt.SetLevels
- Unary class magic GHC.Core.TyCon
- GHC.Core.Unfold call site