
#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