summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--fold.c15
-rw-r--r--isel.c91
2 files changed, 55 insertions, 51 deletions
diff --git a/fold.c b/fold.c
index 0cbd6fa..6129421 100644
--- a/fold.c
+++ b/fold.c
@@ -323,7 +323,7 @@ fold(Fn *fn)
 
 /* boring folding code */
 
-static void
+static int
 foldint(Con *res, int op, int w, Con *cl, Con *cr)
 {
 	union {
@@ -357,8 +357,11 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
 		else if (cr->type == CAddr)
 			err("undefined substraction (num - addr)");
 	}
-	else if (cl->type == CAddr || cr->type == CAddr)
+	else if (cl->type == CAddr || cr->type == CAddr) {
+		if (Ocmpl <= op && op <= Ocmpl1)
+			return 1;
 		err("invalid address operand for '%s'", opdesc[op].name);
+	}
 	switch (op) {
 	case Oadd:  x = l.u + r.u; break;
 	case Osub:  x = l.u - r.u; break;
@@ -440,6 +443,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
 	res->bits.i = x;
 	if (lab)
 		strcpy(res->label, lab);
+	return 0;
 }
 
 static void
@@ -492,9 +496,10 @@ opfold(int op, int cls, Con *cl, Con *cr, Fn *fn)
 	if ((op == Odiv || op == Oudiv
 	|| op == Orem || op == Ourem) && czero(cr, KWIDE(cls)))
 		err("null divisor in '%s'", opdesc[op].name);
-	if (cls == Kw || cls == Kl)
-		foldint(&c, op, cls == Kl, cl, cr);
-	else
+	if (cls == Kw || cls == Kl) {
+		if (foldint(&c, op, cls == Kl, cl, cr))
+			return Bot;
+	} else
 		foldflt(&c, op, cls == Kd, cl, cr);
 	if (c.type == CBits)
 		nc = getcon(c.bits.i, fn).val;
diff --git a/isel.c b/isel.c
index 8b4b823..75d712a 100644
--- a/isel.c
+++ b/isel.c
@@ -47,30 +47,24 @@ fcmptoi(int fc)
 static int
 iscmp(int op, int *pk, int *pc)
 {
-	int k, c;
-
 	if (Ocmpw <= op && op <= Ocmpw1) {
-		c = op - Ocmpw;
-		k = Kw;
+		*pc = op - Ocmpw;
+		*pk = Kw;
 	}
 	else if (Ocmpl <= op && op <= Ocmpl1) {
-		c = op - Ocmpl;
-		k = Kl;
+		*pc = op - Ocmpl;
+		*pk = Kl;
 	}
 	else if (Ocmps <= op && op <= Ocmps1) {
-		c = fcmptoi(op - Ocmps);
-		k = Ks;
+		*pc = fcmptoi(op - Ocmps);
+		*pk = Ks;
 	}
 	else if (Ocmpd <= op && op <= Ocmpd1) {
-		c = fcmptoi(op - Ocmpd);
-		k = Kd;
+		*pc = fcmptoi(op - Ocmpd);
+		*pk = Kd;
 	}
 	else
 		return 0;
-	if (pk)
-		*pk = k;
-	if (pc)
-		*pc = c;
 	return 1;
 }
 
@@ -197,21 +191,28 @@ seladdr(Ref *r, ANum *an, Fn *fn)
 	}
 }
 
-static void
+static int
 selcmp(Ref arg[2], int k, Fn *fn)
 {
+	int swap;
 	Ref r, *iarg;
 
-	if (rtype(arg[0]) == RCon) {
+	swap = rtype(arg[0]) == RCon;
+	if (swap) {
 		r = arg[1];
 		arg[1] = arg[0];
 		arg[0] = r;
 	}
-	assert(rtype(arg[0]) != RCon);
 	emit(Oxcmp, k, R, arg[1], arg[0]);
-	iarg = curi->arg; /* fixarg() can change curi */
+	iarg = curi->arg;
+	if (rtype(arg[0]) == RCon) {
+		assert(k == Kl);
+		iarg[1] = newtmp("isel", k, fn);
+		emit(Ocopy, k, iarg[1], arg[0], R);
+	}
 	fixarg(&iarg[0], k, 0, fn);
 	fixarg(&iarg[1], k, 0, fn);
+	return swap;
 }
 
 static void
@@ -220,7 +221,7 @@ sel(Ins i, ANum *an, Fn *fn)
 	Ref r0, r1, *iarg;
 	int x, k, kc;
 	int64_t sz;
-	Ins *i0;
+	Ins *i0, *i1;
 
 	if (rtype(i.to) == RTmp)
 	if (!isreg(i.to) && !isreg(i.arg[0]) && !isreg(i.arg[1]))
@@ -349,10 +350,10 @@ Emit:
 		if (isload(i.op))
 			goto case_Oload;
 		if (iscmp(i.op, &kc, &x)) {
-			if (rtype(i.arg[0]) == RCon)
-				x = icmpop(x);
 			emit(Oxset+x, k, i.to, R, R);
-			selcmp(i.arg, kc, fn);
+			i1 = curi;
+			if (selcmp(i.arg, kc, fn))
+				i1->op = Oxset + icmpop(x);
 			break;
 		}
 		die("unknown instruction %s", opdesc[i.op].name);
@@ -400,30 +401,31 @@ seljmp(Blk *b, Fn *fn)
 		return;
 	}
 	fi = flagi(b->ins, &b->ins[b->nins]);
-	if (fi && req(fi->to, r)) {
-		if (iscmp(fi->op, &k, &c)) {
-			if (rtype(fi->arg[0]) == RCon)
+	if (!fi || !req(fi->to, r)) {
+		selcmp((Ref[2]){r, CON_Z}, Kw, fn); /* todo, long jnz */
+		b->jmp.type = Jxjc + ICne;
+	}
+	else if (iscmp(fi->op, &k, &c)) {
+		if (t->nuse == 1) {
+			if (selcmp(fi->arg, k, fn))
 				c = icmpop(c);
-			b->jmp.type = Jxjc + c;
-			if (t->nuse == 1) {
-				selcmp(fi->arg, k, fn);
-				*fi = (Ins){.op = Onop};
-			}
-			return;
+			*fi = (Ins){.op = Onop};
 		}
-		if (fi->op == Oand && t->nuse == 1
-		&& (rtype(fi->arg[0]) == RTmp ||
-		    rtype(fi->arg[1]) == RTmp)) {
-			fi->op = Oxtest;
-			fi->to = R;
-			b->jmp.type = Jxjc + ICne;
-			if (rtype(fi->arg[1]) == RCon) {
-				r = fi->arg[1];
-				fi->arg[1] = fi->arg[0];
-				fi->arg[0] = r;
-			}
-			return;
+		b->jmp.type = Jxjc + c;
+	}
+	else if (fi->op == Oand && t->nuse == 1
+	     && (rtype(fi->arg[0]) == RTmp ||
+	         rtype(fi->arg[1]) == RTmp)) {
+		fi->op = Oxtest;
+		fi->to = R;
+		b->jmp.type = Jxjc + ICne;
+		if (rtype(fi->arg[1]) == RCon) {
+			r = fi->arg[1];
+			fi->arg[1] = fi->arg[0];
+			fi->arg[0] = r;
 		}
+	}
+	else {
 		/* since flags are not tracked in liveness,
 		 * the result of the flag-setting instruction
 		 * has to be marked as live
@@ -431,10 +433,7 @@ seljmp(Blk *b, Fn *fn)
 		if (t->nuse == 1)
 			emit(Ocopy, Kw, R, r, R);
 		b->jmp.type = Jxjc + ICne;
-		return;
 	}
-	selcmp((Ref[2]){r, CON_Z}, Kw, fn); /* todo, add long branch if non-zero */
-	b->jmp.type = Jxjc + ICne;
 }
 
 static int