Account for evaluatedness of scrutinees in `sizeExpr`
The motivation for !12239 boils down to the following. Consider the following functions:
f1 xs = case xs of xs' { __DEFAULT ->
let t = blah xs'
in
case xs' of {
[] -> (t, True)
_:_ -> (t, False)
}}
f2 xs =
let t = blah xs
in
case xs of {
[] -> (t, True)
_:_ -> (t, False)
}
These two functions are semantically equivalent. It might appear that f1
is larger than f2
, since the former has one extra case
statement, but in fact due to tag inference the two functions will generate nearly the same amount of code: In f1
the outer case xs
will perform an eval and the inner case xs'
will perform a branch but no eval, while in f2
the case xs
will perform both an eval and a branch. (f2
will probably actually generate slightly more code because it has to store an extra free variable t
across the call to xs.)
But this subtlety is lost on sizeExpr
, which ultimately drives our inlining decisions. We should improve sizeExpr
so that the f1
form of this function is no less likely to inline than the f2
form.
(!12239 proposes to rewrite f1
into f2
in the hopes of slightly better inlining, even though f2
is arguably just plain worse: If t
is ever entered, xs
will certainly already have been evaluated but blah
may only get a pointer to the location of the original thunk (now containing an IND if GC hasn't run yet) rather a pointer to the properly evaluated result xs'
of evaluating xs
.)