mirror of
https://github.com/golang/go
synced 2024-11-25 15:57:57 -07:00
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
This commit is contained in:
parent
0184081eb9
commit
8fd65b0e1d
@ -39,6 +39,7 @@ char *runtimeimport =
|
|||||||
"func @\"\".stringiter2(? string, ? int) (@\"\".retk int, @\"\".retv rune)\n"
|
"func @\"\".stringiter2(? string, ? int) (@\"\".retk int, @\"\".retv rune)\n"
|
||||||
"func @\"\".copy(@\"\".to any, @\"\".fr any, @\"\".wid uint32) (? int)\n"
|
"func @\"\".copy(@\"\".to any, @\"\".fr any, @\"\".wid uint32) (? int)\n"
|
||||||
"func @\"\".slicestringcopy(@\"\".to any, @\"\".fr any) (? 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 @\"\".convI2E(@\"\".elem any) (@\"\".ret any)\n"
|
||||||
"func @\"\".convI2I(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
|
"func @\"\".convI2I(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
|
||||||
"func @\"\".convT2E(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
|
"func @\"\".convT2E(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
|
||||||
|
@ -410,7 +410,7 @@ gen(Node *n)
|
|||||||
p1 = gjmp(P); // goto test
|
p1 = gjmp(P); // goto test
|
||||||
p2 = gjmp(P); // p2: goto else
|
p2 = gjmp(P); // p2: goto else
|
||||||
patch(p1, pc); // test:
|
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
|
genlist(n->nbody); // then
|
||||||
p3 = gjmp(P); // goto done
|
p3 = gjmp(P); // goto done
|
||||||
patch(p2, pc); // else:
|
patch(p2, pc); // else:
|
||||||
@ -746,12 +746,17 @@ ret:
|
|||||||
void
|
void
|
||||||
cgen_eface(Node *n, Node *res)
|
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;
|
Node dst;
|
||||||
dst = *res;
|
dst = *res;
|
||||||
dst.type = types[tptr];
|
dst.type = types[tptr];
|
||||||
cgen(n->left, &dst);
|
|
||||||
dst.xoffset += widthptr;
|
dst.xoffset += widthptr;
|
||||||
cgen(n->right, &dst);
|
cgen(n->right, &dst);
|
||||||
|
dst.xoffset -= widthptr;
|
||||||
|
cgen(n->left, &dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -257,6 +257,7 @@ struct Node
|
|||||||
uchar implicit;
|
uchar implicit;
|
||||||
uchar addrtaken; // address taken, even if not moved to heap
|
uchar addrtaken; // address taken, even if not moved to heap
|
||||||
uchar dupok; // duplicate definitions ok (for func)
|
uchar dupok; // duplicate definitions ok (for func)
|
||||||
|
schar likely; // likeliness of if statement
|
||||||
|
|
||||||
// most nodes
|
// most nodes
|
||||||
Type* type;
|
Type* type;
|
||||||
|
@ -59,6 +59,7 @@ func copy(to any, fr any, wid uint32) int
|
|||||||
func slicestringcopy(to any, fr any) int
|
func slicestringcopy(to any, fr any) int
|
||||||
|
|
||||||
// interface conversions
|
// interface conversions
|
||||||
|
func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte)
|
||||||
func convI2E(elem any) (ret any)
|
func convI2E(elem any) (ret any)
|
||||||
func convI2I(typ *byte, elem any) (ret any)
|
func convI2I(typ *byte, elem any) (ret any)
|
||||||
func convT2E(typ *byte, elem any) (ret any)
|
func convT2E(typ *byte, elem any) (ret any)
|
||||||
|
@ -374,7 +374,7 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
int et;
|
int et;
|
||||||
int64 v;
|
int64 v;
|
||||||
int32 lno;
|
int32 lno;
|
||||||
Node *n, *fn;
|
Node *n, *fn, *n1, *n2;
|
||||||
Sym *sym;
|
Sym *sym;
|
||||||
char buf[100], *p;
|
char buf[100], *p;
|
||||||
|
|
||||||
@ -771,6 +771,44 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
l = nod(OADDR, sym->def, N);
|
l = nod(OADDR, sym->def, N);
|
||||||
l->addable = 1;
|
l->addable = 1;
|
||||||
ll = list(ll, l);
|
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);
|
ll = list(ll, n->left);
|
||||||
argtype(fn, n->left->type);
|
argtype(fn, n->left->type);
|
||||||
@ -1168,7 +1206,7 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
else
|
else
|
||||||
r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
|
r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
|
||||||
typecheck(&r, Erv);
|
typecheck(&r, Erv);
|
||||||
walkexpr(&r, nil);
|
walkexpr(&r, init);
|
||||||
r->type = n->type;
|
r->type = n->type;
|
||||||
n = r;
|
n = r;
|
||||||
goto ret;
|
goto ret;
|
||||||
|
@ -183,6 +183,18 @@ copyout(Type *t, void **src, void *dst)
|
|||||||
alg->copy(size, dst, *src);
|
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)
|
// func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
|
||||||
#pragma textflag 7
|
#pragma textflag 7
|
||||||
void
|
void
|
||||||
|
Loading…
Reference in New Issue
Block a user