[GHC] #8763: forM_ [1..N] does not get fused (allocates 50% more)

GHC ghc-devs at haskell.org
Tue Sep 4 11:57:18 UTC 2018


#8763: forM_ [1..N] does not get fused (allocates 50% more)
-------------------------------------+-------------------------------------
        Reporter:  nh2               |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.8.1
       Component:  Compiler          |              Version:  7.6.3
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Runtime           |  Unknown/Multiple
  performance bug                    |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #7206             |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by sgraf):

 ----

 I can think of another transformation that would save the day here: We
 just have to put `c` in the same recursive group as `go_up` and recognize
 the mutual recursive join point. Seems like a better way than to mess with
 the simplifier and we don't even risk duplication of any code! So

 {{{
 let c x k s = case (body x s) of (_, s') -> k s'
 in ...
    let go_up x
          | isTrue# (x ># y') = I# x `c` n
          | otherwise = I# x `c` go_up (x +# delta)
 ==> float `c` inwards into the same recursive group, specialise it for
 `go_up (x+#delta)` and `n` as `k` (SpecConstr? Would entail seeing tail-
 calls as kind-of a pattern match for functions)
 join go_up x
        | isTrue# (x ># y') = jump c1 (I# x)
        | otherwise = c2 (I# x) go_up (x +# delta)
      c1 x s = -- k = n
        case (body x s) of (_, s') -> n s'
      c2 x s = -- k = go_up (x +# delta)
        case (body x s) of (_, s') -> go_up (x +# delta) s'
 }}}

 Well, it's probably not SpecConstr that will do the specialisation. Also,
 why specialise when we could just inline `c`? Seems like we risk
 duplication of the potentially huge `body` after all.

 Although the same weakness doesn't apply to the situation in comment:71:
 It's enough to specialise for the `emit` argument (which serves a similar
 role as `go_up`) without any specific arguments to see that it's tail
 called:

 {{{
 let c_a2jU x k s = case (body x s) of (_, s') -> k s'
 in join emit_a4hf next_ok next =
           ...
           case ==# next_ovf_a3hz delta_ovf_a3h0 of {
             __DEFAULT ->
               case b_a2jS of { __DEFAULT ->
                 c_a2jU
                   (GHC.Types.I# ds_d42Y)
                   (emit_a3hf GHC.Types.False next_a3hx)
               };
             1# ->
               case b_a2jS of next_ok_a2k8 { __DEFAULT ->
                 c_a2jU
                   (GHC.Types.I# ds_d42Y)
                   (emit_a3hf next_ok_a2k8 next_a3hx)
               }
           }
 ==> Specialising `c` for the call pattern
     `[ds s next_ok next] |> [I# ds, emit next_ok next, s]`
     as `c'`
 join c' ds s next_ok next =
        case (body (I# ds) s) of (_, s') -> emit_a4hf next_ok next s'
      emit_a4hf next_ok next s =
        ...
        case ==# next_ovf_a3hz delta_ovf_a3h0 of {
          __DEFAULT ->
            case b_a2jS of { __DEFAULT ->
              jump c' ds_d42Y GHC.Types.False next_a3hx s
            };
          1# ->
            case b_a2jS of next_ok_a2k8 { __DEFAULT ->
              jump c' ds_d42Y next_ok_a2k8 next_a3hx s
            }
        }
 }}}

 This latter case is probably a lot easier to handle. Maybe this is worth
 some specialised pass?

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


More information about the ghc-tickets mailing list