Commit 4238b183 authored by Ken Thompson's avatar Ken Thompson

1. check for dups in complex literals

   structtype{a:1, a:2}
   maptypetype{"xx":1, "xx":2}
   arraytypetype{5:1, 5:2}
2. bug in registerization concerning
   alias of a struct and one of its elements
3. code optimization of struct.field
   (which exposed bug in 2)

R=r
OCL=29315
CL=29315
parent 368b4210
......@@ -106,6 +106,7 @@ cgen(Node *n, Node *res)
nl = n->left;
nr = n->right;
if(nl != N && nl->ullman >= UINF)
if(nr != N && nr->ullman >= UINF) {
tempname(&n1, nl->type);
......@@ -555,7 +556,6 @@ agen(Node *n, Node *res)
break;
case ODOT:
t = nl->type;
agen(nl, res);
if(n->xoffset != 0) {
nodconst(&n1, types[TINT64], n->xoffset);
......@@ -564,9 +564,6 @@ agen(Node *n, Node *res)
break;
case ODOTPTR:
t = nl->type;
if(!isptr[t->etype])
fatal("agen: not ptr %N", n);
cgen(nl, res);
if(n->xoffset != 0) {
nodconst(&n1, types[TINT64], n->xoffset);
......
......@@ -23,6 +23,7 @@ struct Addr
char sval[NSNAME];
Sym* sym;
int width;
uchar type;
uchar index;
uchar etype;
......
......@@ -717,7 +717,7 @@ stataddr(Node *nam, Node *n)
switch(n->op) {
case ONAME:
*nam = *n;
return 1;
return n->addable;
case ODOT:
if(!stataddr(nam, n->left))
......
......@@ -1088,7 +1088,8 @@ naddr(Node *n, Addr *a)
case OPARAM:
// n->left is PHEAP ONAME for stack parameter.
// compute address of actual parameter on stack.
a->etype = n->left->type->etype;
a->etype = simtype[n->left->type->etype];
a->width = n->left->type->width;
a->offset = n->xoffset;
a->sym = n->left->sym;
a->type = D_PARAM;
......@@ -1096,8 +1097,11 @@ naddr(Node *n, Addr *a)
case ONAME:
a->etype = 0;
if(n->type != T)
a->width = 0;
if(n->type != T) {
a->etype = simtype[n->type->etype];
a->width = n->type->width;
}
a->offset = n->xoffset;
a->sym = n->sym;
if(a->sym == S)
......@@ -1819,6 +1823,15 @@ odot:
if(nn == N)
goto no;
if(nn->addable && o == 1 && oary[0] >= 0) {
// directly addressable set of DOTs
n1 = *nn;
n1.type = n->type;
n1.xoffset += oary[0];
naddr(&n1, a);
goto yes;
}
regalloc(reg, types[tptr], N);
n1 = *reg;
n1.op = OINDREG;
......
......@@ -752,7 +752,7 @@ Bits
mkvar(Reg *r, Adr *a)
{
Var *v;
int i, t, n, et, z;
int i, t, n, et, z, w;
int32 o;
Bits bit;
Sym *s;
......@@ -787,31 +787,29 @@ mkvar(Reg *r, Adr *a)
s = a->sym;
if(s == S)
goto none;
// if(s->name[0] == '!')
// goto none;
if(s->name[0] == '.')
goto none;
et = a->etype;
o = a->offset;
w = a->width;
v = var;
for(i=0; i<nvar; i++) {
if(s == v->sym)
if(n == v->name)
if(o == v->offset)
goto out;
v++;
}
switch(et) {
case 0:
case TFUNC:
case TARRAY:
case 0:
goto none;
}
if(nvar >= NVAR) {
if(debug['w'] > 1 && s)
fatal("variable not optimized: %s", s->name);
fatal("variable not optimized: %D", a);
goto none;
}
i = nvar;
......@@ -821,8 +819,9 @@ mkvar(Reg *r, Adr *a)
v->offset = o;
v->name = n;
v->etype = et;
v->width = w;
if(debug['R'])
print("bit=%2d et=%2d %D\n", i, et, a);
print("bit=%2d et=%2d w=%d %D\n", i, et, w, a);
ostats.nvar++;
out:
......@@ -833,10 +832,17 @@ out:
if(n == D_PARAM)
for(z=0; z<BITS; z++)
params.b[z] |= bit.b[z];
if(v->etype != et) {
// this has horrible consequences -
// no structure elements are registerized,
// but i dont know how to be more specific
if(v->etype != et || v->width != w || v->offset != o) {
/* funny punning */
if(debug['R'])
print("pun %d %d %S\n", v->etype, et, s);
print("pun et=%d/%d w=%d/%d o=%d/%d %D\n",
v->etype, et,
v->width, w,
v->offset, o, a);
for(z=0; z<BITS; z++)
addrs.b[z] |= bit.b[z];
}
......
......@@ -434,6 +434,7 @@ struct Var
{
vlong offset;
Sym* sym;
int width;
char name;
char etype;
};
......
......@@ -41,14 +41,6 @@ initlin(Node* n)
case OCALL:
// call to mapassign1
if(n->left->op != ONAME ||
n->right->op != OLIST ||
n->right->left->op != OAS ||
n->right->right->op != OLIST ||
n->right->right->left->op != OAS ||
n->right->right->right->op != OAS ||
strcmp(n->left->sym->name, "mapassign1") != 0)
dump("o=call", n);
n->ninit = N;
xxx.list = list(xxx.list, n);
break;
......@@ -72,7 +64,7 @@ inittmp(Node *n)
if(n->op == ONAME)
if(n->sym != S)
if(n->class == PAUTO)
if(strcmp(n->sym->name, "!tmpname!") == 0)
if(memcmp(n->sym->name, "autotmp_", 8) == 0)
return 1;
return 0;
}
......@@ -325,8 +317,9 @@ initfix(Node* n)
xxx.list = N;
initlin(n);
xxx.list = rev(xxx.list);
if(1)
return xxx.list;
if(debug['A'])
dump("preinitfix", xxx.list);
......
......@@ -2379,7 +2379,10 @@ tempname(Node *n, Type *t)
t = types[TINT32];
}
s = lookup("!tmpname!");
// give each tmp a different name so that there
// a chance to registerizer them
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
s = lookup(namebuf);
memset(n, 0, sizeof(*n));
n->op = ONAME;
......
......@@ -3980,6 +3980,27 @@ reorder4(Node *n)
return n;
}
static void
fielddup(Node *n, Node *hash[], ulong nhash)
{
uint h;
char *s;
Node *a;
if(n->op != ONAME)
fatal("fielddup: not ONAME");
s = n->sym->name;
h = stringhash(s)%nhash;
for(a=hash[h]; a!=N; a=a->ntest) {
if(strcmp(a->sym->name, s) == 0) {
yyerror("duplicate field name in struct literal: %s", s);
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
Node*
structlit(Node *n, Node *var)
{
......@@ -3987,6 +4008,7 @@ structlit(Node *n, Node *var)
Type *l, *t;
Node *r, *a;
int mixflag;
Node* hash[101];
t = n->type;
if(t->etype != TSTRUCT)
......@@ -4004,61 +4026,86 @@ structlit(Node *n, Node *var)
return var;
mixflag = 0;
if(r->op == OKEY) {
a = nod(OAS, var, N);
addtop = list(addtop, a);
goto loop2;
}
if(r->op == OKEY)
goto keyval;
l = structfirst(&savel, &n->type);
loop1:
// assignment to every field
if(l == T || r == N) {
if(l != T)
yyerror("struct literal expect expr of type %T", l);
if(r != N)
yyerror("struct literal too many expressions");
if(mixflag)
yyerror("mixture of field:value initializers");
return var;
}
if(r->op == OKEY) {
mixflag = 1;
goto incr1;
while(r != N) {
// assignment to every field
if(l == T)
break;
if(r->op == OKEY) {
mixflag = 1; // defer diagnostic
l = structnext(&savel);
r = listnext(&saver);
continue;
}
// build list of var.field = expr
a = nod(ODOT, var, newname(l->sym));
a = nod(OAS, a, r);
walktype(a, Etop);
addtop = list(addtop, a);
l = structnext(&savel);
r = listnext(&saver);
}
if(l != T)
yyerror("struct literal expect expr of type %T", l);
if(r != N)
yyerror("struct literal too many expressions");
if(mixflag)
yyerror("mixture of field:value initializers");
return var;
// build list of var.field = expr
a = nod(ODOT, var, newname(l->sym));
a = nod(OAS, a, r);
walktype(a, Etop);
keyval:
memset(hash, 0, sizeof(hash));
a = nod(OAS, var, N);
addtop = list(addtop, a);
incr1:
l = structnext(&savel);
r = listnext(&saver);
goto loop1;
while(r != N) {
// assignment to field:value elements
if(r->op != OKEY) {
mixflag = 1;
r = listnext(&saver);
continue;
}
loop2:
// assignment to field:value elements
if(r == N) {
if(mixflag)
yyerror("mixture of field:value initializers");
return var;
}
if(r->op != OKEY) {
mixflag = 1;
goto incr2;
// build list of var.field = expr
a = nod(ODOT, var, newname(r->left->sym));
fielddup(a->right, hash, nelem(hash));
a = nod(OAS, a, r->right);
walktype(a, Etop);
addtop = list(addtop, a);
r = listnext(&saver);
}
if(mixflag)
yyerror("mixture of field:value initializers");
return var;
}
// build list of var.field = expr
a = nod(ODOT, var, newname(r->left->sym));
a = nod(OAS, a, r->right);
walktype(a, Etop);
addtop = list(addtop, a);
static void
indexdup(Node *n, Node *hash[], ulong nhash)
{
uint h;
Node *a;
ulong b, c;
incr2:
r = listnext(&saver);
goto loop2;
if(n->op != OLITERAL)
fatal("indexdup: not OLITERAL");
b = mpgetfix(n->val.u.xval);
h = b%nhash;
for(a=hash[h]; a!=N; a=a->ntest) {
c = mpgetfix(a->val.u.xval);
if(b == c) {
yyerror("duplicate index in array literal: %ld", b);
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
Node*
......@@ -4068,6 +4115,7 @@ arraylit(Node *n, Node *var)
Type *t;
Node *r, *a;
long ninit, b;
Node* hash[101];
t = n->type;
if(t->etype != TARRAY)
......@@ -4126,6 +4174,8 @@ arraylit(Node *n, Node *var)
r = listfirst(&saver, &n->left);
if(r != N && r->op == OEMPTY)
r = N;
memset(hash, 0, sizeof(hash));
while(r != N) {
// build list of var[c] = expr
if(r->op == OKEY) {
......@@ -4137,6 +4187,7 @@ arraylit(Node *n, Node *var)
r = r->right;
}
a = nodintconst(b);
indexdup(a, hash, nelem(hash));
a = nod(OINDEX, var, a);
a = nod(OAS, a, r);
......@@ -4149,12 +4200,68 @@ arraylit(Node *n, Node *var)
return var;
}
static void
keydup(Node *n, Node *hash[], ulong nhash)
{
uint h;
ulong b;
double d;
int i;
Node *a;
Node cmp;
char *s;
evconst(n);
if(n->op != OLITERAL)
return; // we dont check variables
switch(n->val.ctype) {
default: // unknown, bool, nil
b = 23;
break;
case CTINT:
b = mpgetfix(n->val.u.xval);
break;
case CTFLT:
d = mpgetflt(n->val.u.fval);
s = (char*)&d;
b = 0;
for(i=sizeof(d); i>0; i--)
b = b*PRIME1 + *s++;
break;
case CTSTR:
b = 0;
s = n->val.u.sval->s;
for(i=n->val.u.sval->len; i>0; i--)
b = b*PRIME1 + *s++;
break;
}
h = b%nhash;
memset(&cmp, 0, sizeof(cmp));
for(a=hash[h]; a!=N; a=a->ntest) {
cmp.op = OEQ;
cmp.left = n;
cmp.right = a;
evconst(&cmp);
b = cmp.val.u.bval;
if(b) {
// too lazy to print the literal
yyerror("duplicate key in map literal");
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
Node*
maplit(Node *n, Node *var)
{
Iter saver;
Type *t;
Node *r, *a;
Node* hash[101];
t = n->type;
if(t->etype != TMAP)
......@@ -4174,6 +4281,7 @@ maplit(Node *n, Node *var)
if(r != N && r->op == OEMPTY)
r = N;
memset(hash, 0, sizeof(hash));
while(r != N) {
if(r == N)
break;
......@@ -4184,9 +4292,11 @@ maplit(Node *n, Node *var)
}
// build list of var[c] = expr
keydup(r->left, hash, nelem(hash));
a = nod(OINDEX, var, r->left);
a = nod(OAS, a, r->right);
walktype(a, Etop); // add any assignments in r to addtop
walktype(a, Etop);
addtop = list(addtop, a);
r = listnext(&saver);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment