[GHC] #13720: INLINE pragma semantics changed since 8.0.2

#13720: INLINE pragma semantics changed since 8.0.2 -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.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: -------------------------------------+------------------------------------- It now seems that unfoldings for INLINE things are optimised slightly. This causes different interactions with `RULES` than before. {{{#!hs module A where {-# INLINE f #-} f x = h x h x = x {-# RULES "h x" forall x . h x = error "REWRITE" #-} }}} {{{#!hs module B where import A qux = f 5 }}} Then running {{{
ghc-8.0.2 B.hs -O2 -fforce-recomp -ddump-simpl | grep qux -A5 qux :: Integer [GblId, Str=DmdType x] qux = error .... }}}
{{{
ghc-8.2.0.20170507 B.hs -O2 -fforce-recomp -ddump-simpl | grep qux -A5 qux :: Integer [GblId, Caf=NoCafRefs, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 100 0}] qux = 5 }}}
Inspecting the unfoldings, we see that 8.2 optimises the unfoldings to
inline `h` before the rule can apply.
{{{
d61439f58ce9c5a268304423a43b9b44
f :: p -> p
{- Arity: 1, HasNoCafRefs, Strictness: ,
Inline: (sat-args=1),
Unfolding: InlineRule (1, False, True) (\ @ p (x :: p) -> x) -}
}}}
Is this new behaviour intentional? It seems possible that it will break
some programs which use rewrite rules.
--
Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13720
GHC http://www.haskell.org/ghc/
The Glasgow Haskell Compiler

#13720: INLINE pragma semantics changed since 8.0.2 -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 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: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * cc: simonpj (added) Comment: Commit 2effe18ab51d66474724d38b20e49cc1b8738f60 (The Early Inline Patch) caused this. From that commit, I see a Note was added, which might explain why this behavior was adopted: {{{#!hs {- Note [Inline in InitialPhase] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In GHC 8 and earlier we did not inline anything in the InitialPhase. But that is confusing for users because when they say INLINE they expect the function to inline right away. So now we do inlining immediately, even in the InitialPhase, assuming that the Id's Activation allows it. This is a surprisingly big deal. Compiler performance improved a lot when I made this change: perf/compiler/T5837.run T5837 [stat too good] (normal) perf/compiler/parsing001.run parsing001 [stat too good] (normal) perf/compiler/T12234.run T12234 [stat too good] (optasm) perf/compiler/T9020.run T9020 [stat too good] (optasm) perf/compiler/T3064.run T3064 [stat too good] (normal) perf/compiler/T9961.run T9961 [stat too good] (normal) perf/compiler/T13056.run T13056 [stat too good] (optasm) perf/compiler/T9872d.run T9872d [stat too good] (normal) perf/compiler/T783.run T783 [stat too good] (normal) perf/compiler/T12227.run T12227 [stat too good] (normal) perf/should_run/lazy-bs-alloc.run lazy-bs-alloc [stat too good] (normal) perf/compiler/T1969.run T1969 [stat too good] (normal) perf/compiler/T9872a.run T9872a [stat too good] (normal) perf/compiler/T9872c.run T9872c [stat too good] (normal) perf/compiler/T9872b.run T9872b [stat too good] (normal) perf/compiler/T9872d.run T9872d [stat too good] (normal) -} }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13720#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13720: INLINE pragma semantics changed since 8.0.2 -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 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: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): BTW, there's a warning you get when compiling `A`: {{{ A.hs:9:11: warning: [-Winline-rule-shadowing] Rule "h x" may never fire because ‘h’ might inline first Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘h’ | 9 | {-# RULES "h x" forall x . h x = error "REWRITE" #-} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }}} If you follow GHC's advice: {{{#!hs module A where {-# INLINE f #-} f x = h x {-# INLINE[0] h #-} h x = x {-# RULES "h x" forall x . h x = error "REWRITE" #- }}} Then you get back the pre-8.2 behavior: {{{ $ /opt/ghc/8.2.1/bin/ghc B.hs -O2 -fforce-recomp -ddump-simpl | grep qux -A5 qux :: Integer [GblId, Str=x] qux = error .... }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13720#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13720: INLINE pragma semantics changed since 8.0.2 -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: invalid | 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: | -------------------------------------+------------------------------------- Changes (by simonpj): * status: new => closed * resolution: => invalid Comment: Yes, and the warning is spot on target. Without the pragma there is no reason to suppose that the rule would ever fire; that it did so before is a happy accident. So I think GHC is behaving as advertised. Re-open if you disagree. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13720#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13720: INLINE pragma semantics changed since 8.0.2 -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: invalid | 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: | -------------------------------------+------------------------------------- Comment (by mpickering): I feel that the user guide should be updated then to precisely state which optimisations will be performed on `INLINE` bindings. https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts... #inline-pragma It currently states that "GHC guarantees to inline precisely the code that you wrote, no more and no less." which doesn't seem to be true. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13720#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13720: INLINE pragma semantics changed since 8.0.2 -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: invalid | 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: | -------------------------------------+------------------------------------- Comment (by simonpj): Good point. But what it's doing is indistinguishable from that! If you optimise and then inline, it's the same as if you inline and the optimise -- provided you respect the phases, which GHC does. So I supose we could say "GHC guarantees to behave as if it had inlined precisely the code that you wrote, no more and no less". The "as if" is the important bit! -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13720#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC