Apart from reducing the number of LEAL/LEAQ instructions by about
30%, it gives 8g easier registerization in several cases,
for example in strconv. Performance with 6g is not affected.
Before (386):
src/pkg/strconv/decimal.go:22 TEXT (*decimal).String+0(SB),$240-12
src/pkg/strconv/extfloat.go:540 TEXT (*extFloat).ShortestDecimal+0(SB),$584-20
After (386):
src/pkg/strconv/decimal.go:22 TEXT (*decimal).String+0(SB),$196-12
src/pkg/strconv/extfloat.go:540 TEXT (*extFloat).ShortestDecimal+0(SB),$420-20
Benchmarks with GOARCH=386 (on a Core 2).
benchmark old ns/op new ns/op delta
BenchmarkBinaryTree17
7110191000 7079644000 -0.43%
BenchmarkFannkuch11
7769274000 7766514000 -0.04%
BenchmarkGobDecode
33454820 34755400 +3.89%
BenchmarkGobEncode
11675710 11007050 -5.73%
BenchmarkGzip
2013519000 1593855000 -20.84%
BenchmarkGunzip
253368200 242667600 -4.22%
BenchmarkJSONEncode
152443900 120763400 -20.78%
BenchmarkJSONDecode
304112800 247461800 -18.63%
BenchmarkMandelbrot200
29245520 29240490 -0.02%
BenchmarkParse
8484105 8088660 -4.66%
BenchmarkRevcomp
2695688000 2841263000 +5.40%
BenchmarkTemplate
363759800 277271200 -23.78%
benchmark old ns/op new ns/op delta
BenchmarkAtof64Decimal 127 129 +1.57%
BenchmarkAtof64Float 166 164 -1.20%
BenchmarkAtof64FloatExp 308 300 -2.60%
BenchmarkAtof64Big 584 571 -2.23%
BenchmarkAppendFloatDecimal 440 430 -2.27%
BenchmarkAppendFloat 995 776 -22.01%
BenchmarkAppendFloatExp 897 746 -16.83%
BenchmarkAppendFloatNegExp 900 752 -16.44%
BenchmarkAppendFloatBig 1528 1228 -19.63%
BenchmarkAppendFloat32Integer 443 453 +2.26%
BenchmarkAppendFloat32ExactFraction 812 661 -18.60%
BenchmarkAppendFloat32Point 1002 773 -22.85%
BenchmarkAppendFloat32Exp 858 725 -15.50%
BenchmarkAppendFloat32NegExp 848 728 -14.15%
BenchmarkAppendFloat64Fixed1 447 431 -3.58%
BenchmarkAppendFloat64Fixed2 480 462 -3.75%
BenchmarkAppendFloat64Fixed3 461 457 -0.87%
BenchmarkAppendFloat64Fixed4 509 484 -4.91%
Update #1914.
R=rsc, nigeltao
CC=golang-dev, remy
https://golang.org/cl/
6494107
Type *fp;
Iter flist;
Node n1, n2;
-
+
switch(n->op) {
case ONAME:
if((n->class&PHEAP) || n->class == PPARAMREF)
*a = *n;
return;
+ case OINDREG:
+ // Increase the refcount of the register so that igen's caller
+ // has to call regfree.
+ if(n->val.u.reg != D_SP)
+ reg[n->val.u.reg]++;
+ *a = *n;
+ return;
+
+ case ODOT:
+ igen(n->left, a, res);
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ return;
+
+ case ODOTPTR:
+ regalloc(a, types[tptr], res);
+ cgen(n->left, a);
+ if(n->xoffset != 0) {
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(n->left->type->type->width >= unmappedzero) {
+ n1 = *a;
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ }
+ }
+ a->op = OINDREG;
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ return;
+
case OCALLFUNC:
fp = structfirst(&flist, getoutarg(n->left->type));
cgen_call(n, 0);
}
if(isslice(nl->type)) {
igen(nl, &n1, res);
- n1.op = OINDREG;
n1.type = types[TUINT32];
- n1.xoffset = Array_cap;
+ n1.xoffset += Array_cap;
gmove(&n1, res);
regfree(&n1);
break;
void
igen(Node *n, Node *a, Node *res)
{
- Node n1;
Type *fp;
Iter flist;
-
+ Node n1;
+
switch(n->op) {
case ONAME:
if((n->class&PHEAP) || n->class == PPARAMREF)
*a = *n;
return;
+ case OINDREG:
+ // Increase the refcount of the register so that igen's caller
+ // has to call regfree.
+ if(n->val.u.reg != D_SP)
+ reg[n->val.u.reg]++;
+ *a = *n;
+ return;
+
+ case ODOT:
+ igen(n->left, a, res);
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ return;
+
+ case ODOTPTR:
+ regalloc(a, types[tptr], res);
+ cgen(n->left, a);
+ if(n->xoffset != 0) {
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(n->left->type->type->width >= unmappedzero) {
+ n1 = *a;
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ }
+ }
+ a->op = OINDREG;
+ a->xoffset += n->xoffset;
+ a->type = n->type;
+ return;
+
case OCALLFUNC:
fp = structfirst(&flist, getoutarg(n->left->type));
cgen_call(n, 0);
for(i=0; i<nelem(reg); i++)
reg[i] = 1;
- for(i=D_AL; i<=D_DI; i++)
+ for(i=D_AX; i<=D_DI; i++)
reg[i] = 0;
for(i=0; i<nelem(resvd); i++)
reg[resvd[i]]++;
for(i=0; i<nelem(resvd); i++)
reg[resvd[i]]--;
- for(i=D_AL; i<=D_DI; i++)
+ for(i=D_AX; i<=D_DI; i++)
if(reg[i])
yyerror("reg %R left allocated at %ux", i, regpc[i]);
}
{
int i, j;
- for(i=D_AL; i<=D_DI; i++) {
+ for(i=D_AX; i<=D_DI; i++) {
if(reg[i] == 0)
goto ok;
for(j=0; j<nelem(resvd); j++)
vlong argwid;
// most nodes
- Type* type;
- vlong width; // offset in TFIELD, width in all others
+ Type* type; // actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx
+ vlong width; // offset in TFIELD, width in all others
// TFIELD
- Type* down; // also used in TMAP
+ Type* down; // next struct field, also key type in TMAP
Strlit* note; // literal string annotation
// TARRAY