summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lisc/isel.c60
-rw-r--r--lisc/lisc.h13
-rw-r--r--lisc/live.c12
-rw-r--r--lisc/main.c1
-rw-r--r--lisc/parse.c7
-rw-r--r--lisc/rega.c55
-rw-r--r--lisc/spill.c16
7 files changed, 125 insertions, 39 deletions
diff --git a/lisc/isel.c b/lisc/isel.c
index 6928a1a..1712333 100644
--- a/lisc/isel.c
+++ b/lisc/isel.c
@@ -442,10 +442,51 @@ classify(AInfo *a, Typ *t)
 	}
 }
 
+int rsave[NRSave] = {RDI, RSI, RDX, RCX, R8, R9, R10, R11, RAX};
+
+uint64_t calldef(Ins i, int *p)
+{
+	uint64_t b;
+	int n;
+
+	n = i.arg[1].val & 15;
+	b = 1ll << RAX;
+	if (n == 2)
+		b |= 1ll << RDX;
+	if (p)
+		*p = n;
+	return b;
+}
+
+uint64_t calluse(Ins i, int *p)
+{
+	uint64_t b;
+	int j, n;
+
+	n = (i.arg[1].val >> 4) & 15;
+	for (j = 0, b = 0; j < n; j++)
+		b |= 1ll << rsave[j];
+	if (p)
+		*p = n;
+	return b;
+}
+
+uint64_t callclb(Ins i, int *p)
+{
+	uint64_t b;
+	int j, n;
+
+	n = (i.arg[1].val >> 4) & 15;
+	for (j = n, b = 0; j < NRSave; j++)
+		b |= 1ll << rsave[j];
+	if (p)
+		*p = n;
+	return b;
+}
+
 static void
 selcall(Fn *fn, Ins *i0, Ins *i1)
 {
-	static int ireg[8] = {RDI, RSI, RDX, RCX, R8, R9, R10, R11};
 	Ins *i;
 	AInfo *ai, *a;
 	int nint, nsse, ni, ns, n;
@@ -497,20 +538,15 @@ selcall(Fn *fn, Ins *i0, Ins *i1)
 		}
 	stk += stk & 15;
 
-	if (rtype(i1->arg[1]) == RTyp)
+	if (!req(i1->arg[1], R))
 		diag("struct-returning function not implemented");
 
 	if (stk) {
 		r = newcon(-(int64_t)stk, fn);
 		emit(OSAlloc, 0, R, r, R);
 	}
-	for (n=0; n<8; n++)
-		emit(OCopy, 0, R, TMP(ireg[n]), R);
 	emit(OCopy, i1->wide, i1->to, TMP(RAX), R);
-	emit(OCall, 0, R, i->arg[0], R);
-	emit(OCopy, 1, TMP(RAX), R, R);
-	for (n=6-nint; n<8; n++)
-		emit(OCopy, 1, TMP(ireg[n]), R, R);
+	emit(OCall, 0, R, i->arg[0], CALL(1 + ((6-nint) << 4)));
 
 	for (i=i0, a=ai, ni=0; i<i1; i++, a++) {
 		if (a->inmem)
@@ -519,18 +555,18 @@ selcall(Fn *fn, Ins *i0, Ins *i1)
 			if (a->rty[0] == RSse || a->rty[1] == RSse)
 				diag("isel: unsupported float struct");
 			if (a->size > 8) {
-				r = TMP(ireg[ni+1]);
+				r = TMP(rsave[ni+1]);
 				r1 = newtmp(fn);
 				emit(OLoad, 1, r, r1, R);
 				r = newcon(8, fn);
 				emit(OAdd, 1, r1, i->arg[1], r);
-				r = TMP(ireg[ni]);
+				r = TMP(rsave[ni]);
 				ni += 2;
 			} else
-				r = TMP(ireg[ni++]);
+				r = TMP(rsave[ni++]);
 			emit(OLoad, 1, r, i->arg[1], R);
 		} else {
-			r = TMP(ireg[ni++]);
+			r = TMP(rsave[ni++]);
 			emit(OCopy, i->wide, r, i->arg[0], R);
 		}
 	}
diff --git a/lisc/lisc.h b/lisc/lisc.h
index c85c521..ff80900 100644
--- a/lisc/lisc.h
+++ b/lisc/lisc.h
@@ -43,7 +43,8 @@ enum Reg {
 
 	Tmp0, /* first non-reg temporary */
 
-	NReg = R12 - RAX + 1
+	NReg = R12 - RAX + 1,
+	NRSave = 9,
 };
 
 enum {
@@ -76,7 +77,8 @@ enum {
 	RTmp,
 	RCon,
 	RSlot,
-	RTyp,
+	RAlt,
+	RCallm = 0x1000,
 	NRef = (1<<14) - 1
 };
 
@@ -85,7 +87,8 @@ enum {
 #define CON(x)   (Ref){RCon, x}
 #define CON_Z    CON(0)          /* reserved zero constant */
 #define SLOT(x)  (Ref){RSlot, x}
-#define TYP(x)   (Ref){RTyp, x}
+#define TYP(x)   (Ref){RAlt, x}
+#define CALL(x)  (Ref){RAlt, x|RCallm}
 
 static inline int req(Ref a, Ref b)
 { return a.type == b.type && a.val == b.val; }
@@ -274,6 +277,10 @@ void ssafix(Fn *, int);
 void filllive(Fn *);
 
 /* isel.c */
+extern int rsave[NRSave];
+uint64_t calldef(Ins, int *);
+uint64_t calluse(Ins, int *);
+uint64_t callclb(Ins, int *);
 int slota(int, int, int *);
 void isel(Fn *);
 
diff --git a/lisc/live.c b/lisc/live.c
index 64fcf6a..c3aae86 100644
--- a/lisc/live.c
+++ b/lisc/live.c
@@ -21,7 +21,7 @@ filllive(Fn *f)
 	Blk *b;
 	Ins *i;
 	Phi *p;
-	int z, n, chg, nlv;
+	int z, m, n, chg, nlv;
 	uint a;
 	Bits tb;
 
@@ -50,7 +50,15 @@ Again:
 		bset(b->jmp.arg, b, &nlv);
 		b->nlive = nlv;
 		for (i=&b->ins[b->nins]; i!=b->ins;) {
-			i--;
+			if ((--i)->op == OCall) {
+				b->in.t[0] &= ~calldef(*i, &m);
+				nlv -= m;
+				if (nlv + NRSave > b->nlive)
+					b->nlive = nlv + NRSave;
+				b->in.t[0] |= calluse(*i, &m);
+				nlv += m;
+				bset(i->arg[0], b, &nlv);
+			}
 			if (!req(i->to, R)) {
 				assert(rtype(i->to) == RTmp);
 				nlv -= BGET(b->in, i->to.val);
diff --git a/lisc/main.c b/lisc/main.c
index cb2e82e..1452ff6 100644
--- a/lisc/main.c
+++ b/lisc/main.c
@@ -63,6 +63,7 @@ main(int ac, char *av[])
 		Blk *b;
 
 		fprintf(stderr, "[Testing Liveness]\n");
+		isel(fn);
 		fillrpo(fn);
 		filllive(fn);
 		for (b=fn->start; b; b=b->link) {
diff --git a/lisc/parse.c b/lisc/parse.c
index 957fae1..29f5653 100644
--- a/lisc/parse.c
+++ b/lisc/parse.c
@@ -779,8 +779,11 @@ printref(Ref r, Fn *fn, FILE *f)
 	case RSlot:
 		fprintf(f, "S%d", r.val);
 		break;
-	case RTyp:
-		fprintf(f, ":%s", typ[r.val].name);
+	case RAlt:
+		if (r.val & RCallm)
+			fprintf(f, "%x", r.val & (RCallm-1));
+		else
+			fprintf(f, ":%s", typ[r.val].name);
 		break;
 	}
 }
diff --git a/lisc/rega.c b/lisc/rega.c
index b4e4572..1263c6a 100644
--- a/lisc/rega.c
+++ b/lisc/rega.c
@@ -192,36 +192,50 @@ pmgen()
 	free(status);
 }
 
+static void
+move(int r, Ref to, RMap *m)
+{
+	int n, t, r1;
+
+	r1 = req(to, R) ? -1 : rfree(m, to.val);
+	if (BGET(m->b, r) && r1 != r) {
+		/* r is used and not by to */
+		for (n=0; m->r[n] != r; n++)
+			assert(n+1 < m->n);
+		t = m->t[n];
+		rfree(m, t);
+		BSET(m->b, r);
+		ralloc(m, t);
+		BCLR(m->b, r);
+	}
+	t = r1 == -1 ? r : to.val;
+	radd(m, t, r);
+}
+
 static Ins *
 dopm(Blk *b, Ins *i, RMap *m)
 {
 	RMap m0;
 	int n, r, r1, t, nins;
 	Ins *i1, *ib, *ip, *ir;
+	uint64_t def;
 
 	m0 = *m;
 	i1 = i+1;
 	for (;; i--) {
-		r = i->arg[0].val;
-		r1 = req(i->to, R) ? -1 : rfree(m, i->to.val);
-		if (BGET(m->b, r) && r1 != r) {
-			/* r is used and not by i->to, */
-			for (n=0; m->r[n] != r; n++)
-				assert(n+1 < m->n);
-			t = m->t[n];
-			rfree(m, t);
-			BSET(m->b, r);
-			ralloc(m, t);
-			BCLR(m->b, r);
-		}
-		t = r1 == -1 ? r : i->to.val;
-		radd(m, t, r);
+		move(i->arg[0].val, i->to, m);
 		if (i == b->ins
 		|| (i-1)->op != OCopy
 		|| !isreg((i-1)->arg[0]))
 			break;
 	}
 	assert(m0.n <= m->n);
+	if (i > b->ins && (i-1)->op == OCall) {
+		def = calldef(*i, 0);
+		for (r=0; r<NRSave; r++)
+			if (!((1ll << rsave[r]) & def))
+				move(rsave[r], R, m);
+	}
 	for (npm=0, n=0; n<m->n; n++)
 		if ((t = m->t[n]) >= Tmp0) {
 			r1 = m->r[n];
@@ -266,6 +280,7 @@ rega(Fn *fn)
 	Phi *p;
 	uint a;
 	Ref src, dst;
+	uint64_t rs;
 
 	tmp = fn->tmp;
 	end = alloc(fn->nblk * sizeof end[0]);
@@ -303,8 +318,16 @@ rega(Fn *fn)
 		if (rtype(b->jmp.arg) == RTmp)
 			b->jmp.arg = ralloc(&cur, b->jmp.arg.val);
 		for (i=&b->ins[b->nins]; i!=b->ins;) {
-			i--;
-			if (i->op == OCopy && isreg(i->arg[0])) {
+			switch ((--i)->op) {
+			case OCall:
+				rs = calldef(*i, 0) | callclb(*i, 0);
+				for (r=0; r<NReg; r++)
+					if ((1ll << r) & rs)
+						rfree(&cur, r);
+				continue;
+			case OCopy:
+				if (!isreg(i->arg[0]))
+					break;
 				i = dopm(b, i, &cur);
 				continue;
 			}
diff --git a/lisc/spill.c b/lisc/spill.c
index 2625ceb..7b2476e 100644
--- a/lisc/spill.c
+++ b/lisc/spill.c
@@ -277,6 +277,7 @@ inregs(Blk *b, Blk *s) /* todo, move to live.c */
 static Ins *
 dopm(Blk *b, Ins *i, Bits *v)
 {
+	int j;
 	Ins *i1;
 
 	/* consecutive moves from
@@ -293,7 +294,14 @@ dopm(Blk *b, Ins *i, Bits *v)
 		|| !isreg((i-1)->arg[0]))
 			break;
 	}
-	limit(v, NReg, 0);
+	if (i > b->ins && (i-1)->op == OCall) {
+		calldef(*--i, &j);
+		limit(v, NReg - NRSave + j, 0);
+		v->t[0] &= ~calldef(*i, 0);
+		v->t[0] |= calluse(*i, 0);
+		setloc(&i->arg[0], v, &(Bits){{0}});
+	} else
+		limit(v, NReg, 0);
 	do
 		emit(*--i1);
 	while (i1 != i);
@@ -388,21 +396,21 @@ spill(Fn *fn)
 		for (i=&b->ins[b->nins]; i!=b->ins;) {
 			assert(bcnt(&v) <= NReg);
 			i--;
-			s = 0;
 			if (i->op == OCopy && isreg(i->arg[0])) {
 				i = dopm(b, i, &v);
 				continue;
 			}
+			s = 0;
+			w = (Bits){{0}};
 			if (!req(i->to, R)) {
 				assert(rtype(i->to) == RTmp);
 				t = i->to.val;
 				if (BGET(v, t))
 					BCLR(v, t);
 				else
-					limit(&v, NReg-1, &w);
+					limit(&v, NReg-1, 0);
 				s = tmp[t].spill;
 			}
-			w = (Bits){{0}};
 			j = opdesc[i->op].nmem;
 			if (!j && rtype(i->arg[0]) == RTmp)
 				BSET(w, i->arg[0].val);