summaryrefslogtreecommitdiff
path: root/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'amd64')
-rw-r--r--amd64/emit.c22
-rw-r--r--amd64/isel.c2
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;