]> Cypherpunks repositories - gostls13.git/commitdiff
gc: optimize interface ==, !=
authorRuss Cox <rsc@golang.org>
Sat, 11 Feb 2012 05:19:24 +0000 (00:19 -0500)
committerRuss Cox <rsc@golang.org>
Sat, 11 Feb 2012 05:19:24 +0000 (00:19 -0500)
If the values being compared have different concrete types,
then they're clearly unequal without needing to invoke the
actual interface compare routine.  This speeds tests for
specific values, like if err == io.EOF, by about 3x.

benchmark                  old ns/op    new ns/op    delta
BenchmarkIfaceCmp100             843          287  -65.95%
BenchmarkIfaceCmpNil100          184          182   -1.09%

Fixes #2591.

R=ken2
CC=golang-dev
https://golang.org/cl/5651073

src/cmd/5g/cgen.c
src/cmd/5g/gsubr.c
src/cmd/6g/cgen.c
src/cmd/6g/gsubr.c
src/cmd/8g/cgen.c
src/cmd/8g/gsubr.c
src/cmd/gc/go.h
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
src/pkg/runtime/runtime_test.go [new file with mode: 0644]

index 4912dcd99c78e525c9a573a28fd8695ee3896413..cccef94c94b5395fd954d04ce1b7d2e1c63be1b4 100644 (file)
@@ -64,6 +64,9 @@ cgen(Node *n, Node *res)
                if(isslice(n->left->type))
                        n->addable = n->left->addable;
                break;
+       case OITAB:
+               n->addable = n->left->addable;
+               break;
        }
 
        // if both are addressable, move
@@ -280,6 +283,20 @@ cgen(Node *n, Node *res)
                regfree(&n1);
                break;
 
+       case OITAB:
+               // itable of interface value
+               igen(nl, &n1, res);
+               n1.op = OREGISTER;      // was OINDREG
+               regalloc(&n2, n->type, &n1);
+               n1.op = OINDREG;
+               n1.type = n->type;
+               n1.xoffset = 0;
+               gmove(&n1, &n2);
+               gmove(&n2, res);
+               regfree(&n1);
+               regfree(&n2);
+               break;
+
        case OLEN:
                if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
                        // map has len in the first 32-bit word.
index d8460ff7547aac4ab4537ae05d69e6213d1d9f8f..94caeb0918879761da36fbd62a4bed832d136ce5 100644 (file)
@@ -346,6 +346,8 @@ anyregalloc(void)
        return 0;
 }
 
+uintptr regpc[REGALLOC_RMAX+1];
+
 /*
  * allocate register of type t, leave in n.
  * if o != N, o is desired fixed register.
@@ -389,9 +391,12 @@ regalloc(Node *n, Type *t, Node *o)
                                goto out;
                }
                for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
-                       if(reg[i] == 0)
+                       if(reg[i] == 0) {
+                               regpc[i] = (uintptr)getcallerpc(&n);
                                goto out;
-
+                       }
+               for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+                       print("%d %p\n", i, regpc[i]);
                yyerror("out of fixed registers");
                goto err;
 
@@ -451,6 +456,8 @@ regfree(Node *n)
        if(reg[i] <= 0)
                fatal("regfree: reg not allocated");
        reg[i]--;
+       if(reg[i] == 0)
+               regpc[i] = 0;
 }
 
 /*
@@ -1347,6 +1354,16 @@ naddr(Node *n, Addr *a, int canemitcode)
                }
                break;
 
+       case OITAB:
+               // itable of interface value
+               naddr(n->left, a, canemitcode);
+               a->etype = TINT32;
+               if(a->type == D_CONST && a->offset == 0)
+                       break;  // len(nil)
+               if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+                       checkoffset(a, canemitcode);
+               break;
+
        case OLEN:
                // len of string or slice
                naddr(n->left, a, canemitcode);
index 2521b02d23766dfc598ad9138c0a4b74fefa985c..00334e71b12fe98b718ebd610f24395f10d78139 100644 (file)
@@ -125,6 +125,9 @@ cgen(Node *n, Node *res)
                if(isslice(n->left->type))
                        n->addable = n->left->addable;
                break;
+       case OITAB:
+               n->addable = n->left->addable;
+               break;
        }
 
        if(complexop(n, res)) {
@@ -259,6 +262,14 @@ cgen(Node *n, Node *res)
                gmove(&n1, res);
                regfree(&n1);
                break;
+       
+       case OITAB:
+               // interface table is first word of interface value
+               igen(nl, &n1, res);
+               n1.type = n->type;
+               gmove(&n1, res);
+               regfree(&n1);
+               break;
 
        case OLEN:
                if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
index 22fea9b16604bb6b533a20f89744016e02db6522..02df69ac3c6d3478b01f4cec479ad1f029e8f414 100644 (file)
@@ -563,6 +563,7 @@ int
 ismem(Node *n)
 {
        switch(n->op) {
+       case OITAB:
        case OLEN:
        case OCAP:
        case OINDREG:
@@ -1219,6 +1220,17 @@ naddr(Node *n, Addr *a, int canemitcode)
                                break;
                        }
                fatal("naddr: OADDR\n");
+       
+       case OITAB:
+               // itable of interface value
+               naddr(n->left, a, canemitcode);
+               if(a->type == D_CONST && a->offset == 0)
+                       break;  // itab(nil)
+               a->etype = tptr;
+               a->width = widthptr;
+               if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+                       checkoffset(a, canemitcode);
+               break;
 
        case OLEN:
                // len of string or slice
index 7dd3a7bb12815d8950597a4c1a3a853a172a5d52..5d8be4678b292b42952eeefd9949921ca9a63595 100644 (file)
@@ -98,6 +98,9 @@ cgen(Node *n, Node *res)
                if(isslice(n->left->type))
                        n->addable = n->left->addable;
                break;
+       case OITAB:
+               n->addable = n->left->addable;
+               break;
        }
 
        // if both are addressable, move
@@ -252,6 +255,13 @@ cgen(Node *n, Node *res)
                regfree(&n1);
                break;
 
+       case OITAB:
+               igen(nl, &n1, res);
+               n1.type = ptrto(types[TUINTPTR]);
+               gmove(&n1, res);
+               regfree(&n1);
+               break;
+
        case OLEN:
                if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
                        // map has len in the first 32-bit word.
index 44dcd50b5472d039cfaac15fd19dc2fd2b9b6822..dd35c51b082fdc29c08910c09a0d2da02ca13361 100644 (file)
@@ -1041,6 +1041,7 @@ int
 ismem(Node *n)
 {
        switch(n->op) {
+       case OITAB:
        case OLEN:
        case OCAP:
        case OINDREG:
@@ -1926,6 +1927,17 @@ naddr(Node *n, Addr *a, int canemitcode)
                                break;
                        }
                fatal("naddr: OADDR\n");
+       
+       case OITAB:
+               // itable of interface value
+               naddr(n->left, a, canemitcode);
+               if(a->type == D_CONST && a->offset == 0)
+                       break;  // len(nil)
+               a->etype = tptr;
+               a->width = widthptr;
+               if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+                       checkoffset(a, canemitcode);
+               break;
 
        case OLEN:
                // len of string or slice
index 6b0709c16ef28cfdf9f7e12d9be0f5d3f9ec781b..0fde5065772812cbaea55ea1726b6559a88c24f1 100644 (file)
@@ -484,6 +484,7 @@ enum
        ODDD,
        ODDDARG,
        OINLCALL,       // intermediary representation of an inlined call
+       OITAB,  // itable word of interface value
 
        // for back ends
        OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
index edd6b729d0ebb2e082fbbcfbd058cb56acd3abaf..91f545849ac70f61fe93e9b5973f8474c07ae985 100644 (file)
@@ -1304,6 +1304,16 @@ reswitch:
                if(n->type == T)
                        goto error;
                goto ret;
+       
+       case OITAB:
+               ok |= Erv;
+               typecheck(&n->left, Erv);
+               if((t = n->left->type) == T)
+                       goto error;
+               if(t->etype != TINTER)
+                       fatal("OITAB of %T", t);
+               n->type = ptrto(types[TUINTPTR]);
+               goto ret;
 
        /*
         * statements
index 37691f029f2775aea0fec621b2d59ca206b9a41d..0118c08a746d1e2d2609d7bc8d9aca3ccc28db9a 100644 (file)
@@ -432,6 +432,10 @@ walkexpr(Node **np, NodeList **init)
                walkexpr(&n->left, init);
                goto ret;
 
+       case OITAB:
+               walkexpr(&n->left, init);
+               goto ret;
+
        case OLEN:
        case OCAP:
                walkexpr(&n->left, init);
@@ -1176,10 +1180,21 @@ walkexpr(Node **np, NodeList **init)
                argtype(fn, n->right->type);
                argtype(fn, n->left->type);
                r = mkcall1(fn, n->type, init, n->left, n->right);
-               if(n->etype == ONE) {
+               if(n->etype == ONE)
                        r = nod(ONOT, r, N);
-                       typecheck(&r, Erv);
-               }
+               
+               // check itable/type before full compare.
+               if(n->etype == OEQ)
+                       r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+               else
+                       r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+               typecheck(&r, Erv);
+               walkexpr(&r, nil);
+
+               n = r;
+               goto ret;
+
+       
                n = r;
                goto ret;
 
diff --git a/src/pkg/runtime/runtime_test.go b/src/pkg/runtime/runtime_test.go
new file mode 100644 (file)
index 0000000..d68b363
--- /dev/null
@@ -0,0 +1,40 @@
+// 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.
+
+package runtime_test
+
+import (
+       "io"
+       "testing"
+)
+
+var errf error
+
+func errfn() error {
+       return errf
+}
+
+func errfn1() error {
+       return io.EOF
+}
+
+func BenchmarkIfaceCmp100(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               for j := 0; j < 100; j++ {
+                       if errfn() == io.EOF {
+                               b.Fatal("bad comparison")
+                       }
+               }
+       }
+}
+
+func BenchmarkIfaceCmpNil100(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               for j := 0; j < 100; j++ {
+                       if errfn1() == nil {
+                               b.Fatal("bad comparison")
+                       }
+               }
+       }
+}