]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: inline convT2E when T is uintptr-shaped.
authorNigel Tao <nigeltao@golang.org>
Thu, 14 Jun 2012 00:43:20 +0000 (10:43 +1000)
committerNigel Tao <nigeltao@golang.org>
Thu, 14 Jun 2012 00:43:20 +0000 (10:43 +1000)
GOARCH=amd64 benchmarks

src/pkg/runtime
benchmark                  old ns/op    new ns/op    delta
BenchmarkConvT2ESmall             10           10   +1.00%
BenchmarkConvT2EUintptr            9            0  -92.07%
BenchmarkConvT2EBig               74           74   -0.27%
BenchmarkConvT2I                  27           26   -3.62%
BenchmarkConvI2E                   4            4   -7.05%
BenchmarkConvI2I                  20           19   -2.99%

test/bench/go1
benchmark                 old ns/op    new ns/op    delta
BenchmarkBinaryTree17    5930908000   5937260000   +0.11%
BenchmarkFannkuch11      3927057000   3933556000   +0.17%
BenchmarkGobDecode         21998090     21870620   -0.58%
BenchmarkGobEncode         12725310     12734480   +0.07%
BenchmarkGzip             567617600    567892800   +0.05%
BenchmarkGunzip           178284100    178706900   +0.24%
BenchmarkJSONEncode        87693550     86794300   -1.03%
BenchmarkJSONDecode       314212600    324115000   +3.15%
BenchmarkMandelbrot200      7016640      7073766   +0.81%
BenchmarkParse              7852100      7892085   +0.51%
BenchmarkRevcomp         1285663000   1286147000   +0.04%
BenchmarkTemplate         566823800    567606200   +0.14%

I'm not entirely sure why the JSON* numbers have changed, but
eyeballing the profile suggests that it could be spending less
and more time in runtime.{new,old}stack, so it could simply be
stack-split boundary noise.

R=rsc, dave, bsiegert, dsymonds
CC=golang-dev
https://golang.org/cl/6280049

src/cmd/5g/cgen.c
src/cmd/6g/cgen.c
src/cmd/8g/cgen.c
src/cmd/gc/gen.c
src/cmd/gc/go.h
src/cmd/gc/walk.c
src/pkg/runtime/iface_test.go
test/convT2E.go [new file with mode: 0644]

index 2e13f9a6c9997d68012eb9ee0712387235843d8e..4f56cccbd3e0b22481b915f3d8e48bf6f4457952 100644 (file)
@@ -41,6 +41,14 @@ cgen(Node *n, Node *res)
                } else
                        cgen_slice(n, res);
                return;
+       case OEFACE:
+               if (res->op != ONAME || !res->addable) {
+                       tempname(&n1, n->type);
+                       cgen_eface(n, &n1);
+                       cgen(&n1, res);
+               } else
+                       cgen_eface(n, res);
+               return;
        }
 
        while(n->op == OCONVNOP)
@@ -598,6 +606,12 @@ agen(Node *n, Node *res)
                agen(&n1, res);
                break;
 
+       case OEFACE:
+               tempname(&n1, n->type);
+               cgen_eface(n, &n1);
+               agen(&n1, res);
+               break;
+
        case OINDEX:
                p2 = nil;  // to be patched to panicindex.
                w = n->type->width;
index e38fb86a32378d4812faeeb989794a6091213fb6..c2760375ffcd3c35f4e7eb91ad7c4052a37afe3d 100644 (file)
@@ -44,6 +44,14 @@ cgen(Node *n, Node *res)
                } else
                        cgen_slice(n, res);
                goto ret;
+       case OEFACE:
+               if (res->op != ONAME || !res->addable) {
+                       tempname(&n1, n->type);
+                       cgen_eface(n, &n1);
+                       cgen(&n1, res);
+               } else
+                       cgen_eface(n, res);
+               goto ret;
        }
 
        if(n->ullman >= UINF) {
@@ -549,6 +557,12 @@ agen(Node *n, Node *res)
                agen(&n1, res);
                break;
 
+       case OEFACE:
+               tempname(&n1, n->type);
+               cgen_eface(n, &n1);
+               agen(&n1, res);
+               break;
+
        case OINDEX:
                w = n->type->width;
                if(nr->addable)
index 860e8cb6c046f2f62ad4ae1a3a1045edc923683d..aefa15a6707fb8367592d00217e0a9f4a29d4b70 100644 (file)
@@ -74,6 +74,14 @@ cgen(Node *n, Node *res)
                } else
                        cgen_slice(n, res);
                return;
+       case OEFACE:
+               if (res->op != ONAME || !res->addable) {
+                       tempname(&n1, n->type);
+                       cgen_eface(n, &n1);
+                       cgen(&n1, res);
+               } else
+                       cgen_eface(n, res);
+               return;
        }
 
        while(n->op == OCONVNOP)
@@ -549,6 +557,12 @@ agen(Node *n, Node *res)
                agen(&n1, res);
                break;
 
+       case OEFACE:
+               tempname(&n1, n->type);
+               cgen_eface(n, &n1);
+               agen(&n1, res);
+               break;
+
        case OINDEX:
                p2 = nil;  // to be patched to panicindex.
                w = n->type->width;
index 569bf461738966594652e594f28452c6bab510d9..ebb410ba54cd4d9818d8049c731bab1e9521d627 100644 (file)
@@ -737,6 +737,22 @@ ret:
        ;
 }
 
+/*
+ * generate:
+ *     res = iface{typ, data}
+ * n->left is typ
+ * n->right is data
+ */
+void
+cgen_eface(Node *n, Node *res)
+{
+       Node dst;
+       dst = *res;
+       dst.type = types[tptr];
+       cgen(n->left, &dst);
+       dst.xoffset += widthptr;
+       cgen(n->right, &dst);
+}
 
 /*
  * generate:
@@ -744,15 +760,12 @@ ret:
  * n->left is s
  * n->list is (cap(s)-lo(TUINT32), hi-lo(TUINT32)[, lo*width(TUINTPTR)])
  * caller (cgen) guarantees res is an addable ONAME.
- *
  */
 void
 cgen_slice(Node *n, Node *res)
 {
        Node src, dst, *cap, *len, *offs, *add;
 
-//     print("cgen_slice: %N = %+N\n", res, n);
-
        cap = n->list->n;
        len = n->list->next->n;
        offs = N;
index 1212b42172ad71e7bf7e976f11ffaa18a95b2e0b..7864b7b72d4fa20e280783d7458a73d7287bf399 100644 (file)
@@ -488,6 +488,7 @@ enum
        ODDD,
        ODDDARG,
        OINLCALL,       // intermediary representation of an inlined call
+       OEFACE, // itable and data words of empty-interface value
        OITAB,  // itable word of interface value
 
        // for back ends
@@ -989,6 +990,7 @@ void        dumplist(char *s, NodeList *l);
 void   addrescapes(Node *n);
 void   cgen_as(Node *nl, Node *nr);
 void   cgen_callmeth(Node *n, int proc);
+void   cgen_eface(Node* n, Node* res);
 void   cgen_slice(Node* n, Node* res);
 void   clearlabels(void);
 void   checklabels(void);
index 706fe44191d7c30e0403ab98626b56572e00020f..f5ccc198b3cb2dff2c461dfff36edaf53eb5ee91 100644 (file)
@@ -436,6 +436,11 @@ walkexpr(Node **np, NodeList **init)
                walkexpr(&n->left, init);
                goto ret;
 
+       case OEFACE:
+               walkexpr(&n->left, init);
+               walkexpr(&n->right, init);
+               goto ret;
+
        case OITAB:
                walkexpr(&n->left, init);
                goto ret;
@@ -713,10 +718,22 @@ walkexpr(Node **np, NodeList **init)
                goto ret;
 
        case OCONVIFACE:
+               walkexpr(&n->left, init);
+
+               // Optimize convT2E as a two-word copy when T is uintptr-shaped.
+               if(!isinter(n->left->type) && isnilinter(n->type) &&
+                  (n->left->type->width == widthptr) &&
+                  isint[simsimtype(n->left->type)]) {
+                       l = nod(OEFACE, typename(n->left->type), n->left);
+                       l->type = n->type;
+                       l->typecheck = n->typecheck;
+                       n = l;
+                       goto ret;
+               }
+
                // Build name of function: convI2E etc.
                // Not all names are possible
                // (e.g., we'll never generate convE2E or convE2I).
-               walkexpr(&n->left, init);
                strcpy(buf, "conv");
                p = buf+strlen(buf);
                if(isnilinter(n->left->type))
index fbbb2c933b2a32a715d3a01428d20fee74bea622..ee534db15defb55795319684538786576604e9cd 100644 (file)
@@ -20,14 +20,20 @@ var (
        Big [2]*int
 )
 
-func BenchmarkConvT2E(b *testing.B) {
+func BenchmarkConvT2ESmall(b *testing.B) {
        for i := 0; i < b.N; i++ {
-               I = 1
+               I = uint16(1)
+       }
+}
+
+func BenchmarkConvT2EUintptr(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               I = uintptr(1)
        }
 }
 
 func BenchmarkConvT2EBig(b *testing.B) {
-       v := [2]*int{}
+       v := [2]uintptr{1, 2}
        for i := 0; i < b.N; i++ {
                I = v
        }
diff --git a/test/convT2E.go b/test/convT2E.go
new file mode 100644 (file)
index 0000000..975808f
--- /dev/null
@@ -0,0 +1,114 @@
+// run
+
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test conversion from non-interface types to the empty interface.
+
+package main
+
+var (
+       z    = struct{}{}
+       p    = &z
+       pp   = &p
+       u16  = uint16(1)
+       u32  = uint32(2)
+       u64  = uint64(3)
+       u128 = [2]uint64{4, 5}
+       f32  = float32(6)
+       f64  = float64(7)
+       c128 = complex128(8 + 9i)
+       s    = "10"
+       b    = []byte("11")
+       m    = map[int]int{12: 13}
+       c    = make(chan int, 14)
+)
+
+var (
+       iz    interface{} = z
+       ip    interface{} = p
+       ipp   interface{} = pp
+       iu16  interface{} = u16
+       iu32  interface{} = u32
+       iu64  interface{} = u64
+       iu128 interface{} = u128
+       if32  interface{} = f32
+       if64  interface{} = f64
+       ic128 interface{} = c128
+       is    interface{} = s
+       ib    interface{} = b
+       im    interface{} = m
+       ic    interface{} = c
+)
+
+func second(a ...interface{}) interface{} {
+       return a[1]
+}
+
+func main() {
+       // Test equality. There are no tests for b and m, as slices and
+       // maps are not comparable by ==.
+       if z != iz {
+               panic("z != iz")
+       }
+       if p != ip {
+               panic("p != ip")
+       }
+       if pp != ipp {
+               panic("pp != ipp")
+       }
+       if u16 != iu16 {
+               panic("u16 != iu16")
+       }
+       if u32 != iu32 {
+               panic("u32 != iu32")
+       }
+       if u64 != iu64 {
+               panic("u64 != iu64")
+       }
+       if u128 != iu128 {
+               panic("u128 != iu128")
+       }
+       if f32 != if32 {
+               panic("f32 != if32")
+       }
+       if f64 != if64 {
+               panic("f64 != if64")
+       }
+       if c128 != ic128 {
+               panic("c128 != ic128")
+       }
+       if s != is {
+               panic("s != is")
+       }
+       if c != ic {
+               panic("c != ic")
+       }
+
+       // Test that non-interface types can be used as ...interface{} arguments.
+       if got := second(z, p, pp, u16, u32, u64, u128, f32, f64, c128, s, b, m, c); got != ip {
+               println("second: got", got, "want", ip)
+               panic("fail")
+       }
+
+       // Test that non-interface types can be sent on a chan interface{}.
+       const n = 100
+       uc := make(chan interface{})
+       go func() {
+               for i := 0; i < n; i++ {
+                       select {
+                       case uc <- nil:
+                       case uc <- u32:
+                       case uc <- u64:
+                       case uc <- u128:
+                       }
+               }
+       }()
+       for i := 0; i < n; i++ {
+               if got := <-uc; got != nil && got != u32 && got != u64 && got != u128 {
+                       println("recv: i", i, "got", got)
+                       panic("fail")
+               }
+       }
+}