summary refs log tree commit diff
path: root/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'amd64')
-rw-r--r--amd64/emit.c22
-rw-r--r--amd64/isel.c2
2 files changed, 19 insertions, 5 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index 4d4d3be..51833b4 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -350,6 +350,11 @@ Next:
 	goto Next;
 }
 
+static void *negmask[4] = {
+	[Ks] = (uint32_t[4]){ 0x80000000 },
+	[Kd] = (uint64_t[2]){ 0x8000000000000000 },
+};
+
 static void
 emitins(Ins i, Fn *fn, FILE *f)
 {
@@ -398,16 +403,25 @@ emitins(Ins i, Fn *fn, FILE *f)
 		goto Table;
 	case Osub:
 		/* we have to use the negation trick to handle
-		 * some 3-address substractions */
+		 * some 3-address subtractions */
 		if (req(i.to, i.arg[1])) {
-			emitf("neg%k %=", &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)
+				);
 			emitf("add%k %0, %=", &i, fn, f);
 			break;
 		}
 		goto Table;
 	case Odiv:
-		/* adjust the instruction when the conversion to
-		 * a 2-address division is impossible */
+		/* use xmm15 to adjust the instruction when the
+		 * conversion to 2-address in emitf() would fail */
 		if (req(i.to, i.arg[1])) {
 			i.arg[1] = TMP(XMM0+15);
 			emitf("mov%k %=, %1", &i, fn, f);
diff --git a/amd64/isel.c b/amd64/isel.c
index 180439b..4202610 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -80,7 +80,7 @@ fixarg(Ref *r, int k, int op, Fn *fn)
 		memset(&a, 0, sizeof a);
 		a.offset.type = CAddr;
 		a.offset.local = 1;
-		n = gasstashfp(fn->con[r0.val].bits.i, KWIDE(k));
+		n = gasstash(&fn->con[r0.val].bits, KWIDE(k) ? 8 : 4);
 		sprintf(buf, "fp%d", n);
 		a.offset.label = intern(buf);
 		fn->mem[fn->nmem-1] = a;