summary refs log tree commit diff
diff options
context:
space:
mode:
authorEyal Sawady <ecs@d2evs.net>2022-01-17 22:00:48 +0000
committerQuentin Carbonneaux <quentin@c9x.me>2022-01-23 11:43:59 +0100
commite91d12158122b23271ff49de8977c92fef7f3908 (patch)
treeea5051ef69ae917f23249fe7a6adc8569deb3718
parent367c8215d99054892740ad74c690b106c45ebf60 (diff)
downloadroux-e91d12158122b23271ff49de8977c92fef7f3908.tar.gz
Add a negation instruction
Necessary for floating-point negation, because
`%result = sub 0, %operand` doesn't give the correct sign for 0/-0.
-rw-r--r--amd64/emit.c29
-rw-r--r--amd64/isel.c1
-rw-r--r--arm64/emit.c2
-rw-r--r--doc/il.txt1
-rw-r--r--fold.c3
-rw-r--r--ops.h1
-rw-r--r--parse.c2
-rw-r--r--tools/lexh.c2
8 files changed, 28 insertions, 13 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:
diff --git a/arm64/emit.c b/arm64/emit.c
index bd0ebdc..de1859b 100644
--- a/arm64/emit.c
+++ b/arm64/emit.c
@@ -43,6 +43,8 @@ static struct {
 	{ Oadd,    Ka, "fadd %=, %0, %1" },
 	{ Osub,    Ki, "sub %=, %0, %1" },
 	{ Osub,    Ka, "fsub %=, %0, %1" },
+	{ Oneg,    Ki, "neg %=, %0" },
+	{ Oneg,    Ka, "fneg %=, %0" },
 	{ Oand,    Ki, "and %=, %0, %1" },
 	{ Oor,     Ki, "orr %=, %0, %1" },
 	{ Oxor,    Ki, "eor %=, %0, %1" },
diff --git a/doc/il.txt b/doc/il.txt
index 87a4d9f..48ecb23 100644
--- a/doc/il.txt
+++ b/doc/il.txt
@@ -524,6 +524,7 @@ return type used is long, the argument must be of type double.
 ~~~~~~~~~~~~~~~~~~~~~
 
   * `add`, `sub`, `div`, `mul` -- `T(T,T)`
+  * `neg` -- `T(T)`
   * `udiv`, `rem`, `urem` -- `I(I,I)`
   * `or`, `xor`, `and` -- `I(I,I)`
   * `sar`, `shr`, `shl` -- `I(I,ww)`
diff --git a/fold.c b/fold.c
index 348e532..9923f75 100644
--- a/fold.c
+++ b/fold.c
@@ -368,6 +368,7 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
 	switch (op) {
 	case Oadd:  x = l.u + r.u; break;
 	case Osub:  x = l.u - r.u; break;
+	case Oneg:  x = -l.u; break;
 	case Odiv:  x = w ? l.s / r.s : (int32_t)l.s / (int32_t)r.s; break;
 	case Orem:  x = w ? l.s % r.s : (int32_t)l.s % (int32_t)r.s; break;
 	case Oudiv: x = w ? l.u / r.u : (uint32_t)l.u / (uint32_t)r.u; break;
@@ -464,6 +465,7 @@ foldflt(Con *res, int op, int w, Con *cl, Con *cr)
 		switch (op) {
 		case Oadd: xd = ld + rd; break;
 		case Osub: xd = ld - rd; break;
+		case Oneg: xd = -ld; break;
 		case Odiv: xd = ld / rd; break;
 		case Omul: xd = ld * rd; break;
 		case Oswtof: xd = (int32_t)cl->bits.i; break;
@@ -480,6 +482,7 @@ foldflt(Con *res, int op, int w, Con *cl, Con *cr)
 		switch (op) {
 		case Oadd: xs = ls + rs; break;
 		case Osub: xs = ls - rs; break;
+		case Oneg: xs = -ls; break;
 		case Odiv: xs = ls / rs; break;
 		case Omul: xs = ls * rs; break;
 		case Oswtof: xs = (int32_t)cl->bits.i; break;
diff --git a/ops.h b/ops.h
index 535be71..0729d46 100644
--- a/ops.h
+++ b/ops.h
@@ -15,6 +15,7 @@
 /* Arithmetic and Bits */
 O(add,     T(w,l,s,d, w,l,s,d), 1) X(2, 1, 0)
 O(sub,     T(w,l,s,d, w,l,s,d), 1) X(2, 1, 0)
+O(neg,     T(w,l,s,d, x,x,x,x), 1) X(1, 1, 0)
 O(div,     T(w,l,s,d, w,l,s,d), 1) X(0, 0, 0)
 O(rem,     T(w,l,e,e, w,l,e,e), 1) X(0, 0, 0)
 O(udiv,    T(w,l,e,e, w,l,e,e), 1) X(0, 0, 0)
diff --git a/parse.c b/parse.c
index 6e22e1f..c05c370 100644
--- a/parse.c
+++ b/parse.c
@@ -109,7 +109,7 @@ enum {
 	TMask = 16383, /* for temps hash */
 	BMask = 8191, /* for blocks hash */
 
-	K = 3233235, /* found using tools/lexh.c */
+	K = 4331239, /* found using tools/lexh.c */
 	M = 23,
 };
 
diff --git a/tools/lexh.c b/tools/lexh.c
index 2ebb022..3c5ae24 100644
--- a/tools/lexh.c
+++ b/tools/lexh.c
@@ -8,7 +8,7 @@
 
 char *tok[] = {
 
-	"add", "sub", "div", "rem", "udiv", "urem", "mul",
+	"add", "sub", "neg", "div", "rem", "udiv", "urem", "mul",
 	"and", "or", "xor", "sar", "shr", "shl", "stored",
 	"stores", "storel", "storew", "storeh", "storeb",
 	"load", "loadsw", "loaduw", "loadsh", "loaduh",