[GHC] #14948: A program which benefits from a late specialisation pass

#14948: A program which benefits from a late specialisation pass -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 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: -------------------------------------+------------------------------------- In this repo there is a small program which performs much better with a late specialisation pass. There is a plugin which implements this pass. Instructions about how to build the repo are in the README. https://github.com/mpickering/legendary-train Without plugin {{{ time benchmarks () real 0m0.112s }}} With plugin (comparable to hand-written code) {{{ time benchmarks () real 0m0.049s }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14948 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14948: A program which benefits from a late specialisation pass -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 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 simonpj): Interesting! Do you have any insight about ''why'' it benefits from late specialisaion? In general that's unusual. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14948#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14948: A program which benefits from a late specialisation pass -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 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 mpickering): The code in question first uses a type class to generate an overloaded function. The overloaded function is not immediately apparent, it is defined in terms of combinators which must be inlined and then later we get calls of `fmap` next to a dictionary which can be specialised upon. Diffing the core output immediately shows where the difference is. In the bad version we have lots of calls to `fmap` which are not eliminated because the function they are contained in is not specialised. {{{ 1486,1497c1514,1560 < -- RHS size: {terms: 13, types: 12, coercions: 13, joins: 0/0} < $s$fGHasTypeskaK1_$cgtypes_$s$dHastypes' < $s$fGHasTypeskaK1_$cgtypes_$s$dHastypes' < = \ eta_B2 eta1_B1 -> < case eta1_B1 of { < [] -> [] `cast` Co:4; < : g1_ab8Q g2_ab8R -> < (: ((eta_B2 g1_ab8Q) `cast` Co:2) < (($s$fGHasTypeskaK1_$cgtypes_$s$dHastypes' eta_B2 g2_ab8R) < `cast` Co:3)) < `cast` Co:4 < } ---
-- RHS size: {terms: 63, types: 791, coercions: 308, joins: 0/0} $s$fGHasTypeskaK1_$cgtypes1 $s$fGHasTypeskaK1_$cgtypes1 = \ @ f_a5xv $dApplicative_a5xx eta_B2 eta1_B1 -> fmap ($p1Applicative $dApplicative_a5xx) $fGeneric[]_$cto ((fmap ($p1Applicative $dApplicative_a5xx) ($s$fGHasTypeskaK1_$cgtypes8 `cast` Co:121) (case eta1_B1 of { [] -> fmap ($p1Applicative $dApplicative_a5xx) L1 (fmap ($p1Applicative $dApplicative_a5xx) ($s$fGHasTypeskaK1_$cgtypes7 `cast` Co:22) (pure $dApplicative_a5xx U1)); : g1_abai g2_abaj -> fmap ($p1Applicative $dApplicative_a5xx) R1 (fmap ($p1Applicative $dApplicative_a5xx) ($s$fGHasTypeskaK1_$cgtypes6 `cast` Co:78) (<*> $dApplicative_a5xx (fmap ($p1Applicative $dApplicative_a5xx) :*: (fmap ($p1Applicative $dApplicative_a5xx) ($s$fGHasTypeskaK1_$cgtypes5 `cast` Co:28) (fmap ($p1Applicative $dApplicative_a5xx) ($s$fGHasTypeskaK1_$cgtypes4 `cast` Co:11) (eta_B2 g1_abai)))) (fmap ($p1Applicative $dApplicative_a5xx) ($s$fGHasTypeskaK1_$cgtypes3 `cast` Co:28) (fmap ($p1Applicative $dApplicative_a5xx) ($s$fGHasTypeskaK1_$cgtypes2 `cast` Co:13) ($s$fGHasTypeskaK1_$cgtypes1 $dApplicative_a5xx eta_B2 g2_abaj))))) })) `cast` Co:7) }}}
-- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14948#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

$s$fGHasTypeskaK1_$cgtypes1 = \ @ f_a5xv $dApplicative_a5xx eta_B2 eta1_B1 -> }}} It has a dictionary argument so it'd ususally have been specialised earlier. Looking at it, it could originally have been a function of type {{{ foo :: forall a. C a => foralll b. D b => blah }}} Now, I think the specialiser might specialise only one "layer" of a function like that at a time. And ''that'' might be fixable, if that's
#14948: A program which benefits from a late specialisation pass -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 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 simonpj): The odd thing is that this function still exists {{{ the problem. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14948#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14948: A program which benefits from a late specialisation pass -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 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 dfeuer): I don't know if this is related. I asked Johan Tibell the other day why `unordered-containers` marks almost everything `INLINE` instead of `INLINABLE`. He replied that when an `INLINE` function calls an `INLINABLE` one, we end up calling to specialize. He also indicated that he'd opened a ticket about this long ago; I don't know which one. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14948#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14948: A program which benefits from a late specialisation pass -------------------------------------+------------------------------------- Reporter: mpickering | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.2 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 dfeuer): * cc: dfeuer (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14948#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC