summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lisc/lisc.h1
-rw-r--r--lisc/spill.c39
2 files changed, 36 insertions, 4 deletions
diff --git a/lisc/lisc.h b/lisc/lisc.h
index c39b22d..29e0b4c 100644
--- a/lisc/lisc.h
+++ b/lisc/lisc.h
@@ -280,6 +280,7 @@ void fillcost(Fn *);
 void spill(Fn *);
 
 /* rega.c */
+int isreg(Ref);
 void rega(Fn *);
 
 /* emit.c */
diff --git a/lisc/spill.c b/lisc/spill.c
index 49a7db4..30077b9 100644
--- a/lisc/spill.c
+++ b/lisc/spill.c
@@ -278,6 +278,33 @@ inregs(Blk *b, Blk *s) /* todo, move to live.c */
 	return v;
 }
 
+static Ins *
+dopm(Blk *b, Ins *i, Bits *v)
+{
+	Ins *i1;
+
+	/* consecutive moves from
+	 * registers need to handled
+	 * as one large instruction
+	 */
+	i1 = i+1;
+	for (;; i--) {
+		if (!req(i->to, R))
+			BCLR(*v, i->to.val);
+		BSET(*v, i->arg[0].val);
+		if (i == b->ins
+		|| (i-1)->op != OCopy
+		|| !isreg((i-1)->arg[0]))
+			break;
+	}
+	limit(v, NReg, 0);
+	do {
+		i1--;
+		emit(OCopy, i1->to, i1->arg[0], R);
+	} while (i1 != i);
+	return i;
+}
+
 /* spill code insertion
  * requires spill costs, rpo, liveness
  *
@@ -359,14 +386,18 @@ spill(Fn *fn)
 			assert(bcnt(&v) <= NReg);
 			i--;
 			s = 0;
+			if (i->op == OCopy && isreg(i->arg[0])) {
+				i = dopm(b, i, &v);
+				continue;
+			}
 			if (!req(i->to, R)) {
 				assert(rtype(i->to) == RTmp);
-				j = i->to.val;
-				if (BGET(v, j))
-					BCLR(v, j);
+				t = i->to.val;
+				if (BGET(v, t))
+					BCLR(v, t);
 				else
 					limit(&v, NReg-1, &w);
-				s = tmp[j].spill;
+				s = tmp[t].spill;
 			}
 			w = (Bits){{0}};
 			j = opdesc[i->op].nmem;