Function mz_transform::normalize_lets::inlining::inline_lets_core
source · pub(super) fn inline_lets_core(
expr: &mut MirRelationExpr,
inline_mfp: bool
) -> Result<(), TransformError>
Expand description
Considers inlining actions to perform for a sequence of bindings and a following body.
A let binding may be inlined only in subsequent bindings or in the body;
other bindings should not “immediately” observe the binding, as that
would be a change to the semantics of LetRec
. For example, it would
not be correct to replace C
with A
in the definition of B
here:
let A = ...;
let B = A - C;
let C = A;
The explanation is that B
should always be the difference between the
current and previous A
, and that the substitution of C
would instead
make it always zero, changing its definition.
Here a let binding is proposed for inlining if any of the following is true:
- It has a single reference across all bindings and the body.
- It is a “sufficiently simple”
Get
, determined in part by theinline_mfp
argument.
We don’t need extra checks for limits
, because
limits
is only relevant when a binding is directly used through a back edge (because that is where the rendering puts thelimits
check);- when a binding is directly used through a back edge, it can’t be inlined anyway.
- Also note that if a
LetRec
completely disappears at the end ofinline_lets_core
, then there was no recursion in it.
The case of Constant
binding is handled here (as opposed to
FoldConstants
) in a somewhat limited manner (see #18180). Although a
bit weird, constants should also not be inlined into prior bindings as
this does change the behavior from one where the collection is initially
empty to one where it is always the constant.
Having inlined bindings, many of them may now be dead (with no
transitive references from body
). These can now be removed. They may
not be exactly those bindings that were inlineable, as we may not always
be able to apply inlining due to ordering (we cannot inline a binding
into one that is not strictly later).