Note [notWorthFloating]
`notWorthFloating` returns True if the expression would be replaced by something
bigger than it is now. One big goal is that floating should be idempotent. Eg
if we replace e with (lvl79 x y) and then run FloatOut again, don't want to
replace (lvl79 x y) with (lvl83 x y)!
For example:
abs_vars = tvars only: return True if e is trivial,
but False for anything bigger
abs_vars = [x] (an Id): return True for trivial, or an application (f x)
but False for (f x x)
(NWF1a) It's important to float Integer literals, so that they get shared, rather
than being allocated every time round the loop. Hence the litIsTrivial.
Ditto literal strings (LitString), which we'd like to float to top
level, which is now possible.
(NWF1b) You might think that a literal should never be applied to a value
(hence n=0) but actually we can get (see test T23024):
RUBBISH @(a->b) (x::a)
See Note [Rubbish literals] in GHC.Types.Literal. (Mind you, we should be
in dead code at this point!)
(NWF2) We don’t float out variables applied only to type arguments, since the
extra binding would be pointless: type arguments are completely erased.
But *coercion* arguments aren’t (see Note [Coercion tokens] in
"GHC.CoreToStg" and Note [inlineBoringOk] in"GHC.Core.Unfold"),
so we still want to float out variables applied only to
coercion arguments.
(NWF3) Some expressions have trivial wrappers:
- Casts (e |> co)
- Unary-class applications:
- Dictionary applications (MkC meth)
- Class-op applictions (op dict)
- Case of empty alts
- Unsafe-equality case
In all these cases we say "not worth floating", and we do so /regardless/
of the wrapped expression. The SetLevels stuff may subsequently float the
components of the expression.
Example: is it worth floating (f x |> co)? No! If we did we'd get
lvl = f x |> co
...lvl....
Then we'd do cast worker/wrapper and end up with.
lvl' = f x
...(lvl' |> co)...
Silly! Better not to float it in the first place. If we say "no" here,
we'll subsequently say "yes" for (f x) and get
lvl = f x
....(lvl |> co)...
which is what we want. In short: don't float trivial wrappers.
(NWF4) The only non-trivial expression that we say "not worth floating" for
is an application
f x y z
where the number of value arguments is <= the number of abstracted Ids.
This is what makes floating idempotent. Hence counting the number of
value arguments in `go`
(NWF5) In #24471 we had something like
x1 = I# 1
...
x1000 = I# 1000
foo = f x1 (f x2 (f x3 ....))
So every sub-expression in `foo` has lots and lots of free variables. But
none of these sub-expressions float anywhere; the entire float-out pass is a
no-op.
So `notWorthFloating` tries to avoid evaluating `n_abs_vars`, in cases where
it obviously /is/ worth floating. (In #24471 it turned out that we were
testing `abs_vars` (a relatively complicated calculation that takes at least
O(n-free-vars) time to compute) for every sub-expression.)
Hence testing `n_abs_vars only` at the very end. References 3
- inlineBoringOk GHC.Core.Unfold
- Coercion tokens GHC.CoreToStg
- Rubbish literals GHC.Types.Literal
Referenced by 1
- GHC.Core.Opt.SetLevels call site