#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <inttypes.h>#include <ctype.h>#include <string.h>#include <assert.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h> #include "util.h"#include "parse.h"#include "mi.h"#include "../config.h" typedef struct Flattenctx Flattenctx;typedef struct Loop Loop; struct Loop { Node *lcnt; Node *lbrk; Stab *body;}; /* takes a list of nodes, and reduces it (and it's subnodes) to a list * following these constraints: * - All nodes are expression node * - Nodes with side effects are root node * - All nodes operate on machine-primitive types and tuple */struct Flattenctx { int isglobl; Node **stmts; size_t nstmts; /* return handling */ Node *tret; /* pre/postinc handling */ Node **incqueue; size_t nqueue; /* break/continue handling */ Loop loop; unsigned inloop; Stab *curst; /* location handling */ Htab *globls; size_t stksz;}; static Node *flatten(Flattenctx *s, Node *n);static Node *rval(Flattenctx *s, Node *n);static Node *lval(Flattenctx *s, Node *n);static Node *assign(Flattenctx *s, Node *lhs, Node *rhs);static void draininc(Flattenctx *c); static voidappend(Flattenctx *s, Node *n){ if (debugopt['F']) dumpn(n, stdout); lappend(&s->stmts, &s->nstmts, n);} static voidcjmp(Flattenctx *s, Node *cond, Node *iftrue, Node *iffalse){ Node *jmp; jmp = mkexpr(cond->loc, Ocjmp, cond, iftrue, iffalse, NULL); jmp->expr.type = mktype(cond->loc, Tyvoid); append(s, jmp);} static voidjmp(Flattenctx *s, Node *lbl){ Node *n; n = mkexpr(lbl->loc, Ojmp, lbl, NULL); n->expr.type = mktype(n->loc, Tyvoid); append(s, n);} static Node *asn(Node *a, Node *b){ Node *n; assert(a != NULL && b != NULL); if (tybase(exprtype(a))->type == Tyvoid) return a; n = mkexpr(a->loc, Oasn, a, b, NULL); n->expr.type = exprtype(a); return n;} static intislbl(Node *n){ Node *l; if (exprop(n) != Olit) return 0; l = n->expr.args[0]; return l->type == Nlit && l->lit.littype == Llbl;} static Node *temp(Flattenctx *flatten, Node *e){ Node *t; assert(e->type == Nexpr); t = gentemp(e->loc, e->expr.type, NULL); return t;} static Node *add(Node *a, Node *b){ Node *n; n = mkexpr(a->loc, Oadd, a, b, NULL); n->expr.type = a->expr.type; return n;} static Node *addk(Node *n, uvlong v){ Node *k; k = mkintlit(n->loc, v); k->expr.type = exprtype(n); return add(n, k);} static Node *sub(Node *a, Node *b){ Node *n; n = mkexpr(a->loc, Osub, a, b, NULL); n->expr.type = a->expr.type; return n;} static Node *subk(Node *n, uvlong v){ Node *k; k = mkintlit(n->loc, v); k->expr.type = exprtype(n); return sub(n, k);} static Node *seqlen(Flattenctx *s, Node *n, Type *ty){ Node *r; if (!ty) ty = n->expr.type; if (exprtype(n)->type == Tyarray) { r = mkexpr(n->loc, Osllen, rval(s, n), NULL); r->expr.type = ty; } else if (exprtype(n)->type == Tyslice) { r = mkexpr(n->loc, Osllen, rval(s, n), NULL); r->expr.type = ty; } else { die("invalid seq type for len"); } return r;} static Node *visit(Flattenctx *s, Node *n){ size_t i; Node *r; for (i = 0; i < n->expr.nargs; i++) n->expr.args[i] = rval(s, n->expr.args[i]); if (opispure[exprop(n)]) { r = n; } else { if (exprtype(n)->type == Tyvoid) { r = mkexpr(n->loc, Olit, mkvoid(n->loc), NULL); r->expr.type = mktype(n->loc, Tyvoid); append(s, n); } else { r = temp(s, n); append(s, asn(r, n)); } } return r;} static Node *traitfn(Srcloc loc, Trait *tr, char *fn, Type *ty){ Node *proto, *dcl, *var; char *name; size_t i; for (i = 0; i < tr->nproto; i++) { name = declname(tr->proto[i]); if (!strcmp(fn, name)) { proto = tr->proto[i]; dcl = htget(proto->decl.impls, ty); var = mkexpr(loc, Ovar, dcl->decl.name, NULL); var->expr.type = dcl->decl.type; var->expr.did = dcl->decl.did; return var; } } return NULL;} static voiddispose(Flattenctx *s, Stab *st, size_t n){ Node *e, *call, *func; Trait *tr; Type *ty; size_t i; tr = traittab[Tcdisp]; /* dispose in reverse order of appearance */ for (i = st->nautotmp; i-- > n;) { e = st->autotmp[i]; ty = exprtype(e); func = traitfn(Zloc, tr, "__dispose__", ty); call = mkexpr(Zloc, Ocall, func, e, NULL); call->expr.type = mktype(Zloc, Tyvoid); flatten(s, call); }} static voidflattencond(Flattenctx *s, Node *n, Node *ltrue, Node *lfalse){ Node **args; Node *v, *lnext; args = n->expr.args; switch (exprop(n)) { case Oland: lnext = genlbl(n->loc); flattencond(s, args[0], lnext, lfalse); append(s, lnext); flattencond(s, args[1], ltrue, lfalse); break; case Olor: lnext = genlbl(n->loc); flattencond(s, args[0], ltrue, lnext); append(s, lnext); flattencond(s, args[1], ltrue, lfalse); break; case Olnot: flattencond(s, args[0], lfalse, ltrue); break; default: v = rval(s, n); cjmp(s, v, ltrue, lfalse); break; }} static Node*flattentern(Flattenctx *s, Node *n){ Node *l1, *l2, *l3; Node *res, *t; l1 = genlbl(n->loc); l2 = genlbl(n->loc); l3 = genlbl(n->loc); res = temp(s, n); flattencond(s, n->expr.args[0], l1, l2); append(s, l1); t = assign(s, res, rval(s, n->expr.args[1])); append(s, t); jmp(s, l3); append(s, l2); t = assign(s, res, rval(s, n->expr.args[2])); append(s, t); append(s, l3); return res;} /* flatten * a || b * to * if a || b * t = true * else * t = false * ;; */static Node *flattenlazy(Flattenctx *s, Node *n){ Node *r, *t, *u; Node *ltrue, *lfalse, *ldone; /* set up temps and labels */ r = temp(s, n); ltrue = genlbl(n->loc); lfalse = genlbl(n->loc); ldone = genlbl(n->loc); /* flatten the conditional */ flattencond(s, n, ltrue, lfalse); /* if true */ append(s, ltrue); u = mkexpr(n->loc, Olit, mkbool(n->loc, 1), NULL); u->expr.type = mktype(n->loc, Tybool); t = asn(r, u); append(s, t); jmp(s, ldone); /* if false */ append(s, lfalse); u = mkexpr(n->loc, Olit, mkbool(n->loc, 0), NULL); u->expr.type = mktype(n->loc, Tybool); t = asn(r, u); append(s, t); jmp(s, ldone); /* finish */ append(s, ldone); return r;} static Node *destructure(Flattenctx *s, Node *lhs, Node *rhs){ Node *lv, *rv, *idx; Node **args; size_t i; args = lhs->expr.args; rhs = rval(s, rhs); for (i = 0; i < lhs->expr.nargs; i++) { idx = mkintlit(rhs->loc, i); idx->expr.type = mktype(rhs->loc, Tyuint64); rv = mkexpr(rhs->loc, Otupget, rhs, idx, NULL); rv->expr.type = lhs->expr.type; if (exprop(args[i]) == Otup) { destructure(s, args[i], rv); } else { lv = lval(s, args[i]); append(s, assign(s, lv, rv)); } } return rhs;} static Node *comparecomplex(Flattenctx *s, Node *n, Op op){ Type *ty; Node *l, *r, *e; /* special case: unions with nullary constructors can be compared easily. */ ty = tybase(exprtype(n->expr.args[0])); if (ty->type == Tyunion && isenum(ty)) { l = mkexpr(n->loc, Outag, rval(s, n->expr.args[0]), NULL); r = mkexpr(n->loc, Outag, rval(s, n->expr.args[1]), NULL); l->expr.type = mktype(n->loc, Tyuint32); r->expr.type = mktype(n->loc, Tyuint32); if (op == Oeq) e = mkexpr(n->loc, Oueq, l, r, NULL); else if (op == One) e = mkexpr(n->loc, Oune, l, r, NULL); else fatal(n, "unsupported operator %s for enum union", opstr[op]); e->expr.type = mktype(n->loc, Tybool); return e; } fatal(n, "cannot compare values of type %s for equality\n", tystr(exprtype(n->expr.args[0]))); return NULL;} static Node *compare(Flattenctx *s, Node *n, int fields){ const Op cmpmap[Numops][3] = { [Oeq] = {Oeq, Oueq, Ofeq}, [One] = {One, Oune, Ofne}, [Ogt] = {Ogt, Ougt, Ofgt}, [Oge] = {Oge, Ouge, Ofge}, [Olt] = {Olt, Oult, Oflt}, [Ole] = {Ole, Oule, Ofle} }; Node *r; Type *ty; Op newop; /* void is always void */ if (tybase(exprtype(n->expr.args[0]))->type == Tyvoid) return mkboollit(n->loc, 1); newop = Obad; ty = tybase(exprtype(n->expr.args[0])); if (istysigned(ty)) newop = cmpmap[n->expr.op][0]; else if (istyunsigned(ty)) newop = cmpmap[n->expr.op][1]; else if (istyunsigned(ty)) newop = cmpmap[n->expr.op][1]; else if (ty->type == Typtr) newop = cmpmap[n->expr.op][1]; else if (istyfloat(ty)) newop = cmpmap[n->expr.op][2]; if (newop != Obad) { n->expr.op = newop; r = visit(s, n); } else if (fields) { r = comparecomplex(s, n, exprop(n)); } else { fatal(n, "unsupported comparison on type %s", tystr(ty)); } r->expr.type = mktype(n->loc, Tybool); return r;} static Node *assign(Flattenctx *s, Node *lhs, Node *rhs){ Node *r, *t, *e, *u; if (exprop(lhs) == Otup) { r = destructure(s, lhs, rhs); } else if (tybase(exprtype(lhs))->type != Tyvoid) { t = lval(s, lhs); u = rval(s, rhs); e = asn(t, u); append(s, e); r = t; } else { r = rval(s, rhs); } return r;} /* * If protect is not null, returns a node with the * unmodified value. */static voiddraininc(Flattenctx *fc){ size_t i; for (i = 0; i < fc->nqueue; i++) append(fc, fc->incqueue[i]); lfree(&fc->incqueue, &fc->nqueue);} /* returns 1 when the exit jump needs to be emitted */static intexitscope(Flattenctx *s, Stab *stop, Srcloc loc, Exit x){ Node *exit; Stab *st; for (st = s->curst;; st = st->super) { exit = st->exit[x]; if (st->ndisposed[x] < st->nautotmp) { st->exit[x] = genlbl(loc); flatten(s, st->exit[x]); dispose(s, st, st->ndisposed[x]); st->ndisposed[x] = st->nautotmp; } if (exit) { jmp(s, exit); return 0; } if ((!stop && st->isfunc) || st == stop) { return 1;Lines 1–500 of 1157. Load more
#include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <inttypes.h> #include <ctype.h> #include <string.h> #include <assert.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "util.h" #include "parse.h" #include "mi.h" #include "../config.h" typedef struct Flattenctx Flattenctx; typedef struct Loop Loop; struct Loop { Node *lcnt; Node *lbrk; Stab *body; }; /* takes a list of nodes, and reduces it (and it's subnodes) to a list * following these constraints: * - All nodes are expression node * - Nodes with side effects are root node * - All nodes operate on machine-primitive types and tuple */ struct Flattenctx { int isglobl; Node **stmts; size_t nstmts; /* return handling */ Node *tret; /* pre/postinc handling */ Node **incqueue; size_t nqueue; /* break/continue handling */ Loop loop; unsigned inloop; Stab *curst; /* location handling */ Htab *globls; size_t stksz; }; static Node *flatten(Flattenctx *s, Node *n); static Node *rval(Flattenctx *s, Node *n); static Node *lval(Flattenctx *s, Node *n); static Node *assign(Flattenctx *s, Node *lhs, Node *rhs); static void draininc(Flattenctx *c); static void append(Flattenctx *s, Node *n) { if (debugopt['F']) dumpn(n, stdout); lappend(&s->stmts, &s->nstmts, n); } static void cjmp(Flattenctx *s, Node *cond, Node *iftrue, Node *iffalse) { Node *jmp; jmp = mkexpr(cond->loc, Ocjmp, cond, iftrue, iffalse, NULL); jmp->expr.type = mktype(cond->loc, Tyvoid); append(s, jmp); } static void jmp(Flattenctx *s, Node *lbl) { Node *n; n = mkexpr(lbl->loc, Ojmp, lbl, NULL); n->expr.type = mktype(n->loc, Tyvoid); append(s, n); } static Node * asn(Node *a, Node *b) { Node *n; assert(a != NULL && b != NULL); if (tybase(exprtype(a))->type == Tyvoid) return a; n = mkexpr(a->loc, Oasn, a, b, NULL); n->expr.type = exprtype(a); return n; } static int islbl(Node *n) { Node *l; if (exprop(n) != Olit) return 0; l = n->expr.args[0]; return l->type == Nlit && l->lit.littype == Llbl; } static Node * temp(Flattenctx *flatten, Node *e) { Node *t; assert(e->type == Nexpr); t = gentemp(e->loc, e->expr.type, NULL); return t; } static Node * add(Node *a, Node *b) { Node *n; n = mkexpr(a->loc, Oadd, a, b, NULL); n->expr.type = a->expr.type; return n; } static Node * addk(Node *n, uvlong v) { Node *k; k = mkintlit(n->loc, v); k->expr.type = exprtype(n); return add(n, k); } static Node * sub(Node *a, Node *b) { Node *n; n = mkexpr(a->loc, Osub, a, b, NULL); n->expr.type = a->expr.type; return n; } static Node * subk(Node *n, uvlong v) { Node *k; k = mkintlit(n->loc, v); k->expr.type = exprtype(n); return sub(n, k); } static Node * seqlen(Flattenctx *s, Node *n, Type *ty) { Node *r; if (!ty) ty = n->expr.type; if (exprtype(n)->type == Tyarray) { r = mkexpr(n->loc, Osllen, rval(s, n), NULL); r->expr.type = ty; } else if (exprtype(n)->type == Tyslice) { r = mkexpr(n->loc, Osllen, rval(s, n), NULL); r->expr.type = ty; } else { die("invalid seq type for len"); } return r; } static Node * visit(Flattenctx *s, Node *n) { size_t i; Node *r; for (i = 0; i < n->expr.nargs; i++) n->expr.args[i] = rval(s, n->expr.args[i]); if (opispure[exprop(n)]) { r = n; } else { if (exprtype(n)->type == Tyvoid) { r = mkexpr(n->loc, Olit, mkvoid(n->loc), NULL); r->expr.type = mktype(n->loc, Tyvoid); append(s, n); } else { r = temp(s, n); append(s, asn(r, n)); } } return r; } static Node * traitfn(Srcloc loc, Trait *tr, char *fn, Type *ty) { Node *proto, *dcl, *var; char *name; size_t i; for (i = 0; i < tr->nproto; i++) { name = declname(tr->proto[i]); if (!strcmp(fn, name)) { proto = tr->proto[i]; dcl = htget(proto->decl.impls, ty); var = mkexpr(loc, Ovar, dcl->decl.name, NULL); var->expr.type = dcl->decl.type; var->expr.did = dcl->decl.did; return var; } } return NULL; } static void dispose(Flattenctx *s, Stab *st, size_t n) { Node *e, *call, *func; Trait *tr; Type *ty; size_t i; tr = traittab[Tcdisp]; /* dispose in reverse order of appearance */ for (i = st->nautotmp; i-- > n;) { e = st->autotmp[i]; ty = exprtype(e); func = traitfn(Zloc, tr, "__dispose__", ty); call = mkexpr(Zloc, Ocall, func, e, NULL); call->expr.type = mktype(Zloc, Tyvoid); flatten(s, call); } } static void flattencond(Flattenctx *s, Node *n, Node *ltrue, Node *lfalse) { Node **args; Node *v, *lnext; args = n->expr.args; switch (exprop(n)) { case Oland: lnext = genlbl(n->loc); flattencond(s, args[0], lnext, lfalse); append(s, lnext); flattencond(s, args[1], ltrue, lfalse); break; case Olor: lnext = genlbl(n->loc); flattencond(s, args[0], ltrue, lnext); append(s, lnext); flattencond(s, args[1], ltrue, lfalse); break; case Olnot: flattencond(s, args[0], lfalse, ltrue); break; default: v = rval(s, n); cjmp(s, v, ltrue, lfalse); break; } } static Node* flattentern(Flattenctx *s, Node *n) { Node *l1, *l2, *l3; Node *res, *t; l1 = genlbl(n->loc); l2 = genlbl(n->loc); l3 = genlbl(n->loc); res = temp(s, n); flattencond(s, n->expr.args[0], l1, l2); append(s, l1); t = assign(s, res, rval(s, n->expr.args[1])); append(s, t); jmp(s, l3); append(s, l2); t = assign(s, res, rval(s, n->expr.args[2])); append(s, t); append(s, l3); return res; } /* flatten * a || b * to * if a || b * t = true * else * t = false * ;; */ static Node * flattenlazy(Flattenctx *s, Node *n) { Node *r, *t, *u; Node *ltrue, *lfalse, *ldone; /* set up temps and labels */ r = temp(s, n); ltrue = genlbl(n->loc); lfalse = genlbl(n->loc); ldone = genlbl(n->loc); /* flatten the conditional */ flattencond(s, n, ltrue, lfalse); /* if true */ append(s, ltrue); u = mkexpr(n->loc, Olit, mkbool(n->loc, 1), NULL); u->expr.type = mktype(n->loc, Tybool); t = asn(r, u); append(s, t); jmp(s, ldone); /* if false */ append(s, lfalse); u = mkexpr(n->loc, Olit, mkbool(n->loc, 0), NULL); u->expr.type = mktype(n->loc, Tybool); t = asn(r, u); append(s, t); jmp(s, ldone); /* finish */ append(s, ldone); return r; } static Node * destructure(Flattenctx *s, Node *lhs, Node *rhs) { Node *lv, *rv, *idx; Node **args; size_t i; args = lhs->expr.args; rhs = rval(s, rhs); for (i = 0; i < lhs->expr.nargs; i++) { idx = mkintlit(rhs->loc, i); idx->expr.type = mktype(rhs->loc, Tyuint64); rv = mkexpr(rhs->loc, Otupget, rhs, idx, NULL); rv->expr.type = lhs->expr.type; if (exprop(args[i]) == Otup) { destructure(s, args[i], rv); } else { lv = lval(s, args[i]); append(s, assign(s, lv, rv)); } } return rhs; } static Node * comparecomplex(Flattenctx *s, Node *n, Op op) { Type *ty; Node *l, *r, *e; /* special case: unions with nullary constructors can be compared easily. */ ty = tybase(exprtype(n->expr.args[0])); if (ty->type == Tyunion && isenum(ty)) { l = mkexpr(n->loc, Outag, rval(s, n->expr.args[0]), NULL); r = mkexpr(n->loc, Outag, rval(s, n->expr.args[1]), NULL); l->expr.type = mktype(n->loc, Tyuint32); r->expr.type = mktype(n->loc, Tyuint32); if (op == Oeq) e = mkexpr(n->loc, Oueq, l, r, NULL); else if (op == One) e = mkexpr(n->loc, Oune, l, r, NULL); else fatal(n, "unsupported operator %s for enum union", opstr[op]); e->expr.type = mktype(n->loc, Tybool); return e; } fatal(n, "cannot compare values of type %s for equality\n", tystr(exprtype(n->expr.args[0]))); return NULL; } static Node * compare(Flattenctx *s, Node *n, int fields) { const Op cmpmap[Numops][3] = { [Oeq] = {Oeq, Oueq, Ofeq}, [One] = {One, Oune, Ofne}, [Ogt] = {Ogt, Ougt, Ofgt}, [Oge] = {Oge, Ouge, Ofge}, [Olt] = {Olt, Oult, Oflt}, [Ole] = {Ole, Oule, Ofle} }; Node *r; Type *ty; Op newop; /* void is always void */ if (tybase(exprtype(n->expr.args[0]))->type == Tyvoid) return mkboollit(n->loc, 1); newop = Obad; ty = tybase(exprtype(n->expr.args[0])); if (istysigned(ty)) newop = cmpmap[n->expr.op][0]; else if (istyunsigned(ty)) newop = cmpmap[n->expr.op][1]; else if (istyunsigned(ty)) newop = cmpmap[n->expr.op][1]; else if (ty->type == Typtr) newop = cmpmap[n->expr.op][1]; else if (istyfloat(ty)) newop = cmpmap[n->expr.op][2]; if (newop != Obad) { n->expr.op = newop; r = visit(s, n); } else if (fields) { r = comparecomplex(s, n, exprop(n)); } else { fatal(n, "unsupported comparison on type %s", tystr(ty)); } r->expr.type = mktype(n->loc, Tybool); return r; } static Node * assign(Flattenctx *s, Node *lhs, Node *rhs) { Node *r, *t, *e, *u; if (exprop(lhs) == Otup) { r = destructure(s, lhs, rhs); } else if (tybase(exprtype(lhs))->type != Tyvoid) { t = lval(s, lhs); u = rval(s, rhs); e = asn(t, u); append(s, e); r = t; } else { r = rval(s, rhs); } return r; } /* * If protect is not null, returns a node with the * unmodified value. */ static void draininc(Flattenctx *fc) { size_t i; for (i = 0; i < fc->nqueue; i++) append(fc, fc->incqueue[i]); lfree(&fc->incqueue, &fc->nqueue); } /* returns 1 when the exit jump needs to be emitted */ static int exitscope(Flattenctx *s, Stab *stop, Srcloc loc, Exit x) { Node *exit; Stab *st; for (st = s->curst;; st = st->super) { exit = st->exit[x]; if (st->ndisposed[x] < st->nautotmp) { st->exit[x] = genlbl(loc); flatten(s, st->exit[x]); dispose(s, st, st->ndisposed[x]); st->ndisposed[x] = st->nautotmp; } if (exit) { jmp(s, exit); return 0; } if ((!stop && st->isfunc) || st == stop) { return 1;