[GHC] #14137: Do more inlining into non-recursive join points
GHC
ghc-devs at haskell.org
Sat Aug 19 13:31:15 UTC 2017
#14137: Do more inlining into non-recursive join points
-------------------------------------+-------------------------------------
Reporter: simonpj | Owner: nomeata
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.2.1
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):
Also note that floating out the exit code paths from recursive join points
greatly improves the effectivity of the demand analyser, possibly to the
point of making Call Arity obsolete (at least in some common cases).
Consider this code:
{{{
let t = f a -- a thunk
in let go 0 y = t y + 5
go n y = go (n-1) (y*y)
in case go 100 2 of …
}}}
The cardinality analysis is not able to eta-expand `t` because it has to
assume it is used multiple times. Call Arity, with the rather complicate
co-call graph analysis finds that `t` is called at most once and allows
for its eta-expansion.
But let’s see what happens if we apply some of the ideas from this tickets
and from #14068. First we apply #14068:
{{{
let t = f a -- a thunk
in let go n y = joinrec j 0 y = t y + 5
j n y = call j (n-1) (y*y)
in call j n y
in case go 100 2 of …
}}}
I’d like to call this ''first joinrec normal form'', defined as “every
recursive function where all recursive calls are tail-recursive is a
recursive join point”.
Next we apply the idea above of floating out all expressions not
mentioning the join point
{{{
let t = f a -- a thunk
in let go n y = join jexit y = t y + 5
joinrec j 0 y = call jexit y
j n y = call j (n-1) (y*y)
in call j n y
in case go 100 2 of …
}}}
I’d like to call this ''second joinrec normal form'', defined as “first
joinrec normal form, and all subexpressions of a recursive join point `j`
that are in tail-call position and do not mention `j` are invocations a
join point”.
This form minimizes the amount of code that is inside the `joinrec`, which
is good, as many parts of the compiler (simplifier, demand analyzer) have
to make conservative assumptions with recursion.
Now the normal demand analyser can infer that the non-recursive `go` is
called at most once, hence the join-point `jexit` is called at most once
(by virtue of being a join-point, it can do so without looking at its use-
site, which are inside a recursive group), and hence `t` is used at most
once. Success!
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14137#comment:12>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list