3df95385bc
Section 6.5.15 of the C99 spec requires that if one argument of a ?: expression is a null pointer constant, and the other has a pointer type T*, then the type of the expression is T*. We were attempting to follow this rule, however, we only handled literal expressions when checking for null pointers. This change looks through casts, so 'nil' and 'NULL', and their expansion '(void*)0' are all detected as null pointer constants.
2124 lines
35 KiB
C
2124 lines
35 KiB
C
#include "cc.h"
|
|
|
|
Node*
|
|
new(int t, Node *l, Node *r)
|
|
{
|
|
Node *n;
|
|
|
|
n = alloc(sizeof(*n));
|
|
n->op = t;
|
|
n->left = l;
|
|
n->right = r;
|
|
if(l && t != OGOTO)
|
|
n->lineno = l->lineno;
|
|
else if(r)
|
|
n->lineno = r->lineno;
|
|
else
|
|
n->lineno = lineno;
|
|
newflag = 1;
|
|
return n;
|
|
}
|
|
|
|
Node*
|
|
new1(int o, Node *l, Node *r)
|
|
{
|
|
Node *n;
|
|
|
|
n = new(o, l, r);
|
|
n->lineno = nearln;
|
|
return n;
|
|
}
|
|
|
|
void
|
|
prtree(Node *n, char *s)
|
|
{
|
|
|
|
print(" == %s ==\n", s);
|
|
prtree1(n, 0, 0);
|
|
print("\n");
|
|
}
|
|
|
|
void
|
|
prtree1(Node *n, int d, int f)
|
|
{
|
|
int i;
|
|
|
|
if(f)
|
|
for(i=0; i<d; i++)
|
|
print(" ");
|
|
if(n == Z) {
|
|
print("Z\n");
|
|
return;
|
|
}
|
|
if(n->op == OLIST) {
|
|
prtree1(n->left, d, 0);
|
|
prtree1(n->right, d, 1);
|
|
return;
|
|
}
|
|
d++;
|
|
print("%O", n->op);
|
|
i = 3;
|
|
switch(n->op)
|
|
{
|
|
case ONAME:
|
|
print(" \"%F\"", n);
|
|
print(" %ld", n->xoffset);
|
|
i = 0;
|
|
break;
|
|
|
|
case OINDREG:
|
|
print(" %ld(R%d)", n->xoffset, n->reg);
|
|
i = 0;
|
|
break;
|
|
|
|
case OREGISTER:
|
|
if(n->xoffset)
|
|
print(" %ld+R%d", n->xoffset, n->reg);
|
|
else
|
|
print(" R%d", n->reg);
|
|
i = 0;
|
|
break;
|
|
|
|
case OSTRING:
|
|
print(" \"%s\"", n->cstring);
|
|
i = 0;
|
|
break;
|
|
|
|
case OLSTRING:
|
|
print(" \"%S\"", n->rstring);
|
|
i = 0;
|
|
break;
|
|
|
|
case ODOT:
|
|
case OELEM:
|
|
print(" \"%F\"", n);
|
|
break;
|
|
|
|
case OCONST:
|
|
if(typefd[n->type->etype])
|
|
print(" \"%.8e\"", n->fconst);
|
|
else
|
|
print(" \"%lld\"", n->vconst);
|
|
i = 0;
|
|
break;
|
|
}
|
|
if(n->addable != 0)
|
|
print(" <%d>", n->addable);
|
|
if(n->type != T)
|
|
print(" %T", n->type);
|
|
if(n->complex != 0)
|
|
print(" (%d)", n->complex);
|
|
print(" %L\n", n->lineno);
|
|
if(i & 2)
|
|
prtree1(n->left, d, 1);
|
|
if(i & 1)
|
|
prtree1(n->right, d, 1);
|
|
}
|
|
|
|
Type*
|
|
typ(int et, Type *d)
|
|
{
|
|
Type *t;
|
|
|
|
t = alloc(sizeof(*t));
|
|
t->etype = et;
|
|
t->link = d;
|
|
t->down = T;
|
|
t->sym = S;
|
|
t->width = ewidth[et];
|
|
t->offset = 0;
|
|
t->shift = 0;
|
|
t->nbits = 0;
|
|
t->garb = 0;
|
|
return t;
|
|
}
|
|
|
|
Type*
|
|
copytyp(Type *t)
|
|
{
|
|
Type *nt;
|
|
|
|
nt = typ(TXXX, T);
|
|
*nt = *t;
|
|
return nt;
|
|
}
|
|
|
|
Type*
|
|
garbt(Type *t, long b)
|
|
{
|
|
Type *t1;
|
|
|
|
if(b & BGARB) {
|
|
t1 = copytyp(t);
|
|
t1->garb = simpleg(b);
|
|
return t1;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
int
|
|
simpleg(long b)
|
|
{
|
|
|
|
b &= BGARB;
|
|
switch(b) {
|
|
case BCONSTNT:
|
|
return GCONSTNT;
|
|
case BVOLATILE:
|
|
return GVOLATILE;
|
|
case BVOLATILE|BCONSTNT:
|
|
return GCONSTNT|GVOLATILE;
|
|
}
|
|
return GXXX;
|
|
}
|
|
|
|
int
|
|
simplec(long b)
|
|
{
|
|
|
|
b &= BCLASS;
|
|
switch(b) {
|
|
case 0:
|
|
case BREGISTER:
|
|
return CXXX;
|
|
case BAUTO:
|
|
case BAUTO|BREGISTER:
|
|
return CAUTO;
|
|
case BEXTERN:
|
|
return CEXTERN;
|
|
case BEXTERN|BREGISTER:
|
|
return CEXREG;
|
|
case BSTATIC:
|
|
return CSTATIC;
|
|
case BTYPEDEF:
|
|
return CTYPEDEF;
|
|
case BTYPESTR:
|
|
return CTYPESTR;
|
|
}
|
|
diag(Z, "illegal combination of classes %Q", b);
|
|
return CXXX;
|
|
}
|
|
|
|
Type*
|
|
simplet(long b)
|
|
{
|
|
|
|
b &= ~BCLASS & ~BGARB;
|
|
switch(b) {
|
|
case BCHAR:
|
|
case BCHAR|BSIGNED:
|
|
return types[TCHAR];
|
|
|
|
case BCHAR|BUNSIGNED:
|
|
return types[TUCHAR];
|
|
|
|
case BSHORT:
|
|
case BSHORT|BINT:
|
|
case BSHORT|BSIGNED:
|
|
case BSHORT|BINT|BSIGNED:
|
|
return types[TSHORT];
|
|
|
|
case BUNSIGNED|BSHORT:
|
|
case BUNSIGNED|BSHORT|BINT:
|
|
return types[TUSHORT];
|
|
|
|
case 0:
|
|
case BINT:
|
|
case BINT|BSIGNED:
|
|
case BSIGNED:
|
|
return types[TINT];
|
|
|
|
case BUNSIGNED:
|
|
case BUNSIGNED|BINT:
|
|
return types[TUINT];
|
|
|
|
case BLONG:
|
|
case BLONG|BINT:
|
|
case BLONG|BSIGNED:
|
|
case BLONG|BINT|BSIGNED:
|
|
return types[TLONG];
|
|
|
|
case BUNSIGNED|BLONG:
|
|
case BUNSIGNED|BLONG|BINT:
|
|
return types[TULONG];
|
|
|
|
case BVLONG|BLONG:
|
|
case BVLONG|BLONG|BINT:
|
|
case BVLONG|BLONG|BSIGNED:
|
|
case BVLONG|BLONG|BINT|BSIGNED:
|
|
return types[TVLONG];
|
|
|
|
case BVLONG|BLONG|BUNSIGNED:
|
|
case BVLONG|BLONG|BINT|BUNSIGNED:
|
|
return types[TUVLONG];
|
|
|
|
case BFLOAT:
|
|
return types[TFLOAT];
|
|
|
|
case BDOUBLE:
|
|
case BDOUBLE|BLONG:
|
|
case BFLOAT|BLONG:
|
|
return types[TDOUBLE];
|
|
|
|
case BVOID:
|
|
return types[TVOID];
|
|
}
|
|
|
|
diag(Z, "illegal combination of types %Q", b);
|
|
return types[TINT];
|
|
}
|
|
|
|
int
|
|
stcompat(Node *n, Type *t1, Type *t2, long ttab[])
|
|
{
|
|
int i;
|
|
ulong b;
|
|
|
|
i = 0;
|
|
if(t2 != T)
|
|
i = t2->etype;
|
|
b = 1L << i;
|
|
i = 0;
|
|
if(t1 != T)
|
|
i = t1->etype;
|
|
if(b & ttab[i]) {
|
|
if(ttab == tasign)
|
|
if(b == BSTRUCT || b == BUNION)
|
|
if(!sametype(t1, t2))
|
|
return 1;
|
|
if(n->op != OCAST)
|
|
if(b == BIND && i == TIND)
|
|
if(!sametype(t1, t2))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
tcompat(Node *n, Type *t1, Type *t2, long ttab[])
|
|
{
|
|
|
|
if(stcompat(n, t1, t2, ttab)) {
|
|
if(t1 == T)
|
|
diag(n, "incompatible type: \"%T\" for op \"%O\"",
|
|
t2, n->op);
|
|
else
|
|
diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
|
|
t1, t2, n->op);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
makedot(Node *n, Type *t, long o)
|
|
{
|
|
Node *n1, *n2;
|
|
|
|
if(t->nbits) {
|
|
n1 = new(OXXX, Z, Z);
|
|
*n1 = *n;
|
|
n->op = OBIT;
|
|
n->left = n1;
|
|
n->right = Z;
|
|
n->type = t;
|
|
n->addable = n1->left->addable;
|
|
n = n1;
|
|
}
|
|
n->addable = n->left->addable;
|
|
if(n->addable == 0) {
|
|
n1 = new1(OCONST, Z, Z);
|
|
n1->vconst = o;
|
|
n1->type = types[TLONG];
|
|
n->right = n1;
|
|
n->type = t;
|
|
return;
|
|
}
|
|
n->left->type = t;
|
|
if(o == 0) {
|
|
*n = *n->left;
|
|
return;
|
|
}
|
|
n->type = t;
|
|
n1 = new1(OCONST, Z, Z);
|
|
n1->vconst = o;
|
|
t = typ(TIND, t);
|
|
t->width = types[TIND]->width;
|
|
n1->type = t;
|
|
|
|
n2 = new1(OADDR, n->left, Z);
|
|
n2->type = t;
|
|
|
|
n1 = new1(OADD, n1, n2);
|
|
n1->type = t;
|
|
|
|
n->op = OIND;
|
|
n->left = n1;
|
|
n->right = Z;
|
|
}
|
|
|
|
Type*
|
|
dotsearch(Sym *s, Type *t, Node *n, long *off)
|
|
{
|
|
Type *t1, *xt, *rt;
|
|
|
|
xt = T;
|
|
|
|
/*
|
|
* look it up by name
|
|
*/
|
|
for(t1 = t; t1 != T; t1 = t1->down)
|
|
if(t1->sym == s) {
|
|
if(xt != T)
|
|
goto ambig;
|
|
xt = t1;
|
|
}
|
|
|
|
/*
|
|
* look it up by type
|
|
*/
|
|
if(s->class == CTYPEDEF || s->class == CTYPESTR)
|
|
for(t1 = t; t1 != T; t1 = t1->down)
|
|
if(t1->sym == S && typesu[t1->etype])
|
|
if(sametype(s->type, t1)) {
|
|
if(xt != T)
|
|
goto ambig;
|
|
xt = t1;
|
|
}
|
|
if(xt != T) {
|
|
*off = xt->offset;
|
|
return xt;
|
|
}
|
|
|
|
/*
|
|
* look it up in unnamed substructures
|
|
*/
|
|
for(t1 = t; t1 != T; t1 = t1->down)
|
|
if(t1->sym == S && typesu[t1->etype]){
|
|
rt = dotsearch(s, t1->link, n, off);
|
|
if(rt != T) {
|
|
if(xt != T)
|
|
goto ambig;
|
|
xt = rt;
|
|
*off += t1->offset;
|
|
}
|
|
}
|
|
return xt;
|
|
|
|
ambig:
|
|
diag(n, "ambiguous structure element: %s", s->name);
|
|
return xt;
|
|
}
|
|
|
|
long
|
|
dotoffset(Type *st, Type *lt, Node *n)
|
|
{
|
|
Type *t;
|
|
Sym *g;
|
|
long o, o1;
|
|
|
|
o = -1;
|
|
/*
|
|
* first try matching at the top level
|
|
* for matching tag names
|
|
*/
|
|
g = st->tag;
|
|
if(g != S)
|
|
for(t=lt->link; t!=T; t=t->down)
|
|
if(t->sym == S)
|
|
if(g == t->tag) {
|
|
if(o >= 0)
|
|
goto ambig;
|
|
o = t->offset;
|
|
}
|
|
if(o >= 0)
|
|
return o;
|
|
|
|
/*
|
|
* second try matching at the top level
|
|
* for similar types
|
|
*/
|
|
for(t=lt->link; t!=T; t=t->down)
|
|
if(t->sym == S)
|
|
if(sametype(st, t)) {
|
|
if(o >= 0)
|
|
goto ambig;
|
|
o = t->offset;
|
|
}
|
|
if(o >= 0)
|
|
return o;
|
|
|
|
/*
|
|
* last try matching sub-levels
|
|
*/
|
|
for(t=lt->link; t!=T; t=t->down)
|
|
if(t->sym == S)
|
|
if(typesu[t->etype]) {
|
|
o1 = dotoffset(st, t, n);
|
|
if(o1 >= 0) {
|
|
if(o >= 0)
|
|
goto ambig;
|
|
o = o1 + t->offset;
|
|
}
|
|
}
|
|
return o;
|
|
|
|
ambig:
|
|
diag(n, "ambiguous unnamed structure element");
|
|
return o;
|
|
}
|
|
|
|
/*
|
|
* look into tree for floating point constant expressions
|
|
*/
|
|
int
|
|
allfloat(Node *n, int flag)
|
|
{
|
|
|
|
if(n != Z) {
|
|
if(n->type->etype != TDOUBLE)
|
|
return 1;
|
|
switch(n->op) {
|
|
case OCONST:
|
|
if(flag)
|
|
n->type = types[TFLOAT];
|
|
return 1;
|
|
case OADD: /* no need to get more exotic than this */
|
|
case OSUB:
|
|
case OMUL:
|
|
case ODIV:
|
|
if(!allfloat(n->right, flag))
|
|
break;
|
|
case OCAST:
|
|
if(!allfloat(n->left, flag))
|
|
break;
|
|
if(flag)
|
|
n->type = types[TFLOAT];
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
constas(Node *n, Type *il, Type *ir)
|
|
{
|
|
Type *l, *r;
|
|
|
|
l = il;
|
|
r = ir;
|
|
|
|
if(l == T)
|
|
return;
|
|
if(l->garb & GCONSTNT) {
|
|
warn(n, "assignment to a constant type (%T)", il);
|
|
return;
|
|
}
|
|
if(r == T)
|
|
return;
|
|
for(;;) {
|
|
if(l->etype != TIND || r->etype != TIND)
|
|
break;
|
|
l = l->link;
|
|
r = r->link;
|
|
if(l == T || r == T)
|
|
break;
|
|
if(r->garb & GCONSTNT)
|
|
if(!(l->garb & GCONSTNT)) {
|
|
warn(n, "assignment of a constant pointer type (%T)", ir);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
typeext1(Type *st, Node *l)
|
|
{
|
|
if(st->etype == TFLOAT && allfloat(l, 0))
|
|
allfloat(l, 1);
|
|
}
|
|
|
|
void
|
|
typeext(Type *st, Node *l)
|
|
{
|
|
Type *lt;
|
|
Node *n1, *n2;
|
|
long o;
|
|
|
|
lt = l->type;
|
|
if(lt == T)
|
|
return;
|
|
if(st->etype == TIND && vconst(l) == 0) {
|
|
l->type = st;
|
|
l->vconst = 0;
|
|
return;
|
|
}
|
|
typeext1(st, l);
|
|
|
|
/*
|
|
* extension of C
|
|
* if assign of struct containing unnamed sub-struct
|
|
* to type of sub-struct, insert the DOT.
|
|
* if assign of *struct containing unnamed substruct
|
|
* to type of *sub-struct, insert the add-offset
|
|
*/
|
|
if(typesu[st->etype] && typesu[lt->etype]) {
|
|
o = dotoffset(st, lt, l);
|
|
if(o >= 0) {
|
|
n1 = new1(OXXX, Z, Z);
|
|
*n1 = *l;
|
|
l->op = ODOT;
|
|
l->left = n1;
|
|
l->right = Z;
|
|
makedot(l, st, o);
|
|
}
|
|
return;
|
|
}
|
|
if(st->etype == TIND && typesu[st->link->etype])
|
|
if(lt->etype == TIND && typesu[lt->link->etype]) {
|
|
o = dotoffset(st->link, lt->link, l);
|
|
if(o >= 0) {
|
|
l->type = st;
|
|
if(o == 0)
|
|
return;
|
|
n1 = new1(OXXX, Z, Z);
|
|
*n1 = *l;
|
|
n2 = new1(OCONST, Z, Z);
|
|
n2->vconst = o;
|
|
n2->type = st;
|
|
l->op = OADD;
|
|
l->left = n1;
|
|
l->right = n2;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* a cast that generates no code
|
|
* (same size move)
|
|
*/
|
|
int
|
|
nocast(Type *t1, Type *t2)
|
|
{
|
|
int i, b;
|
|
|
|
if(t1->nbits)
|
|
return 0;
|
|
i = 0;
|
|
if(t2 != T)
|
|
i = t2->etype;
|
|
b = 1<<i;
|
|
i = 0;
|
|
if(t1 != T)
|
|
i = t1->etype;
|
|
if(b & ncast[i])
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* a cast that has a noop semantic
|
|
* (small to large, convert)
|
|
*/
|
|
int
|
|
nilcast(Type *t1, Type *t2)
|
|
{
|
|
int et1, et2;
|
|
|
|
if(t1 == T)
|
|
return 0;
|
|
if(t1->nbits)
|
|
return 0;
|
|
if(t2 == T)
|
|
return 0;
|
|
et1 = t1->etype;
|
|
et2 = t2->etype;
|
|
if(et1 == et2)
|
|
return 1;
|
|
if(typefd[et1] && typefd[et2]) {
|
|
if(ewidth[et1] < ewidth[et2])
|
|
return 1;
|
|
return 0;
|
|
}
|
|
if(typechlp[et1] && typechlp[et2]) {
|
|
if(ewidth[et1] < ewidth[et2])
|
|
return 1;
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* "the usual arithmetic conversions are performed"
|
|
*/
|
|
void
|
|
arith(Node *n, int f)
|
|
{
|
|
Type *t1, *t2;
|
|
int i, j, k;
|
|
Node *n1;
|
|
long w, x;
|
|
|
|
t1 = n->left->type;
|
|
if(n->right == Z)
|
|
t2 = t1;
|
|
else
|
|
t2 = n->right->type;
|
|
i = TXXX;
|
|
if(t1 != T)
|
|
i = t1->etype;
|
|
j = TXXX;
|
|
if(t2 != T)
|
|
j = t2->etype;
|
|
k = tab[i][j];
|
|
if(k == TIND) {
|
|
if(i == TIND)
|
|
n->type = t1;
|
|
else
|
|
if(j == TIND)
|
|
n->type = t2;
|
|
} else {
|
|
/* convert up to at least int */
|
|
if(f == 1)
|
|
while(k < TINT)
|
|
k += 2;
|
|
n->type = types[k];
|
|
}
|
|
if(n->op == OSUB)
|
|
if(i == TIND && j == TIND) {
|
|
w = n->right->type->link->width;
|
|
if(w < 1) {
|
|
snap(n->right->type->link);
|
|
w = n->right->type->link->width;
|
|
}
|
|
x = 0;
|
|
if(n->left->type->link != T) {
|
|
x = n->left->type->link->width;
|
|
if(x < 1) {
|
|
snap(n->left->type->link);
|
|
x = n->left->type->link->width;
|
|
}
|
|
}
|
|
if(w < 1 || x < 1)
|
|
goto bad;
|
|
n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
|
|
if(w > 1) {
|
|
n1 = new1(OXXX, Z, Z);
|
|
*n1 = *n;
|
|
n->op = ODIV;
|
|
n->left = n1;
|
|
n1 = new1(OCONST, Z, Z);
|
|
n1->vconst = w;
|
|
n1->type = n->type;
|
|
n->right = n1;
|
|
w = vlog(n1);
|
|
if(w >= 0) {
|
|
n->op = OASHR;
|
|
n1->vconst = w;
|
|
}
|
|
}
|
|
if(0 && ewidth[TIND] > ewidth[TLONG]){
|
|
n1 = new1(OXXX, Z, Z);
|
|
*n1 = *n;
|
|
n->op = OCAST;
|
|
n->left = n1;
|
|
n->right = Z;
|
|
n->type = types[TLONG];
|
|
}
|
|
return;
|
|
}
|
|
if(!sametype(n->type, n->left->type)) {
|
|
n->left = new1(OCAST, n->left, Z);
|
|
n->left->type = n->type;
|
|
if(n->type->etype == TIND) {
|
|
w = n->type->link->width;
|
|
if(w < 1) {
|
|
snap(n->type->link);
|
|
w = n->type->link->width;
|
|
if(w < 1)
|
|
goto bad;
|
|
}
|
|
if(w > 1) {
|
|
n1 = new1(OCONST, Z, Z);
|
|
n1->vconst = w;
|
|
n1->type = n->type;
|
|
n->left = new1(OMUL, n->left, n1);
|
|
n->left->type = n->type;
|
|
}
|
|
}
|
|
}
|
|
if(n->right != Z)
|
|
if(!sametype(n->type, n->right->type)) {
|
|
n->right = new1(OCAST, n->right, Z);
|
|
n->right->type = n->type;
|
|
if(n->type->etype == TIND) {
|
|
w = n->type->link->width;
|
|
if(w < 1) {
|
|
snap(n->type->link);
|
|
w = n->type->link->width;
|
|
if(w < 1)
|
|
goto bad;
|
|
}
|
|
if(w != 1) {
|
|
n1 = new1(OCONST, Z, Z);
|
|
n1->vconst = w;
|
|
n1->type = n->type;
|
|
n->right = new1(OMUL, n->right, n1);
|
|
n->right->type = n->type;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
bad:
|
|
diag(n, "pointer addition not fully declared: %T", n->type->link);
|
|
}
|
|
|
|
/*
|
|
* try to rewrite shift & mask
|
|
*/
|
|
void
|
|
simplifyshift(Node *n)
|
|
{
|
|
ulong c3;
|
|
int o, s1, s2, c1, c2;
|
|
|
|
if(!typechlp[n->type->etype])
|
|
return;
|
|
switch(n->op) {
|
|
default:
|
|
return;
|
|
case OASHL:
|
|
s1 = 0;
|
|
break;
|
|
case OLSHR:
|
|
s1 = 1;
|
|
break;
|
|
case OASHR:
|
|
s1 = 2;
|
|
break;
|
|
}
|
|
if(n->right->op != OCONST)
|
|
return;
|
|
if(n->left->op != OAND)
|
|
return;
|
|
if(n->left->right->op != OCONST)
|
|
return;
|
|
switch(n->left->left->op) {
|
|
default:
|
|
return;
|
|
case OASHL:
|
|
s2 = 0;
|
|
break;
|
|
case OLSHR:
|
|
s2 = 1;
|
|
break;
|
|
case OASHR:
|
|
s2 = 2;
|
|
break;
|
|
}
|
|
if(n->left->left->right->op != OCONST)
|
|
return;
|
|
|
|
c1 = n->right->vconst;
|
|
c2 = n->left->left->right->vconst;
|
|
c3 = n->left->right->vconst;
|
|
|
|
/*
|
|
if(debug['h'])
|
|
print("%.3o %ld %ld %d #%.lux\n",
|
|
(s1<<3)|s2, c1, c2, topbit(c3), c3);
|
|
*/
|
|
|
|
o = n->op;
|
|
switch((s1<<3)|s2) {
|
|
case 000: /* (((e <<u c2) & c3) <<u c1) */
|
|
c3 >>= c2;
|
|
c1 += c2;
|
|
if(c1 >= 32)
|
|
break;
|
|
goto rewrite1;
|
|
|
|
case 002: /* (((e >>s c2) & c3) <<u c1) */
|
|
if(topbit(c3) >= (32-c2))
|
|
break;
|
|
case 001: /* (((e >>u c2) & c3) <<u c1) */
|
|
if(c1 > c2) {
|
|
c3 <<= c2;
|
|
c1 -= c2;
|
|
o = OASHL;
|
|
goto rewrite1;
|
|
}
|
|
c3 <<= c1;
|
|
if(c1 == c2)
|
|
goto rewrite0;
|
|
c1 = c2-c1;
|
|
o = OLSHR;
|
|
goto rewrite2;
|
|
|
|
case 022: /* (((e >>s c2) & c3) >>s c1) */
|
|
if(c2 <= 0)
|
|
break;
|
|
case 012: /* (((e >>s c2) & c3) >>u c1) */
|
|
if(topbit(c3) >= (32-c2))
|
|
break;
|
|
goto s11;
|
|
case 021: /* (((e >>u c2) & c3) >>s c1) */
|
|
if(topbit(c3) >= 31 && c2 <= 0)
|
|
break;
|
|
goto s11;
|
|
case 011: /* (((e >>u c2) & c3) >>u c1) */
|
|
s11:
|
|
c3 <<= c2;
|
|
c1 += c2;
|
|
if(c1 >= 32)
|
|
break;
|
|
o = OLSHR;
|
|
goto rewrite1;
|
|
|
|
case 020: /* (((e <<u c2) & c3) >>s c1) */
|
|
if(topbit(c3) >= 31)
|
|
break;
|
|
case 010: /* (((e <<u c2) & c3) >>u c1) */
|
|
c3 >>= c1;
|
|
if(c1 == c2)
|
|
goto rewrite0;
|
|
if(c1 > c2) {
|
|
c1 -= c2;
|
|
goto rewrite2;
|
|
}
|
|
c1 = c2 - c1;
|
|
o = OASHL;
|
|
goto rewrite2;
|
|
}
|
|
return;
|
|
|
|
rewrite0: /* get rid of both shifts */
|
|
if(debug['<'])prtree(n, "rewrite0");
|
|
*n = *n->left;
|
|
n->left = n->left->left;
|
|
n->right->vconst = c3;
|
|
return;
|
|
rewrite1: /* get rid of lower shift */
|
|
if(debug['<'])prtree(n, "rewrite1");
|
|
n->left->left = n->left->left->left;
|
|
n->left->right->vconst = c3;
|
|
n->right->vconst = c1;
|
|
n->op = o;
|
|
return;
|
|
rewrite2: /* get rid of upper shift */
|
|
if(debug['<'])prtree(n, "rewrite2");
|
|
*n = *n->left;
|
|
n->right->vconst = c3;
|
|
n->left->right->vconst = c1;
|
|
n->left->op = o;
|
|
}
|
|
|
|
/*
|
|
* replace shift/or with rotate left
|
|
*/
|
|
void
|
|
rolor(Node *n)
|
|
{
|
|
Node *l, *r;
|
|
|
|
if(!typeu[n->type->etype])
|
|
return;
|
|
|
|
l = n->left;
|
|
r = n->right;
|
|
switch(l->op){
|
|
case OASHL:
|
|
if(r->op == OLSHR)
|
|
break;
|
|
return;
|
|
case OLSHR:
|
|
if(r->op == OASHL){
|
|
r = l;
|
|
l = n->right;
|
|
break;
|
|
}
|
|
default:
|
|
return;
|
|
}
|
|
if(l->right->op != OCONST || r->right->op != OCONST)
|
|
return;
|
|
if(vconst(l->right) + vconst(r->right) != ewidth[n->type->etype]*8)
|
|
return;
|
|
if(l->left->type != n->type || r->left->type != n->type)
|
|
return;
|
|
if(l->left->op != ONAME || r->left->op != ONAME || l->left->sym != r->left->sym)
|
|
return;
|
|
|
|
*n = *l;
|
|
n->op = OROL;
|
|
}
|
|
|
|
int
|
|
side(Node *n)
|
|
{
|
|
|
|
loop:
|
|
if(n != Z)
|
|
switch(n->op) {
|
|
case OCAST:
|
|
case ONOT:
|
|
case OADDR:
|
|
case OIND:
|
|
case OCOM:
|
|
case ONEG:
|
|
case OPOS:
|
|
case OTST:
|
|
n = n->left;
|
|
goto loop;
|
|
|
|
case OCOND:
|
|
if(side(n->left))
|
|
break;
|
|
n = n->right;
|
|
|
|
case OEQ:
|
|
case ONE:
|
|
case OLT:
|
|
case OGE:
|
|
case OGT:
|
|
case OLE:
|
|
case OADD:
|
|
case OSUB:
|
|
case OMUL:
|
|
case OLMUL:
|
|
case ODIV:
|
|
case OLDIV:
|
|
case OLSHR:
|
|
case OASHL:
|
|
case OASHR:
|
|
case OROL:
|
|
case OAND:
|
|
case OOR:
|
|
case OXOR:
|
|
case OMOD:
|
|
case OLMOD:
|
|
case OANDAND:
|
|
case OOROR:
|
|
case OCOMMA:
|
|
case ODOT:
|
|
case OFAS:
|
|
case OINDEX:
|
|
if(side(n->left))
|
|
break;
|
|
n = n->right;
|
|
goto loop;
|
|
|
|
case OSIGN:
|
|
case OSIZE:
|
|
case OCONST:
|
|
case OSTRING:
|
|
case OLSTRING:
|
|
case ONAME:
|
|
case OREGPAIR:
|
|
case OEXREG:
|
|
case OREGISTER:
|
|
case OINDREG:
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
zpconst(Node *n)
|
|
{
|
|
while(n->op == OCAST){
|
|
if(n->type == T)
|
|
break;
|
|
if(n->type->etype != TIND)
|
|
break;
|
|
if(n->type->link->etype != TVOID)
|
|
break;
|
|
n = n->left;
|
|
}
|
|
return vconst(n) == 0;
|
|
}
|
|
|
|
int
|
|
vconst(Node *n)
|
|
{
|
|
int i;
|
|
|
|
if(n == Z)
|
|
goto no;
|
|
if(n->op != OCONST)
|
|
goto no;
|
|
if(n->type == T)
|
|
goto no;
|
|
switch(n->type->etype)
|
|
{
|
|
case TFLOAT:
|
|
case TDOUBLE:
|
|
i = 100;
|
|
if(n->fconst > i || n->fconst < -i)
|
|
goto no;
|
|
i = n->fconst;
|
|
if(i != n->fconst)
|
|
goto no;
|
|
return i;
|
|
|
|
case TVLONG:
|
|
case TUVLONG:
|
|
i = n->vconst;
|
|
if(i != n->vconst)
|
|
goto no;
|
|
return i;
|
|
|
|
case TCHAR:
|
|
case TUCHAR:
|
|
case TSHORT:
|
|
case TUSHORT:
|
|
case TINT:
|
|
case TUINT:
|
|
case TLONG:
|
|
case TULONG:
|
|
case TIND:
|
|
i = n->vconst;
|
|
if(i != n->vconst)
|
|
goto no;
|
|
return i;
|
|
}
|
|
no:
|
|
return -159; /* first uninteresting constant */
|
|
}
|
|
|
|
/*
|
|
* return log(n) if n is a power of 2 constant
|
|
*/
|
|
int
|
|
log2(uvlong v)
|
|
{
|
|
int s, i;
|
|
uvlong m;
|
|
|
|
s = 0;
|
|
m = MASK(8*sizeof(uvlong));
|
|
for(i=32; i; i>>=1) {
|
|
m >>= i;
|
|
if(!(v & m)) {
|
|
v >>= i;
|
|
s += i;
|
|
}
|
|
}
|
|
if(v == 1)
|
|
return s;
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
vlog(Node *n)
|
|
{
|
|
if(n->op != OCONST)
|
|
goto bad;
|
|
if(typefd[n->type->etype])
|
|
goto bad;
|
|
|
|
return log2(n->vconst);
|
|
|
|
bad:
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
topbit(ulong v)
|
|
{
|
|
int i;
|
|
|
|
for(i = -1; v; i++)
|
|
v >>= 1;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
* try to cast a constant down
|
|
* rather than cast a variable up
|
|
* example:
|
|
* if(c == 'a')
|
|
*/
|
|
void
|
|
relcon(Node *l, Node *r)
|
|
{
|
|
vlong v;
|
|
|
|
if(l->op != OCONST)
|
|
return;
|
|
if(r->op != OCAST)
|
|
return;
|
|
if(!nilcast(r->left->type, r->type))
|
|
return;
|
|
switch(r->type->etype) {
|
|
default:
|
|
return;
|
|
case TCHAR:
|
|
case TUCHAR:
|
|
case TSHORT:
|
|
case TUSHORT:
|
|
v = convvtox(l->vconst, r->type->etype);
|
|
if(v != l->vconst)
|
|
return;
|
|
break;
|
|
}
|
|
l->type = r->left->type;
|
|
*r = *r->left;
|
|
}
|
|
|
|
int
|
|
relindex(int o)
|
|
{
|
|
|
|
switch(o) {
|
|
default:
|
|
diag(Z, "bad in relindex: %O", o);
|
|
case OEQ: return 0;
|
|
case ONE: return 1;
|
|
case OLE: return 2;
|
|
case OLS: return 3;
|
|
case OLT: return 4;
|
|
case OLO: return 5;
|
|
case OGE: return 6;
|
|
case OHS: return 7;
|
|
case OGT: return 8;
|
|
case OHI: return 9;
|
|
}
|
|
}
|
|
|
|
Node*
|
|
invert(Node *n)
|
|
{
|
|
Node *i;
|
|
|
|
if(n == Z || n->op != OLIST)
|
|
return n;
|
|
i = n;
|
|
for(n = n->left; n != Z; n = n->left) {
|
|
if(n->op != OLIST)
|
|
break;
|
|
i->left = n->right;
|
|
n->right = i;
|
|
i = n;
|
|
}
|
|
i->left = n;
|
|
return i;
|
|
}
|
|
|
|
int
|
|
bitno(long b)
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i<32; i++)
|
|
if(b & (1L<<i))
|
|
return i;
|
|
diag(Z, "bad in bitno");
|
|
return 0;
|
|
}
|
|
|
|
long
|
|
typebitor(long a, long b)
|
|
{
|
|
long c;
|
|
|
|
c = a | b;
|
|
if(a & b)
|
|
if((a & b) == BLONG)
|
|
c |= BVLONG; /* long long => vlong */
|
|
else
|
|
warn(Z, "once is enough: %Q", a & b);
|
|
return c;
|
|
}
|
|
|
|
void
|
|
diag(Node *n, char *fmt, ...)
|
|
{
|
|
char buf[STRINGSZ];
|
|
va_list arg;
|
|
|
|
va_start(arg, fmt);
|
|
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
|
va_end(arg);
|
|
Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
|
|
|
|
if(debug['X']){
|
|
Bflush(&diagbuf);
|
|
abort();
|
|
}
|
|
if(n != Z)
|
|
if(debug['v'])
|
|
prtree(n, "diagnostic");
|
|
|
|
nerrors++;
|
|
if(nerrors > 10) {
|
|
Bprint(&diagbuf, "too many errors\n");
|
|
errorexit();
|
|
}
|
|
}
|
|
|
|
void
|
|
warn(Node *n, char *fmt, ...)
|
|
{
|
|
char buf[STRINGSZ];
|
|
va_list arg;
|
|
|
|
if(debug['w']) {
|
|
Bprint(&diagbuf, "warning: ");
|
|
va_start(arg, fmt);
|
|
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
|
va_end(arg);
|
|
Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
|
|
|
|
if(n != Z)
|
|
if(debug['v'])
|
|
prtree(n, "warning");
|
|
}
|
|
}
|
|
|
|
void
|
|
yyerror(char *fmt, ...)
|
|
{
|
|
char buf[STRINGSZ];
|
|
va_list arg;
|
|
|
|
/*
|
|
* hack to intercept message from yaccpar
|
|
*/
|
|
if(strcmp(fmt, "syntax error") == 0) {
|
|
yyerror("syntax error, last name: %s", symb);
|
|
return;
|
|
}
|
|
va_start(arg, fmt);
|
|
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
|
va_end(arg);
|
|
Bprint(&diagbuf, "%L %s\n", lineno, buf);
|
|
nerrors++;
|
|
if(nerrors > 10) {
|
|
Bprint(&diagbuf, "too many errors\n");
|
|
errorexit();
|
|
}
|
|
}
|
|
|
|
void
|
|
fatal(Node *n, char *fmt, ...)
|
|
{
|
|
char buf[STRINGSZ];
|
|
va_list arg;
|
|
|
|
va_start(arg, fmt);
|
|
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
|
va_end(arg);
|
|
Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
|
|
|
|
if(debug['X']){
|
|
Bflush(&diagbuf);
|
|
abort();
|
|
}
|
|
if(n != Z)
|
|
if(debug['v'])
|
|
prtree(n, "diagnostic");
|
|
|
|
nerrors++;
|
|
errorexit();
|
|
}
|
|
|
|
ulong thash1 = 0x2edab8c9;
|
|
ulong thash2 = 0x1dc74fb8;
|
|
ulong thash3 = 0x1f241331;
|
|
ulong thash[NALLTYPES];
|
|
Init thashinit[] =
|
|
{
|
|
TXXX, 0x17527bbd, 0,
|
|
TCHAR, 0x5cedd32b, 0,
|
|
TUCHAR, 0x552c4454, 0,
|
|
TSHORT, 0x63040b4b, 0,
|
|
TUSHORT, 0x32a45878, 0,
|
|
TINT, 0x4151d5bd, 0,
|
|
TUINT, 0x5ae707d6, 0,
|
|
TLONG, 0x5ef20f47, 0,
|
|
TULONG, 0x36d8eb8f, 0,
|
|
TVLONG, 0x6e5e9590, 0,
|
|
TUVLONG, 0x75910105, 0,
|
|
TFLOAT, 0x25fd7af1, 0,
|
|
TDOUBLE, 0x7c40a1b2, 0,
|
|
TIND, 0x1b832357, 0,
|
|
TFUNC, 0x6babc9cb, 0,
|
|
TARRAY, 0x7c50986d, 0,
|
|
TVOID, 0x44112eff, 0,
|
|
TSTRUCT, 0x7c2da3bf, 0,
|
|
TUNION, 0x3eb25e98, 0,
|
|
TENUM, 0x44b54f61, 0,
|
|
TFILE, 0x19242ac3, 0,
|
|
TOLD, 0x22b15988, 0,
|
|
TDOT, 0x0204f6b3, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
char* bnames[NALIGN];
|
|
Init bnamesinit[] =
|
|
{
|
|
Axxx, 0, "Axxx",
|
|
Ael1, 0, "el1",
|
|
Ael2, 0, "el2",
|
|
Asu2, 0, "su2",
|
|
Aarg0, 0, "arg0",
|
|
Aarg1, 0, "arg1",
|
|
Aarg2, 0, "arg2",
|
|
Aaut3, 0, "aut3",
|
|
-1, 0, 0,
|
|
};
|
|
|
|
char* tnames[NALLTYPES];
|
|
Init tnamesinit[] =
|
|
{
|
|
TXXX, 0, "TXXX",
|
|
TCHAR, 0, "CHAR",
|
|
TUCHAR, 0, "UCHAR",
|
|
TSHORT, 0, "SHORT",
|
|
TUSHORT, 0, "USHORT",
|
|
TINT, 0, "INT",
|
|
TUINT, 0, "UINT",
|
|
TLONG, 0, "LONG",
|
|
TULONG, 0, "ULONG",
|
|
TVLONG, 0, "VLONG",
|
|
TUVLONG, 0, "UVLONG",
|
|
TFLOAT, 0, "FLOAT",
|
|
TDOUBLE, 0, "DOUBLE",
|
|
TIND, 0, "IND",
|
|
TFUNC, 0, "FUNC",
|
|
TARRAY, 0, "ARRAY",
|
|
TVOID, 0, "VOID",
|
|
TSTRUCT, 0, "STRUCT",
|
|
TUNION, 0, "UNION",
|
|
TENUM, 0, "ENUM",
|
|
TFILE, 0, "FILE",
|
|
TOLD, 0, "OLD",
|
|
TDOT, 0, "DOT",
|
|
-1, 0, 0,
|
|
};
|
|
|
|
char* gnames[NGTYPES];
|
|
Init gnamesinit[] =
|
|
{
|
|
GXXX, 0, "GXXX",
|
|
GCONSTNT, 0, "CONST",
|
|
GVOLATILE, 0, "VOLATILE",
|
|
GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE",
|
|
-1, 0, 0,
|
|
};
|
|
|
|
char* qnames[NALLTYPES];
|
|
Init qnamesinit[] =
|
|
{
|
|
TXXX, 0, "TXXX",
|
|
TCHAR, 0, "CHAR",
|
|
TUCHAR, 0, "UCHAR",
|
|
TSHORT, 0, "SHORT",
|
|
TUSHORT, 0, "USHORT",
|
|
TINT, 0, "INT",
|
|
TUINT, 0, "UINT",
|
|
TLONG, 0, "LONG",
|
|
TULONG, 0, "ULONG",
|
|
TVLONG, 0, "VLONG",
|
|
TUVLONG, 0, "UVLONG",
|
|
TFLOAT, 0, "FLOAT",
|
|
TDOUBLE, 0, "DOUBLE",
|
|
TIND, 0, "IND",
|
|
TFUNC, 0, "FUNC",
|
|
TARRAY, 0, "ARRAY",
|
|
TVOID, 0, "VOID",
|
|
TSTRUCT, 0, "STRUCT",
|
|
TUNION, 0, "UNION",
|
|
TENUM, 0, "ENUM",
|
|
|
|
TAUTO, 0, "AUTO",
|
|
TEXTERN, 0, "EXTERN",
|
|
TSTATIC, 0, "STATIC",
|
|
TTYPEDEF, 0, "TYPEDEF",
|
|
TTYPESTR, 0, "TYPESTR",
|
|
TREGISTER, 0, "REGISTER",
|
|
TCONSTNT, 0, "CONSTNT",
|
|
TVOLATILE, 0, "VOLATILE",
|
|
TUNSIGNED, 0, "UNSIGNED",
|
|
TSIGNED, 0, "SIGNED",
|
|
TDOT, 0, "DOT",
|
|
TFILE, 0, "FILE",
|
|
TOLD, 0, "OLD",
|
|
-1, 0, 0,
|
|
};
|
|
char* cnames[NCTYPES];
|
|
Init cnamesinit[] =
|
|
{
|
|
CXXX, 0, "CXXX",
|
|
CAUTO, 0, "AUTO",
|
|
CEXTERN, 0, "EXTERN",
|
|
CGLOBL, 0, "GLOBL",
|
|
CSTATIC, 0, "STATIC",
|
|
CLOCAL, 0, "LOCAL",
|
|
CTYPEDEF, 0, "TYPEDEF",
|
|
CTYPESTR, 0, "TYPESTR",
|
|
CPARAM, 0, "PARAM",
|
|
CSELEM, 0, "SELEM",
|
|
CLABEL, 0, "LABEL",
|
|
CEXREG, 0, "EXREG",
|
|
-1, 0, 0,
|
|
};
|
|
|
|
char* onames[OEND+1];
|
|
Init onamesinit[] =
|
|
{
|
|
OXXX, 0, "OXXX",
|
|
OADD, 0, "ADD",
|
|
OADDR, 0, "ADDR",
|
|
OAND, 0, "AND",
|
|
OANDAND, 0, "ANDAND",
|
|
OARRAY, 0, "ARRAY",
|
|
OAS, 0, "AS",
|
|
OASI, 0, "ASI",
|
|
OASADD, 0, "ASADD",
|
|
OASAND, 0, "ASAND",
|
|
OASASHL, 0, "ASASHL",
|
|
OASASHR, 0, "ASASHR",
|
|
OASDIV, 0, "ASDIV",
|
|
OASHL, 0, "ASHL",
|
|
OASHR, 0, "ASHR",
|
|
OASLDIV, 0, "ASLDIV",
|
|
OASLMOD, 0, "ASLMOD",
|
|
OASLMUL, 0, "ASLMUL",
|
|
OASLSHR, 0, "ASLSHR",
|
|
OASMOD, 0, "ASMOD",
|
|
OASMUL, 0, "ASMUL",
|
|
OASOR, 0, "ASOR",
|
|
OASSUB, 0, "ASSUB",
|
|
OASXOR, 0, "ASXOR",
|
|
OBIT, 0, "BIT",
|
|
OBREAK, 0, "BREAK",
|
|
OCASE, 0, "CASE",
|
|
OCAST, 0, "CAST",
|
|
OCOMMA, 0, "COMMA",
|
|
OCOND, 0, "COND",
|
|
OCONST, 0, "CONST",
|
|
OCONTINUE, 0, "CONTINUE",
|
|
ODIV, 0, "DIV",
|
|
ODOT, 0, "DOT",
|
|
ODOTDOT, 0, "DOTDOT",
|
|
ODWHILE, 0, "DWHILE",
|
|
OENUM, 0, "ENUM",
|
|
OEQ, 0, "EQ",
|
|
OFOR, 0, "FOR",
|
|
OFUNC, 0, "FUNC",
|
|
OGE, 0, "GE",
|
|
OGOTO, 0, "GOTO",
|
|
OGT, 0, "GT",
|
|
OHI, 0, "HI",
|
|
OHS, 0, "HS",
|
|
OIF, 0, "IF",
|
|
OIND, 0, "IND",
|
|
OINDREG, 0, "INDREG",
|
|
OINIT, 0, "INIT",
|
|
OLABEL, 0, "LABEL",
|
|
OLDIV, 0, "LDIV",
|
|
OLE, 0, "LE",
|
|
OLIST, 0, "LIST",
|
|
OLMOD, 0, "LMOD",
|
|
OLMUL, 0, "LMUL",
|
|
OLO, 0, "LO",
|
|
OLS, 0, "LS",
|
|
OLSHR, 0, "LSHR",
|
|
OLT, 0, "LT",
|
|
OMOD, 0, "MOD",
|
|
OMUL, 0, "MUL",
|
|
ONAME, 0, "NAME",
|
|
ONE, 0, "NE",
|
|
ONOT, 0, "NOT",
|
|
OOR, 0, "OR",
|
|
OOROR, 0, "OROR",
|
|
OPOSTDEC, 0, "POSTDEC",
|
|
OPOSTINC, 0, "POSTINC",
|
|
OPREDEC, 0, "PREDEC",
|
|
OPREINC, 0, "PREINC",
|
|
OPROTO, 0, "PROTO",
|
|
OREGISTER, 0, "REGISTER",
|
|
ORETURN, 0, "RETURN",
|
|
OROL, 0, "ROL",
|
|
OSET, 0, "SET",
|
|
OSIGN, 0, "SIGN",
|
|
OSIZE, 0, "SIZE",
|
|
OSTRING, 0, "STRING",
|
|
OLSTRING, 0, "LSTRING",
|
|
OSTRUCT, 0, "STRUCT",
|
|
OSUB, 0, "SUB",
|
|
OSWITCH, 0, "SWITCH",
|
|
OUNION, 0, "UNION",
|
|
OUSED, 0, "USED",
|
|
OWHILE, 0, "WHILE",
|
|
OXOR, 0, "XOR",
|
|
OPOS, 0, "POS",
|
|
ONEG, 0, "NEG",
|
|
OCOM, 0, "COM",
|
|
OELEM, 0, "ELEM",
|
|
OTST, 0, "TST",
|
|
OINDEX, 0, "INDEX",
|
|
OFAS, 0, "FAS",
|
|
OREGPAIR, 0, "REGPAIR",
|
|
OEXREG, 0, "EXREG",
|
|
OEND, 0, "END",
|
|
-1, 0, 0,
|
|
};
|
|
|
|
/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
|
|
char comrel[12] =
|
|
{
|
|
ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
|
|
};
|
|
char invrel[12] =
|
|
{
|
|
OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
|
|
};
|
|
char logrel[12] =
|
|
{
|
|
OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
|
|
};
|
|
|
|
char typei[NTYPE];
|
|
int typeiinit[] =
|
|
{
|
|
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
|
|
};
|
|
char typeu[NTYPE];
|
|
int typeuinit[] =
|
|
{
|
|
TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
|
|
};
|
|
|
|
char typesuv[NTYPE];
|
|
int typesuvinit[] =
|
|
{
|
|
TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
|
|
};
|
|
|
|
char typeilp[NTYPE];
|
|
int typeilpinit[] =
|
|
{
|
|
TINT, TUINT, TLONG, TULONG, TIND, -1
|
|
};
|
|
|
|
char typechl[NTYPE];
|
|
char typechlv[NTYPE];
|
|
char typechlvp[NTYPE];
|
|
int typechlinit[] =
|
|
{
|
|
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
|
|
};
|
|
|
|
char typechlp[NTYPE];
|
|
int typechlpinit[] =
|
|
{
|
|
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
|
|
};
|
|
|
|
char typechlpfd[NTYPE];
|
|
int typechlpfdinit[] =
|
|
{
|
|
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
|
|
};
|
|
|
|
char typec[NTYPE];
|
|
int typecinit[] =
|
|
{
|
|
TCHAR, TUCHAR, -1
|
|
};
|
|
|
|
char typeh[NTYPE];
|
|
int typehinit[] =
|
|
{
|
|
TSHORT, TUSHORT, -1,
|
|
};
|
|
|
|
char typeil[NTYPE];
|
|
int typeilinit[] =
|
|
{
|
|
TINT, TUINT, TLONG, TULONG, -1,
|
|
};
|
|
|
|
char typev[NTYPE];
|
|
int typevinit[] =
|
|
{
|
|
TVLONG, TUVLONG, -1,
|
|
};
|
|
|
|
char typefd[NTYPE];
|
|
int typefdinit[] =
|
|
{
|
|
TFLOAT, TDOUBLE, -1,
|
|
};
|
|
|
|
char typeaf[NTYPE];
|
|
int typeafinit[] =
|
|
{
|
|
TFUNC, TARRAY, -1,
|
|
};
|
|
|
|
char typesu[NTYPE];
|
|
int typesuinit[] =
|
|
{
|
|
TSTRUCT, TUNION, -1,
|
|
};
|
|
|
|
long tasign[NTYPE];
|
|
Init tasigninit[] =
|
|
{
|
|
TCHAR, BNUMBER, 0,
|
|
TUCHAR, BNUMBER, 0,
|
|
TSHORT, BNUMBER, 0,
|
|
TUSHORT, BNUMBER, 0,
|
|
TINT, BNUMBER, 0,
|
|
TUINT, BNUMBER, 0,
|
|
TLONG, BNUMBER, 0,
|
|
TULONG, BNUMBER, 0,
|
|
TVLONG, BNUMBER, 0,
|
|
TUVLONG, BNUMBER, 0,
|
|
TFLOAT, BNUMBER, 0,
|
|
TDOUBLE, BNUMBER, 0,
|
|
TIND, BIND, 0,
|
|
TSTRUCT, BSTRUCT, 0,
|
|
TUNION, BUNION, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long tasadd[NTYPE];
|
|
Init tasaddinit[] =
|
|
{
|
|
TCHAR, BNUMBER, 0,
|
|
TUCHAR, BNUMBER, 0,
|
|
TSHORT, BNUMBER, 0,
|
|
TUSHORT, BNUMBER, 0,
|
|
TINT, BNUMBER, 0,
|
|
TUINT, BNUMBER, 0,
|
|
TLONG, BNUMBER, 0,
|
|
TULONG, BNUMBER, 0,
|
|
TVLONG, BNUMBER, 0,
|
|
TUVLONG, BNUMBER, 0,
|
|
TFLOAT, BNUMBER, 0,
|
|
TDOUBLE, BNUMBER, 0,
|
|
TIND, BINTEGER, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long tcast[NTYPE];
|
|
Init tcastinit[] =
|
|
{
|
|
TCHAR, BNUMBER|BIND|BVOID, 0,
|
|
TUCHAR, BNUMBER|BIND|BVOID, 0,
|
|
TSHORT, BNUMBER|BIND|BVOID, 0,
|
|
TUSHORT, BNUMBER|BIND|BVOID, 0,
|
|
TINT, BNUMBER|BIND|BVOID, 0,
|
|
TUINT, BNUMBER|BIND|BVOID, 0,
|
|
TLONG, BNUMBER|BIND|BVOID, 0,
|
|
TULONG, BNUMBER|BIND|BVOID, 0,
|
|
TVLONG, BNUMBER|BIND|BVOID, 0,
|
|
TUVLONG, BNUMBER|BIND|BVOID, 0,
|
|
TFLOAT, BNUMBER|BVOID, 0,
|
|
TDOUBLE, BNUMBER|BVOID, 0,
|
|
TIND, BINTEGER|BIND|BVOID, 0,
|
|
TVOID, BVOID, 0,
|
|
TSTRUCT, BSTRUCT|BVOID, 0,
|
|
TUNION, BUNION|BVOID, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long tadd[NTYPE];
|
|
Init taddinit[] =
|
|
{
|
|
TCHAR, BNUMBER|BIND, 0,
|
|
TUCHAR, BNUMBER|BIND, 0,
|
|
TSHORT, BNUMBER|BIND, 0,
|
|
TUSHORT, BNUMBER|BIND, 0,
|
|
TINT, BNUMBER|BIND, 0,
|
|
TUINT, BNUMBER|BIND, 0,
|
|
TLONG, BNUMBER|BIND, 0,
|
|
TULONG, BNUMBER|BIND, 0,
|
|
TVLONG, BNUMBER|BIND, 0,
|
|
TUVLONG, BNUMBER|BIND, 0,
|
|
TFLOAT, BNUMBER, 0,
|
|
TDOUBLE, BNUMBER, 0,
|
|
TIND, BINTEGER, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long tsub[NTYPE];
|
|
Init tsubinit[] =
|
|
{
|
|
TCHAR, BNUMBER, 0,
|
|
TUCHAR, BNUMBER, 0,
|
|
TSHORT, BNUMBER, 0,
|
|
TUSHORT, BNUMBER, 0,
|
|
TINT, BNUMBER, 0,
|
|
TUINT, BNUMBER, 0,
|
|
TLONG, BNUMBER, 0,
|
|
TULONG, BNUMBER, 0,
|
|
TVLONG, BNUMBER, 0,
|
|
TUVLONG, BNUMBER, 0,
|
|
TFLOAT, BNUMBER, 0,
|
|
TDOUBLE, BNUMBER, 0,
|
|
TIND, BINTEGER|BIND, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long tmul[NTYPE];
|
|
Init tmulinit[] =
|
|
{
|
|
TCHAR, BNUMBER, 0,
|
|
TUCHAR, BNUMBER, 0,
|
|
TSHORT, BNUMBER, 0,
|
|
TUSHORT, BNUMBER, 0,
|
|
TINT, BNUMBER, 0,
|
|
TUINT, BNUMBER, 0,
|
|
TLONG, BNUMBER, 0,
|
|
TULONG, BNUMBER, 0,
|
|
TVLONG, BNUMBER, 0,
|
|
TUVLONG, BNUMBER, 0,
|
|
TFLOAT, BNUMBER, 0,
|
|
TDOUBLE, BNUMBER, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long tand[NTYPE];
|
|
Init tandinit[] =
|
|
{
|
|
TCHAR, BINTEGER, 0,
|
|
TUCHAR, BINTEGER, 0,
|
|
TSHORT, BINTEGER, 0,
|
|
TUSHORT, BINTEGER, 0,
|
|
TINT, BNUMBER, 0,
|
|
TUINT, BNUMBER, 0,
|
|
TLONG, BINTEGER, 0,
|
|
TULONG, BINTEGER, 0,
|
|
TVLONG, BINTEGER, 0,
|
|
TUVLONG, BINTEGER, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long trel[NTYPE];
|
|
Init trelinit[] =
|
|
{
|
|
TCHAR, BNUMBER, 0,
|
|
TUCHAR, BNUMBER, 0,
|
|
TSHORT, BNUMBER, 0,
|
|
TUSHORT, BNUMBER, 0,
|
|
TINT, BNUMBER, 0,
|
|
TUINT, BNUMBER, 0,
|
|
TLONG, BNUMBER, 0,
|
|
TULONG, BNUMBER, 0,
|
|
TVLONG, BNUMBER, 0,
|
|
TUVLONG, BNUMBER, 0,
|
|
TFLOAT, BNUMBER, 0,
|
|
TDOUBLE, BNUMBER, 0,
|
|
TIND, BIND, 0,
|
|
-1, 0, 0,
|
|
};
|
|
|
|
long tfunct[1] =
|
|
{
|
|
BFUNC,
|
|
};
|
|
|
|
long tindir[1] =
|
|
{
|
|
BIND,
|
|
};
|
|
|
|
long tdot[1] =
|
|
{
|
|
BSTRUCT|BUNION,
|
|
};
|
|
|
|
long tnot[1] =
|
|
{
|
|
BNUMBER|BIND,
|
|
};
|
|
|
|
long targ[1] =
|
|
{
|
|
BNUMBER|BIND|BSTRUCT|BUNION,
|
|
};
|
|
|
|
char tab[NTYPE][NTYPE] =
|
|
{
|
|
/*TXXX*/ { 0,
|
|
},
|
|
|
|
/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
|
|
TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
|
|
TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
|
|
TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
|
|
TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
|
|
TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
|
|
TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
|
|
TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
|
|
TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
|
|
TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
|
|
TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
|
|
TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
|
|
TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
|
|
},
|
|
/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND,
|
|
TIND, TIND, TIND, TIND, TIND, TIND,
|
|
},
|
|
};
|
|
|
|
void
|
|
urk(char *name, int max, int i)
|
|
{
|
|
if(i >= max) {
|
|
fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
|
|
exits("init");
|
|
}
|
|
}
|
|
|
|
void
|
|
tinit(void)
|
|
{
|
|
int *ip;
|
|
Init *p;
|
|
|
|
for(p=thashinit; p->code >= 0; p++) {
|
|
urk("thash", nelem(thash), p->code);
|
|
thash[p->code] = p->value;
|
|
}
|
|
for(p=bnamesinit; p->code >= 0; p++) {
|
|
urk("bnames", nelem(bnames), p->code);
|
|
bnames[p->code] = p->s;
|
|
}
|
|
for(p=tnamesinit; p->code >= 0; p++) {
|
|
urk("tnames", nelem(tnames), p->code);
|
|
tnames[p->code] = p->s;
|
|
}
|
|
for(p=gnamesinit; p->code >= 0; p++) {
|
|
urk("gnames", nelem(gnames), p->code);
|
|
gnames[p->code] = p->s;
|
|
}
|
|
for(p=qnamesinit; p->code >= 0; p++) {
|
|
urk("qnames", nelem(qnames), p->code);
|
|
qnames[p->code] = p->s;
|
|
}
|
|
for(p=cnamesinit; p->code >= 0; p++) {
|
|
urk("cnames", nelem(cnames), p->code);
|
|
cnames[p->code] = p->s;
|
|
}
|
|
for(p=onamesinit; p->code >= 0; p++) {
|
|
urk("onames", nelem(onames), p->code);
|
|
onames[p->code] = p->s;
|
|
}
|
|
for(ip=typeiinit; *ip>=0; ip++) {
|
|
urk("typei", nelem(typei), *ip);
|
|
typei[*ip] = 1;
|
|
}
|
|
for(ip=typeuinit; *ip>=0; ip++) {
|
|
urk("typeu", nelem(typeu), *ip);
|
|
typeu[*ip] = 1;
|
|
}
|
|
for(ip=typesuvinit; *ip>=0; ip++) {
|
|
urk("typesuv", nelem(typesuv), *ip);
|
|
typesuv[*ip] = 1;
|
|
}
|
|
for(ip=typeilpinit; *ip>=0; ip++) {
|
|
urk("typeilp", nelem(typeilp), *ip);
|
|
typeilp[*ip] = 1;
|
|
}
|
|
for(ip=typechlinit; *ip>=0; ip++) {
|
|
urk("typechl", nelem(typechl), *ip);
|
|
typechl[*ip] = 1;
|
|
typechlv[*ip] = 1;
|
|
typechlvp[*ip] = 1;
|
|
}
|
|
for(ip=typechlpinit; *ip>=0; ip++) {
|
|
urk("typechlp", nelem(typechlp), *ip);
|
|
typechlp[*ip] = 1;
|
|
typechlvp[*ip] = 1;
|
|
}
|
|
for(ip=typechlpfdinit; *ip>=0; ip++) {
|
|
urk("typechlpfd", nelem(typechlpfd), *ip);
|
|
typechlpfd[*ip] = 1;
|
|
}
|
|
for(ip=typecinit; *ip>=0; ip++) {
|
|
urk("typec", nelem(typec), *ip);
|
|
typec[*ip] = 1;
|
|
}
|
|
for(ip=typehinit; *ip>=0; ip++) {
|
|
urk("typeh", nelem(typeh), *ip);
|
|
typeh[*ip] = 1;
|
|
}
|
|
for(ip=typeilinit; *ip>=0; ip++) {
|
|
urk("typeil", nelem(typeil), *ip);
|
|
typeil[*ip] = 1;
|
|
}
|
|
for(ip=typevinit; *ip>=0; ip++) {
|
|
urk("typev", nelem(typev), *ip);
|
|
typev[*ip] = 1;
|
|
typechlv[*ip] = 1;
|
|
typechlvp[*ip] = 1;
|
|
}
|
|
for(ip=typefdinit; *ip>=0; ip++) {
|
|
urk("typefd", nelem(typefd), *ip);
|
|
typefd[*ip] = 1;
|
|
}
|
|
for(ip=typeafinit; *ip>=0; ip++) {
|
|
urk("typeaf", nelem(typeaf), *ip);
|
|
typeaf[*ip] = 1;
|
|
}
|
|
for(ip=typesuinit; *ip >= 0; ip++) {
|
|
urk("typesu", nelem(typesu), *ip);
|
|
typesu[*ip] = 1;
|
|
}
|
|
for(p=tasigninit; p->code >= 0; p++) {
|
|
urk("tasign", nelem(tasign), p->code);
|
|
tasign[p->code] = p->value;
|
|
}
|
|
for(p=tasaddinit; p->code >= 0; p++) {
|
|
urk("tasadd", nelem(tasadd), p->code);
|
|
tasadd[p->code] = p->value;
|
|
}
|
|
for(p=tcastinit; p->code >= 0; p++) {
|
|
urk("tcast", nelem(tcast), p->code);
|
|
tcast[p->code] = p->value;
|
|
}
|
|
for(p=taddinit; p->code >= 0; p++) {
|
|
urk("tadd", nelem(tadd), p->code);
|
|
tadd[p->code] = p->value;
|
|
}
|
|
for(p=tsubinit; p->code >= 0; p++) {
|
|
urk("tsub", nelem(tsub), p->code);
|
|
tsub[p->code] = p->value;
|
|
}
|
|
for(p=tmulinit; p->code >= 0; p++) {
|
|
urk("tmul", nelem(tmul), p->code);
|
|
tmul[p->code] = p->value;
|
|
}
|
|
for(p=tandinit; p->code >= 0; p++) {
|
|
urk("tand", nelem(tand), p->code);
|
|
tand[p->code] = p->value;
|
|
}
|
|
for(p=trelinit; p->code >= 0; p++) {
|
|
urk("trel", nelem(trel), p->code);
|
|
trel[p->code] = p->value;
|
|
}
|
|
|
|
/* 32-bit defaults */
|
|
typeword = typechlp;
|
|
typeswitch = typechl;
|
|
typecmplx = typesuv;
|
|
}
|
|
|
|
/*
|
|
* return 1 if it is impossible to jump into the middle of n.
|
|
*/
|
|
static int
|
|
deadhead(Node *n, int caseok)
|
|
{
|
|
loop:
|
|
if(n == Z)
|
|
return 1;
|
|
switch(n->op) {
|
|
case OLIST:
|
|
if(!deadhead(n->left, caseok))
|
|
return 0;
|
|
rloop:
|
|
n = n->right;
|
|
goto loop;
|
|
|
|
case ORETURN:
|
|
break;
|
|
|
|
case OLABEL:
|
|
return 0;
|
|
|
|
case OGOTO:
|
|
break;
|
|
|
|
case OCASE:
|
|
if(!caseok)
|
|
return 0;
|
|
goto rloop;
|
|
|
|
case OSWITCH:
|
|
return deadhead(n->right, 1);
|
|
|
|
case OWHILE:
|
|
case ODWHILE:
|
|
goto rloop;
|
|
|
|
case OFOR:
|
|
goto rloop;
|
|
|
|
case OCONTINUE:
|
|
break;
|
|
|
|
case OBREAK:
|
|
break;
|
|
|
|
case OIF:
|
|
return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
|
|
|
|
case OSET:
|
|
case OUSED:
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
deadheads(Node *c)
|
|
{
|
|
return deadhead(c->left, 0) && deadhead(c->right, 0);
|
|
}
|
|
|
|
int
|
|
mixedasop(Type *l, Type *r)
|
|
{
|
|
return !typefd[l->etype] && typefd[r->etype];
|
|
}
|
|
|
|
|
|
/*
|
|
* (uvlong)~ul creates a ul mask with top bits zero, which is usually wrong
|
|
* an explicit cast to ulong after ~ suppresses the diagnostic
|
|
*/
|
|
int
|
|
castucom(Node *r)
|
|
{
|
|
Node *rl;
|
|
|
|
if(r->op == OCAST &&
|
|
(rl = r->left)->op == OCOM &&
|
|
(r->type->etype == TVLONG || r->type->etype == TUVLONG) &&
|
|
typeu[rl->type->etype] && typechl[rl->type->etype])
|
|
return 1;
|
|
return 0;
|
|
}
|