Note [Don't w/w join points for CPR]
There's no point in exploiting CPR info on a join point. If the whole function
is getting CPR'd, then the case expression around the worker function will get
pushed into the join point by the simplifier, which will have the same effect
that w/w'ing for CPR would have - the result will be returned in an unboxed
tuple.
f z = let join j x y = (x+1, y+1)
in case z of A -> j 1 2
B -> j 2 3
=>
f z = case $wf z of (# a, b #) -> (a, b)
$wf z = case (let join j x y = (x+1, y+1)
in case z of A -> j 1 2
B -> j 2 3) of (a, b) -> (# a, b #)
=>
f z = case $wf z of (# a, b #) -> (a, b)
$wf z = let join j x y = (# x+1, y+1 #)
in case z of A -> j 1 2
B -> j 2 3
Note that we still want to give `j` the CPR property, so that `f` has it. So
CPR *analyse* join points as regular functions, but don't *transform* them.
We could retain the CPR /signature/ on the worker after W/W, but it would
become outright wrong if the Simplifier pushes a non-trivial continuation
into it. For example:
case (let $j x = (x,x) in ...) of alts
==>
let $j x = case (x,x) of alts in case ... of alts
Before pushing the case in, `$j` has the CPR property, but not afterwards.
So we simply zap the CPR signature for join pints as part of the W/W pass.
The signature served its purpose during CPR analysis in propagating the
CPR property of `$j`.
Doing W/W for returned products on a join point would be tricky anyway, as the
worker could not be a join point because it would not be tail-called. However,
doing the *argument* part of W/W still works for join points, since the wrapper
body will make a tail call:
f z = let join j x y = x + y
in ...
=>
f z = let join $wj x# y# = x# +# y#
j x y = case x of I# x# ->
case y of I# y# ->
$wj x# y#
in ... References 0
This Note does not link to any other.
Referenced by 3
- GHC.Core.Opt.WorkWrap call site ×2
- Do not eta-expand join points GHC.Core.Opt.Arity