[GHC] #13208: Do two-phase inlining in simpleOptPgm

GHC ghc-devs at haskell.org
Mon Jan 30 06:32:33 UTC 2017


#13208: Do two-phase inlining in simpleOptPgm
-------------------------------------+-------------------------------------
           Reporter:  lukemaurer     |             Owner:
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.1
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 As of #12988, 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.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13208>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list