| #include "c.h" |
| |
| static char rcsid[] = "$Id: enode.c 355 2007-02-18 22:08:49Z drh $"; |
| |
| 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 (isunsigned(l->type)) |
| l = cast(l, unsignedptr); |
| else |
| l = cast(l, signedptr); |
| 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(int n, Type ty) { |
| if (isarray(ty)) |
| ty = atop(ty); |
| else assert(isint(ty)); |
| return cnsttree(ty, (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) { |
| ty1 = unqual(ty1); |
| ty2 = unqual(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 = unqual(l->type), yty = unqual(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); |
| } |