From: Daniel Morsing Date: Tue, 11 Sep 2012 19:42:30 +0000 (+0200) Subject: cmd/gc: Inline pointer sized T2I interface conversions X-Git-Tag: go1.1rc2~2477 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8fd65b0e1d6b737072982a1cf846ff76b1353f02;p=gostls13.git cmd/gc: Inline pointer sized T2I interface conversions This CL also adds support for marking the likelyness of IF nodes in the AST being true. This feature is being used here to mark the slow path as unlikely. src/pkg/runtime: benchmark old ns/op new ns/op delta BenchmarkConvT2IUintptr 16 1 -91.63% test/bench/go1: benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 5416917000 5461355000 +0.82% BenchmarkFannkuch11 3810355000 3842609000 +0.85% BenchmarkGobDecode 19950950 19855420 -0.48% BenchmarkGobEncode 11301220 11308530 +0.06% BenchmarkGzip 548119600 546869200 -0.23% BenchmarkGunzip 176145400 180208300 +2.31% BenchmarkJSONEncode 93117400 70163100 -24.65% BenchmarkJSONDecode 406626800 409999200 +0.83% BenchmarkMandelbrot200 6300992 6317866 +0.27% BenchmarkParse 7664396 7451625 -2.78% BenchmarkRevcomp 1189424000 1412332000 +18.74% BenchmarkTemplate 491308400 458654200 -6.65% benchmark old MB/s new MB/s speedup BenchmarkGobDecode 38.47 38.66 1.00x BenchmarkGobEncode 67.92 67.87 1.00x BenchmarkGzip 35.40 35.48 1.00x BenchmarkGunzip 110.16 107.68 0.98x BenchmarkJSONEncode 20.84 27.66 1.33x BenchmarkJSONDecode 4.77 4.73 0.99x BenchmarkParse 7.56 7.77 1.03x BenchmarkRevcomp 213.69 179.96 0.84x BenchmarkTemplate 3.95 4.23 1.07x R=rsc, dave, nigeltao CC=golang-dev https://golang.org/cl/6351090 --- diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 535e38fac5..6354fa22c8 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -39,6 +39,7 @@ char *runtimeimport = "func @\"\".stringiter2(? string, ? int) (@\"\".retk int, @\"\".retv rune)\n" "func @\"\".copy(@\"\".to any, @\"\".fr any, @\"\".wid uint32) (? int)\n" "func @\"\".slicestringcopy(@\"\".to any, @\"\".fr any) (? int)\n" + "func @\"\".typ2Itab(@\"\".typ *byte, @\"\".typ2 *byte, @\"\".cache **byte) (@\"\".ret *byte)\n" "func @\"\".convI2E(@\"\".elem any) (@\"\".ret any)\n" "func @\"\".convI2I(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n" "func @\"\".convT2E(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n" diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index ebb410ba54..9b667775eb 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -410,7 +410,7 @@ gen(Node *n) p1 = gjmp(P); // goto test p2 = gjmp(P); // p2: goto else patch(p1, pc); // test: - bgen(n->ntest, 0, 0, p2); // if(!test) goto p2 + bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2 genlist(n->nbody); // then p3 = gjmp(P); // goto done patch(p2, pc); // else: @@ -746,12 +746,17 @@ ret: void cgen_eface(Node *n, Node *res) { + /* + * the right node of an eface may contain function calls that uses res as an argument, + * so it's important that it is done first + */ Node dst; dst = *res; dst.type = types[tptr]; - cgen(n->left, &dst); dst.xoffset += widthptr; cgen(n->right, &dst); + dst.xoffset -= widthptr; + cgen(n->left, &dst); } /* diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 7bbaabb378..4a8d191dc7 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -257,6 +257,7 @@ struct Node uchar implicit; uchar addrtaken; // address taken, even if not moved to heap uchar dupok; // duplicate definitions ok (for func) + schar likely; // likeliness of if statement // most nodes Type* type; diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 408f624cff..7ab24a0440 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -59,6 +59,7 @@ func copy(to any, fr any, wid uint32) int func slicestringcopy(to any, fr any) int // interface conversions +func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte) func convI2E(elem any) (ret any) func convI2I(typ *byte, elem any) (ret any) func convT2E(typ *byte, elem any) (ret any) diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 4855b13ba9..935fa6d65d 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -374,7 +374,7 @@ walkexpr(Node **np, NodeList **init) int et; int64 v; int32 lno; - Node *n, *fn; + Node *n, *fn, *n1, *n2; Sym *sym; char buf[100], *p; @@ -771,6 +771,44 @@ walkexpr(Node **np, NodeList **init) l = nod(OADDR, sym->def, N); l->addable = 1; ll = list(ll, l); + + if(n->left->type->width == widthptr && + isint[simsimtype(n->left->type)]) { + /* For pointer types, we can make a special form of optimization + * + * These statements are put onto the expression init list: + * Itab *tab = atomicloadtype(&cache); + * if(tab == nil) + * tab = typ2Itab(type, itype, &cache); + * + * The CONVIFACE expression is replaced with this: + * OEFACE{tab, ptr}; + */ + l = temp(ptrto(types[TUINT8])); + + n1 = nod(OAS, l, sym->def); + typecheck(&n1, Etop); + *init = list(*init, n1); + + fn = syslook("typ2Itab", 1); + n1 = nod(OCALL, fn, N); + n1->list = ll; + typecheck(&n1, Erv); + walkexpr(&n1, init); + + n2 = nod(OIF, N, N); + n2->ntest = nod(OEQ, l, nodnil()); + n2->nbody = list1(nod(OAS, l, n1)); + n2->likely = -1; + typecheck(&n2, Etop); + *init = list(*init, n2); + + l = nod(OEFACE, l, n->left); + l->typecheck = n->typecheck; + l->type = n->type; + n = l; + goto ret; + } } ll = list(ll, n->left); argtype(fn, n->left->type); @@ -1168,7 +1206,7 @@ walkexpr(Node **np, NodeList **init) else r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r); typecheck(&r, Erv); - walkexpr(&r, nil); + walkexpr(&r, init); r->type = n->type; n = r; goto ret; diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c index 864954d0d5..8e0150d07b 100644 --- a/src/pkg/runtime/iface.c +++ b/src/pkg/runtime/iface.c @@ -183,6 +183,18 @@ copyout(Type *t, void **src, void *dst) alg->copy(size, dst, *src); } +#pragma textflag 7 +void +runtime·typ2Itab(Type *t, InterfaceType *inter, Itab **cache, Itab *ret) +{ + Itab *tab; + + tab = itab(inter, t, 0); + runtime·atomicstorep(cache, tab); + ret = tab; + FLUSH(&ret); +} + // func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any) #pragma textflag 7 void