1157 lines · 22.8 KB · C
RawDownload
#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.