[GHC] #15578: Honour INLINE pragmas on 0-arity bindings

GHC ghc-devs at haskell.org
Thu Aug 30 08:07:07 UTC 2018


#15578: Honour INLINE pragmas on 0-arity bindings
-------------------------------------+-------------------------------------
        Reporter:  simonpj           |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.6.1
       Component:  Compiler          |              Version:  8.4.3
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------
Description changed by simonpj:

Old description:

> Currently if we see
> {{{
> x = factorial 200
> {-# INLINE x #-}
>
> f y = ...x...
> }}}
> we won't inline `x`, lest we duplicate the work of `factorial 200`.  But
> this caution has some bad consequences:
>
> * Suppose `x` is used exactly once, not inside a lambda, thus
> {{{
> x = blah
> {-# INLINE x #-}
> g = ...x...
> }}}
>     Then, if there is ''no'' INLINE pragma, `x` will get inlined (by
> `preInlineUnconditionally`. But if there ''is'' an INLINE pragma,
> currently `x` is ''not'' inlined by `preInlineUnconditionally`: see `Note
> [Stable unfoldings and preInlineUnconditionally]` in `SimplUtils`.  This
> is insane!
>
> * INLINE says "inline me at every saturated call", where "saturated" is
> determined by the number of arguments syntactically to the left of the
> "=" in the source bindings.  In this case, there are no arguments to the
> left, so every occurrence is saturated.  So it's inconsistent not to
> inline.
>
> * Occasionally it's very important to inline `x`: see Trac #15519 for a
> real-world example.  Ignoring the users explicit instruction to do so
> seems silly.
>
> Bottom line: if a 0-ary binding has an INLINE pragma, I think we should
> inline it at every use site
> * Regardless of the work duplication
> * Including inside lambdas
>
> Note, however, that there is a real risk that full laziness will float it
> right back out again.  Consider again
> {{{
> x = factorial 200
> {-# INLINE x #-}
> f y = ...x...
> }}}
> After inlining we get
> {{{
> f y = ...(factorial 200)...
> }}}
> but it's entirely possible that full laziness will do
> {{{
> lvl23 = factorial 200
> f y = l...lvl23...
> }}}
> That's a problem for another day.  Presumably the reason the user wanted
> to inline it was to get some rule to fire, and this change gives at least
> some chance that will happen, and makes INLINE behave consistently.

New description:

 Currently if we see
 {{{
 x = factorial 200
 {-# INLINE x #-}

 f y = ...x...
 }}}
 we won't inline `x`, lest we duplicate the work of `factorial 200`.  But
 this caution has some bad consequences:

 * Suppose `x` is used exactly once, not inside a lambda, thus
 {{{
 x = blah
 {-# INLINE x #-}
 g = ...x...
 }}}
     Then, if there is ''no'' INLINE pragma, `x` will get inlined (by
 `preInlineUnconditionally`. But if there ''is'' an INLINE pragma,
 currently `x` is ''not'' inlined by `preInlineUnconditionally`: see `Note
 [Stable unfoldings and preInlineUnconditionally]` in `SimplUtils`.  This
 is insane!

 * INLINE says "inline me at every saturated call", where "saturated" is
 determined by the number of arguments syntactically to the left of the "="
 in the source bindings.  In this case, there are no arguments to the left,
 so every occurrence is saturated.  So it's inconsistent not to inline.

 * Occasionally it's very important to inline `x`: see Trac #15519 for a
 real-world example.  Ignoring the users explicit instruction to do so
 seems silly.

 Bottom line: if a 0-ary binding has an INLINE pragma, I think we should
 inline it at every use site
 * Regardless of the work duplication
 * Including inside lambdas

 Note, however, that there is a real risk that full laziness will float it
 right back out again.  Consider again
 {{{
 x = factorial 200
 {-# INLINE x #-}
 f y = ...x...
 }}}
 After inlining we get
 {{{
 f y = ...(factorial 200)...
 }}}
 but it's entirely possible that full laziness will do
 {{{
 lvl23 = factorial 200
 f y = ...lvl23...
 }}}
 That's a problem for another day.  Presumably the reason the user wanted
 to inline it was to get some rule to fire, and this change gives at least
 some chance that will happen, and makes INLINE behave consistently.

--

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


More information about the ghc-tickets mailing list