summary refs log tree commit diff
path: root/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'amd64')
-rw-r--r--amd64/emit.c29
-rw-r--r--amd64/isel.c1
2 files changed, 19 insertions, 11 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index a888000..4cb340d 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -365,6 +365,7 @@ emitins(Ins i, Fn *fn, FILE *f)
 	Ref r;
 	int64_t val;
 	int o, t0;
+	Ins ineg;
 
 	switch (i.op) {
 	default:
@@ -376,7 +377,7 @@ emitins(Ins i, Fn *fn, FILE *f)
 			/* this linear search should really be a binary
 			 * search */
 			if (omap[o].op == NOp)
-				die("no match for %s(%d)",
+				die("no match for %s(%c)",
 					optab[i.op].name, "wlsd"[i.cls]);
 			if (omap[o].op == i.op)
 			if (omap[o].cls == i.cls
@@ -409,20 +410,26 @@ emitins(Ins i, Fn *fn, FILE *f)
 		/* we have to use the negation trick to handle
 		 * some 3-address subtractions */
 		if (req(i.to, i.arg[1]) && !req(i.arg[0], i.to)) {
-			if (KBASE(i.cls) == 0)
-				emitf("neg%k %=", &i, fn, f);
-			else
-				fprintf(f,
-					"\txorp%c %sfp%d(%%rip), %%%s\n",
-					"xxsd"[i.cls],
-					gasloc,
-					gasstash(negmask[i.cls], 16),
-					regtoa(i.to.val, SLong)
-				);
+			ineg = (Ins){Oneg, i.cls, i.to, {i.to}};
+			emitins(ineg, fn, f);
 			emitf("add%k %0, %=", &i, fn, f);
 			break;
 		}
 		goto Table;
+	case Oneg:
+		if (!req(i.to, i.arg[0]))
+			emitf("mov%k %0, %=", &i, fn, f);
+		if (KBASE(i.cls) == 0)
+			emitf("neg%k %=", &i, fn, f);
+		else
+			fprintf(f,
+				"\txorp%c %sfp%d(%%rip), %%%s\n",
+				"xxsd"[i.cls],
+				gasloc,
+				gasstash(negmask[i.cls], 16),
+				regtoa(i.to.val, SLong)
+			);
+		break;
 	case Odiv:
 		/* use xmm15 to adjust the instruction when the
 		 * conversion to 2-address in emitf() would fail */
diff --git a/amd64/isel.c b/amd64/isel.c
index 0f4c7a5..404b714 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -290,6 +290,7 @@ sel(Ins i, ANum *an, Fn *fn)
 	case Ocopy:
 	case Oadd:
 	case Osub:
+	case Oneg:
 	case Omul:
 	case Oand:
 	case Oor: