summary refs log tree commit diff
path: root/lisc
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-08-24 12:39:55 -0400
committerQuentin Carbonneaux <quentin.carbonneaux@yale.edu>2015-09-15 23:01:32 -0400
commit28110b14395e0964d8e70cd2fa57b0d9d8fdaa43 (patch)
treeb2eb86cfb97b7873146096bb35cab3c2cee45893 /lisc
parent0ad9bf1c602f071a4ae74945d6c751457f9e6f75 (diff)
downloadroux-28110b14395e0964d8e70cd2fa57b0d9d8fdaa43.tar.gz
add a size to all operations (wip)
Diffstat (limited to 'lisc')
-rw-r--r--lisc/Makefile2
-rw-r--r--lisc/isel.c117
-rw-r--r--lisc/lisc.h37
-rw-r--r--lisc/main.c2
-rw-r--r--lisc/parse.c44
-rw-r--r--lisc/rega.c47
-rw-r--r--lisc/spill.c41
-rw-r--r--lisc/ssa.c26
8 files changed, 126 insertions, 190 deletions
diff --git a/lisc/Makefile b/lisc/Makefile
index 799ec93..8e9d86b 100644
--- a/lisc/Makefile
+++ b/lisc/Makefile
@@ -1,5 +1,5 @@
 BIN = lisc
-OBJ = parse.o ssa.o live.o isel.o spill.o rega.o emit.o main.o
+OBJ = parse.o ssa.o live.o isel.o main.o spill.o # rega.o emit.o main.o
 
 CFLAGS = -Wall -Wextra -std=c99 -g -pedantic
 
diff --git a/lisc/isel.c b/lisc/isel.c
index dd70a57..cceb128 100644
--- a/lisc/isel.c
+++ b/lisc/isel.c
@@ -20,15 +20,15 @@
 extern Ins insb[NIns], *curi; /* shared work buffer */
 
 static void
-emit(short op, Ref to, Ref arg0, Ref arg1)
+emit(int op, int w, Ref to, Ref arg0, Ref arg1)
 {
 	if (curi == insb)
 		diag("isel: too many instructions");
-	*--curi = (Ins){op, to, {arg0, arg1}};
+	*--curi = (Ins){op, w, to, {arg0, arg1}};
 }
 
 static Ref
-newtmp(int type, Fn *fn)
+newtmp(Fn *fn)
 {
 	static int n;
 	int t;
@@ -37,7 +37,7 @@ newtmp(int type, Fn *fn)
 	fn->tmp = realloc(fn->tmp, fn->ntmp * sizeof fn->tmp[0]);
 	if (!fn->tmp)
 		diag("isel: out of memory");
-	fn->tmp[t] = (Tmp){.type = type};
+	memset(&fn->tmp[t], 0, sizeof fn->tmp[t]);
 	sprintf(fn->tmp[t].name, "isel%d", ++n);
 	return TMP(t);
 }
@@ -80,17 +80,10 @@ noimm(Ref r, Fn *fn)
 	}
 }
 
-static int
-islong(Ref r, Fn *fn)
-{
-	return rtype(r) == RTmp && fn->tmp[r.val].type == TLong;
-}
-
 static void
-selcmp(Ref arg[2], Fn *fn)
+selcmp(Ref arg[2], int w, Fn *fn)
 {
 	Ref r;
-	int lng;
 
 	if (rtype(arg[0]) == RCon) {
 		r = arg[1];
@@ -98,12 +91,11 @@ selcmp(Ref arg[2], Fn *fn)
 		arg[0] = r;
 	}
 	assert(rtype(arg[0]) != RCon);
-	lng = islong(arg[0], fn) || islong(arg[1], fn);
-	emit(lng ? OXCmpl : OXCmpw, R, arg[1], arg[0]);
+	emit(OXCmp, w, R, arg[1], arg[0]);
 	r = arg[1];
-	if (lng && rtype(r) == RCon && noimm(r, fn)) {
-		curi->arg[0] = newtmp(TLong, fn);
-		emit(OCopy, curi->arg[0], r, R);
+	if (w && rtype(r) == RCon && noimm(r, fn)) {
+		curi->arg[0] = newtmp(fn);
+		emit(OCopy, w, curi->arg[0], r, R);
 	}
 }
 
@@ -118,8 +110,8 @@ rslot(Ref r, Fn *fn)
 static void
 sel(Ins i, Fn *fn)
 {
-	Ref r0, r1, ra, rd;
-	int n, ty, c, s;
+	Ref r0, r1;
+	int n, c, s, w;
 	int64_t val;
 	struct {
 		Ref r;
@@ -131,52 +123,38 @@ sel(Ins i, Fn *fn)
 		cpy[n].s = 0;
 		s = rslot(r0, fn);
 		if (s) {
-			r0 = newtmp(TLong, fn);
+			r0 = newtmp(fn);
 			i.arg[n] = r0;
 			cpy[n].r = r0;
 			cpy[n].s = s;
 		}
 	}
 
+	w = i.wide;
 	switch (i.op) {
 	case ODiv:
 	case ORem:
-		ty = fn->tmp[i.to.val].type;
-		switch (ty) {
-		default:
-			diag("isel: invalid division");
-		case TWord:
-			ra = TMP(EAX);
-			rd = TMP(EDX);
-			break;
-		case TLong:
-			ra = TMP(RAX);
-			rd = TMP(RDX);
-			break;
-		}
-		r0 = i.op == ODiv ? ra : rd;
-		r1 = i.op == ODiv ? rd : ra;
-		emit(OCopy, i.to, r0, R);
-		emit(OCopy, R, r1, R);
+		if (i.op == ODiv)
+			r0 = TMP(RAX), r1 = TMP(RDX);
+		else
+			r0 = TMP(RDX), r1 = TMP(RAX);
+		emit(OCopy, w, i.to, r0, R);
+		emit(OCopy, w, R, r1, R);
 		if (rtype(i.arg[1]) == RCon) {
 			/* immediates not allowed for
 			 * divisions in x86
 			 */
-			r0 = newtmp(ty, fn);
+			r0 = newtmp(fn);
 		} else
 			r0 = i.arg[1];
-		emit(OXDiv, R, r0, R);
-		emit(OSign, rd, ra, R);
-		emit(OCopy, ra, i.arg[0], R);
+		emit(OXDiv, w, R, r0, R);
+		emit(OSign, w, TMP(RDX), TMP(RAX), R);
+		emit(OCopy, w, TMP(RAX), i.arg[0], R);
 		if (rtype(i.arg[1]) == RCon)
-			emit(OCopy, r0, i.arg[1], R);
+			emit(OCopy, w, r0, i.arg[1], R);
 		break;
 	case ONop:
 		break;
-	case OXTestw:
-	case OXTestl:
-		n = i.op == OXTestl ? 2 : 0;
-		goto Emit;
 	case OSext:
 	case OZext:
 		n = 0;
@@ -189,10 +167,8 @@ sel(Ins i, Fn *fn)
 	case OMul:
 	case OAnd:
 	case OCopy:
-		if (fn->tmp[i.to.val].type == TLong)
-			n = 2;
-		else
-			n = 0;
+	case OXTest:
+		n = w ? 2 : 0;
 		goto Emit;
 	case OStorel:
 	case OStorew:
@@ -215,7 +191,7 @@ sel(Ins i, Fn *fn)
 		}
 		n = 0;
 Emit:
-		emit(i.op, i.to, i.arg[0], i.arg[1]);
+		emit(i.op, w, i.to, i.arg[0], i.arg[1]);
 		while (n--) {
 			/* load constants that do not fit in
 			 * a 32bit signed integer into a
@@ -223,8 +199,8 @@ Emit:
 			 */
 			r0 = i.arg[n];
 			if (rtype(r0) == RCon && noimm(r0, fn)) {
-				curi->arg[n] = newtmp(TLong, fn);
-				emit(OCopy, curi->arg[n], r0, R);
+				curi->arg[n] = newtmp(fn);
+				emit(OCopy, 1, curi->arg[n], r0, R);
 			}
 		}
 		break;
@@ -243,14 +219,14 @@ Emit:
 			val = (val + 15)  & ~INT64_C(15);
 			if (val < 0 || val > INT32_MAX)
 				diag("isel: alloc too large");
-			emit(OAlloc, i.to, newcon(val, fn), R);
+			emit(OAlloc, 0, i.to, newcon(val, fn), R);
 		} else {
 			/* r0 = (i.arg[0] + 15) & -16 */
-			r0 = newtmp(TLong, fn);
-			r1 = newtmp(TLong, fn);
-			emit(OAlloc, i.to, r0, R);
-			emit(OAnd, r0, r1, newcon(-16, fn));
-			emit(OAdd, r1, i.arg[0], newcon(15, fn));
+			r0 = newtmp(fn);
+			r1 = newtmp(fn);
+			emit(OAlloc, 0, i.to, r0, R);
+			emit(OAnd, 1, r0, r1, newcon(-16, fn));
+			emit(OAdd, 1, r1, i.arg[0], newcon(15, fn));
 		}
 		break;
 	default:
@@ -258,8 +234,8 @@ Emit:
 			c = i.op - OCmp;
 			if (rtype(i.arg[0]) == RCon)
 				c = COP(c);
-			emit(OXSet+c, i.to, R, R);
-			selcmp(i.arg, fn);
+			emit(OXSet+c, 0, i.to, R, R);
+			selcmp(i.arg, w, fn);
 			break;
 		}
 		diag("isel: non-exhaustive implementation");
@@ -267,7 +243,7 @@ Emit:
 
 	for (n=0; n<2; n++)
 		if (cpy[n].s)
-			emit(OAddr, cpy[n].r, SLOT(cpy[n].s), R);
+			emit(OAddr, 0, cpy[n].r, SLOT(cpy[n].s), R);
 }
 
 static Ins *
@@ -327,19 +303,16 @@ seljmp(Blk *b, Fn *fn)
 				c = COP(c);
 			b->jmp.type = JXJc + c;
 			if (fn->tmp[r.val].nuse == 1) {
-				assert(fn->tmp[r.val].ndef==1);
-				selcmp(fi->arg, fn);
-				*fi = (Ins){ONop, R, {R, R}};
+				assert(fn->tmp[r.val].ndef == 1);
+				selcmp(fi->arg, fi->wide, fn);
+				*fi = (Ins){.op = ONop};
 			}
 			return;
 		}
 		if (fi->op == OAnd && fn->tmp[r.val].nuse == 1
 		&& (rtype(fi->arg[0]) == RTmp ||
 		    rtype(fi->arg[1]) == RTmp)) {
-			if (fn->tmp[r.val].type == TLong)
-				fi->op = OXTestl;
-			else
-				fi->op = OXTestw;
+			fi->op = OXTest;
 			fi->to = R;
 			b->jmp.type = JXJc + Cne;
 			if (rtype(fi->arg[1]) == RCon) {
@@ -354,7 +327,7 @@ seljmp(Blk *b, Fn *fn)
 			return;
 		}
 	}
-	selcmp((Ref[2]){r, CON_Z}, fn);
+	selcmp((Ref[2]){r, CON_Z}, 0, fn); /* fixme, add long branch if non-zero */
 	b->jmp.type = JXJc + Cne;
 }
 
@@ -452,8 +425,8 @@ isel(Fn *fn)
 					assert(a+1 < p->narg);
 				s = rslot(p->arg[a], fn);
 				if (s) {
-					p->arg[a] = newtmp(TLong, fn);
-					emit(OAddr, p->arg[a], SLOT(s), R);
+					p->arg[a] = newtmp(fn);
+					emit(OAddr, 0, p->arg[a], SLOT(s), R);
 				}
 			}
 		curi = &insb[NIns];
diff --git a/lisc/lisc.h b/lisc/lisc.h
index 29e0b4c..a5312aa 100644
--- a/lisc/lisc.h
+++ b/lisc/lisc.h
@@ -40,30 +40,11 @@ enum Reg {
 	RBP, /* reserved */
 	RSP,
 
-	EAX, /* 32bits */
-	ECX,
-	EDX,
-	ESI,
-	EDI,
-	R8D,
-	R9D,
-	R10D,
-	R11D,
-
-	EBX,
-	R12D,
-	R13D,
-	R14D,
-	R15D,
-
 	Tmp0, /* first non-reg temporary */
 
 	NReg = RDX - RAX + 1
 };
 
-#define RWORD(r) (r + (EAX-RAX))
-#define RBASE(r) (r < EAX ? r : r - (EAX-RAX))
-
 enum {
 	NString = 32,
 	NPred   = 15,
@@ -105,6 +86,8 @@ static inline int req(Ref a, Ref b)
 { return a.type == b.type && a.val == b.val; }
 static inline int rtype(Ref r)
 { return req(r, R) ? -1 : r.type; }
+static inline int isreg(Ref r)
+{ return rtype(r) == RTmp && r.val < Tmp0; }
 
 enum Cmp {
 	Ceq,
@@ -153,12 +136,10 @@ enum Op {
 	OSwap,
 	OSign,
 	OXDiv,
-	OXCmpw,
-	OXCmpl,
+	OXCmp,
 	OXSet,
 	OXSet1 = OXSet + NCmp-1,
-	OXTestw,
-	OXTestl,
+	OXTest,
 	NOp
 };
 
@@ -179,7 +160,8 @@ struct OpDesc {
 };
 
 struct Ins {
-	short op;
+	uint16_t op:15;
+	uint16_t wide:1;
 	Ref to;
 	Ref arg[2];
 };
@@ -189,6 +171,7 @@ struct Phi {
 	Ref arg[NPred];
 	Blk *blk[NPred];
 	uint narg;
+	uint wide;
 	Phi *link;
 };
 
@@ -215,16 +198,19 @@ struct Blk {
 };
 
 struct Tmp {
+#if 0
 	enum {
 		TUndef,
 		TWord,
 		TLong,
 		TReg,
 	} type;
+#endif
 	char name[NString];
 	uint ndef, nuse;
 	uint cost;
-	uint spill;
+	short spill;
+	short wide;
 	int hint;
 };
 
@@ -280,7 +266,6 @@ void fillcost(Fn *);
 void spill(Fn *);
 
 /* rega.c */
-int isreg(Ref);
 void rega(Fn *);
 
 /* emit.c */
diff --git a/lisc/main.c b/lisc/main.c
index f4ed6ea..b15332b 100644
--- a/lisc/main.c
+++ b/lisc/main.c
@@ -101,6 +101,7 @@ main(int ac, char *av[])
 		printf("\n");
 		break;
 	}
+	#if 0
 	case 'a': {
 		fprintf(stderr, "[Testing Register Allocation]\n");
 		debug['R'] = 1;
@@ -136,6 +137,7 @@ main(int ac, char *av[])
 		pr = 0;
 		break;
 	}
+	#endif
 	default:
 		break;
 	}
diff --git a/lisc/parse.c b/lisc/parse.c
index 9f8e7a6..94d07ab 100644
--- a/lisc/parse.c
+++ b/lisc/parse.c
@@ -35,10 +35,8 @@ OpDesc opdesc[NOp] = {
 	[OSwap]   = { "swap",   2, 2 },
 	[OSign]   = { "sign",   1, 0 },
 	[OXDiv]   = { "xdiv",   1, 1 },
-	[OXCmpw]  = { "xcmpw",  2, 1 },
-	[OXCmpl]  = { "xcmpl",  2, 1 },
-	[OXTestw] = { "xtestw", 2, 1 },
-	[OXTestl] = { "xtestl", 2, 1 },
+	[OXCmp]   = { "xcmp",  2, 1 },
+	[OXTest]  = { "xtest", 2, 1 },
 	[OAddr]   = { "addr",   1, 0 },
 	[OAlloc]   = { "alloc4",  1, 1 },
 	[OAlloc+1] = { "alloc8",  1, 1 },
@@ -368,7 +366,7 @@ parseline(PState ps)
 	Phi *phi;
 	Ref r;
 	Blk *b;
-	int t, op, i;
+	int t, op, i, w;
 
 	do
 		t = next();
@@ -432,10 +430,10 @@ parseline(PState ps)
 	expect(TEq);
 	switch (next()) {
 	case TW:
-		tmp[r.val].type = TWord;
+		w = 0;
 		break;
 	case TL:
-		tmp[r.val].type = TLong;
+		w = 1;
 		break;
 	default:
 		err("class expected after =");
@@ -476,6 +474,7 @@ DoOp:
 		if (curi - insb >= NIns)
 			err("too many instructions in block");
 		curi->op = op;
+		curi->wide = w;
 		curi->to = r;
 		curi->arg[0] = arg[0];
 		curi->arg[1] = arg[1];
@@ -484,6 +483,7 @@ DoOp:
 	} else {
 		phi = alloc(sizeof *phi);
 		phi->to = r;
+		phi->wide = w;
 		memcpy(phi->arg, arg, i * sizeof arg[0]);
 		memcpy(phi->blk, blk, i * sizeof blk[0]);
 		phi->narg = i;
@@ -504,11 +504,8 @@ parsefn(FILE *f)
 	thead = TXXX;
 	for (i=0; i<NBlk; i++)
 		bmap[i] = 0;
-	for (i=0; i<NTmp; i++)
-		if (i < Tmp0)
-			tmp[i] = (Tmp){.type = TReg};
-		else
-			tmp[i] = (Tmp){.name = ""};
+	for (i=Tmp0; i<NTmp; i++)
+		tmp[i] = (Tmp){.name = ""};
 	ntmp = Tmp0;
 	ncon = 1; /* first constant must be 0 */
 	curi = insb;
@@ -536,23 +533,16 @@ parsefn(FILE *f)
 	return fn;
 }
 
-static char *
+static void
 printref(Ref r, Fn *fn, FILE *f)
 {
-	static char *ttoa[] = {
-		[TUndef] = "?",
-		[TWord] = "w",
-		[TLong] = "l",
-		[TReg] = "",
-	};
-
 	switch (r.type) {
 	case RTmp:
 		if (r.val < Tmp0)
 			fprintf(f, "R%d", r.val);
 		else
 			fprintf(f, "%%%s", fn->tmp[r.val].name);
-		return ttoa[fn->tmp[r.val].type];
+		break;
 	case RCon:
 		switch (fn->con[r.val].type) {
 		case CAddr:
@@ -571,7 +561,6 @@ printref(Ref r, Fn *fn, FILE *f)
 		fprintf(f, "S%d", r.val);
 		break;
 	}
-	return "";
 }
 
 void
@@ -590,14 +579,13 @@ printfn(Fn *fn, FILE *f)
 	Phi *p;
 	Ins *i;
 	uint n;
-	char *cl;
 
 	for (b=fn->start; b; b=b->link) {
 		fprintf(f, "@%s\n", b->name);
 		for (p=b->phi; p; p=p->link) {
 			fprintf(f, "\t");
-			cl = printref(p->to, fn, f);
-			fprintf(f, " =%s phi ", cl);
+			printref(p->to, fn, f);
+			fprintf(f, " =%s phi ", p->wide ? "l" : "w");
 			assert(p->narg);
 			for (n=0;; n++) {
 				fprintf(f, "@%s ", p->blk[n]->name);
@@ -612,10 +600,12 @@ printfn(Fn *fn, FILE *f)
 		for (i=b->ins; i-b->ins < b->nins; i++) {
 			fprintf(f, "\t");
 			if (!req(i->to, R)) {
-				cl = printref(i->to, fn, f);
-				fprintf(f, " =%s ", cl);
+				printref(i->to, fn, f);
+				fprintf(f, " =");
 			}
 			assert(opdesc[i->op].name);
+			if (OStorel > i->op || i->op > OStoreb)
+				fprintf(f, i->wide ? "l " : "w ");
 			fprintf(f, "%s", opdesc[i->op].name);
 			n = opdesc[i->op].arity;
 			if (n > 0) {
diff --git a/lisc/rega.c b/lisc/rega.c
index 5d2b9f5..6f70851 100644
--- a/lisc/rega.c
+++ b/lisc/rega.c
@@ -4,7 +4,6 @@
 	#define assert(x) assert_test(#x, x)
 #endif
 
-
 typedef struct RMap RMap;
 struct RMap {
 	int t[NReg];
@@ -17,6 +16,7 @@ extern Ins insb[NIns], *curi;
 static Tmp *tmp;       /* function temporaries */
 static struct {
 	Ref src, dst;
+	int wide;
 } *pm;                 /* parallel move constructed */
 static int cpm, npm;   /* capacity and size of pm */
 
@@ -32,20 +32,6 @@ rfind(RMap *m, int t)
 }
 
 static Ref
-reg(int r, int t)
-{
-	assert(r < Tmp0);
-	switch (tmp[t].type) {
-	default:
-		diag("rega: invalid temporary");
-	case TWord:
-		return TMP(RWORD(r));
-	case TLong:
-		return TMP(r);
-	}
-}
-
-static Ref
 rref(RMap *m, int t)
 {
 	int r, s;
@@ -56,7 +42,7 @@ rref(RMap *m, int t)
 		assert(s && "should have spilled");
 		return SLOT(s);
 	} else
-		return reg(r, t);
+		return TMP(r);
 }
 
 static void
@@ -80,7 +66,7 @@ ralloc(RMap *m, int t)
 	int r;
 
 	if (t < Tmp0) {
-		assert(BGET(m->b, RBASE(t)));
+		assert(BGET(m->b, t));
 		return TMP(t);
 	}
 	if (BGET(m->b, t)) {
@@ -96,7 +82,7 @@ ralloc(RMap *m, int t)
 		if (tmp[t].hint == -1)
 			tmp[t].hint = r;
 	}
-	return reg(r, t);
+	return TMP(r);
 }
 
 static int
@@ -104,8 +90,6 @@ rfree(RMap *m, int t)
 {
 	int i, r;
 
-	if (t < Tmp0)
-		t = RBASE(t);
 	if (!BGET(m->b, t))
 		return -1;
 	for (i=0; m->t[i] != t; i++)
@@ -132,7 +116,7 @@ mdump(RMap *m)
 }
 
 static void
-pmadd(Ref src, Ref dst)
+pmadd(Ref src, Ref dst, int w)
 {
 	if (npm == cpm) {
 		cpm = cpm * 2 + 16;
@@ -142,6 +126,7 @@ pmadd(Ref src, Ref dst)
 	}
 	pm[npm].src = src;
 	pm[npm].dst = dst;
+	pm[npm].wide = w;
 	npm++;
 }
 
@@ -202,12 +187,6 @@ pmgen()
 	free(status);
 }
 
-int
-isreg(Ref r)
-{
-	return rtype(r) == RTmp && r.val < Tmp0;
-}
-
 static Ins *
 dopm(Blk *b, Ins *i, RMap *m)
 {
@@ -218,7 +197,7 @@ dopm(Blk *b, Ins *i, RMap *m)
 	m0 = *m;
 	i1 = i+1;
 	for (;; i--) {
-		r = RBASE(i->arg[0].val);
+		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, */
@@ -243,12 +222,12 @@ dopm(Blk *b, Ins *i, RMap *m)
 			r1 = m->r[n];
 			r = rfind(&m0, t);
 			assert(r != -1);
-			pmadd(reg(r1, t), reg(r, t));
+			pmadd(TMP(r1), TMP(r));
 		}
 	for (ip=i; ip<i1; ip++) {
 		if (!req(ip->to, R))
 			rfree(m, ip->to.val);
-		r = RBASE(ip->arg[0].val);
+		r = ip->arg[0].val;
 		if (rfind(m, r) == -1)
 			radd(m, r, r);
 	}
@@ -295,9 +274,9 @@ rega(Fn *fn)
 			if (i->op != OCopy)
 				continue;
 			if (rtype(i->arg[0]) == RTmp && isreg(i->to))
-				tmp[i->arg[0].val].hint = RBASE(i->to.val);
+				tmp[i->arg[0].val].hint = i->to.val;
 			if (rtype(i->to) == RTmp && isreg(i->arg[0]))
-				tmp[i->to.val].hint = RBASE(i->arg[0].val);
+				tmp[i->to.val].hint = i->arg[0].val;
 		}
 
 	/* 2. assign registers backwards */
@@ -332,7 +311,7 @@ rega(Fn *fn)
 					continue;
 				}
 				if (i->to.val >= Tmp0)
-					i->to = reg(r, i->to.val);
+					i->to = TMP(r);
 			} else
 				r = 0;
 			for (x=0; x<2; x++)
@@ -378,7 +357,7 @@ rega(Fn *fn)
 					r = rfind(&beg[s->id], dst.val);
 					if (r == -1)
 						continue;
-					dst = reg(r, dst.val);
+					dst = TMP(r);
 				}
 				for (a=0; p->blk[a]!=b; a++)
 					assert(a+1 < p->narg);
diff --git a/lisc/spill.c b/lisc/spill.c
index 30077b9..2625ceb 100644
--- a/lisc/spill.c
+++ b/lisc/spill.c
@@ -1,6 +1,5 @@
 #include "lisc.h"
 
-
 static void
 loopmark(Blk *hd, Blk *b, Phi *p)
 {
@@ -170,41 +169,37 @@ slot(int t)
 		diag("spill: cannot spill register");
 	s = tmp[t].spill;
 	if (!s) {
-		if (tmp[t].type == TWord)
-			s = slota(1, 0, svec);
-		else if (tmp[t].type == TLong)
+		if (tmp[t].wide)
 			s = slota(2, 1, svec);
 		else
-			diag("spill: unknown type (1)");
+			s = slota(1, 0, svec);
 		tmp[t].spill = s;
 	}
 	return SLOT(s);
 }
 
 static void
-emit(short op, Ref to, Ref arg0, Ref arg1)
+emit(Ins i)
 {
 	if (curi == insb)
 		diag("spill: too many instructions");
-	*--curi = (Ins){op, to, {arg0, arg1}};
+	*--curi = i;
 }
 
 static void
 store(Ref r, int s)
 {
-	if (tmp[r.val].type == TLong)
-		emit(OStorel, R, r, SLOT(s));
-	else if (tmp[r.val].type == TWord)
-		emit(OStorew, R, r, SLOT(s));
+	if (tmp[r.val].wide)
+		emit((Ins){OStorel, 0, R, {r, SLOT(s)}});
 	else
-		diag("spill: unknown type (2)");
+		emit((Ins){OStorew, 0, R, {r, SLOT(s)}});
 }
 
 static int
 limit(Bits *b, int k, Bits *fst)
 {
 	static int *tarr, maxt;
-	int i, t, nt;
+	int i, t, nt, w;
 
 	nt = bcnt(b);
 	if (nt <= k)
@@ -232,8 +227,9 @@ limit(Bits *b, int k, Bits *fst)
 	for (; i<nt; i++) {
 		slot(tarr[i]);
 		if (curi) {
-			emit(OLoad, TMP(tarr[i]), slot(tarr[i]), R);
 			t = tarr[i];
+			w = tmp[t].wide;
+			emit((Ins){OLoad, w, TMP(t), {slot(t)}});
 		}
 	}
 	return t;
@@ -298,10 +294,9 @@ dopm(Blk *b, Ins *i, Bits *v)
 			break;
 	}
 	limit(v, NReg, 0);
-	do {
-		i1--;
-		emit(OCopy, i1->to, i1->arg[0], R);
-	} while (i1 != i);
+	do
+		emit(*--i1);
+	while (i1 != i);
 	return i;
 }
 
@@ -332,6 +327,14 @@ spill(Fn *fn)
 	ntmp = fn->ntmp;
 	assert(ntmp < NBit*BITS);
 
+	for (b=fn->start; b; b=b->link) {
+		for (p=b->phi; p; p=p->link)
+			tmp[p->to.val].wide = p->wide;
+		for (i=b->ins; i-b->ins < b->nins; i++)
+			if (rtype(i->to) == RTmp)
+				tmp[i->to.val].wide = i->wide;
+	}
+
 	for (n=fn->nblk-1; n>=0; n--) {
 		/* invariant: m>n => in,out of m updated */
 		b = fn->rpo[n];
@@ -409,7 +412,7 @@ spill(Fn *fn)
 			j -= setloc(&i->arg[1], &v, &w);
 			if (s)
 				store(i->to, s);
-			emit(i->op, i->to, i->arg[0], i->arg[1]);
+			emit(*i);
 		}
 
 		for (p=b->phi; p; p=p->link) {
diff --git a/lisc/ssa.c b/lisc/ssa.c
index cd9e1a7..9002443 100644
--- a/lisc/ssa.c
+++ b/lisc/ssa.c
@@ -90,22 +90,22 @@ fillrpo(Fn *f)
 }
 
 static Ref *top, *bot;
-static Ref topdef(Blk *, Fn *);
+static Ref topdef(Blk *, Fn *, int);
 
 static Ref
-botdef(Blk *b, Fn *f)
+botdef(Blk *b, Fn *f, int w)
 {
 	Ref r;
 
 	if (!req(bot[b->id], R))
 		return bot[b->id];
-	r = topdef(b, f);
+	r = topdef(b, f, w);
 	bot[b->id] = r;
 	return r;
 }
 
 static Ref
-topdef(Blk *b, Fn *f)
+topdef(Blk *b, Fn *f, int w)
 {
 	uint i;
 	int t1;
@@ -116,7 +116,7 @@ topdef(Blk *b, Fn *f)
 		return top[b->id];
 	assert(b->npred && "invalid ssa program detected");
 	if (b->npred == 1) {
-		r = botdef(b->pred[0], f);
+		r = botdef(b->pred[0], f, w);
 		top[b->id] = r;
 		return r;
 	}
@@ -128,8 +128,9 @@ topdef(Blk *b, Fn *f)
 	p->link = b->phi;
 	b->phi = p;
 	p->to = r;
+	p->wide = w;
 	for (i=0; i<b->npred; i++) {
-		p->arg[i] = botdef(b->pred[i], f);
+		p->arg[i] = botdef(b->pred[i], f, w);
 		p->blk[i] = b->pred[i];
 	}
 	p->narg = i;
@@ -143,12 +144,13 @@ void
 ssafix(Fn *f, int t)
 {
 	uint n;
-	int t0, t1;
+	int t0, t1, w;
 	Ref rt;
 	Blk *b;
 	Phi *p;
 	Ins *i;
 
+	w = 0;
 	top = alloc(f->nblk * sizeof top[0]);
 	bot = alloc(f->nblk * sizeof bot[0]);
 	rt = TMP(t);
@@ -160,6 +162,7 @@ ssafix(Fn *f, int t)
 			if (req(p->to, rt)) {
 				t1 = f->ntmp++;
 				p->to = TMP(t1);
+				w |= p->wide;
 			}
 		for (i=b->ins; i-b->ins < b->nins; i++) {
 			if (t1) {
@@ -169,6 +172,7 @@ ssafix(Fn *f, int t)
 					i->arg[1] = TMP(t1);
 			}
 			if (req(i->to, rt)) {
+				w |= i->wide;
 				t1 = f->ntmp++;
 				i->to = TMP(t1);
 			}
@@ -182,15 +186,15 @@ ssafix(Fn *f, int t)
 		for (p=b->phi; p; p=p->link)
 			for (n=0; n<p->narg; n++)
 				if (req(p->arg[n], rt))
-					p->arg[n] = botdef(p->blk[n], f);
+					p->arg[n] = botdef(p->blk[n], f, w);
 		for (i=b->ins; i-b->ins < b->nins; i++) {
 			if (req(i->arg[0], rt))
-				i->arg[0] = topdef(b, f);
+				i->arg[0] = topdef(b, f, w);
 			if (req(i->arg[1], rt))
-				i->arg[1] = topdef(b, f);
+				i->arg[1] = topdef(b, f, w);
 		}
 		if (req(b->jmp.arg, rt))
-			b->jmp.arg = topdef(b, f);
+			b->jmp.arg = topdef(b, f, w);
 	}
 	/* add new temporaries */
 	f->tmp = realloc(f->tmp, f->ntmp * sizeof f->tmp[0]);