[GHC] #14287: Early inlining causes potential join points to be missed
GHC
ghc-devs at haskell.org
Fri Sep 29 09:07:42 UTC 2017
#14287: Early inlining causes potential join points to be missed
-------------------------------------+-------------------------------------
Reporter: jheek | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.2.1
Resolution: | Keywords:
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 simonpj):
A major goal in GHC is to avoid sensitivity to ordering of
transformations. Otherwise things
become too finely balanced.
Here are three programs
{{{
-- Recursive function
-- go is not a join point
f1 x = letrec go s = case s of
Done -> Done
Yield x s' | pred x -> Yield x s'
| otherwise -> go s'
in case go s2 of ...
-- Same but float inwards
-- Now go becomes a join point
f2 x = case letrec go s = case s of
Done -> Done
Yield x s' | pred x -> Yield x s'
| otherwise -> go s'
in go s2 of ...
-- Same but float outwards
-- Now go becomes top-level
go pred s = case s of
Done -> Done
Yield x s' | pred x -> Yield x s'
| otherwise -> go s'
f3 x = case go pred s2 of ...
}}}
Points to note:
* Float-in can create join points; see the transition from `f1` to `f2`
* Even though `go` is a join point in `f2`, we need a run of the
Simplifier to mark it as such. Once it is marked as a join point, it'll
stay that way.
* Float-out is currently pretty aggressive about floating things to top
level, and so will tend to generate `f3`. By itself that is not too bad.
But now the `case` in `f3` can't fuse with the loop.
* Don't forget that the user might write the program in the `f3` form in
the first place. Ideally we want all forms to optimise the same way.
I think that the Right Solution to these fragilities is the loopification
plan in #14068. Then, even in the top-level form we'd get
{{{
go pred s = letrec go' s = case s of
Done -> Done
Yield x s' | pred x -> Yield x s'
| otherwise -> go' s'
in go' s
f3 x = case go pred s2 of ...
}}}
Now (a) `go'` is a join point, and (b) `go` is non-recursive and will
inline.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14287#comment:6>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list