[GHC] #14610: newtype wrapping of a monadic stack kills performance

GHC ghc-devs at haskell.org
Tue Jan 2 12:57:50 UTC 2018


#14610: newtype wrapping of a monadic stack kills performance
-------------------------------------+-------------------------------------
        Reporter:  mrkkrp            |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.6.1
       Component:  Compiler          |              Version:  8.2.2
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Runtime           |  Unknown/Multiple
  performance bug                    |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #14620            |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 > Maybe it is enough to relax the rule “The return type must not depend on
 any arguments” to “The return type must be representatoinally equal for
 all arguments” and that might allow us to e `cast` co to be a tail-call
 position

 Actually I think we may just be able to say that if `(f x)` is a tail
 call, then `(f x |> co)` is a tail call.  So in this code:
 {{{
 occAnal env (Cast expr co)
   = case occAnal env expr of { (usage, expr') ->
     let usage1 = zapDetailsIf (isRhsEnv env) usage
           -- usage1: if we see let x = y `cast` co
           -- then mark y as 'Many' so that we don't
           -- immediately inline y again.
         usage2 = addManyOccsSet usage1 (coVarsOfCo co)
           -- usage2: see Note [Gather occurrences of coercion variables]
     in (markAllNonTailCalled usage2, Cast expr' co)
     }
 }}}
 just remove the `markAllNonTailCalled`.  That call was in Luke's original
 join-point patch, but it seems over-conservative to me.

 That said, I'm intrigued about how this happens in practice, if it really
 does.  In the example given in comment:5, a single run of the simplifer
 removes the redundant casts, and for recursive join points the tail calls
 really must return the same type as the function itself, so the cast seems
 unlikely.  While the change above (removing `markAllNonTailCalled`) is ok
 (I think), I'm surprised if it has any effect.  An example would be great.

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


More information about the ghc-tickets mailing list