1
0
mirror of https://github.com/golang/go synced 2024-11-24 21:10:04 -07:00

optimization of static initialization

R=rsc
CC=golang-dev
https://golang.org/cl/1677049
This commit is contained in:
Ken Thompson 2010-06-27 17:37:01 -07:00
parent 56f3c70111
commit 33da9afc3e
4 changed files with 203 additions and 129 deletions

View File

@ -1016,7 +1016,7 @@ void walkselect(Node *sel);
/*
* sinit.c
*/
void anylit(Node *n, Node *var, NodeList **init);
void anylit(int ctxt, Node *n, Node *var, NodeList **init);
int gen_as_init(Node *n);
NodeList* initfix(NodeList *l);
int oaslit(Node *n, NodeList **init);

View File

@ -617,7 +617,7 @@ typename(Type *t)
Sym *s;
Node *n;
if((isptr[t->etype] && t->type == T) || isideal(t))
if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
fatal("typename %T", t);
s = typesym(t);
if(s->def == N) {

View File

@ -185,6 +185,11 @@ initfix(NodeList *l)
* part of the composit literal.
*/
static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
static void slicelit(int ctxt, Node *n, Node *var, NodeList **init);
static void maplit(int ctxt, Node *n, Node *var, NodeList **init);
static int
isliteral(Node *n)
{
@ -211,10 +216,54 @@ no:
return 0;
}
static void arraylit(Node *n, Node *var, int pass, NodeList **init);
static void
litas(Node *l, Node *r, NodeList **init)
{
Node *a;
a = nod(OAS, l, r);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
}
enum
{
MODEDYNAM = 1,
MODECONST = 2,
};
static int
getdyn(Node *n, int top)
{
NodeList *nl;
Node *value;
int mode;
mode = 0;
switch(n->op) {
default:
if(isliteral(n))
return MODECONST;
return MODEDYNAM;
case OARRAYLIT:
if(!top && n->type->bound < 0)
return MODEDYNAM;
case OSTRUCTLIT:
break;
}
for(nl=n->list; nl; nl=nl->next) {
value = nl->n->right;
mode |= getdyn(value, 0);
if(mode == (MODEDYNAM|MODECONST))
break;
}
return mode;
}
static void
structlit(Node *n, Node *var, int pass, NodeList **init)
structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
{
Node *r, *a;
NodeList *nl;
@ -229,15 +278,26 @@ structlit(Node *n, Node *var, int pass, NodeList **init)
switch(value->op) {
case OARRAYLIT:
if(value->type->bound < 0)
break;
if(value->type->bound < 0) {
if(pass == 1 && ctxt != 0) {
a = nod(ODOT, var, newname(index->sym));
slicelit(ctxt, value, a, init);
} else
if(pass == 2 && ctxt == 0) {
a = nod(ODOT, var, newname(index->sym));
slicelit(ctxt, value, a, init);
} else
if(pass == 3)
break;
continue;
}
a = nod(ODOT, var, newname(index->sym));
arraylit(value, a, pass, init);
arraylit(ctxt, pass, value, a, init);
continue;
case OSTRUCTLIT:
a = nod(ODOT, var, newname(index->sym));
structlit(value, a, pass, init);
structlit(ctxt, pass, value, a, init);
continue;
}
@ -263,7 +323,7 @@ structlit(Node *n, Node *var, int pass, NodeList **init)
}
static void
arraylit(Node *n, Node *var, int pass, NodeList **init)
arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
{
Node *r, *a;
NodeList *l;
@ -278,15 +338,26 @@ arraylit(Node *n, Node *var, int pass, NodeList **init)
switch(value->op) {
case OARRAYLIT:
if(value->type->bound < 0)
break;
if(value->type->bound < 0) {
if(pass == 1 && ctxt != 0) {
a = nod(OINDEX, var, index);
slicelit(ctxt, value, a, init);
} else
if(pass == 2 && ctxt == 0) {
a = nod(OINDEX, var, index);
slicelit(ctxt, value, a, init);
} else
if(pass == 3)
break;
continue;
}
a = nod(OINDEX, var, index);
arraylit(value, a, pass, init);
arraylit(ctxt, pass, value, a, init);
continue;
case OSTRUCTLIT:
a = nod(OINDEX, var, index);
structlit(value, a, pass, init);
structlit(ctxt, pass, value, a, init);
continue;
}
@ -312,13 +383,14 @@ arraylit(Node *n, Node *var, int pass, NodeList **init)
}
static void
slicelit(Node *n, Node *var, NodeList **init)
slicelit(int ctxt, Node *n, Node *var, NodeList **init)
{
Node *r, *a;
NodeList *l;
Type *t;
Node *vstat, *vheap;
Node *vstat, *vauto;
Node *index, *value;
int mode;
// make an array type
t = shallow(n->type);
@ -327,53 +399,97 @@ slicelit(Node *n, Node *var, NodeList **init)
t->sym = nil;
dowidth(t);
// make static initialized array
vstat = staticname(t);
arraylit(n, vstat, 1, init);
if(ctxt != 0) {
// make new *array heap
vheap = nod(OXXX, N, N);
tempname(vheap, ptrto(t));
// put everything into static array
vstat = staticname(t);
arraylit(ctxt, 1, n, vstat, init);
arraylit(ctxt, 2, n, vstat, init);
// copy static to slice
a = nod(OADDR, vstat, N);
a = nod(OAS, var, a);
typecheck(&a, Etop);
a->dodata = 2;
*init = list(*init, a);
return;
}
// recipe for var = []t{...}
// 1. make a static array
// var vstat [...]t
// 2. assign (data statements) the constant part
// vstat = constpart{}
// 3. make an auto pointer to array and allocate heap to it
// var vauto *[...]t = new([...]t)
// 4. copy the static array to the auto array
// *vauto = vstat
// 5. assign slice of allocated heap to var
// var = [0:]*auto
// 6. for each dynamic part assign to the slice
// var[i] = dynamic part
//
// an optimization is done if there is no constant part
// 3. var vauto *[...]t = new([...]t)
// 5. var = [0:]*auto
// 6. var[i] = dynamic part
// if the literal contains constants,
// make static initialized array (1),(2)
vstat = N;
mode = getdyn(n, 1);
if(mode & MODECONST) {
vstat = staticname(t);
arraylit(ctxt, 1, n, vstat, init);
}
// make new auto *array (3 declare)
vauto = nod(OXXX, N, N);
tempname(vauto, ptrto(t));
// set auto to point at new heap (3 assign)
a = nod(ONEW, N, N);
a->list = list1(typenod(t));
a = nod(OAS, vheap, a);
a = nod(OAS, vauto, a);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
// copy static to heap
a = nod(OIND, vheap, N);
a = nod(OAS, a, vstat);
if(vstat != N) {
// copy static to heap (4)
a = nod(OIND, vauto, N);
a = nod(OAS, a, vstat);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
}
// make slice out of heap (5)
a = nod(OAS, var, vauto);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
// make slice out of heap
a = nod(OAS, var, vheap);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
// put dynamics into slice
// put dynamics into slice (6)
for(l=n->list; l; l=l->next) {
r = l->n;
if(r->op != OKEY)
fatal("slicelit: rhs not OKEY: %N", r);
index = r->left;
value = r->right;
a = nod(OINDEX, var, index);
a->etype = 1; // no bounds checking
// TODO need to check bounds?
switch(value->op) {
case OARRAYLIT:
if(value->type->bound < 0)
break;
a = nod(OINDEX, var, index);
arraylit(value, a, 2, init);
arraylit(ctxt, 2, value, a, init);
continue;
case OSTRUCTLIT:
a = nod(OINDEX, var, index);
structlit(value, a, 2, init);
structlit(ctxt, 2, value, a, init);
continue;
}
@ -381,16 +497,15 @@ slicelit(Node *n, Node *var, NodeList **init)
continue;
// build list of var[c] = expr
a = nod(OINDEX, var, index);
a = nod(OAS, a, value);
typecheck(&a, Etop);
walkexpr(&a, init); // add any assignments in r to top
walkexpr(&a, init);
*init = list(*init, a);
}
}
static void
maplit(Node *n, Node *var, NodeList **init)
maplit(int ctxt, Node *n, Node *var, NodeList **init)
{
Node *r, *a;
NodeList *l;
@ -404,10 +519,7 @@ maplit(Node *n, Node *var, NodeList **init)
a = nod(OMAKE, N, N);
a->list = list1(typenod(n->type));
a = nod(OAS, var, a);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
litas(var, a, init);
// count the initializers
b = 0;
@ -497,9 +609,11 @@ maplit(Node *n, Node *var, NodeList **init)
tempname(index, types[TINT]);
a = nod(OINDEX, vstat, index);
a->etype = 1; // no bounds checking
a = nod(ODOT, a, newname(symb));
r = nod(OINDEX, vstat, index);
r->etype = 1; // no bounds checking
r = nod(ODOT, r, newname(syma));
r = nod(OINDEX, var, r);
@ -543,7 +657,7 @@ maplit(Node *n, Node *var, NodeList **init)
}
void
anylit(Node *n, Node *var, NodeList **init)
anylit(int ctxt, Node *n, Node *var, NodeList **init)
{
Type *t;
Node *a, *vstat;
@ -559,18 +673,23 @@ anylit(Node *n, Node *var, NodeList **init)
if(simplename(var)) {
// lay out static data
vstat = staticname(t);
structlit(n, vstat, 1, init);
if(ctxt == 0) {
// lay out static data
vstat = staticname(t);
structlit(1, 1, n, vstat, init);
// copy static to automatic
a = nod(OAS, var, vstat);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
// copy static to var
a = nod(OAS, var, vstat);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
// add expressions to automatic
structlit(n, var, 2, init);
// add expressions to automatic
structlit(ctxt, 2, n, var, init);
break;
}
structlit(ctxt, 1, n, var, init);
structlit(ctxt, 2, n, var, init);
break;
}
@ -581,31 +700,36 @@ anylit(Node *n, Node *var, NodeList **init)
walkexpr(&a, init);
*init = list(*init, a);
}
structlit(n, var, 3, init);
structlit(ctxt, 3, n, var, init);
break;
case OARRAYLIT:
if(t->etype != TARRAY)
fatal("anylit: not array");
if(t->bound < 0) {
slicelit(n, var, init);
slicelit(ctxt, n, var, init);
break;
}
if(simplename(var)) {
// lay out static data
vstat = staticname(t);
arraylit(n, vstat, 1, init);
if(ctxt == 0) {
// lay out static data
vstat = staticname(t);
arraylit(1, 1, n, vstat, init);
// copy static to automatic
a = nod(OAS, var, vstat);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
// copy static to automatic
a = nod(OAS, var, vstat);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
// add expressions to automatic
arraylit(n, var, 2, init);
// add expressions to automatic
arraylit(ctxt, 2, n, var, init);
break;
}
arraylit(ctxt, 1, n, var, init);
arraylit(ctxt, 2, n, var, init);
break;
}
@ -616,13 +740,13 @@ anylit(Node *n, Node *var, NodeList **init)
walkexpr(&a, init);
*init = list(*init, a);
}
arraylit(n, var, 3, init);
arraylit(ctxt, 3, n, var, init);
break;
case OMAPLIT:
if(t->etype != TMAP)
fatal("anylit: not map");
maplit(n, var, init);
maplit(ctxt, n, var, init);
break;
}
}
@ -630,8 +754,7 @@ anylit(Node *n, Node *var, NodeList **init)
int
oaslit(Node *n, NodeList **init)
{
Type *t;
Node *vstat, *a;
int ctxt;
if(n->left == N || n->right == N)
goto no;
@ -641,8 +764,13 @@ oaslit(Node *n, NodeList **init)
goto no;
if(!eqtype(n->left->type, n->right->type))
goto no;
// context is init() function.
// implies generated data executed
// exactly once and not subject to races.
ctxt = 0;
if(n->dodata == 1)
goto initctxt;
ctxt = 1;
switch(n->right->op) {
default:
@ -653,7 +781,7 @@ oaslit(Node *n, NodeList **init)
case OMAPLIT:
if(vmatch1(n->left, n->right))
goto no;
anylit(n->right, n->left, init);
anylit(ctxt, n->right, n->left, init);
break;
}
n->op = OEMPTY;
@ -662,60 +790,6 @@ oaslit(Node *n, NodeList **init)
no:
// not a special composit literal assignment
return 0;
initctxt:
// in the initialization context
// we are trying to put data statements
// right into the initialized variables
switch(n->right->op) {
default:
goto no;
case OSTRUCTLIT:
structlit(n->right, n->left, 1, init);
structlit(n->right, n->left, 2, init);
break;
case OARRAYLIT:
t = n->right->type;
if(t == T)
goto no;
if(t->bound >= 0) {
arraylit(n->right, n->left, 1, init);
arraylit(n->right, n->left, 2, init);
break;
}
// make a static slice
// make an array type
t = shallow(t);
t->bound = mpgetfix(n->right->right->val.u.xval);
t->width = 0;
t->sym = nil;
dowidth(t);
// make static initialized array
vstat = staticname(t);
arraylit(n->right, vstat, 1, init);
arraylit(n->right, vstat, 2, init);
// copy static to slice
a = nod(OADDR, vstat, N);
a = nod(OAS, n->left, a);
typecheck(&a, Etop);
// turns into a function that is hard to parse
// in ggen where it is turned into DATA statements
// walkexpr(&a, init);
a->dodata = 2;
*init = list(*init, a);
break;
case OMAPLIT:
maplit(n->right, n->left, init);
break;
}
n->op = OEMPTY;
return 1;
}
static int

View File

@ -813,7 +813,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case ODOTTYPE:
case ODOTTYPE2:
case ODOTTYPE2:
// Build name of function: assertI2E2 etc.
strcpy(buf, "assert");
p = buf+strlen(buf);
@ -1081,7 +1081,7 @@ walkexpr(Node **np, NodeList **init)
case OMAPLIT:
case OSTRUCTLIT:
nvar = makenewvar(n->type, init, &nstar);
anylit(n->left, nstar, init);
anylit(0, n->left, nstar, init);
n = nvar;
goto ret;
}
@ -1262,7 +1262,7 @@ walkexpr(Node **np, NodeList **init)
case OSTRUCTLIT:
nvar = nod(OXXX, N, N);
tempname(nvar, n->type);
anylit(n, nvar, init);
anylit(0, n, nvar, init);
n = nvar;
goto ret;