[GHC] #14079: Failure to do CPR in the presence of a local letrec
GHC
ghc-devs at haskell.org
Thu Aug 3 14:12:37 UTC 2017
#14079: Failure to do CPR in the presence of a local letrec
-------------------------------------+-------------------------------------
Reporter: nomeata | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.3
Resolution: | Keywords: JoinPoints
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by nomeata):
Not sure to what extend there is a bug, but I believe it explains the
regressions when we introduce loopification.
Let’s start with this code.
{{{
je :: (Int, Int) -> Int -> (Int, Int)
je !x y | y > 0 = x
| otherwise = je x (makeBig y + 1)
}}}
Without loopification, this stays a top-level recursive bindings. Even if
it is small, it is never inlined, so w/w happens, and we get a nice
worker, with both tuples unboxed:
{{{
$wje :: Int -> Int -> Int# -> (# Int, Int #)
}}}
This avoid allocation of tuples, which is great.
Now, let’s do loopification by hand (the extra `n` is just to avoid
floating `je` to the top-level, because we do not support top-level join
points:
{{{
e :: (Int, Int) -> Int -> Int -> (Int, Int)
e x y n = je x y
where je !x y | y > 0 = x
| otherwise = je x (y + n)
}}}
Now `e` is small and, by changing from recursive to non-recursive, now
inlineable. Therefore w/w refuses to work on `e` and we get no worker for
`e`. We do get a worker for the local join point `je`, but because it is a
join-point, no CPR happens, and its type is
{{{
$wje :: Int -> Int -> Int# -> (Int, Int)
}}}
As you point out that other changes to `e` (such as making it look big, or
marking it `NOINLINE`) avoid this and give it a nice wrapper. But that is
a red herring: The code out there _is_ small and _isn’t_ marked
`NOINLINE`.
Anyways, so we are stuck with an inlineable `e` without a worker. The next
question is hence: What happens with it? If we indeed inline `e`, and
inline it into a nice context (say, into `case _ of (x,y) -> _`, then
case-of-case (and case-of-joinrec) will move this `case` deep into the
`letrec`. But (and at this point I am running out of concrete examples. I
guess I have to look closer at nofib), what if that does not happen?
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14079#comment:3>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list