summaryrefslogtreecommitdiff
path: root/test/devirt.go
diff options
context:
space:
mode:
authorphilhofer <phofer@umich.edu>2017-03-13 15:03:17 -0700
committerDavid Chase <drchase@google.com>2017-03-14 18:49:23 +0000
commit295307ae78f8dd463a2ab8d85a1592ca76619d36 (patch)
treef6222675f59f884597f0684b3249937ec9a0e1e5 /test/devirt.go
parent691755304ce49887f65f8f84e18cda3814b46e5c (diff)
downloadgo-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.go39
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")
+ }
+}