Skip to content

runRW# ruins join points

Found this while poking around in the example for #12781 (closed). Suppose we have code like this:

let loop :: Int -> State# RealWorld -> (State# RealWorld, Int)
    loop n = ... loop (n+1) {- tail call -} ...
in runRW# @ 'PtrRepLifted @ Int (loop 0)

We would love for loop to be a join point, but it can't be because it's invoked in the argument to runRW#. In this situation, we're often rescued by Float In, which we might hope to give us this:

runRW# @ 'PtrRepLifted @ Int (
  let loop :: Int -> State# RealWorld -> (State# RealWorld, Int)
      loop n s = ... loop (n+1) s' {- tail call -} ...
  in loop 0
)

Two problems:

  1. Float In won't do this to begin with because loop 0 is a partial application.
  2. It's still not eligible to be a join point, again because loop 0 is a partial application.

What we would //like// to see is this:

runRW# @ 'PtrRepLifted @ Int (
  \s0 ->
    let loop :: Int -> State# RealWorld -> (State# RealWorld, Int)
        loop n s = ... loop (n+1) s' {- tail call -} ...
    in loop 0 s0
)

Now we're golden. But someone has to have thought to eta-expand the argument to runRW# first. (Float In should then float loop into the lambda because, due to the state hack, the lambda is considered one-shot.)

Perhaps the simplifier should //always// eta-expand the argument to runRW#?

Trac metadata
Trac field Value
Version 8.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information