Note [Worker/wrapper for CPR]
'mkWWcpr_entry' is the entry-point to the worker/wrapper transformation that
exploits CPR info. Here's an example:
```
f :: ... -> (Int, Int)
f ... = <body>
```
Let's assume the CPR info `body_cpr` for the body of `f` says
"unbox the pair and its components" and `body_ty` is the type of the function
body `body` (i.e., `(Int, Int)`). Then `mkWWcpr_entry body_ty body_cpr` returns
* A result-unpacking expression for the worker, with a hole for the fun body:
```
unpack body = ( case <body> of r __DEFAULT -> ) -- (1)
( case r of (i, j) -> ) -- (2)
( case i of I# a -> ) -- (2)
( case j of I# b -> ) -- (2)
( (# a, b #) ) -- (3)
```
* A result-building expression for the wrapper, with a hole for the worker call:
```
build wkr_call = ( case <wkr_call> of (# a, b #) -> ) -- (3)
( (I# a, I# b) ) -- (2)
```
* The result type of the worker, e.g., `(# Int#, Int# #)` above.
To achieve said transformation, 'mkWWcpr_entry'
1. First allocates a fresh result binder `r`, giving a name to the `body`
expression and contributing part (1) of the unpacker and builder.
2. Then it delegates to 'mkWWcpr_one', which recurses into all result fields
to unbox, contributing the parts marked with (2). Crucially, it knows
what belongs in the case scrutinee of the unpacker through the communicated
Id `r`: The unpacking expression will be free in that variable.
(This is a similar contract as that of 'mkWWstr_one' for strict args.)
3. 'mkWWstr_one' produces a bunch of *transit vars*: Those result variables
that have to be transferred from the worker to the wrapper, where the
constructed result can be rebuilt, `a` and `b` above. Part (3) is
responsible for tupling them up in the worker and taking the tuple apart
in the wrapper. This is implemented in 'move_transit_vars'. References 0
This Note does not link to any other.
Referenced by 7
- GHC.Core.Opt.WorkWrap.Utils call site ×6
- No unboxed tuple for single, unlifted transit var GHC.Core.Opt.WorkWrap.Utils