shithub: scc

Download patch

ref: 8fdfb3f17b5a6bb6cfe3da6bf2f00145217912f8
parent: ec632e06b5e6b66954cf811d2dd99b511273dc31
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Sat Feb 4 16:42:12 EST 2017

[cc1] Rewrite fold.c

The big problem of simplify() was being no recursive, and it meant
that a lot of oportunities to fold were lost.

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -420,7 +420,7 @@
 #define BTYPE(np) ((np)->type->op)
 
 /* fold.c */
-extern Node *simplify(int op, Type *tp, Node *lp, Node *rp);
+extern Node *simplify(Node *np);
 extern TUINT ones(int nbytes);
 
 /* expr.c */
--- a/cc1/expr.c
+++ b/cc1/expr.c
@@ -11,7 +11,7 @@
 
 #define XCHG(lp, rp, np) (np = lp, lp = rp, rp = np)
 
-Node *expr(void);
+static Node *xexpr(void);
 
 int
 cmpnode(Node *np, TUINT val)
@@ -215,7 +215,7 @@
 	if (!(lp->type->prop & TINTEGER) || !(rp->type->prop & TINTEGER))
 		error("operator requires integer operands");
 	arithconv(&lp, &rp);
-	return simplify(op, lp->type, lp, rp);
+	return node(op, lp->type, lp, rp);
 }
 
 static Node *
@@ -224,9 +224,7 @@
 	if (!(np->type->prop & TINTEGER))
 		error("unary operator requires integer operand");
 	np = promote(np);
-	if (op == OCPL && np->op == OCPL)
-		return np->left;
-	return simplify(op, np->type, np, NULL);
+	return node(op, np->type, np, NULL);
 }
 
 static Node *
@@ -235,70 +233,9 @@
 	if (!(np->type->prop & TARITH))
 		error("unary operator requires numerical operand");
 	np = promote(np);
-	if (op == OSNEG && np->op == OSNEG)
-		return np->left;
-	if (op == OADD)
-		return np;
-	return simplify(op, np->type, np, NULL);
+	return node(op, np->type, np, NULL);
 }
 
-/* TODO: check validity of types */
-static Node *
-castcode(Node *np, Type *newtp)
-{
-	TUINT negmask, mask, u;
-	Type *oldtp = np->type;
-	Symbol aux, *sym, *osym = np->sym;
-
-	if (!(np->flags & NCONST))
-		goto noconstant;
-
-	switch (newtp->op) {
-	case PTR:
-	case INT:
-	case ENUM:
-		switch (oldtp->op) {
-		case PTR:
-		case INT:
-		case ENUM:
-			u = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
-			break;
-		case FLOAT:
-			oldtp = newtp;
-			u = osym->u.f;
-			break;
-		default:
-			goto noconstant;
-		}
-		mask = ones(newtp->size);
-		if (newtp->prop & TSIGNED) {
-			negmask = ~mask;
-			if (u & (negmask >> 1) & mask)
-				u |= negmask;
-			aux.u.i = u;
-		} else {
-			aux.u.u = u & mask;
-		}
-		break;
-	case FLOAT:
-		/* FIXME: The cast can be from another float type */
-		aux.u.f = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
-		break;
-	default:
-		goto noconstant;
-	}
-
-	sym = newsym(NS_IDEN, NULL);
-	np->type = sym->type = newtp;
-	np->sym = sym;
-	sym->u = aux.u;
-
-	return np;
-
-noconstant:
-	return node(OCAST, newtp, np, NULL);
-}
-
 Node *
 convert(Node *np, Type *newtp, char iscast)
 {
@@ -345,7 +282,7 @@
 	default:
 		return NULL;
 	}
-	return castcode(np, newtp);
+	return node(OCAST, newtp, np, NULL);
 }
 
 static Node *
@@ -375,10 +312,10 @@
 		goto incorrect;
 
 	rp = convert(promote(rp), sizettype, 0);
-	rp = simplify(OMUL, sizettype, rp, size);
+	rp = node(OMUL, sizettype, rp, size);
 	rp = convert(rp, tp, 1);
 
-	return simplify(op, tp, lp, rp);
+	return node(op, tp, lp, rp);
 
 incomplete:
 	errorp("invalid use of undefined type");
@@ -396,7 +333,7 @@
 
 	if ((ltp->prop & TARITH) && (rtp->prop & TARITH)) {
 		arithconv(&lp, &rp);
-		return simplify(op, lp->type, lp, rp);
+		return node(op, lp->type, lp, rp);
 	} else if ((ltp->op == PTR || rtp->op == PTR)) {
 		switch (op) {
 		case OADD:
@@ -432,7 +369,7 @@
 	}
 	if (err)
 		errorp("incompatible types in comparison");
-	return simplify(op, inttype, lp, rp);
+	return node(op, inttype, lp, rp);
 }
 
 static Node *
@@ -447,7 +384,7 @@
 		return pcompare(op, rp, lp);
 	} else if ((ltp->prop & TARITH) && (rtp->prop & TARITH)) {
 		arithconv(&lp, &rp);
-		return simplify(op, inttype, lp, rp);
+		return node(op, inttype, lp, rp);
 	} else {
 		errorp("incompatible types in comparison");
 		freetree(lp);
@@ -532,7 +469,7 @@
 {
 	lp = exp2cond(lp, 0);
 	rp = exp2cond(rp, 0);
-	return simplify(op, inttype, lp, rp);
+	return node(op, inttype, lp, rp);
 }
 
 static Node *
@@ -657,13 +594,7 @@
 dont_check_lvalue:
 	if (np->sym && (np->sym->flags & SREGISTER))
 		errorp("address of register variable '%s' requested", yytext);
-	if (np->op == OPTR) {
-		Node *new = np->left;
-		free(np);
-		return new;
-	}
 	new = node(op, mktype(np->type, PTR, 0, NULL), np, NULL);
-
 	if (np->sym && np->sym->flags & (SGLOBAL|SLOCAL|SPRIVATE))
 		new->flags |= NCONST;
 	return new;
@@ -674,7 +605,6 @@
 {
 	if (!(np->type->prop & TARITH) && np->type->op != PTR) {
 		errorp("invalid argument of unary '!'");
-		freetree(np);
 		return constnode(zero);
 	}
 	return exp2cond(np, 1);
@@ -864,7 +794,7 @@
 			switch (yytoken) {
 			case '[':
 				next();
-				rp = expr();
+				rp = xexpr();
 				expect(']');
 				lp = array(lp, rp);
 				break;
@@ -987,7 +917,7 @@
 		if (nested == NR_SUBEXPR)
 			error("too many expressions nested by parentheses");
 		++nested;
-		rp = expr();
+		rp = xexpr();
 		--nested;
 		expect(')');
 		rp = postfix(rp);
@@ -1155,11 +1085,11 @@
 		Node *ifyes, *ifno, *np;
 
 		cond = exp2cond(cond, 0);
-		ifyes = expr();
+		ifyes = xexpr();
 		expect(':');
 		ifno = ternary();
 		np = chkternary(ifyes, ifno);
-		cond = simplify(OASK, np->type, cond, np);
+		cond = node(OASK, np->type, cond, np);
 	}
 	return cond;
 }
@@ -1193,6 +1123,19 @@
 	}
 }
 
+static Node *
+xexpr(void)
+{
+	Node *lp, *rp;
+
+	lp = assign();
+	while (accept(',')) {
+		rp = assign();
+		lp = node(OCOMMA, rp->type, lp, rp);
+	}
+	return lp;
+}
+
 Node *
 constexpr(void)
 {
@@ -1199,25 +1142,19 @@
 	Node *np;
 
 	np = ternary();
-	if (!np || !(np->flags & NCONST) || np->type->op != INT) {
-		freetree(np);
-		return NULL;
+	if (np && np->type->op == INT) {
+		np = simplify(convert(np, inttype, 0));
+		if (np->flags & NCONST)
+			return np;
 	}
-	return convert(np, inttype, 0);
+	freetree(np);
+	return NULL;
 }
 
 Node *
 expr(void)
 {
-	Node *lp, *rp;
-
-	lp = assign();
-	while (accept(',')) {
-		rp = assign();
-		lp = node(OCOMMA, rp->type, lp, rp);
-	}
-
-	return lp;
+	return simplify(xexpr());
 }
 
 Node *
@@ -1225,8 +1162,8 @@
 {
 	Node *np;
 
-	np = exp2cond(expr(), 0);
+	np = exp2cond(xexpr(), 0);
 	if (np->flags & NCONST)
 		warn("conditional expression is constant");
-	return np;
+	return simplify(np);
 }
--- a/cc1/fold.c
+++ b/cc1/fold.c
@@ -195,7 +195,7 @@
 	}
 	res->u.i = i;
 
-	DBG("FOLD %lld %d %lld = %lld", l, op, r, i);
+	DBG("FOLD i l=%lld %d r=%lld = %lld", l, op, r, i);
 	return 1;
 }
 
@@ -231,13 +231,13 @@
 	}
 	res->u.u = u & ones(res->type->size);
 
-	DBG("FOLD %llu %d %llu = %llu", l, op, r, i);
+	DBG("FOLD ui l=%llu %d r=%llu = %llu", l, op, r, i);
 	return 1;
 
 sign:
 	res->u.i = i;
 
-	DBG("FOLD %llu %d %llu = %llu", l, op, r, i);
+	DBG("FOLD sui %llu %d %llu = %llu", l, op, r, i);
 	return 1;
 }
 
@@ -273,10 +273,14 @@
 	default:   return 0;
 	}
 	res->u.f = f;
+
+	DBG("FOLD f l=%lf %d r=%lf = %lf", l, op, r, f);
 	return 1;
 
 comparison:
 	res->u.i = i;
+
+	DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
 	return 1;
 }
 
@@ -307,6 +311,7 @@
 		break;
 	}
 	sym = newsym(NS_IDEN, NULL);
+	sym->flags |= SCONSTANT;
 	sym->type = tp;
 	sym->u = aux.u;
 	return constnode(sym);
@@ -313,13 +318,115 @@
 }
 
 static Node *
-fold(int op, Type *tp, Node *lp, Node *rp)
+foldcast(Node *np, Node *l)
 {
+	TUINT negmask, mask, u;
+	Type *newtp = np->type, *oldtp = l->type;
+	Symbol aux, *sym, *osym = l->sym;
+
+	if (!(l->flags & NCONST))
+		return np;
+
+	switch (newtp->op) {
+	case PTR:
+	case INT:
+	case ENUM:
+		switch (oldtp->op) {
+		case PTR:
+		case INT:
+		case ENUM:
+			u = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
+			break;
+		case FLOAT:
+			oldtp = newtp;
+			u = osym->u.f;
+			break;
+		default:
+			return  np;
+		}
+		mask = ones(newtp->size);
+		if (newtp->prop & TSIGNED) {
+			negmask = ~mask;
+			if (u & (negmask >> 1) & mask)
+				u |= negmask;
+			aux.u.i = u;
+		} else {
+			aux.u.u = u & mask;
+		}
+		break;
+	case FLOAT:
+		/* FIXME: The cast can be from another float type */
+		aux.u.f = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
+		break;
+	default:
+		return np;
+	}
+	DBG("FOLD cast %c->%c", oldtp->letter, newtp->letter);
+	freetree(np);
+	sym = newsym(NS_IDEN, NULL);
+	sym->flags |= SCONSTANT;
+	sym->type = newtp;
+	sym->u = aux.u;
+	return constnode(sym);
+}
+
+static Node *
+foldunary(Node *np, Node *l)
+{
+	int op = l->op;
+	Node *aux;
+
+	switch (np->op) {
+	case OADD:
+		DBG("FOLD unary delete %d", np->op);
+		np->left = NULL;
+		freetree(np);
+		return l;
+	case OCAST:
+		if (op != OCAST)
+			return foldcast(np, l);
+		DBG("FOLD unary collapse %d", np->op);
+		np->left = l->left;
+		l->left = NULL;
+		freetree(l);
+		return np;
+	case OSNEG:
+	case OCPL:
+		if (op != np->op)
+			return NULL;
+		break;
+	case OPTR:
+		if (op != OADDR)
+			return NULL;
+		break;
+	case OADDR:
+		if (op != OPTR)
+			return NULL;
+		break;
+	default:
+		return NULL;
+	}
+	DBG("FOLD unary cancel %d", np->op);
+	aux = l->left;
+	l->left = NULL;
+	freetree(np);
+	return aux;
+}
+
+static Node *
+fold(Node *np)
+{
 	Symbol *rs, *ls;
-	Node *np;
 	Type *optype;
 	int type;
+	int op = np->op;
+	Node *p, *lp = np->left, *rp = np->right;
+	Type *tp = np->type;
 
+	if (!lp && !rp)
+		return np;
+	if (!rp && (p = foldunary(np, lp)) != NULL)
+		return p;
 	if ((op == ODIV || op == OMOD) && cmpnode(rp, 0)) {
 		warn("division by 0");
 		return NULL;
@@ -331,13 +438,18 @@
 	 * (when we don't know the physical address so
 	 * we cannot fold it)
 	 */
-	if (!(lp->flags & NCONST) || !lp->sym ||
-	    rp && (!(rp->flags & NCONST) || !rp->sym)) {
-		return NULL;
+	if (!rp) {
+		rs = NULL;
+	} else {
+		if (!(rp->flags & NCONST) || !rp->sym)
+			return NULL;
+		rs = rp->sym;
 	}
+
+	if (!(lp->flags & NCONST) || !lp->sym)
+		return NULL;
 	optype = lp->type;
 	ls = lp->sym;
-	rs = (rp) ? rp->sym : NULL;
 
 	switch (type = optype->op) {
 	case ENUM:
@@ -346,31 +458,30 @@
 			type = UNSIGNED;
 	case PTR:
 	case FLOAT:
-		if ((np = foldconst(type, op, tp, ls, rs)) != NULL)
-			break;
+		if ((p = foldconst(type, op, tp, ls, rs)) == NULL)
+			return NULL;
+		freetree(np);
+		return p;
 	default:
 		return NULL;
 	}
-
-	freetree(lp);
-	freetree(rp);
-	return np;
 }
 
 static void
-commutative(int *op, Node **lp, Node **rp)
+commutative(Node *np, Node *l, Node *r)
 {
-	Node *l = *lp, *r = *rp, *aux;
+	int op = np->op;
 
-	if (r == NULL || r->flags & NCONST || !(l->flags & NCONST))
+	if (r == NULL || r->flags&NCONST || !(l->flags&NCONST))
 		return;
 
-	switch (*op) {
+	switch (op) {
 	case OLT:
 	case OGT:
 	case OGE:
 	case OLE:
-		*op = negop(*op);
+		DBG("FOLD neg commutative %d", np->op);
+		np->op = negop(op);
 	case OEQ:
 	case ONE:
 	case OADD:
@@ -378,20 +489,19 @@
 	case OBAND:
 	case OBXOR:
 	case OBOR:
-		aux = l;
-		l = r;
-		r = aux;
+		DBG("FOLD commutative %d", np->op);
+		np->left = r;
+		np->right = l;
 		break;
 	}
-	*rp = r;
-	*lp = l;
 }
 
 static Node *
-identity(int *op, Node *lp, Node *rp)
+identity(Node *np)
 {
 	int iszeror, isoner, istruer;
 	int iszerol, isonel, istruel;
+	Node *lp = np->left, *rp = np->right;
 
 	if (!rp)
 		return NULL;
@@ -403,7 +513,7 @@
 	isonel = cmpnode(lp, 1),
 	istruel = !iszerol && lp->flags & NCONST;
 
-	switch (*op) {
+	switch (np->op) {
 	case OOR:
 		/*
 		 * 1 || i => 1    (free right)
@@ -485,28 +595,28 @@
 	}
 
 free_right:
-	DBG("FOLD identity %d", op);
-	freetree(rp);
+	DBG("FOLD identity %d", np->op);
+	np->left = NULL;
+	freetree(np);
 	return lp;
 
 free_left:
-	DBG("FOLD identity %d", op);
-	freetree(lp);
+	DBG("FOLD identity %d", np->op);
+	np->right = NULL;
+	freetree(np);
 	return rp;
 
 change_to_comma:
-	DBG("FOLD identity %d", op);
-	*op = OCOMMA;
-	return NULL;
+	DBG("FOLD identity %d", np->op);
+	np->op = OCOMMA;
+	return np;
 }
 
 static Node *
-foldternary(int op, Type *tp, Node *cond, Node *body)
+foldternary(Node *np, Node *cond, Node *body)
 {
-	Node *np;
-
 	if (!(cond->flags & NCONST))
-		return node(op, tp, cond, body);
+		return np;
 	if (cmpnode(cond, 0)) {
 		np = body->right;
 		freetree(body->left);
@@ -514,86 +624,43 @@
 		np = body->left;
 		freetree(body->right);
 	}
+
 	DBG("FOLD ternary");
+	body->left = NULL;
+	body->right = NULL;
 	freetree(cond);
 	free(body);
 	return np;
 }
 
-/*
- * TODO: transform simplify in a recursivity
- * function, because we are losing optimization
- * chances
- */
-Node *
-simplify(int op, Type *tp, Node *lp, Node *rp)
-{
-	Node *np;
+/* TODO: fold OCOMMA */
 
-	if (op == OASK)
-		return foldternary(op, tp, lp, rp);
-	commutative(&op, &lp, &rp);
-	if ((np = fold(op, tp, lp, rp)) != NULL)
-		return np;
-	if ((np = identity(&op, lp, rp)) != NULL)
-		return np;
-	return node(op, tp, lp, rp);
-}
-
-/* TODO: check validity of types */
-
 Node *
-castcode(Node *np, Type *newtp)
+simplify(Node *np)
 {
-	TUINT negmask, mask, u;
-	Type *oldtp = np->type;
-	Symbol aux, *sym, *osym = np->sym;
+	Node *p, *l, *r;
+	extern int debug;
 
-	if (!(np->flags & NCONST))
-		goto noconstant;
+	if (!np)
+		return NULL;
+	if (debug)
+		prtree(np);
 
-	switch (newtp->op) {
-	case PTR:
-	case INT:
-	case ENUM:
-		switch (oldtp->op) {
-		case PTR:
-		case INT:
-		case ENUM:
-			u = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
-			break;
-		case FLOAT:
-			oldtp = newtp;
-			u = osym->u.f;
-			break;
-		default:
-			goto noconstant;
-		}
-		mask = ones(newtp->size);
-		if (newtp->prop & TSIGNED) {
-			negmask = ~mask;
-			if (u & (negmask >> 1) & mask)
-				u |= negmask;
-			aux.u.i = u;
-		} else {
-			aux.u.u = u & mask;
-		}
-		break;
-	case FLOAT:
-		/* FIXME: The cast can be from another float type */
-		aux.u.f = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
-		break;
+	l = np->left = simplify(np->left);
+	r = np->right = simplify(np->right);
+
+	switch (np->op) {
+	case OASK:
+		return foldternary(np, l, r);
+	case OCALL:
+	case OPAR:
+		return np;
 	default:
-		goto noconstant;
+		commutative(np, l, r);
+		if ((p = fold(np)) != NULL)
+			return p;
+		if ((p = identity(np)) != NULL)
+			return p;
+		return np;
 	}
-
-	sym = newsym(NS_IDEN, NULL);
-	np->type = sym->type = newtp;
-	np->sym = sym;
-	sym->u = aux.u;
-
-	return np;
-
-noconstant:
-	return node(OCAST, newtp, np, NULL);
 }
--- a/cc1/init.c
+++ b/cc1/init.c
@@ -94,7 +94,7 @@
 static Node *
 initialize(Type *tp)
 {
-	Node *np, *aux;
+	Node *np;
 	Symbol *sym;
 	Type *btp;
 	size_t len;
@@ -133,12 +133,16 @@
 		np->type = sym->type;
 
 		return np;
+	} else {
+		if (eqtype(tp, np->type, 1))
+			return np;
+		np = convert(decay(np), tp, 0);
+		if (!np) {
+			errorp("incorrect initializer");
+			goto return_zero;
+		}
 	}
-	if (eqtype(tp, np->type, 1))
-		return np;
-	if ((aux = convert(decay(np), tp, 0)) != NULL)
-		return aux;
-	errorp("incorrect initializer");
+	return simplify(np);
 
 return_zero:
 	return constnode(zero);