keepAlive# primop

Ben Gamari ben at well-typed.com
Mon Apr 13 17:51:42 UTC 2020


Ccing ghc-devs@ since this discussion is something of general interest
to the community.


Sylvain Henry <sylvain at haskus.fr> writes:

> Simon, Ben,
>
> I've been reading and thinking about `readRW#` issues which are very 
> related to issues we have with `keepAlive#` primop.
>
> To recap, the problem is that we want some transformations (that Simon 
> has listed in [1]) to consider:
>
> ```
> case runRW# f of ...
>
> case keepAlive# k a of ...
> ```
>
> as if they were really:
>
> ```
> case f realWorld# of ...
>
> case a of ...
> ```
>
> BUT without breaking the semantics of runRW# and keepAlive#.
>
> I have been thinking about a solution that I have described on the wiki: 
> https://gitlab.haskell.org/ghc/ghc/-/wikis/proposal/with-combinator#option-e-tag-core-case-expression-with-kept-alive-variables
>
> The idea is to keep a set of variable names in each Core case-expression 
> that are kept alive during the evaluation of the scrutinee.
>
> I think it would work very nicely with your `newState#` primop described 
> in [2], both for `runST` and for `unsafeDupablePerformIO` (details on 
> the wiki).
>
> It requires a little more upfront work to adapt the code involving 
> case-expressions. But it will force us to review all transformations to 
> check if they are sound when keep-alive sets are not empty, which we 
> would have to do anyway if we implemented another option. We could start 
> by disabling transformations involving non-empty keep-alive sets and 
> iterate to enable the sound ones.
>
> I would like your opinions on the approach. I may have totally missed 
> something.

Thanks for writing this down!

Indeed it is an interesting idea. However, as expressed on IRC, I
wonder whether this problem rises to the level where it warrants an
adaptation to our Core representation. It feels a bit like the
tail is wagging the dog here, especially given how the "tail" here
merely exists to support FFI.

That being said, this is one of the few options which remain on the
table that doesn't require changes to user code. Moreover, the
applicability to runRW# is quite intriguing.

Another (admittedly, more ad-hoc) option that would avoid modifying Core
would be to teach the simplifier about the class of
"continuation-passing" primops (e.g. `keepAlive#` and `runRW#`), allowing it
to push case analyses into the continuation argument. That is,

    case keepAlive# x expr of pat -> rhs

            ~>

    keepAlive# x (case expr of pat -> rhs)

Of course, doing this is a bit tricky since one must rewrite the
application of keepAlive# to ensure that the resulting application is
well-typed. Admittedly, this doesn't help the runRW# case (although this
could presumably be accommodated by touch#'ing the final state token in
the runRW# desugaring emitted by CorePrep).

On the whole, I'm not a fan of this ad-hoc option. It increases the
complexity of the simplifier all to support a single operation. By
comparison, the Core extension looks somewhat appealing.

Cheers,

- Ben


[1] https://gitlab.haskell.org/ghc/ghc/-/wikis/proposal/with-combinator#option-e-tag-core-case-expression-with-kept-alive-variables

P.S. A minor note: the keepAlive# "pseudo-instruction" mentioned on the
Wiki [1] is precisely the touch# operation we have today.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 487 bytes
Desc: not available
URL: <http://mail.haskell.org/pipermail/ghc-devs/attachments/20200413/a7c99ef3/attachment.sig>


More information about the ghc-devs mailing list