mirror of
https://github.com/golang/go
synced 2024-09-30 04:34:33 -06:00
cmd/gc: separate "has pointers" from "needs zeroing" in stack frame
When the new call site-specific frame bitmaps are available, we can cut the zeroing to just those values that need it due to scope escaping. R=cshapiro, cshapiro CC=golang-dev https://golang.org/cl/13045043
This commit is contained in:
parent
a96d850a5b
commit
3b4d792606
@ -35,11 +35,11 @@ defframe(Prog *ptxt, Bvec *bv)
|
||||
p = ptxt;
|
||||
while(p->link->as == AFUNCDATA || p->link->as == APCDATA || p->link->as == ATYPE)
|
||||
p = p->link;
|
||||
if(stkptrsize >= 8*widthptr) {
|
||||
if(stkzerosize >= 8*widthptr) {
|
||||
p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
|
||||
p = appendp(p, AADD, D_CONST, NREG, 4+frame-stkptrsize, D_REG, 1, 0);
|
||||
p = appendp(p, AADD, D_CONST, NREG, 4+frame-stkzerosize, D_REG, 1, 0);
|
||||
p->reg = REGSP;
|
||||
p = appendp(p, AADD, D_CONST, NREG, stkptrsize, D_REG, 2, 0);
|
||||
p = appendp(p, AADD, D_CONST, NREG, stkzerosize, D_REG, 2, 0);
|
||||
p->reg = 1;
|
||||
p1 = p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4);
|
||||
p->scond |= C_PBIT;
|
||||
@ -49,13 +49,13 @@ defframe(Prog *ptxt, Bvec *bv)
|
||||
patch(p, p1);
|
||||
} else {
|
||||
first = 1;
|
||||
for(i=0, j=0; i<stkptrsize; i+=widthptr, j+=2) {
|
||||
for(i=0, j=(stkptrsize-stkzerosize)/widthptr*2; i<stkzerosize; i+=widthptr, j+=2) {
|
||||
if(bvget(bv, j) || bvget(bv, j+1)) {
|
||||
if(first) {
|
||||
p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
|
||||
first = 0;
|
||||
}
|
||||
p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame-stkptrsize+i);
|
||||
p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame-stkzerosize+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,16 +30,16 @@ defframe(Prog *ptxt, Bvec *bv)
|
||||
// so that garbage collector only sees initialized values
|
||||
// when it looks for pointers.
|
||||
p = ptxt;
|
||||
if(stkptrsize >= 8*widthptr) {
|
||||
if(stkzerosize >= 8*widthptr) {
|
||||
p = appendp(p, AMOVQ, D_CONST, 0, D_AX, 0);
|
||||
p = appendp(p, AMOVQ, D_CONST, stkptrsize/widthptr, D_CX, 0);
|
||||
p = appendp(p, ALEAQ, D_SP+D_INDIR, frame-stkptrsize, D_DI, 0);
|
||||
p = appendp(p, AMOVQ, D_CONST, stkzerosize/widthptr, D_CX, 0);
|
||||
p = appendp(p, ALEAQ, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0);
|
||||
p = appendp(p, AREP, D_NONE, 0, D_NONE, 0);
|
||||
appendp(p, ASTOSQ, D_NONE, 0, D_NONE, 0);
|
||||
} else {
|
||||
for(i=0, j=0; i<stkptrsize; i+=widthptr, j+=2)
|
||||
for(i=0, j=(stkptrsize-stkzerosize)/widthptr*2; i<stkzerosize; i+=widthptr, j+=2)
|
||||
if(bvget(bv, j) || bvget(bv, j+1))
|
||||
p = appendp(p, AMOVQ, D_CONST, 0, D_SP+D_INDIR, frame-stkptrsize+i);
|
||||
p = appendp(p, AMOVQ, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,16 +32,16 @@ defframe(Prog *ptxt, Bvec *bv)
|
||||
// so that garbage collector only sees initialized values
|
||||
// when it looks for pointers.
|
||||
p = ptxt;
|
||||
if(stkptrsize >= 8*widthptr) {
|
||||
if(stkzerosize >= 8*widthptr) {
|
||||
p = appendp(p, AMOVL, D_CONST, 0, D_AX, 0);
|
||||
p = appendp(p, AMOVL, D_CONST, stkptrsize/widthptr, D_CX, 0);
|
||||
p = appendp(p, ALEAL, D_SP+D_INDIR, frame-stkptrsize, D_DI, 0);
|
||||
p = appendp(p, AMOVL, D_CONST, stkzerosize/widthptr, D_CX, 0);
|
||||
p = appendp(p, ALEAL, D_SP+D_INDIR, frame-stkzerosize, D_DI, 0);
|
||||
p = appendp(p, AREP, D_NONE, 0, D_NONE, 0);
|
||||
appendp(p, ASTOSL, D_NONE, 0, D_NONE, 0);
|
||||
} else {
|
||||
for(i=0, j=0; i<stkptrsize; i+=widthptr, j+=2)
|
||||
for(i=0, j=(stkptrsize-stkzerosize)/widthptr*2; i<stkzerosize; i+=widthptr, j+=2)
|
||||
if(bvget(bv, j) || bvget(bv, j+1))
|
||||
p = appendp(p, AMOVL, D_CONST, 0, D_SP+D_INDIR, frame-stkptrsize+i);
|
||||
p = appendp(p, AMOVL, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,6 +270,7 @@ struct Node
|
||||
uchar dupok; // duplicate definitions ok (for func)
|
||||
schar likely; // likeliness of if statement
|
||||
uchar hasbreak; // has break statement
|
||||
uchar needzero; // if it contains pointers, needs to be zeroed on function entry
|
||||
uint esc; // EscXXX
|
||||
int funcdepth;
|
||||
|
||||
@ -940,7 +941,8 @@ EXTERN NodeList* lastconst;
|
||||
EXTERN Node* lasttype;
|
||||
EXTERN vlong maxarg;
|
||||
EXTERN vlong stksize; // stack size for current frame
|
||||
EXTERN vlong stkptrsize; // prefix of stack containing pointers for current frame
|
||||
EXTERN vlong stkptrsize; // prefix of stack containing pointers
|
||||
EXTERN vlong stkzerosize; // prefix of stack that must be zeroed on entry
|
||||
EXTERN int32 blockgen; // max block number
|
||||
EXTERN int32 block; // current block number
|
||||
EXTERN int hasdefer; // flag that curfn has defer statetment
|
||||
|
@ -367,11 +367,11 @@ dumpgclocals(Node* fn, Sym *sym)
|
||||
|
||||
// Sort the list of stack variables. Autos after anything else,
|
||||
// within autos, unused after used, within used, things with
|
||||
// pointers first, and then decreasing size.
|
||||
// pointers first, zeroed things first, and then decreasing size.
|
||||
// Because autos are laid out in decreasing addresses
|
||||
// on the stack, pointers first and decreasing size
|
||||
// really means, in memory, pointers near the top of the
|
||||
// stack and increasing in size.
|
||||
// on the stack, pointers first, zeroed things first and decreasing size
|
||||
// really means, in memory, things with pointers needing zeroing at
|
||||
// the top of the stack and increasing in size.
|
||||
// Non-autos sort on offset.
|
||||
static int
|
||||
cmpstackvar(Node *a, Node *b)
|
||||
@ -394,6 +394,12 @@ cmpstackvar(Node *a, Node *b)
|
||||
bp = haspointers(b->type);
|
||||
if(ap != bp)
|
||||
return bp - ap;
|
||||
|
||||
ap = a->needzero;
|
||||
bp = b->needzero;
|
||||
if(ap != bp)
|
||||
return bp - ap;
|
||||
|
||||
if(a->type->width < b->type->width)
|
||||
return +1;
|
||||
if(a->type->width > b->type->width)
|
||||
@ -409,11 +415,12 @@ allocauto(Prog* ptxt)
|
||||
Node* n;
|
||||
vlong w;
|
||||
|
||||
if(curfn->dcl == nil) {
|
||||
stksize = 0;
|
||||
stkptrsize = 0;
|
||||
stksize = 0;
|
||||
stkptrsize = 0;
|
||||
stkzerosize = 0;
|
||||
|
||||
if(curfn->dcl == nil)
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark the PAUTO's unused.
|
||||
for(ll=curfn->dcl; ll != nil; ll=ll->next)
|
||||
@ -421,6 +428,11 @@ allocauto(Prog* ptxt)
|
||||
ll->n->used = 0;
|
||||
|
||||
markautoused(ptxt);
|
||||
|
||||
// TODO: Remove when liveness analysis sets needzero instead.
|
||||
for(ll=curfn->dcl; ll != nil; ll=ll->next)
|
||||
if (ll->n->class == PAUTO)
|
||||
ll->n->needzero = 1; // ll->n->addrtaken;
|
||||
|
||||
listsort(&curfn->dcl, cmpstackvar);
|
||||
|
||||
@ -430,8 +442,6 @@ allocauto(Prog* ptxt)
|
||||
if (n->class == PAUTO && n->op == ONAME && !n->used) {
|
||||
// No locals used at all
|
||||
curfn->dcl = nil;
|
||||
stksize = 0;
|
||||
stkptrsize = 0;
|
||||
fixautoused(ptxt);
|
||||
return;
|
||||
}
|
||||
@ -446,8 +456,6 @@ allocauto(Prog* ptxt)
|
||||
}
|
||||
|
||||
// Reassign stack offsets of the locals that are still there.
|
||||
stksize = 0;
|
||||
stkptrsize = 0;
|
||||
for(ll = curfn->dcl; ll != nil; ll=ll->next) {
|
||||
n = ll->n;
|
||||
if (n->class != PAUTO || n->op != ONAME)
|
||||
@ -459,8 +467,11 @@ allocauto(Prog* ptxt)
|
||||
fatal("bad width");
|
||||
stksize += w;
|
||||
stksize = rnd(stksize, n->type->align);
|
||||
if(haspointers(n->type))
|
||||
if(haspointers(n->type)) {
|
||||
stkptrsize = stksize;
|
||||
if(n->needzero)
|
||||
stkzerosize = stksize;
|
||||
}
|
||||
if(thechar == '5')
|
||||
stksize = rnd(stksize, widthptr);
|
||||
if(stksize >= (1ULL<<31)) {
|
||||
@ -471,6 +482,7 @@ allocauto(Prog* ptxt)
|
||||
}
|
||||
stksize = rnd(stksize, widthptr);
|
||||
stkptrsize = rnd(stkptrsize, widthptr);
|
||||
stkzerosize = rnd(stkzerosize, widthptr);
|
||||
|
||||
fixautoused(ptxt);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user