aboutsummaryrefslogtreecommitdiff
path: root/code/tools/lcc/src/enode.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/tools/lcc/src/enode.c')
-rw-r--r--code/tools/lcc/src/enode.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/code/tools/lcc/src/enode.c b/code/tools/lcc/src/enode.c
new file mode 100644
index 0000000..760096d
--- /dev/null
+++ b/code/tools/lcc/src/enode.c
@@ -0,0 +1,545 @@
+#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, 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);
+}