Quellcode durchsuchen

Add a negation instruction

Necessary for floating-point negation, because
`%result = sub 0, %operand` doesn't give the correct sign for 0/-0.
Eyal Sawady vor 3 Jahren
Ursprung
Commit
e91d121581
8 geänderte Dateien mit 28 neuen und 13 gelöschten Zeilen
  1. 18 11
      amd64/emit.c
  2. 1 0
      amd64/isel.c
  3. 2 0
      arm64/emit.c
  4. 1 0
      doc/il.txt
  5. 3 0
      fold.c
  6. 1 0
      ops.h
  7. 1 1
      parse.c
  8. 1 1
      tools/lexh.c

+ 18 - 11
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 */

+ 1 - 0
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:

+ 2 - 0
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" },

+ 1 - 0
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)`

+ 3 - 0
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;

+ 1 - 0
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)

+ 1 - 1
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,
 };
 

+ 1 - 1
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",