commit 64c79edda0bc29d11b7efaffa9d051f64ea431d0
parent 9908ae067af59cb6e43997552cb0e03e8f082f31
Author: Quentin Carbonneaux <quentin@c9x.me>
Date: Tue, 6 Jun 2017 18:06:34 -0400
fix fp subtractions on amd64
The stashing of constants in gas.c was also
changed to support 16-bytes constants.
Diffstat:
5 files changed, 60 insertions(+), 46 deletions(-)
diff --git a/all.h b/all.h
@@ -517,5 +517,5 @@ void rega(Fn *);
extern char *gasloc;
extern char *gassym;
void gasemitdat(Dat *, FILE *);
-int gasstashfp(int64_t, int);
+int gasstash(void *, int);
void gasemitfin(FILE *);
diff --git 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
@@ -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;
diff --git a/arm64/isel.c b/arm64/isel.c
@@ -84,7 +84,7 @@ fixarg(Ref *pr, int k, int phi, Fn *fn)
emit(Ocopy, k, r1, r0, R);
} else {
c = &fn->con[r0.val];
- n = gasstashfp(c->bits.i, KWIDE(k));
+ n = gasstash(&c->bits, KWIDE(k) ? 8 : 4);
vgrow(&fn->con, ++fn->ncon);
c = &fn->con[fn->ncon-1];
sprintf(buf, "fp%d", n);
diff --git a/gas.c b/gas.c
@@ -54,34 +54,30 @@ gasemitdat(Dat *d, FILE *f)
}
}
-typedef struct FBits FBits;
+typedef struct Asmbits Asmbits;
-struct FBits {
- union {
- int64_t n;
- float f;
- double d;
- } bits;
- int wide;
- FBits *link;
+struct Asmbits {
+ char bits[16];
+ int size;
+ Asmbits *link;
};
-static FBits *stash;
+static Asmbits *stash;
int
-gasstashfp(int64_t n, int w)
+gasstash(void *bits, int size)
{
- FBits **pb, *b;
+ Asmbits **pb, *b;
int i;
- /* does a dumb de-dup of fp constants
- * this should be the linker's job */
+ assert(size == 4 || size == 8 || size == 16);
for (pb=&stash, i=0; (b=*pb); pb=&b->link, i++)
- if (n == b->bits.n && w == b->wide)
+ if (size <= b->size)
+ if (memcmp(bits, b->bits, size) == 0)
return i;
b = emalloc(sizeof *b);
- b->bits.n = n;
- b->wide = w;
+ memcpy(b->bits, bits, size);
+ b->size = size;
b->link = 0;
*pb = b;
return i;
@@ -90,31 +86,35 @@ gasstashfp(int64_t n, int w)
void
gasemitfin(FILE *f)
{
- FBits *b;
- int i;
+ Asmbits *b;
+ char *p;
+ int sz, i;
+ double d;
if (!stash)
return;
- fprintf(f, "/* floating point constants */\n");
- fprintf(f, ".data\n.align 8\n");
- for (b=stash, i=0; b; b=b->link, i++)
- if (b->wide)
- fprintf(f,
- "%sfp%d:\n"
- "\t.quad %"PRId64
- " /* %f */\n",
- gasloc, i, b->bits.n,
- b->bits.d
- );
- for (b=stash, i=0; b; b=b->link, i++)
- if (!b->wide)
- fprintf(f,
- "%sfp%d:\n"
- "\t.long %"PRId64
- " /* %lf */\n",
- gasloc, i, b->bits.n & 0xffffffff,
- b->bits.f
- );
+ fprintf(f, "/* floating point constants */\n.data\n");
+ for (sz=16; sz>=4; sz/=2)
+ for (b=stash, i=0; b; b=b->link, i++) {
+ if (b->size == sz) {
+ fprintf(f,
+ ".align %d\n"
+ "%sfp%d:",
+ sz, gasloc, i
+ );
+ for (p=b->bits; p<&b->bits[sz]; p+=4)
+ fprintf(f, "\n\t.int %"PRId32,
+ *(int32_t *)p);
+ if (sz <= 8) {
+ if (sz == 4)
+ d = *(float *)b->bits;
+ else
+ d = *(double *)b->bits;
+ fprintf(f, " /* %f */\n", d);
+ } else
+ fprintf(f, "\n");
+ }
+ }
while ((b=stash)) {
stash = b->link;
free(b);