diff options
Diffstat (limited to 'lcc/src/stmt.c')
-rwxr-xr-x | lcc/src/stmt.c | 1394 |
1 files changed, 697 insertions, 697 deletions
diff --git a/lcc/src/stmt.c b/lcc/src/stmt.c index b742a32..94ab403 100755 --- a/lcc/src/stmt.c +++ b/lcc/src/stmt.c @@ -1,697 +1,697 @@ -#include "c.h"
-
-
-#define SWSIZE 512
-
-#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1))
-
-struct code codehead = { Start };
-Code codelist = &codehead;
-float density = 0.5;
-Table stmtlabs;
-
-static int foldcond(Tree e1, Tree e2);
-static void caselabel(Swtch, long, int);
-static void cmp(int, Symbol, long, int);
-static Tree conditional(int);
-static void dostmt(int, Swtch, int);
-static int equal(Symbol, Symbol);
-static void forstmt(int, Swtch, int);
-static void ifstmt(int, int, Swtch, int);
-static Symbol localaddr(Tree);
-static void stmtlabel(void);
-static void swstmt(int, int, int);
-static void whilestmt(int, Swtch, int);
-Code code(int kind) {
- Code cp;
-
- if (!reachable(kind))
- warning("unreachable code\n");
-
- NEW(cp, FUNC);
- cp->kind = kind;
- cp->prev = codelist;
- cp->next = NULL;
- codelist->next = cp;
- codelist = cp;
- return cp;
-}
-int reachable(int kind) {
- Code cp;
-
- if (kind > Start) {
- Code cp;
- for (cp = codelist; cp->kind < Label; )
- cp = cp->prev;
- if (cp->kind == Jump || cp->kind == Switch)
- return 0;
- }
- return 1;
-}
-void addlocal(Symbol p) {
- if (!p->defined) {
- code(Local)->u.var = p;
- p->defined = 1;
- p->scope = level;
- }
-}
-void definept(Coordinate *p) {
- Code cp = code(Defpoint);
-
- cp->u.point.src = p ? *p : src;
- cp->u.point.point = npoints;
- if (ncalled > 0) {
- int n = findcount(cp->u.point.src.file,
- cp->u.point.src.x, cp->u.point.src.y);
- if (n > 0)
- refinc = (float)n/ncalled;
- }
- if (glevel > 2) locus(identifiers, &cp->u.point.src);
- if (events.points && reachable(Gen))
- {
- Tree e = NULL;
- apply(events.points, &cp->u.point.src, &e);
- if (e)
- listnodes(e, 0, 0);
- }
-}
-void statement(int loop, Swtch swp, int lev) {
- float ref = refinc;
-
- if (Aflag >= 2 && lev == 15)
- warning("more than 15 levels of nested statements\n");
- switch (t) {
- case IF: ifstmt(genlabel(2), loop, swp, lev + 1);
- break;
- case WHILE: whilestmt(genlabel(3), swp, lev + 1); break;
- case DO: dostmt(genlabel(3), swp, lev + 1); expect(';');
- break;
-
- case FOR: forstmt(genlabel(4), swp, lev + 1);
- break;
- case BREAK: walk(NULL, 0, 0);
- definept(NULL);
- if (swp && swp->lab > loop)
- branch(swp->lab + 1);
- else if (loop)
- branch(loop + 2);
- else
- error("illegal break statement\n");
- t = gettok(); expect(';');
- break;
-
- case CONTINUE: walk(NULL, 0, 0);
- definept(NULL);
- if (loop)
- branch(loop + 1);
- else
- error("illegal continue statement\n");
- t = gettok(); expect(';');
- break;
-
- case SWITCH: swstmt(loop, genlabel(2), lev + 1);
- break;
- case CASE: {
- int lab = genlabel(1);
- if (swp == NULL)
- error("illegal case label\n");
- definelab(lab);
- while (t == CASE) {
- static char stop[] = { IF, ID, 0 };
- Tree p;
- t = gettok();
- p = constexpr(0);
- if (generic(p->op) == CNST && isint(p->type)) {
- if (swp) {
- needconst++;
- p = cast(p, swp->sym->type);
- if (p->type->op == UNSIGNED)
- p->u.v.i = extend(p->u.v.u, p->type);
- needconst--;
- caselabel(swp, p->u.v.i, lab);
- }
- } else
- error("case label must be a constant integer expression\n");
-
- test(':', stop);
- }
- statement(loop, swp, lev);
- } break;
- case DEFAULT: if (swp == NULL)
- error("illegal default label\n");
- else if (swp->deflab)
- error("extra default label\n");
- else {
- swp->deflab = findlabel(swp->lab);
- definelab(swp->deflab->u.l.label);
- }
- t = gettok();
- expect(':');
- statement(loop, swp, lev); break;
- case RETURN: {
- Type rty = freturn(cfunc->type);
- t = gettok();
- definept(NULL);
- if (t != ';')
- if (rty == voidtype) {
- error("extraneous return value\n");
- expr(0);
- retcode(NULL);
- } else
- retcode(expr(0));
- else {
- if (rty != voidtype)
- warning("missing return value\n");
- retcode(NULL);
- }
- branch(cfunc->u.f.label);
- } expect(';');
- break;
-
- case '{': compound(loop, swp, lev + 1); break;
- case ';': definept(NULL); t = gettok(); break;
- case GOTO: walk(NULL, 0, 0);
- definept(NULL);
- t = gettok();
- if (t == ID) {
- Symbol p = lookup(token, stmtlabs);
- if (p == NULL) {
- p = install(token, &stmtlabs, 0, FUNC);
- p->scope = LABELS;
- p->u.l.label = genlabel(1);
- p->src = src;
- }
- use(p, src);
- branch(p->u.l.label);
- t = gettok();
- } else
- error("missing label in goto\n"); expect(';');
- break;
-
- case ID: if (getchr() == ':') {
- stmtlabel();
- statement(loop, swp, lev);
- break;
- }
- default: definept(NULL);
- if (kind[t] != ID) {
- error("unrecognized statement\n");
- t = gettok();
- } else {
- Tree e = expr0(0);
- listnodes(e, 0, 0);
- if (nodecount == 0 || nodecount > 200)
- walk(NULL, 0, 0);
- else if (glevel) walk(NULL, 0, 0);
- deallocate(STMT);
- } expect(';');
- break;
-
- }
- if (kind[t] != IF && kind[t] != ID
- && t != '}' && t != EOI) {
- static char stop[] = { IF, ID, '}', 0 };
- error("illegal statement termination\n");
- skipto(0, stop);
- }
- refinc = ref;
-}
-
-static void ifstmt(int lab, int loop, Swtch swp, int lev) {
- t = gettok();
- expect('(');
- definept(NULL);
- walk(conditional(')'), 0, lab);
- refinc /= 2.0;
- statement(loop, swp, lev);
- if (t == ELSE) {
- branch(lab + 1);
- t = gettok();
- definelab(lab);
- statement(loop, swp, lev);
- if (findlabel(lab + 1)->ref)
- definelab(lab + 1);
- } else
- definelab(lab);
-}
-static Tree conditional(int tok) {
- Tree p = expr(tok);
-
- if (Aflag > 1 && isfunc(p->type))
- warning("%s used in a conditional expression\n",
- funcname(p));
- return cond(p);
-}
-static void stmtlabel(void) {
- Symbol p = lookup(token, stmtlabs);
-
- if (p == NULL) {
- p = install(token, &stmtlabs, 0, FUNC);
- p->scope = LABELS;
- p->u.l.label = genlabel(1);
- p->src = src;
- }
- if (p->defined)
- error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src);
-
- p->defined = 1;
- definelab(p->u.l.label);
- t = gettok();
- expect(':');
-}
-static void forstmt(int lab, Swtch swp, int lev) {
- int once = 0;
- Tree e1 = NULL, e2 = NULL, e3 = NULL;
- Coordinate pt2, pt3;
-
- t = gettok();
- expect('(');
- definept(NULL);
- if (kind[t] == ID)
- e1 = texpr(expr0, ';', FUNC);
- else
- expect(';');
- walk(e1, 0, 0);
- pt2 = src;
- refinc *= 10.0;
- if (kind[t] == ID)
- e2 = texpr(conditional, ';', FUNC);
- else
- expect(';');
- pt3 = src;
- if (kind[t] == ID)
- e3 = texpr(expr0, ')', FUNC);
- else {
- static char stop[] = { IF, ID, '}', 0 };
- test(')', stop);
- }
- if (e2) {
- once = foldcond(e1, e2);
- if (!once)
- branch(lab + 3);
- }
- definelab(lab);
- statement(lab, swp, lev);
- definelab(lab + 1);
- definept(&pt3);
- if (e3)
- walk(e3, 0, 0);
- if (e2) {
- if (!once)
- definelab(lab + 3);
- definept(&pt2);
- walk(e2, lab, 0);
- } else {
- definept(&pt2);
- branch(lab);
- }
- if (findlabel(lab + 2)->ref)
- definelab(lab + 2);
-}
-static void swstmt(int loop, int lab, int lev) {
- Tree e;
- struct swtch sw;
- Code head, tail;
-
- t = gettok();
- expect('(');
- definept(NULL);
- e = expr(')');
- if (!isint(e->type)) {
- error("illegal type `%t' in switch expression\n",
- e->type);
- e = retype(e, inttype);
- }
- e = cast(e, promote(e->type));
- if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op)
- && e->kids[0]->u.sym->type == e->type
- && !isvolatile(e->kids[0]->u.sym->type)) {
- sw.sym = e->kids[0]->u.sym;
- walk(NULL, 0, 0);
- } else {
- sw.sym = genident(REGISTER, e->type, level);
- addlocal(sw.sym);
- walk(asgn(sw.sym, e), 0, 0);
- }
- head = code(Switch);
- sw.lab = lab;
- sw.deflab = NULL;
- sw.ncases = 0;
- sw.size = SWSIZE;
- sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC);
- sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC);
- refinc /= 10.0;
- statement(loop, &sw, lev);
- if (sw.deflab == NULL) {
- sw.deflab = findlabel(lab);
- definelab(lab);
- if (sw.ncases == 0)
- warning("switch statement with no cases\n");
- }
- if (findlabel(lab + 1)->ref)
- definelab(lab + 1);
- tail = codelist;
- codelist = head->prev;
- codelist->next = head->prev = NULL;
- if (sw.ncases > 0)
- swgen(&sw);
- branch(lab);
- head->next->prev = codelist;
- codelist->next = head->next;
- codelist = tail;
-}
-static void caselabel(Swtch swp, long val, int lab) {
- int k;
-
- if (swp->ncases >= swp->size)
- {
- long *vals = swp->values;
- Symbol *labs = swp->labels;
- swp->size *= 2;
- swp->values = newarray(swp->size, sizeof *swp->values, FUNC);
- swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC);
- for (k = 0; k < swp->ncases; k++) {
- swp->values[k] = vals[k];
- swp->labels[k] = labs[k];
- }
- }
- k = swp->ncases;
- for ( ; k > 0 && swp->values[k-1] >= val; k--) {
- swp->values[k] = swp->values[k-1];
- swp->labels[k] = swp->labels[k-1];
- }
- if (k < swp->ncases && swp->values[k] == val)
- error("duplicate case label `%d'\n", val);
- swp->values[k] = val;
- swp->labels[k] = findlabel(lab);
- ++swp->ncases;
- if (Aflag >= 2 && swp->ncases == 258)
- warning("more than 257 cases in a switch\n");
-}
-void swgen(Swtch swp) {
- int *buckets, k, n;
- long *v = swp->values;
-
- buckets = newarray(swp->ncases + 1,
- sizeof *buckets, FUNC);
- for (n = k = 0; k < swp->ncases; k++, n++) {
- buckets[n] = k;
- while (n > 0 && den(n-1, k) >= density)
- n--;
- }
- buckets[n] = swp->ncases;
- swcode(swp, buckets, 0, n - 1);
-}
-void swcode(Swtch swp, int b[], int lb, int ub) {
- int hilab, lolab, l, u, k = (lb + ub)/2;
- long *v = swp->values;
-
- if (k > lb && k < ub) {
- lolab = genlabel(1);
- hilab = genlabel(1);
- } else if (k > lb) {
- lolab = genlabel(1);
- hilab = swp->deflab->u.l.label;
- } else if (k < ub) {
- lolab = swp->deflab->u.l.label;
- hilab = genlabel(1);
- } else
- lolab = hilab = swp->deflab->u.l.label;
- l = b[k];
- u = b[k+1] - 1;
- if (u - l + 1 <= 3)
- {
- int i;
- for (i = l; i <= u; i++)
- cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label);
- if (k > lb && k < ub)
- cmp(GT, swp->sym, v[u], hilab);
- else if (k > lb)
- cmp(GT, swp->sym, v[u], hilab);
- else if (k < ub)
- cmp(LT, swp->sym, v[l], lolab);
- else
- assert(lolab == hilab),
- branch(lolab);
- walk(NULL, 0, 0);
- }
- else {
- Tree e;
- Type ty = signedint(swp->sym->type);
- Symbol table = genident(STATIC,
- array(voidptype, u - l + 1, 0), GLOBAL);
- (*IR->defsymbol)(table);
- if (!isunsigned(swp->sym->type) || v[l] != 0)
- cmp(LT, swp->sym, v[l], lolab);
- cmp(GT, swp->sym, v[u], hilab);
- e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l]));
- if (e->type->size < unsignedptr->size)
- e = cast(e, unsignedlong);
- walk(tree(JUMP, voidtype,
- rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL),
- 0, 0);
- code(Switch);
- codelist->u.swtch.table = table;
- codelist->u.swtch.sym = swp->sym;
- codelist->u.swtch.deflab = swp->deflab;
- codelist->u.swtch.size = u - l + 1;
- codelist->u.swtch.values = &v[l];
- codelist->u.swtch.labels = &swp->labels[l];
- if (v[u] - v[l] + 1 >= 10000)
- warning("switch generates a huge table\n");
- }
- if (k > lb) {
- assert(lolab != swp->deflab->u.l.label);
- definelab(lolab);
- swcode(swp, b, lb, k - 1);
- }
- if (k < ub) {
- assert(hilab != swp->deflab->u.l.label);
- definelab(hilab);
- swcode(swp, b, k + 1, ub);
- }
-}
-static void cmp(int op, Symbol p, long n, int lab) {
- Type ty = signedint(p->type);
-
- listnodes(eqtree(op,
- cast(idtree(p), ty),
- cnsttree(ty, n)),
- lab, 0);
-}
-void retcode(Tree p) {
- Type ty;
-
- if (p == NULL) {
- if (events.returns)
- apply(events.returns, cfunc, NULL);
- return;
- }
- p = pointer(p);
- ty = assign(freturn(cfunc->type), p);
- if (ty == NULL) {
- error("illegal return type; found `%t' expected `%t'\n",
- p->type, freturn(cfunc->type));
- return;
- }
- p = cast(p, ty);
- if (retv)
- {
- if (iscallb(p))
- p = tree(RIGHT, p->type,
- tree(CALL+B, p->type,
- p->kids[0]->kids[0], idtree(retv)),
- rvalue(idtree(retv)));
- else
- p = asgntree(ASGN, rvalue(idtree(retv)), p);
- walk(p, 0, 0);
- if (events.returns)
- apply(events.returns, cfunc, rvalue(idtree(retv)));
- return;
- }
- if (events.returns)
- {
- Symbol t1 = genident(AUTO, p->type, level);
- addlocal(t1);
- walk(asgn(t1, p), 0, 0);
- apply(events.returns, cfunc, idtree(t1));
- p = idtree(t1);
- }
- if (!isfloat(p->type))
- p = cast(p, promote(p->type));
- if (isptr(p->type))
- {
- Symbol q = localaddr(p);
- if (q && (q->computed || q->generated))
- warning("pointer to a %s is an illegal return value\n",
- q->scope == PARAM ? "parameter" : "local");
- else if (q)
- warning("pointer to %s `%s' is an illegal return value\n",
- q->scope == PARAM ? "parameter" : "local", q->name);
- }
- walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0);
-}
-void definelab(int lab) {
- Code cp;
- Symbol p = findlabel(lab);
-
- assert(lab);
- walk(NULL, 0, 0);
- code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p);
- for (cp = codelist->prev; cp->kind <= Label; )
- cp = cp->prev;
- while ( cp->kind == Jump
- && cp->u.forest->kids[0]
- && specific(cp->u.forest->kids[0]->op) == ADDRG+P
- && cp->u.forest->kids[0]->syms[0] == p) {
- assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab);
- p->ref--;
- assert(cp->next);
- assert(cp->prev);
- cp->prev->next = cp->next;
- cp->next->prev = cp->prev;
- cp = cp->prev;
- while (cp->kind <= Label)
- cp = cp->prev;
- }
-}
-Node jump(int lab) {
- Symbol p = findlabel(lab);
-
- p->ref++;
- return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p),
- NULL, NULL);
-}
-void branch(int lab) {
- Code cp;
- Symbol p = findlabel(lab);
-
- assert(lab);
- walk(NULL, 0, 0);
- code(Label)->u.forest = jump(lab);
- for (cp = codelist->prev; cp->kind < Label; )
- cp = cp->prev;
- while ( cp->kind == Label
- && cp->u.forest->op == LABEL+V
- && !equal(cp->u.forest->syms[0], p)) {
- equatelab(cp->u.forest->syms[0], p);
- assert(cp->next);
- assert(cp->prev);
- cp->prev->next = cp->next;
- cp->next->prev = cp->prev;
- cp = cp->prev;
- while (cp->kind < Label)
- cp = cp->prev;
- }
- if (cp->kind == Jump || cp->kind == Switch) {
- p->ref--;
- codelist->prev->next = NULL;
- codelist = codelist->prev;
- } else {
- codelist->kind = Jump;
- if (cp->kind == Label
- && cp->u.forest->op == LABEL+V
- && equal(cp->u.forest->syms[0], p))
- warning("source code specifies an infinite loop");
- }
-}
-void equatelab(Symbol old, Symbol new) {
- assert(old->u.l.equatedto == NULL);
- old->u.l.equatedto = new;
- new->ref++;
-}
-static int equal(Symbol lprime, Symbol dst) {
- assert(dst && lprime);
- for ( ; dst; dst = dst->u.l.equatedto)
- if (lprime == dst)
- return 1;
- return 0;
-}
-/* dostmt - do statement while ( expression ) */
-static void dostmt(int lab, Swtch swp, int lev) {
- refinc *= 10.0;
- t = gettok();
- definelab(lab);
- statement(lab, swp, lev);
- definelab(lab + 1);
- expect(WHILE);
- expect('(');
- definept(NULL);
- walk(conditional(')'), lab, 0);
- if (findlabel(lab + 2)->ref)
- definelab(lab + 2);
-}
-
-/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */
-static int foldcond(Tree e1, Tree e2) {
- int op = generic(e2->op);
- Symbol v;
-
- if (e1 == 0 || e2 == 0)
- return 0;
- if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op)
- && generic(e1->kids[1]->op) == CNST) {
- v = e1->kids[0]->u.sym;
- e1 = e1->kids[1];
- } else
- return 0;
- if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE)
- && generic(e2->kids[0]->op) == INDIR
- && e2->kids[0]->kids[0]->u.sym == v
- && e2->kids[1]->op == e1->op) {
- e1 = simplify(op, e2->type, e1, e2->kids[1]);
- if (e1->op == CNST+I)
- return e1->u.v.i;
- }
- return 0;
-}
-
-/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */
-static Symbol localaddr(Tree p) {
- if (p == NULL)
- return NULL;
- switch (generic(p->op)) {
- case INDIR: case CALL: case ARG:
- return NULL;
- case ADDRL: case ADDRF:
- return p->u.sym;
- case RIGHT: case ASGN:
- if (p->kids[1])
- return localaddr(p->kids[1]);
- return localaddr(p->kids[0]);
- case COND: {
- Symbol q;
- assert(p->kids[1] && p->kids[1]->op == RIGHT);
- if ((q = localaddr(p->kids[1]->kids[0])) != NULL)
- return q;
- return localaddr(p->kids[1]->kids[1]);
- }
- default: {
- Symbol q;
- if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL)
- return q;
- return localaddr(p->kids[1]);
- }
- }
-}
-
-/* whilestmt - while ( expression ) statement */
-static void whilestmt(int lab, Swtch swp, int lev) {
- Coordinate pt;
- Tree e;
-
- refinc *= 10.0;
- t = gettok();
- expect('(');
- walk(NULL, 0, 0);
- pt = src;
- e = texpr(conditional, ')', FUNC);
- branch(lab + 1);
- definelab(lab);
- statement(lab, swp, lev);
- definelab(lab + 1);
- definept(&pt);
- walk(e, lab, 0);
- if (findlabel(lab + 2)->ref)
- definelab(lab + 2);
-}
+#include "c.h" + + +#define SWSIZE 512 + +#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1)) + +struct code codehead = { Start }; +Code codelist = &codehead; +float density = 0.5; +Table stmtlabs; + +static int foldcond(Tree e1, Tree e2); +static void caselabel(Swtch, long, int); +static void cmp(int, Symbol, long, int); +static Tree conditional(int); +static void dostmt(int, Swtch, int); +static int equal(Symbol, Symbol); +static void forstmt(int, Swtch, int); +static void ifstmt(int, int, Swtch, int); +static Symbol localaddr(Tree); +static void stmtlabel(void); +static void swstmt(int, int, int); +static void whilestmt(int, Swtch, int); +Code code(int kind) { + Code cp; + + if (!reachable(kind)) + warning("unreachable code\n"); + + NEW(cp, FUNC); + cp->kind = kind; + cp->prev = codelist; + cp->next = NULL; + codelist->next = cp; + codelist = cp; + return cp; +} +int reachable(int kind) { + Code cp; + + if (kind > Start) { + Code cp; + for (cp = codelist; cp->kind < Label; ) + cp = cp->prev; + if (cp->kind == Jump || cp->kind == Switch) + return 0; + } + return 1; +} +void addlocal(Symbol p) { + if (!p->defined) { + code(Local)->u.var = p; + p->defined = 1; + p->scope = level; + } +} +void definept(Coordinate *p) { + Code cp = code(Defpoint); + + cp->u.point.src = p ? *p : src; + cp->u.point.point = npoints; + if (ncalled > 0) { + int n = findcount(cp->u.point.src.file, + cp->u.point.src.x, cp->u.point.src.y); + if (n > 0) + refinc = (float)n/ncalled; + } + if (glevel > 2) locus(identifiers, &cp->u.point.src); + if (events.points && reachable(Gen)) + { + Tree e = NULL; + apply(events.points, &cp->u.point.src, &e); + if (e) + listnodes(e, 0, 0); + } +} +void statement(int loop, Swtch swp, int lev) { + float ref = refinc; + + if (Aflag >= 2 && lev == 15) + warning("more than 15 levels of nested statements\n"); + switch (t) { + case IF: ifstmt(genlabel(2), loop, swp, lev + 1); + break; + case WHILE: whilestmt(genlabel(3), swp, lev + 1); break; + case DO: dostmt(genlabel(3), swp, lev + 1); expect(';'); + break; + + case FOR: forstmt(genlabel(4), swp, lev + 1); + break; + case BREAK: walk(NULL, 0, 0); + definept(NULL); + if (swp && swp->lab > loop) + branch(swp->lab + 1); + else if (loop) + branch(loop + 2); + else + error("illegal break statement\n"); + t = gettok(); expect(';'); + break; + + case CONTINUE: walk(NULL, 0, 0); + definept(NULL); + if (loop) + branch(loop + 1); + else + error("illegal continue statement\n"); + t = gettok(); expect(';'); + break; + + case SWITCH: swstmt(loop, genlabel(2), lev + 1); + break; + case CASE: { + int lab = genlabel(1); + if (swp == NULL) + error("illegal case label\n"); + definelab(lab); + while (t == CASE) { + static char stop[] = { IF, ID, 0 }; + Tree p; + t = gettok(); + p = constexpr(0); + if (generic(p->op) == CNST && isint(p->type)) { + if (swp) { + needconst++; + p = cast(p, swp->sym->type); + if (p->type->op == UNSIGNED) + p->u.v.i = extend(p->u.v.u, p->type); + needconst--; + caselabel(swp, p->u.v.i, lab); + } + } else + error("case label must be a constant integer expression\n"); + + test(':', stop); + } + statement(loop, swp, lev); + } break; + case DEFAULT: if (swp == NULL) + error("illegal default label\n"); + else if (swp->deflab) + error("extra default label\n"); + else { + swp->deflab = findlabel(swp->lab); + definelab(swp->deflab->u.l.label); + } + t = gettok(); + expect(':'); + statement(loop, swp, lev); break; + case RETURN: { + Type rty = freturn(cfunc->type); + t = gettok(); + definept(NULL); + if (t != ';') + if (rty == voidtype) { + error("extraneous return value\n"); + expr(0); + retcode(NULL); + } else + retcode(expr(0)); + else { + if (rty != voidtype) + warning("missing return value\n"); + retcode(NULL); + } + branch(cfunc->u.f.label); + } expect(';'); + break; + + case '{': compound(loop, swp, lev + 1); break; + case ';': definept(NULL); t = gettok(); break; + case GOTO: walk(NULL, 0, 0); + definept(NULL); + t = gettok(); + if (t == ID) { + Symbol p = lookup(token, stmtlabs); + if (p == NULL) { + p = install(token, &stmtlabs, 0, FUNC); + p->scope = LABELS; + p->u.l.label = genlabel(1); + p->src = src; + } + use(p, src); + branch(p->u.l.label); + t = gettok(); + } else + error("missing label in goto\n"); expect(';'); + break; + + case ID: if (getchr() == ':') { + stmtlabel(); + statement(loop, swp, lev); + break; + } + default: definept(NULL); + if (kind[t] != ID) { + error("unrecognized statement\n"); + t = gettok(); + } else { + Tree e = expr0(0); + listnodes(e, 0, 0); + if (nodecount == 0 || nodecount > 200) + walk(NULL, 0, 0); + else if (glevel) walk(NULL, 0, 0); + deallocate(STMT); + } expect(';'); + break; + + } + if (kind[t] != IF && kind[t] != ID + && t != '}' && t != EOI) { + static char stop[] = { IF, ID, '}', 0 }; + error("illegal statement termination\n"); + skipto(0, stop); + } + refinc = ref; +} + +static void ifstmt(int lab, int loop, Swtch swp, int lev) { + t = gettok(); + expect('('); + definept(NULL); + walk(conditional(')'), 0, lab); + refinc /= 2.0; + statement(loop, swp, lev); + if (t == ELSE) { + branch(lab + 1); + t = gettok(); + definelab(lab); + statement(loop, swp, lev); + if (findlabel(lab + 1)->ref) + definelab(lab + 1); + } else + definelab(lab); +} +static Tree conditional(int tok) { + Tree p = expr(tok); + + if (Aflag > 1 && isfunc(p->type)) + warning("%s used in a conditional expression\n", + funcname(p)); + return cond(p); +} +static void stmtlabel(void) { + Symbol p = lookup(token, stmtlabs); + + if (p == NULL) { + p = install(token, &stmtlabs, 0, FUNC); + p->scope = LABELS; + p->u.l.label = genlabel(1); + p->src = src; + } + if (p->defined) + error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src); + + p->defined = 1; + definelab(p->u.l.label); + t = gettok(); + expect(':'); +} +static void forstmt(int lab, Swtch swp, int lev) { + int once = 0; + Tree e1 = NULL, e2 = NULL, e3 = NULL; + Coordinate pt2, pt3; + + t = gettok(); + expect('('); + definept(NULL); + if (kind[t] == ID) + e1 = texpr(expr0, ';', FUNC); + else + expect(';'); + walk(e1, 0, 0); + pt2 = src; + refinc *= 10.0; + if (kind[t] == ID) + e2 = texpr(conditional, ';', FUNC); + else + expect(';'); + pt3 = src; + if (kind[t] == ID) + e3 = texpr(expr0, ')', FUNC); + else { + static char stop[] = { IF, ID, '}', 0 }; + test(')', stop); + } + if (e2) { + once = foldcond(e1, e2); + if (!once) + branch(lab + 3); + } + definelab(lab); + statement(lab, swp, lev); + definelab(lab + 1); + definept(&pt3); + if (e3) + walk(e3, 0, 0); + if (e2) { + if (!once) + definelab(lab + 3); + definept(&pt2); + walk(e2, lab, 0); + } else { + definept(&pt2); + branch(lab); + } + if (findlabel(lab + 2)->ref) + definelab(lab + 2); +} +static void swstmt(int loop, int lab, int lev) { + Tree e; + struct swtch sw; + Code head, tail; + + t = gettok(); + expect('('); + definept(NULL); + e = expr(')'); + if (!isint(e->type)) { + error("illegal type `%t' in switch expression\n", + e->type); + e = retype(e, inttype); + } + e = cast(e, promote(e->type)); + if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op) + && e->kids[0]->u.sym->type == e->type + && !isvolatile(e->kids[0]->u.sym->type)) { + sw.sym = e->kids[0]->u.sym; + walk(NULL, 0, 0); + } else { + sw.sym = genident(REGISTER, e->type, level); + addlocal(sw.sym); + walk(asgn(sw.sym, e), 0, 0); + } + head = code(Switch); + sw.lab = lab; + sw.deflab = NULL; + sw.ncases = 0; + sw.size = SWSIZE; + sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC); + sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC); + refinc /= 10.0; + statement(loop, &sw, lev); + if (sw.deflab == NULL) { + sw.deflab = findlabel(lab); + definelab(lab); + if (sw.ncases == 0) + warning("switch statement with no cases\n"); + } + if (findlabel(lab + 1)->ref) + definelab(lab + 1); + tail = codelist; + codelist = head->prev; + codelist->next = head->prev = NULL; + if (sw.ncases > 0) + swgen(&sw); + branch(lab); + head->next->prev = codelist; + codelist->next = head->next; + codelist = tail; +} +static void caselabel(Swtch swp, long val, int lab) { + int k; + + if (swp->ncases >= swp->size) + { + long *vals = swp->values; + Symbol *labs = swp->labels; + swp->size *= 2; + swp->values = newarray(swp->size, sizeof *swp->values, FUNC); + swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC); + for (k = 0; k < swp->ncases; k++) { + swp->values[k] = vals[k]; + swp->labels[k] = labs[k]; + } + } + k = swp->ncases; + for ( ; k > 0 && swp->values[k-1] >= val; k--) { + swp->values[k] = swp->values[k-1]; + swp->labels[k] = swp->labels[k-1]; + } + if (k < swp->ncases && swp->values[k] == val) + error("duplicate case label `%d'\n", val); + swp->values[k] = val; + swp->labels[k] = findlabel(lab); + ++swp->ncases; + if (Aflag >= 2 && swp->ncases == 258) + warning("more than 257 cases in a switch\n"); +} +void swgen(Swtch swp) { + int *buckets, k, n; + long *v = swp->values; + + buckets = newarray(swp->ncases + 1, + sizeof *buckets, FUNC); + for (n = k = 0; k < swp->ncases; k++, n++) { + buckets[n] = k; + while (n > 0 && den(n-1, k) >= density) + n--; + } + buckets[n] = swp->ncases; + swcode(swp, buckets, 0, n - 1); +} +void swcode(Swtch swp, int b[], int lb, int ub) { + int hilab, lolab, l, u, k = (lb + ub)/2; + long *v = swp->values; + + if (k > lb && k < ub) { + lolab = genlabel(1); + hilab = genlabel(1); + } else if (k > lb) { + lolab = genlabel(1); + hilab = swp->deflab->u.l.label; + } else if (k < ub) { + lolab = swp->deflab->u.l.label; + hilab = genlabel(1); + } else + lolab = hilab = swp->deflab->u.l.label; + l = b[k]; + u = b[k+1] - 1; + if (u - l + 1 <= 3) + { + int i; + for (i = l; i <= u; i++) + cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label); + if (k > lb && k < ub) + cmp(GT, swp->sym, v[u], hilab); + else if (k > lb) + cmp(GT, swp->sym, v[u], hilab); + else if (k < ub) + cmp(LT, swp->sym, v[l], lolab); + else + assert(lolab == hilab), + branch(lolab); + walk(NULL, 0, 0); + } + else { + Tree e; + Type ty = signedint(swp->sym->type); + Symbol table = genident(STATIC, + array(voidptype, u - l + 1, 0), GLOBAL); + (*IR->defsymbol)(table); + if (!isunsigned(swp->sym->type) || v[l] != 0) + cmp(LT, swp->sym, v[l], lolab); + cmp(GT, swp->sym, v[u], hilab); + e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l])); + if (e->type->size < unsignedptr->size) + e = cast(e, unsignedlong); + walk(tree(JUMP, voidtype, + rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL), + 0, 0); + code(Switch); + codelist->u.swtch.table = table; + codelist->u.swtch.sym = swp->sym; + codelist->u.swtch.deflab = swp->deflab; + codelist->u.swtch.size = u - l + 1; + codelist->u.swtch.values = &v[l]; + codelist->u.swtch.labels = &swp->labels[l]; + if (v[u] - v[l] + 1 >= 10000) + warning("switch generates a huge table\n"); + } + if (k > lb) { + assert(lolab != swp->deflab->u.l.label); + definelab(lolab); + swcode(swp, b, lb, k - 1); + } + if (k < ub) { + assert(hilab != swp->deflab->u.l.label); + definelab(hilab); + swcode(swp, b, k + 1, ub); + } +} +static void cmp(int op, Symbol p, long n, int lab) { + Type ty = signedint(p->type); + + listnodes(eqtree(op, + cast(idtree(p), ty), + cnsttree(ty, n)), + lab, 0); +} +void retcode(Tree p) { + Type ty; + + if (p == NULL) { + if (events.returns) + apply(events.returns, cfunc, NULL); + return; + } + p = pointer(p); + ty = assign(freturn(cfunc->type), p); + if (ty == NULL) { + error("illegal return type; found `%t' expected `%t'\n", + p->type, freturn(cfunc->type)); + return; + } + p = cast(p, ty); + if (retv) + { + if (iscallb(p)) + p = tree(RIGHT, p->type, + tree(CALL+B, p->type, + p->kids[0]->kids[0], idtree(retv)), + rvalue(idtree(retv))); + else + p = asgntree(ASGN, rvalue(idtree(retv)), p); + walk(p, 0, 0); + if (events.returns) + apply(events.returns, cfunc, rvalue(idtree(retv))); + return; + } + if (events.returns) + { + Symbol t1 = genident(AUTO, p->type, level); + addlocal(t1); + walk(asgn(t1, p), 0, 0); + apply(events.returns, cfunc, idtree(t1)); + p = idtree(t1); + } + if (!isfloat(p->type)) + p = cast(p, promote(p->type)); + if (isptr(p->type)) + { + Symbol q = localaddr(p); + if (q && (q->computed || q->generated)) + warning("pointer to a %s is an illegal return value\n", + q->scope == PARAM ? "parameter" : "local"); + else if (q) + warning("pointer to %s `%s' is an illegal return value\n", + q->scope == PARAM ? "parameter" : "local", q->name); + } + walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0); +} +void definelab(int lab) { + Code cp; + Symbol p = findlabel(lab); + + assert(lab); + walk(NULL, 0, 0); + code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p); + for (cp = codelist->prev; cp->kind <= Label; ) + cp = cp->prev; + while ( cp->kind == Jump + && cp->u.forest->kids[0] + && specific(cp->u.forest->kids[0]->op) == ADDRG+P + && cp->u.forest->kids[0]->syms[0] == p) { + assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab); + p->ref--; + assert(cp->next); + assert(cp->prev); + cp->prev->next = cp->next; + cp->next->prev = cp->prev; + cp = cp->prev; + while (cp->kind <= Label) + cp = cp->prev; + } +} +Node jump(int lab) { + Symbol p = findlabel(lab); + + p->ref++; + return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p), + NULL, NULL); +} +void branch(int lab) { + Code cp; + Symbol p = findlabel(lab); + + assert(lab); + walk(NULL, 0, 0); + code(Label)->u.forest = jump(lab); + for (cp = codelist->prev; cp->kind < Label; ) + cp = cp->prev; + while ( cp->kind == Label + && cp->u.forest->op == LABEL+V + && !equal(cp->u.forest->syms[0], p)) { + equatelab(cp->u.forest->syms[0], p); + assert(cp->next); + assert(cp->prev); + cp->prev->next = cp->next; + cp->next->prev = cp->prev; + cp = cp->prev; + while (cp->kind < Label) + cp = cp->prev; + } + if (cp->kind == Jump || cp->kind == Switch) { + p->ref--; + codelist->prev->next = NULL; + codelist = codelist->prev; + } else { + codelist->kind = Jump; + if (cp->kind == Label + && cp->u.forest->op == LABEL+V + && equal(cp->u.forest->syms[0], p)) + warning("source code specifies an infinite loop"); + } +} +void equatelab(Symbol old, Symbol new) { + assert(old->u.l.equatedto == NULL); + old->u.l.equatedto = new; + new->ref++; +} +static int equal(Symbol lprime, Symbol dst) { + assert(dst && lprime); + for ( ; dst; dst = dst->u.l.equatedto) + if (lprime == dst) + return 1; + return 0; +} +/* dostmt - do statement while ( expression ) */ +static void dostmt(int lab, Swtch swp, int lev) { + refinc *= 10.0; + t = gettok(); + definelab(lab); + statement(lab, swp, lev); + definelab(lab + 1); + expect(WHILE); + expect('('); + definept(NULL); + walk(conditional(')'), lab, 0); + if (findlabel(lab + 2)->ref) + definelab(lab + 2); +} + +/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */ +static int foldcond(Tree e1, Tree e2) { + int op = generic(e2->op); + Symbol v; + + if (e1 == 0 || e2 == 0) + return 0; + if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op) + && generic(e1->kids[1]->op) == CNST) { + v = e1->kids[0]->u.sym; + e1 = e1->kids[1]; + } else + return 0; + if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE) + && generic(e2->kids[0]->op) == INDIR + && e2->kids[0]->kids[0]->u.sym == v + && e2->kids[1]->op == e1->op) { + e1 = simplify(op, e2->type, e1, e2->kids[1]); + if (e1->op == CNST+I) + return e1->u.v.i; + } + return 0; +} + +/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */ +static Symbol localaddr(Tree p) { + if (p == NULL) + return NULL; + switch (generic(p->op)) { + case INDIR: case CALL: case ARG: + return NULL; + case ADDRL: case ADDRF: + return p->u.sym; + case RIGHT: case ASGN: + if (p->kids[1]) + return localaddr(p->kids[1]); + return localaddr(p->kids[0]); + case COND: { + Symbol q; + assert(p->kids[1] && p->kids[1]->op == RIGHT); + if ((q = localaddr(p->kids[1]->kids[0])) != NULL) + return q; + return localaddr(p->kids[1]->kids[1]); + } + default: { + Symbol q; + if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL) + return q; + return localaddr(p->kids[1]); + } + } +} + +/* whilestmt - while ( expression ) statement */ +static void whilestmt(int lab, Swtch swp, int lev) { + Coordinate pt; + Tree e; + + refinc *= 10.0; + t = gettok(); + expect('('); + walk(NULL, 0, 0); + pt = src; + e = texpr(conditional, ')', FUNC); + branch(lab + 1); + definelab(lab); + statement(lab, swp, lev); + definelab(lab + 1); + definept(&pt); + walk(e, lab, 0); + if (findlabel(lab + 2)->ref) + definelab(lab + 2); +} |