
#11272: Overloaded state-monadic function is not specialised -------------------------------------+------------------------------------- Reporter: NickSmallbone | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nfrisby): If I add the `INLINABLE overloaded` pragma in `A` and place a `SPECIALIZE overloaded :: Int -> Int -> State () ()` pragma in `B`, then the desired specialization ultimately happens (with GHC 7.10.2). I mention this as a possible workaround for people stuck on this bug. Forcing the `overloaded` wrapper to be specialized creates a "SPEC" rule whose RHS gets gently simplified enough before the Specialise pass such that GHC then notices the specializable call to the `$woverloaded` worker. Since that worker inherits the original `INLINABLE` pragma (see #6056), GHC automatically specializes the worker. The specialized worker eventually ends up in the RHS of `specialised`. This approach was not obvious to me because I hadn't yet realized that forcibly specializing a w/w wrapper function tends to cause the worker to be automatically specialized. Two shortcomings come immediately to mind. 1. I get the `SPECIALISE pragma on INLINE function probably won't fire: ‘overloaded’` warning, even though the rule does fire. 1. In my experience, `SPECIALIZE` pragmas are often rejected with "LHS too complicated to desugar" (e.g. #10555), so you may need to use `GHC.Exts.inline` instead. * Note that `inline` crucially causes the w/w wrapper to be inlined before the Specialise pass (during `Phase = InitialPhase [Gentle]`), whereas the w/w wrapper's `INLINE[0]` activation delays its natural inlining until after the Specialise pass. * This is awkward: we only want to inline `overloaded` '''if it was replaced by a w/w wrapper'''! A "safer" but more troublesome alternative is to have `inline overloaded` somewhere else in the module, but then you must ensure that it's exported from this module, else GHC will cull it and the SPEC rule before the rule can usefully affect `specialise`. This risks binary bloat, but it also prevents `inline` from ever accidentally inlining `overloaded` into the genuine code. It's remarkable that the w/w transform creates the cast that prevents the wrapper from being automatically specialized (that cast floats to the top of the unfolding, which blocks specialization; see `Note [Specialisation shape]` in `Specialise.hs`). The demand analyzer and w/w transform in this example see through the `State` type synonym, `StateT` newtype, and `Identity` newtype all the way to the `s -> (# a, s #)` worker type -- the `Specialise` pass does not yet have the complementary X-ray vision to see through the corresponding cast to the desired lambdas in the wrapper's unfolding. (#9509 is also specialization-blocked-by-a-cast-atop-the-unfolding, but I think the cast in that case comes from an actual bug.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/11272#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler