qbe

Internal scc patchset buffer for QBE
Log | Files | Refs | README | LICENSE

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:
Mamd64/emit.c | 29++++++++++++++++++-----------
Mamd64/isel.c | 1+
Marm64/emit.c | 2++
Mdoc/il.txt | 1+
Mfold.c | 3+++
Mops.h | 1+
Mparse.c | 2+-
Mtools/lexh.c | 2+-
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",