
#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
* Occasionally it's very important to inline `x`: see Trac #15519 for a real-world example. * 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.
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 = 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. -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15578#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler