2005-08-26 17:39:27 +00:00
|
|
|
#include "c.h"
|
|
|
|
|
|
|
|
|
|
|
|
static Tree addtree(int, Tree, Tree);
|
|
|
|
static Tree andtree(int, Tree, Tree);
|
|
|
|
static Tree cmptree(int, Tree, Tree);
|
|
|
|
static int compatible(Type, Type);
|
|
|
|
static int isnullptr(Tree e);
|
|
|
|
static Tree multree(int, Tree, Tree);
|
|
|
|
static Tree subtree(int, Tree, Tree);
|
|
|
|
#define isvoidptr(ty) \
|
|
|
|
(isptr(ty) && unqual(ty->type) == voidtype)
|
|
|
|
|
|
|
|
Tree (*optree[])(int, Tree, Tree) = {
|
|
|
|
#define xx(a,b,c,d,e,f,g) e,
|
|
|
|
#define yy(a,b,c,d,e,f,g) e,
|
|
|
|
#include "token.h"
|
|
|
|
};
|
|
|
|
Tree call(Tree f, Type fty, Coordinate src) {
|
|
|
|
int n = 0;
|
|
|
|
Tree args = NULL, r = NULL, e;
|
|
|
|
Type *proto, rty = unqual(freturn(fty));
|
|
|
|
Symbol t3 = NULL;
|
|
|
|
|
|
|
|
if (fty->u.f.oldstyle)
|
|
|
|
proto = NULL;
|
|
|
|
else
|
|
|
|
proto = fty->u.f.proto;
|
|
|
|
if (hascall(f))
|
|
|
|
r = f;
|
|
|
|
if (isstruct(rty))
|
|
|
|
{
|
|
|
|
t3 = temporary(AUTO, unqual(rty));
|
|
|
|
if (rty->size == 0)
|
|
|
|
error("illegal use of incomplete type `%t'\n", rty);
|
|
|
|
}
|
|
|
|
if (t != ')')
|
|
|
|
for (;;) {
|
|
|
|
Tree q = pointer(expr1(0));
|
|
|
|
if (proto && *proto && *proto != voidtype)
|
|
|
|
{
|
|
|
|
Type aty;
|
|
|
|
q = value(q);
|
|
|
|
aty = assign(*proto, q);
|
|
|
|
if (aty)
|
|
|
|
q = cast(q, aty);
|
|
|
|
else
|
|
|
|
error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f),
|
|
|
|
|
|
|
|
q->type, *proto);
|
|
|
|
if ((isint(q->type) || isenum(q->type))
|
|
|
|
&& q->type->size != inttype->size)
|
|
|
|
q = cast(q, promote(q->type));
|
|
|
|
++proto;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!fty->u.f.oldstyle && *proto == NULL)
|
|
|
|
error("too many arguments to %s\n", funcname(f));
|
|
|
|
q = value(q);
|
|
|
|
if (isarray(q->type) || q->type->size == 0)
|
|
|
|
error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type);
|
|
|
|
|
|
|
|
else
|
|
|
|
q = cast(q, promote(q->type));
|
|
|
|
}
|
|
|
|
if (!IR->wants_argb && isstruct(q->type))
|
|
|
|
if (iscallb(q))
|
|
|
|
q = addrof(q);
|
|
|
|
else {
|
|
|
|
Symbol t1 = temporary(AUTO, unqual(q->type));
|
|
|
|
q = asgn(t1, q);
|
|
|
|
q = tree(RIGHT, ptr(t1->type),
|
|
|
|
root(q), lvalue(idtree(t1)));
|
|
|
|
}
|
|
|
|
if (q->type->size == 0)
|
|
|
|
q->type = inttype;
|
|
|
|
if (hascall(q))
|
|
|
|
r = r ? tree(RIGHT, voidtype, r, q) : q;
|
|
|
|
args = tree(mkop(ARG, q->type), q->type, q, args);
|
|
|
|
n++;
|
|
|
|
if (Aflag >= 2 && n == 32)
|
|
|
|
warning("more than 31 arguments in a call to %s\n",
|
|
|
|
funcname(f));
|
|
|
|
if (t != ',')
|
|
|
|
break;
|
|
|
|
t = gettok();
|
|
|
|
}
|
|
|
|
expect(')');
|
|
|
|
if (proto && *proto && *proto != voidtype)
|
|
|
|
error("insufficient number of arguments to %s\n",
|
|
|
|
funcname(f));
|
|
|
|
if (r)
|
|
|
|
args = tree(RIGHT, voidtype, r, args);
|
|
|
|
e = calltree(f, rty, args, t3);
|
|
|
|
if (events.calls)
|
|
|
|
apply(events.calls, &src, &e);
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
Tree calltree(Tree f, Type ty, Tree args, Symbol t3) {
|
|
|
|
Tree p;
|
|
|
|
|
|
|
|
if (args)
|
|
|
|
f = tree(RIGHT, f->type, args, f);
|
|
|
|
if (isstruct(ty))
|
|
|
|
assert(t3),
|
|
|
|
p = tree(RIGHT, ty,
|
|
|
|
tree(CALL+B, ty, f, addrof(idtree(t3))),
|
|
|
|
idtree(t3));
|
|
|
|
else {
|
|
|
|
Type rty = ty;
|
|
|
|
if (isenum(ty))
|
|
|
|
rty = unqual(ty)->type;
|
|
|
|
if (!isfloat(rty))
|
|
|
|
rty = promote(rty);
|
|
|
|
p = tree(mkop(CALL, rty), rty, f, NULL);
|
|
|
|
if (isptr(ty) || p->type->size > ty->size)
|
|
|
|
p = cast(p, ty);
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
Tree vcall(Symbol func, Type ty, ...) {
|
|
|
|
va_list ap;
|
|
|
|
Tree args = NULL, e, f = pointer(idtree(func)), r = NULL;
|
|
|
|
|
|
|
|
assert(isfunc(func->type));
|
|
|
|
if (ty == NULL)
|
|
|
|
ty = freturn(func->type);
|
|
|
|
va_start(ap, ty);
|
|
|
|
while ((e = va_arg(ap, Tree)) != NULL) {
|
|
|
|
if (hascall(e))
|
|
|
|
r = r == NULL ? e : tree(RIGHT, voidtype, r, e);
|
|
|
|
args = tree(mkop(ARG, e->type), e->type, e, args);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
if (r != NULL)
|
|
|
|
args = tree(RIGHT, voidtype, r, args);
|
|
|
|
return calltree(f, ty, args, NULL);
|
|
|
|
}
|
|
|
|
int iscallb(Tree e) {
|
|
|
|
return e->op == RIGHT && e->kids[0] && e->kids[1]
|
|
|
|
&& e->kids[0]->op == CALL+B
|
|
|
|
&& e->kids[1]->op == INDIR+B
|
|
|
|
&& isaddrop(e->kids[1]->kids[0]->op)
|
|
|
|
&& e->kids[1]->kids[0]->u.sym->temporary;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Tree addtree(int op, Tree l, Tree r) {
|
|
|
|
Type ty = inttype;
|
|
|
|
|
|
|
|
if (isarith(l->type) && isarith(r->type)) {
|
|
|
|
ty = binary(l->type, r->type);
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, ty);
|
|
|
|
} else if (isptr(l->type) && isint(r->type))
|
|
|
|
return addtree(ADD, r, l);
|
|
|
|
else if ( isptr(r->type) && isint(l->type)
|
|
|
|
&& !isfunc(r->type->type))
|
|
|
|
{
|
|
|
|
long n;
|
|
|
|
ty = unqual(r->type);
|
|
|
|
n = unqual(ty->type)->size;
|
|
|
|
if (n == 0)
|
|
|
|
error("unknown size for type `%t'\n", ty->type);
|
|
|
|
l = cast(l, promote(l->type));
|
|
|
|
if (n > 1)
|
|
|
|
l = multree(MUL, cnsttree(signedptr, n), l);
|
|
|
|
if (YYcheck && !isaddrop(r->op)) /* omit */
|
|
|
|
return nullcall(ty, YYcheck, r, l); /* omit */
|
|
|
|
return simplify(ADD, ty, l, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
typeerror(op, l, r);
|
|
|
|
return simplify(op, ty, l, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
Tree cnsttree(Type ty, ...) {
|
|
|
|
Tree p = tree(mkop(CNST,ty), ty, NULL, NULL);
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, ty);
|
|
|
|
switch (ty->op) {
|
|
|
|
case INT: p->u.v.i = va_arg(ap, long); break;
|
|
|
|
case UNSIGNED:p->u.v.u = va_arg(ap, unsigned long)&ones(8*ty->size); break;
|
|
|
|
case FLOAT: p->u.v.d = va_arg(ap, long double); break;
|
|
|
|
case POINTER: p->u.v.p = va_arg(ap, void *); break;
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
Tree consttree(unsigned n, Type ty) {
|
|
|
|
if (isarray(ty))
|
|
|
|
ty = atop(ty);
|
|
|
|
else assert(isint(ty));
|
|
|
|
return cnsttree(ty, (unsigned long)n);
|
|
|
|
}
|
|
|
|
static Tree cmptree(int op, Tree l, Tree r) {
|
|
|
|
Type ty;
|
|
|
|
|
|
|
|
if (isarith(l->type) && isarith(r->type)) {
|
|
|
|
ty = binary(l->type, r->type);
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, ty);
|
|
|
|
} else if (compatible(l->type, r->type)) {
|
|
|
|
ty = unsignedptr;
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, ty);
|
|
|
|
} else {
|
|
|
|
ty = unsignedtype;
|
|
|
|
typeerror(op, l, r);
|
|
|
|
}
|
|
|
|
return simplify(mkop(op,ty), inttype, l, r);
|
|
|
|
}
|
|
|
|
static int compatible(Type ty1, Type ty2) {
|
|
|
|
return isptr(ty1) && !isfunc(ty1->type)
|
|
|
|
&& isptr(ty2) && !isfunc(ty2->type)
|
|
|
|
&& eqtype(unqual(ty1->type), unqual(ty2->type), 0);
|
|
|
|
}
|
|
|
|
static int isnullptr(Tree e) {
|
|
|
|
Type ty = unqual(e->type);
|
|
|
|
|
|
|
|
return generic(e->op) == CNST
|
|
|
|
&& (ty->op == INT && e->u.v.i == 0
|
|
|
|
|| ty->op == UNSIGNED && e->u.v.u == 0
|
|
|
|
|| isvoidptr(ty) && e->u.v.p == NULL);
|
|
|
|
}
|
|
|
|
Tree eqtree(int op, Tree l, Tree r) {
|
|
|
|
Type xty = l->type, yty = r->type;
|
|
|
|
|
|
|
|
if (isptr(xty) && isnullptr(r)
|
|
|
|
|| isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)
|
|
|
|
|| (isptr(xty) && isptr(yty)
|
|
|
|
&& eqtype(unqual(xty->type), unqual(yty->type), 1))) {
|
|
|
|
Type ty = unsignedptr;
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, ty);
|
|
|
|
return simplify(mkop(op,ty), inttype, l, r);
|
|
|
|
}
|
|
|
|
if (isptr(yty) && isnullptr(l)
|
|
|
|
|| isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))
|
|
|
|
return eqtree(op, r, l);
|
|
|
|
return cmptree(op, l, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
Type assign(Type xty, Tree e) {
|
|
|
|
Type yty = unqual(e->type);
|
|
|
|
|
|
|
|
xty = unqual(xty);
|
|
|
|
if (isenum(xty))
|
|
|
|
xty = xty->type;
|
|
|
|
if (xty->size == 0 || yty->size == 0)
|
|
|
|
return NULL;
|
|
|
|
if ( isarith(xty) && isarith(yty)
|
|
|
|
|| isstruct(xty) && xty == yty)
|
|
|
|
return xty;
|
|
|
|
if (isptr(xty) && isnullptr(e))
|
|
|
|
return xty;
|
|
|
|
if ((isvoidptr(xty) && isptr(yty)
|
|
|
|
|| isptr(xty) && isvoidptr(yty))
|
|
|
|
&& ( (isconst(xty->type) || !isconst(yty->type))
|
|
|
|
&& (isvolatile(xty->type) || !isvolatile(yty->type))))
|
|
|
|
return xty;
|
|
|
|
|
|
|
|
if ((isptr(xty) && isptr(yty)
|
|
|
|
&& eqtype(unqual(xty->type), unqual(yty->type), 1))
|
|
|
|
&& ( (isconst(xty->type) || !isconst(yty->type))
|
|
|
|
&& (isvolatile(xty->type) || !isvolatile(yty->type))))
|
|
|
|
return xty;
|
|
|
|
if (isptr(xty) && isptr(yty)
|
|
|
|
&& ( (isconst(xty->type) || !isconst(yty->type))
|
|
|
|
&& (isvolatile(xty->type) || !isvolatile(yty->type)))) {
|
|
|
|
Type lty = unqual(xty->type), rty = unqual(yty->type);
|
|
|
|
if (isenum(lty) && rty == inttype
|
|
|
|
|| isenum(rty) && lty == inttype) {
|
|
|
|
if (Aflag >= 1)
|
|
|
|
warning("assignment between `%t' and `%t' is compiler-dependent\n",
|
|
|
|
xty, yty);
|
|
|
|
return xty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Tree asgntree(int op, Tree l, Tree r) {
|
|
|
|
Type aty, ty;
|
|
|
|
|
|
|
|
r = pointer(r);
|
|
|
|
ty = assign(l->type, r);
|
|
|
|
if (ty)
|
|
|
|
r = cast(r, ty);
|
|
|
|
else {
|
|
|
|
typeerror(ASGN, l, r);
|
|
|
|
if (r->type == voidtype)
|
|
|
|
r = retype(r, inttype);
|
|
|
|
ty = r->type;
|
|
|
|
}
|
|
|
|
if (l->op != FIELD)
|
|
|
|
l = lvalue(l);
|
|
|
|
aty = l->type;
|
|
|
|
if (isptr(aty))
|
|
|
|
aty = unqual(aty)->type;
|
|
|
|
if ( isconst(aty)
|
|
|
|
|| isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)
|
|
|
|
if (isaddrop(l->op)
|
|
|
|
&& !l->u.sym->computed && !l->u.sym->generated)
|
|
|
|
error("assignment to const identifier `%s'\n",
|
|
|
|
l->u.sym->name);
|
|
|
|
else
|
|
|
|
error("assignment to const location\n");
|
|
|
|
if (l->op == FIELD) {
|
|
|
|
long n = 8*l->u.field->type->size - fieldsize(l->u.field);
|
|
|
|
if (n > 0 && isunsigned(l->u.field->type))
|
|
|
|
r = bittree(BAND, r,
|
|
|
|
cnsttree(r->type, (unsigned long)fieldmask(l->u.field)));
|
|
|
|
else if (n > 0) {
|
|
|
|
if (r->op == CNST+I) {
|
|
|
|
n = r->u.v.i;
|
|
|
|
if (n&(1<<(fieldsize(l->u.field)-1)))
|
|
|
|
n |= ~0UL<<fieldsize(l->u.field);
|
|
|
|
r = cnsttree(r->type, n);
|
|
|
|
} else
|
|
|
|
r = shtree(RSH,
|
|
|
|
shtree(LSH, r, cnsttree(inttype, n)),
|
|
|
|
cnsttree(inttype, n));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isstruct(ty) && isaddrop(l->op) && iscallb(r))
|
|
|
|
return tree(RIGHT, ty,
|
|
|
|
tree(CALL+B, ty, r->kids[0]->kids[0], l),
|
|
|
|
idtree(l->u.sym));
|
|
|
|
return tree(mkop(op,ty), ty, l, r);
|
|
|
|
}
|
|
|
|
Tree condtree(Tree e, Tree l, Tree r) {
|
|
|
|
Symbol t1;
|
|
|
|
Type ty, xty = l->type, yty = r->type;
|
|
|
|
Tree p;
|
|
|
|
|
|
|
|
if (isarith(xty) && isarith(yty))
|
|
|
|
ty = binary(xty, yty);
|
|
|
|
else if (eqtype(xty, yty, 1))
|
|
|
|
ty = unqual(xty);
|
|
|
|
else if (isptr(xty) && isnullptr(r))
|
|
|
|
ty = xty;
|
|
|
|
else if (isnullptr(l) && isptr(yty))
|
|
|
|
ty = yty;
|
|
|
|
else if (isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)
|
|
|
|
|| isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))
|
|
|
|
ty = voidptype;
|
|
|
|
else if ((isptr(xty) && isptr(yty)
|
|
|
|
&& eqtype(unqual(xty->type), unqual(yty->type), 1)))
|
|
|
|
ty = xty;
|
|
|
|
else {
|
|
|
|
typeerror(COND, l, r);
|
|
|
|
return consttree(0, inttype);
|
|
|
|
}
|
|
|
|
if (isptr(ty)) {
|
|
|
|
ty = unqual(unqual(ty)->type);
|
|
|
|
if (isptr(xty) && isconst(unqual(xty)->type)
|
|
|
|
|| isptr(yty) && isconst(unqual(yty)->type))
|
|
|
|
ty = qual(CONST, ty);
|
|
|
|
if (isptr(xty) && isvolatile(unqual(xty)->type)
|
|
|
|
|| isptr(yty) && isvolatile(unqual(yty)->type))
|
|
|
|
ty = qual(VOLATILE, ty);
|
|
|
|
ty = ptr(ty);
|
|
|
|
}
|
|
|
|
switch (e->op) {
|
|
|
|
case CNST+I: return cast(e->u.v.i != 0 ? l : r, ty);
|
|
|
|
case CNST+U: return cast(e->u.v.u != 0 ? l : r, ty);
|
|
|
|
case CNST+P: return cast(e->u.v.p != 0 ? l : r, ty);
|
|
|
|
case CNST+F: return cast(e->u.v.d != 0.0 ? l : r, ty);
|
|
|
|
}
|
|
|
|
if (ty != voidtype && ty->size > 0) {
|
|
|
|
t1 = genident(REGISTER, unqual(ty), level);
|
|
|
|
/* t1 = temporary(REGISTER, unqual(ty)); */
|
|
|
|
l = asgn(t1, l);
|
|
|
|
r = asgn(t1, r);
|
|
|
|
} else
|
|
|
|
t1 = NULL;
|
|
|
|
p = tree(COND, ty, cond(e),
|
|
|
|
tree(RIGHT, ty, root(l), root(r)));
|
|
|
|
p->u.sym = t1;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
/* addrof - address of p */
|
|
|
|
Tree addrof(Tree p) {
|
|
|
|
Tree q = p;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
switch (generic(q->op)) {
|
|
|
|
case RIGHT:
|
|
|
|
assert(q->kids[0] || q->kids[1]);
|
|
|
|
q = q->kids[1] ? q->kids[1] : q->kids[0];
|
|
|
|
continue;
|
|
|
|
case ASGN:
|
|
|
|
q = q->kids[1];
|
|
|
|
continue;
|
|
|
|
case COND: {
|
|
|
|
Symbol t1 = q->u.sym;
|
|
|
|
q->u.sym = 0;
|
|
|
|
q = idtree(t1);
|
|
|
|
/* fall thru */
|
|
|
|
}
|
|
|
|
case INDIR:
|
|
|
|
if (p == q)
|
|
|
|
return q->kids[0];
|
|
|
|
q = q->kids[0];
|
|
|
|
return tree(RIGHT, q->type, root(p), q);
|
|
|
|
default:
|
|
|
|
error("addressable object required\n");
|
|
|
|
return value(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* andtree - construct tree for l [&& ||] r */
|
|
|
|
static Tree andtree(int op, Tree l, Tree r) {
|
|
|
|
if (!isscalar(l->type) || !isscalar(r->type))
|
|
|
|
typeerror(op, l, r);
|
|
|
|
return simplify(op, inttype, cond(l), cond(r));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */
|
|
|
|
Tree asgn(Symbol p, Tree e) {
|
|
|
|
if (isarray(p->type))
|
|
|
|
e = tree(ASGN+B, p->type, idtree(p),
|
|
|
|
tree(INDIR+B, e->type, e, NULL));
|
|
|
|
else {
|
|
|
|
Type ty = p->type;
|
|
|
|
p->type = unqual(p->type);
|
|
|
|
if (isstruct(p->type) && p->type->u.sym->u.s.cfields) {
|
|
|
|
p->type->u.sym->u.s.cfields = 0;
|
|
|
|
e = asgntree(ASGN, idtree(p), e);
|
|
|
|
p->type->u.sym->u.s.cfields = 1;
|
|
|
|
} else
|
|
|
|
e = asgntree(ASGN, idtree(p), e);
|
|
|
|
p->type = ty;
|
|
|
|
}
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* bittree - construct tree for l [& | ^ %] r */
|
|
|
|
Tree bittree(int op, Tree l, Tree r) {
|
|
|
|
Type ty = inttype;
|
|
|
|
|
|
|
|
if (isint(l->type) && isint(r->type)) {
|
|
|
|
ty = binary(l->type, r->type);
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, ty);
|
|
|
|
} else
|
|
|
|
typeerror(op, l, r);
|
|
|
|
return simplify(op, ty, l, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* multree - construct tree for l [* /] r */
|
|
|
|
static Tree multree(int op, Tree l, Tree r) {
|
|
|
|
Type ty = inttype;
|
|
|
|
|
|
|
|
if (isarith(l->type) && isarith(r->type)) {
|
|
|
|
ty = binary(l->type, r->type);
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, ty);
|
|
|
|
} else
|
|
|
|
typeerror(op, l, r);
|
|
|
|
return simplify(op, ty, l, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* shtree - construct tree for l [>> <<] r */
|
|
|
|
Tree shtree(int op, Tree l, Tree r) {
|
|
|
|
Type ty = inttype;
|
|
|
|
|
|
|
|
if (isint(l->type) && isint(r->type)) {
|
|
|
|
ty = promote(l->type);
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, inttype);
|
|
|
|
} else
|
|
|
|
typeerror(op, l, r);
|
|
|
|
return simplify(op, ty, l, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* subtree - construct tree for l - r */
|
|
|
|
static Tree subtree(int op, Tree l, Tree r) {
|
|
|
|
long n;
|
|
|
|
Type ty = inttype;
|
|
|
|
|
|
|
|
if (isarith(l->type) && isarith(r->type)) {
|
|
|
|
ty = binary(l->type, r->type);
|
|
|
|
l = cast(l, ty);
|
|
|
|
r = cast(r, ty);
|
|
|
|
} else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) {
|
|
|
|
ty = unqual(l->type);
|
|
|
|
n = unqual(ty->type)->size;
|
|
|
|
if (n == 0)
|
|
|
|
error("unknown size for type `%t'\n", ty->type);
|
|
|
|
r = cast(r, promote(r->type));
|
|
|
|
if (n > 1)
|
|
|
|
r = multree(MUL, cnsttree(signedptr, n), r);
|
|
|
|
if (isunsigned(r->type))
|
|
|
|
r = cast(r, unsignedptr);
|
|
|
|
else
|
|
|
|
r = cast(r, signedptr);
|
|
|
|
return simplify(SUB+P, ty, l, r);
|
|
|
|
} else if (compatible(l->type, r->type)) {
|
|
|
|
ty = unqual(l->type);
|
|
|
|
n = unqual(ty->type)->size;
|
|
|
|
if (n == 0)
|
|
|
|
error("unknown size for type `%t'\n", ty->type);
|
|
|
|
l = simplify(SUB+U, unsignedptr,
|
|
|
|
cast(l, unsignedptr), cast(r, unsignedptr));
|
|
|
|
return simplify(DIV+I, longtype,
|
|
|
|
cast(l, longtype), cnsttree(longtype, n));
|
|
|
|
} else
|
|
|
|
typeerror(op, l, r);
|
|
|
|
return simplify(op, ty, l, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* typeerror - issue "operands of op have illegal types `l' and `r'" */
|
|
|
|
void typeerror(int op, Tree l, Tree r) {
|
|
|
|
int i;
|
|
|
|
static struct { int op; char *name; } ops[] = {
|
|
|
|
ASGN, "=", INDIR, "*", NEG, "-",
|
|
|
|
ADD, "+", SUB, "-", LSH, "<<",
|
|
|
|
MOD, "%", RSH, ">>", BAND, "&",
|
|
|
|
BCOM, "~", BOR, "|", BXOR, "^",
|
|
|
|
DIV, "/", MUL, "*", EQ, "==",
|
|
|
|
GE, ">=", GT, ">", LE, "<=",
|
|
|
|
LT, "<", NE, "!=", AND, "&&",
|
|
|
|
NOT, "!", OR, "||", COND, "?:",
|
|
|
|
0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
op = generic(op);
|
|
|
|
for (i = 0; ops[i].op; i++)
|
|
|
|
if (op == ops[i].op)
|
|
|
|
break;
|
|
|
|
assert(ops[i].name);
|
|
|
|
if (r)
|
|
|
|
error("operands of %s have illegal types `%t' and `%t'\n",
|
|
|
|
ops[i].name, l->type, r->type);
|
|
|
|
else
|
|
|
|
error("operand of unary %s has illegal type `%t'\n", ops[i].name,
|
|
|
|
l->type);
|
|
|
|
}
|