diff options
author | philhofer <phofer@umich.edu> | 2017-03-13 15:03:17 -0700 |
---|---|---|
committer | David Chase <drchase@google.com> | 2017-03-14 18:49:23 +0000 |
commit | 295307ae78f8dd463a2ab8d85a1592ca76619d36 (patch) | |
tree | f6222675f59f884597f0684b3249937ec9a0e1e5 /test/devirt.go | |
parent | 691755304ce49887f65f8f84e18cda3814b46e5c (diff) | |
download | go-git-295307ae78f8dd463a2ab8d85a1592ca76619d36.tar.gz |
cmd/compile: de-virtualize interface calls
With this change, code like
h := sha1.New()
h.Write(buf)
sum := h.Sum()
gets compiled into static calls rather than
interface calls, because the compiler is able
to prove that 'h' is really a *sha1.digest.
The InterCall re-write rule hits a few dozen times
during make.bash, and hundreds of times during all.bash.
The most common pattern identified by the compiler
is a constructor like
func New() Interface { return &impl{...} }
where the constructor gets inlined into the caller,
and the result is used immediately. Examples include
{sha1,md5,crc32,crc64,...}.New, base64.NewEncoder,
base64.NewDecoder, errors.New, net.Pipe, and so on.
Some existing benchmarks that change on darwin/amd64:
Crc64/ISO4KB-8 2.67µs ± 1% 2.66µs ± 0% -0.36% (p=0.015 n=10+10)
Crc64/ISO1KB-8 694ns ± 0% 690ns ± 1% -0.59% (p=0.001 n=10+10)
Adler32KB-8 473ns ± 1% 471ns ± 0% -0.39% (p=0.010 n=10+9)
On architectures like amd64, the reduction in code size
appears to contribute more to benchmark improvements than just
removing the indirect call, since that branch gets predicted
accurately when called in a loop.
Updates #19361
Change-Id: I57d4dc21ef40a05ec0fbd55a9bb0eb74cdc67a3d
Reviewed-on: https://go-review.googlesource.com/38139
Run-TryBot: Philip Hofer <phofer@umich.edu>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'test/devirt.go')
-rw-r--r-- | test/devirt.go | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/test/devirt.go b/test/devirt.go new file mode 100644 index 0000000000..23577098e4 --- /dev/null +++ b/test/devirt.go @@ -0,0 +1,39 @@ +// errorcheck -0 -d=ssa/opt/debug=3 + +package main + +// Trivial interface call devirtualization test. + +type real struct { + value int +} + +func (r *real) Value() int { return r.value } + +type Valuer interface { + Value() int +} + +type indirectiface struct { + a, b, c int +} + +func (i indirectiface) Value() int { + return i.a + i.b + i.c +} + +func main() { + var r Valuer + rptr := &real{value: 3} + r = rptr + + if r.Value() != 3 { // ERROR "de-virtualizing call$" + panic("not 3") + } + + // Can't do types that aren't "direct" interfaces (yet). + r = indirectiface{3, 4, 5} + if r.Value() != 12 { + panic("not 12") + } +} |