275 lines · 5.5 KB · C
RawDownload
#include <stdlib.h>#include <stdio.h>#include <inttypes.h>#include <stdarg.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" size_t (*sizefn)(Node *n); intgetintlit(Node *n, vlong *v){	Node *l; 	if (exprop(n) != Olit)		return 0;	l = n->expr.args[0];	/* It's up to type checking to make sure this is ok */	if (l->lit.littype == Lint)		*v = l->lit.intval;	else if (l->lit.littype == Lchr)		*v = l->lit.chrval;	else		return 0;	return 1;} static intisintval(Node *n, vlong val){	vlong v; 	if (!getintlit(n, &v))		return 0;	return v == val;} static Node *val(Srcloc loc, vlong val, Type *t){	Node *l, *n; 	l = mkint(loc, val);	n = mkexpr(loc, Olit, l, NULL);	l->lit.type = t;	n->expr.type = t;	return n;} static intissmallconst(Node *dcl){	Type *t; 	if (!dcl->decl.isconst)		return 0;	if (!dcl->decl.init)		return 0;	t = tybase(exprtype(dcl->decl.init));	if (t->type <= Tyflt64)		return 1;	return 0;} static Node *foldcast(Node *n){	Type *to, *from;	Node *sub; 	sub = n->expr.args[0];	to = exprtype(n);	from = exprtype(sub); 	switch (tybase(to)->type) {	case Tybool:	case Tyint8: case Tyint16: case Tyint32: case Tyint64:	case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:	case Tyint: case Tyuint: case Tychar: case Tybyte:	case Typtr:		switch (tybase(from)->type) {		case Tybool:		case Tyint8: case Tyint16: case Tyint32: case Tyint64:		case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:		case Tyint: case Tyuint: case Tychar: case Tybyte:		case Typtr:			if (exprop(sub) == Olit || tybase(from)->type == tybase(to)->type) {				sub->expr.type = to;				return sub;			} else {				return n;			}		default:			return n;		}	default:		return n;	}	return n;} intidxcmp(const void *pa, const void *pb){	Node *a, *b;	vlong av, bv; 	a = *(Node **)pa;	b = *(Node **)pb; 	assert(getintlit(a->expr.idx, &av));	assert(getintlit(b->expr.idx, &bv)); 	/* don't trust overflow with int64 */	if (av < bv)		return -1;	else if (av == bv)		return 0;	else		return 1;} Node *fold(Node *n, int foldvar){	Node **args, *r;	Type *t;	vlong a, b;	Ucon *uc;	size_t i; 	if (!n)		return NULL;	if (n->type != Nexpr)		return n; 	r = NULL;	args = n->expr.args;	if (n->expr.idx)		n->expr.idx = fold(n->expr.idx, foldvar);	for (i = 0; i < n->expr.nargs; i++)		args[i] = fold(args[i], foldvar);	switch (exprop(n)) {	case Outag:		if (exprop(args[0]) != Oucon)			break;		uc = finducon(tybase(exprtype(args[0])), args[0]->expr.args[0]);		r = val(n->loc, uc->id, exprtype(n));		break;	case Oudata:		if (exprop(args[0]) != Oucon || args[0]->expr.nargs != 2)			break;		r = args[0]->expr.args[1];		break;	case Ovar:		if (foldvar && issmallconst(decls[n->expr.did]))			r = fold(decls[n->expr.did]->decl.init, foldvar);		break;	case Oadd:		/* x + 0 = 0 */		if (isintval(args[0], 0))			r = args[1];		if (isintval(args[1], 0))			r = args[0];		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a + b, exprtype(n));		break;	case Osub:		/* x - 0 = 0 */		if (isintval(args[1], 0))			r = args[0];		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, (uint64_t)a - b, exprtype(n));		break;	case Omul:		/* 1 * x = x */		if (isintval(args[0], 1))			r = args[1];		if (isintval(args[1], 1))			r = args[0];		/* 0 * x = 0 */		if (isintval(args[0], 0))			r = args[0];		if (isintval(args[1], 0))			r = args[1];		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a * b, exprtype(n));		break;	case Odiv:		/* x/0 = error */		if (isintval(args[1], 0))			fatal(args[1], "division by zero");		/* x/1 = x */		if (isintval(args[1], 1))			r = args[0];		/* 0/x = 0 */		if (isintval(args[1], 0))			r = args[1];		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a / b, exprtype(n));		break;	case Omod:		/* x%0 = error */		if (isintval(args[1], 0))			fatal(args[1], "division by zero");		/* x%1 = 0 */		if (isintval(args[1], 1))			r = val(n->loc, 0, exprtype(n));		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a % b, exprtype(n));		break;	case Oneg:		if (getintlit(args[0], &a))			r = val(n->loc, -a, exprtype(n));		break;	case Obsl:		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, (uint64_t)a << b, exprtype(n));		break;	case Obsr:		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a >> b, exprtype(n));		break;	case Obor:		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a | b, exprtype(n));		break;	case Oband:		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a & b, exprtype(n));		break;	case Obxor:		if (getintlit(args[0], &a) && getintlit(args[1], &b))			r = val(n->loc, a ^ b, exprtype(n));		break;	case Omemb:		t = tybase(exprtype(args[0]));		/* we only fold lengths right now */		if (t->type == Tyarray && !strcmp(namestr(args[1]), "len")) {			r = t->asize;			r->expr.type = exprtype(n);		}		break;	case Oarr:                if (n->expr.nargs > 0)                    qsort(n->expr.args, n->expr.nargs, sizeof(Node*), idxcmp);		break;	case Ocast:		r = foldcast(n);		break;	case Osize:		if (sizefn)			r = val(n->loc, sizefn(n->expr.args[0]), exprtype(n));		break;	default:		break;	} 	if (r && n->expr.idx)		r->expr.idx = n->expr.idx; 	if (r)		return r;	else		return n;}