diff options
Diffstat (limited to 'amd64')
-rw-r--r-- | amd64/emit.c | 22 | ||||
-rw-r--r-- | amd64/isel.c | 2 |
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; |