diff options
author | Dan Scales <danscales@google.com> | 2020-03-31 20:24:05 -0700 |
---|---|---|
committer | Dan Scales <danscales@google.com> | 2020-04-03 21:43:52 +0000 |
commit | ed7a8332c413f41d466db3bfc9606025e0c264d8 (patch) | |
tree | 9f286a5454071f0f0ddde7ad95e3cecb6c34a66f /src/cmd/compile/internal/gc/main.go | |
parent | 339e9c64006d3e1c6b29e9df9332c55124e1e7d3 (diff) | |
download | go-ed7a8332c413f41d466db3bfc9606025e0c264d8.tar.gz go-ed7a8332c413f41d466db3bfc9606025e0c264d8.zip |
cmd/compile: allow mid-stack inlining when there is a cycle of recursion
We still disallow inlining for an immediately-recursive function, but allow
inlining if a function is in a recursion chain.
If all functions in the recursion chain are simple, then we could inline
forever down the recursion chain (eventually running out of stack on the
compiler), so we add a map to keep track of the functions we have
already inlined at a call site. We stop inlining when we reach a
function that we have already inlined in the recursive chain. Of course,
normally the inlining will have stopped earlier, because of the cost
function.
We could also limit the depth of inlining by a simple count (say, limit
max inlining of 10 at any given site). Would that limit other
opportunities too much?
Added a test in test/inline.go. runtime.BenchmarkStackCopyNoCache() is
also already a good test that triggers the check to stop inlining
when we reach the start of the recursive chain again.
For the bent benchmark suite, the performance improvement was mostly not
statistically significant, but the geomean averaged out to: -0.68%. The text size
increase was less than .1% for all bent benchmarks. The cmd/go text size increase
was 0.02% and the cmd/compile text size increase was .1%.
Fixes #29737
Change-Id: I892fa84bb07a947b3125ec8f25ed0e508bf2bdf5
Reviewed-on: https://go-review.googlesource.com/c/go/+/226818
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/gc/main.go')
-rw-r--r-- | src/cmd/compile/internal/gc/main.go | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index d04c09c93e..f65b95a9c9 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -679,8 +679,12 @@ func Main(archInit func(*Arch)) { if Debug['l'] != 0 { // Find functions that can be inlined and clone them before walk expands them. visitBottomUp(xtop, func(list []*Node, recursive bool) { + numfns := numNonClosures(list) for _, n := range list { - if !recursive { + if !recursive || numfns > 1 { + // We allow inlining if there is no + // recursion, or the recursion cycle is + // across more than one function. caninl(n) } else { if Debug['m'] > 1 { @@ -824,6 +828,17 @@ func Main(archInit func(*Arch)) { } } +// numNonClosures returns the number of functions in list which are not closures. +func numNonClosures(list []*Node) int { + count := 0 + for _, n := range list { + if n.Func.Closure == nil { + count++ + } + } + return count +} + func writebench(filename string) error { f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { |