[GHC] #13479: Core Lint issues during slowtest

GHC ghc-devs at haskell.org
Tue Mar 28 20:13:27 UTC 2017


#13479: Core Lint issues during slowtest
-------------------------------------+-------------------------------------
        Reporter:  bgamari           |                Owner:  nomeata
            Type:  bug               |               Status:  new
        Priority:  high              |            Milestone:  8.2.1
       Component:  Compiler          |              Version:  8.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Compile-time      |  Unknown/Multiple
  crash or panic                     |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #10181            |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by nomeata):

 The problem is that Call Arity has not been changed to know about the
 special semantics of join points. This is the code for in question:

 {{{
 f :: forall a. [Int] -> a
 [LclIdX,
  Arity=1,
  Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
          WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 128 0}]
 f = \ (@ a_a1iy) (a_XX6 :: [Int]) ->
       let {
         z_a34C :: Integer -> a_a1iy
         [LclId,
          CallArity=1,
          Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False,
                  WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 28
 0}]
         z_a34C
           = joinrec {
               go_a34D [Occ=LoopBreaker] :: [Int] -> Integer -> a_a1iy
               [LclId[JoinId(1)],
                Arity=1,
                CallArity=2,
                Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True,
 ConLike=True,
                        WorkFree=True, Expandable=True, Guidance=IF_ARGS
 [30] 24 0}]
               go_a34D (ds_a34E :: [Int])
                 = case ds_a34E of {
                     [] -> case lvl_s4VT of wild_00 { };
                     : y_a34J ys_a34K -> jump go_a34D ys_a34K
                   }; } in
             jump go_a34D a_XX6 } in
       letrec {
         go_a34D [Occ=LoopBreaker] :: [Int] -> Integer -> a_a1iy
         [LclId,
          Arity=1,
          CallArity=2,
          Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                  WorkFree=True, Expandable=True, Guidance=IF_ARGS [30] 40
 0}]
         go_a34D
           = \ (ds_a34E :: [Int]) ->
               case ds_a34E of {
                 [] -> z_a34C;
                 : y_a34J ys_a34K -> go_a34D ys_a34K
               }; } in
       go_a34D a_XX6 lvl_s4VV
 }}}

 Call Arity (which analyzes things from bottom to top) correctly finds out
 that the bottom `go_a34D` should have arity 2 (it is called with two
 arguments, and keeps passing the second one around). This implies that
 `z_a34C` is called with one argument, so that gets `CallArity=1`. From
 this Call Arity follows that to first `go_a34D` (the join point) should
 also have arity two, and it records it so.

 The subsequent simplification then eta-expands the `go_a34D` function,
 which turns it into a join point (yay!). But it does not *not* eta-expand
 the join point `go_a34D` (which gets renamed to `go_X45x`):

 {{{
 f = \ (@ a_a1iy) (a_XX6 :: [Int]) ->
       joinrec {
         go_a34D [Occ=LoopBreaker] :: [Int] -> Integer -> a_a1iy
         [LclId[JoinId(2)],
          Arity=2,
          CallArity=2,
          Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                  WorkFree=True, Expandable=True, Guidance=IF_ARGS [36 0]
 54 0}]
         go_a34D (ds_a34E :: [Int]) (eta_B1 :: Integer)
           = case ds_a34E of {
               [] ->
                 joinrec {
                   go_X35x [Occ=LoopBreaker] :: [Int] -> a_a1iy
                   [LclId[JoinId(1)],
                    Arity=1,
                    CallArity=2,
                    Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True,
 ConLike=True,
                            WorkFree=True, Expandable=True,
 Guidance=IF_ARGS [30] 24 0}]
                   go_X35x (ds_X35z :: [Int])
                     = case ds_X35z of {
                         [] -> case lvl_s4VT of wild_00 { };
                         : y_a34J ys_a34K -> jump go_X35x ys_a34K
                       }; } in
                 jump go_X35x a_XX6;
               : y_a34J ys_a34K -> jump go_a34D ys_a34K eta_B1
             }; } in
       jump go_a34D a_XX6 lvl_s4VV
 }}}

 At this point, something went wrong. The now named `go_X45x` is still
 marked as having CallArity=2, but it does not actually have that arity!

 Where did the argument `eta_B1`, which I would have expected to be passed
 to `go_X35x`, disappear? Was it “pushed into the branches”, and then into
 the empty set branches of the empty case there?

 So the simplifier uses the function `tryEtaExpandRhs` to try to eta-expand
 if Call Arity tells it to do so, but it does not even try that for join
 points (see `completeBind` in `Simplify`). I am a bit lost in the code
 right now and cannot quite reproduce what precisely is happening here.
 Something related to `simplJoinRHS` and “Context goes *inside* the
 lambdas.” Certainly, Luke’s opinion would be welcome.

 In any case, I believe the fix is to have the simplifier to simply zap
 Call Arity information. It is the only place where it is actually used,
 and as this demonstrates, the simplifier does not preserve Call Arity
 information. I will prepare a PR for this.

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


More information about the ghc-tickets mailing list