mirror of
https://github.com/golang/go
synced 2024-09-15 22:20:06 +00:00
gc: better loopdepth analysis for labels
This avoids degraded performance caused by extra labels emitted by inlining (breaking strconv ftoa alloc count unittest) and is better in any case. R=rsc CC=golang-dev https://golang.org/cl/5483071
This commit is contained in:
parent
cebf55dc9b
commit
9bf3478658
|
@ -35,6 +35,8 @@
|
|||
static void escfunc(Node *func);
|
||||
static void esclist(NodeList *l);
|
||||
static void esc(Node *n);
|
||||
static void escloopdepthlist(NodeList *l);
|
||||
static void escloopdepth(Node *n);
|
||||
static void escassign(Node *dst, Node *src);
|
||||
static void esccall(Node*);
|
||||
static void escflows(Node *dst, Node *src);
|
||||
|
@ -138,11 +140,64 @@ escfunc(Node *func)
|
|||
escassign(curfn, n);
|
||||
}
|
||||
|
||||
escloopdepthlist(curfn->nbody);
|
||||
esclist(curfn->nbody);
|
||||
curfn = savefn;
|
||||
loopdepth = saveld;
|
||||
}
|
||||
|
||||
// Mark labels that have no backjumps to them as not increasing loopdepth.
|
||||
// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
|
||||
// and set it to one of the following two. Then in esc we'll clear it again.
|
||||
static Label looping;
|
||||
static Label nonlooping;
|
||||
|
||||
static void
|
||||
escloopdepthlist(NodeList *l)
|
||||
{
|
||||
for(; l; l=l->next)
|
||||
escloopdepth(l->n);
|
||||
}
|
||||
|
||||
static void
|
||||
escloopdepth(Node *n)
|
||||
{
|
||||
if(n == N)
|
||||
return;
|
||||
|
||||
escloopdepthlist(n->ninit);
|
||||
|
||||
switch(n->op) {
|
||||
case OLABEL:
|
||||
if(!n->left || !n->left->sym)
|
||||
fatal("esc:label without label: %+N", n);
|
||||
// Walk will complain about this label being already defined, but that's not until
|
||||
// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
|
||||
// if(n->left->sym->label != nil)
|
||||
// fatal("escape analysis messed up analyzing label: %+N", n);
|
||||
n->left->sym->label = &nonlooping;
|
||||
break;
|
||||
case OGOTO:
|
||||
if(!n->left || !n->left->sym)
|
||||
fatal("esc:goto without label: %+N", n);
|
||||
// If we come past one that's uninitialized, this must be a (harmless) forward jump
|
||||
// but if it's set to nonlooping the label must have preceded this goto.
|
||||
if(n->left->sym->label == &nonlooping)
|
||||
n->left->sym->label = &looping;
|
||||
break;
|
||||
}
|
||||
|
||||
escloopdepth(n->left);
|
||||
escloopdepth(n->right);
|
||||
escloopdepthlist(n->list);
|
||||
escloopdepth(n->ntest);
|
||||
escloopdepth(n->nincr);
|
||||
escloopdepthlist(n->nbody);
|
||||
escloopdepthlist(n->nelse);
|
||||
escloopdepthlist(n->rlist);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
esclist(NodeList *l)
|
||||
{
|
||||
|
@ -188,9 +243,20 @@ esc(Node *n)
|
|||
n->left->escloopdepth = loopdepth;
|
||||
break;
|
||||
|
||||
case OLABEL: // TODO: new loop/scope only if there are backjumps to it.
|
||||
loopdepth++;
|
||||
break;
|
||||
case OLABEL:
|
||||
if(n->left->sym->label == &nonlooping) {
|
||||
if(debug['m'] > 1)
|
||||
print("%L:%N non-looping label\n", lineno, n);
|
||||
} else if(n->left->sym->label == &looping) {
|
||||
if(debug['m'] > 1)
|
||||
print("%L: %N looping label\n", lineno, n);
|
||||
loopdepth++;
|
||||
}
|
||||
// See case OLABEL in escloopdepth above
|
||||
// else if(n->left->sym->label == nil)
|
||||
// fatal("escape anaylysis missed or messed up a label: %+N", n);
|
||||
|
||||
n->left->sym->label = nil;
|
||||
|
||||
case ORANGE:
|
||||
// Everything but fixed array is a dereference.
|
||||
|
|
|
@ -913,6 +913,11 @@ stmtfmt(Fmt *f, Node *n)
|
|||
else
|
||||
fmtprint(f, "%#O", n->op);
|
||||
break;
|
||||
|
||||
case OLABEL:
|
||||
fmtprint(f, "%N: ", n->left);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if(extrablock)
|
||||
|
@ -1016,6 +1021,7 @@ static int opprec[] = {
|
|||
[OFALL] = -1,
|
||||
[OFOR] = -1,
|
||||
[OIF] = -1,
|
||||
[OLABEL] = -1,
|
||||
[OPROC] = -1,
|
||||
[ORANGE] = -1,
|
||||
[ORETURN] = -1,
|
||||
|
|
|
@ -1011,3 +1011,24 @@ func foo121b() {
|
|||
go fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
|
||||
}
|
||||
}
|
||||
|
||||
// a harmless forward jump
|
||||
func foo122() {
|
||||
var i *int
|
||||
|
||||
goto L1
|
||||
L1:
|
||||
i = new(int) // ERROR "does not escape"
|
||||
_ = i
|
||||
}
|
||||
|
||||
// a backward jump, increases loopdepth
|
||||
func foo123() {
|
||||
var i *int
|
||||
|
||||
L1:
|
||||
i = new(int) // ERROR "escapes"
|
||||
|
||||
goto L1
|
||||
_ = i
|
||||
}
|
Loading…
Reference in a new issue