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
"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"
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:
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);
}
/*
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;
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)
int et;
int64 v;
int32 lno;
- Node *n, *fn;
+ Node *n, *fn, *n1, *n2;
Sym *sym;
char buf[100], *p;
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);
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;
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