
#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