Do two-phase inlining in simpleOptPgm
As of #12988 (closed), having simpleOptPgm
leave β-redexes lying around is painful because it requires a special loophole in Core Lint to allow a jump inside a β-redex. We'd rather use a two-phase approach, mirroring the simplifier's preInlineUnconditionally
and postInlineUnconditionally
, so we can aggressively eliminate β-redexes without fear of exponential blowup.
Consider:
joinrec j1 x = e1 in
join j2 x y = jump j1 e2 in
jump j2 e3 e4
Since j2
is only used once, it gets inlined. But simpleOptPgm
only performs inlining //after// a binding is simplified, so we end up here:
joinrec j1 x = e1' in
(\x y -> jump j1 e2') e3' e4'
Since e2'
was already simplified, performing the β-reduction here risks exponential blowup for the same reason it can happen in the simplifier (see the Secrets paper; perf/compiler/T783
is a live example, increasing in allocs by over 80% if we re-simplify here). We //could// just let
-bind e3'
and e4'
(carefully avoiding capturing free occurrences of x
in e4'
), but not if one them is actually a type argument. Well, okay, we //could// introduce a type let
, but doing that here means the desugarer can now return a type let
and we're not prepared for that. (Specifically, under certain circumstances, the simplifier never runs in between the desugarer and Float Out, and the latter breaks in the presence of type let
.)
So for the moment, we leave the β-redex there, but this needs a special rule just for β-redexes because normally you can't have a jump under a lambda (or an application, for that matter). In the long term, we'd prefer to take the simplifier's approach instead: If we want to inline something because it only occurs once (even though it may be big), we add it to the substitution //before// simplifying it so that we only simplify it once. This means the substitution has to carry lexical closures around, though, just like the simplifier does (see SimplSR
's ContEx
disjunct), so it's not trivial.
The simpleOptPgm
β-redexes are the only reason for the special rule in Core Lint (see Note [Beta redexes] in CoreLint.hs
), so once this is done we can be rid of that.
Trac metadata
Trac field | Value |
---|---|
Version | 8.1 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |