commit e91d12158122b23271ff49de8977c92fef7f3908
parent 367c8215d99054892740ad74c690b106c45ebf60
Author: Eyal Sawady <ecs@d2evs.net>
Date: Mon, 17 Jan 2022 22:00:48 +0000
Add a negation instruction
Necessary for floating-point negation, because
`%result = sub 0, %operand` doesn't give the correct sign for 0/-0.
Diffstat:
8 files changed, 28 insertions(+), 13 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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",