diff options
author | Quentin Carbonneaux <quentin@c9x.me> | 2017-06-06 18:06:34 -0400 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2017-06-06 18:12:17 -0400 |
commit | 64c79edda0bc29d11b7efaffa9d051f64ea431d0 (patch) | |
tree | 9175df2701786764df606e347ed5b1f347916262 | |
parent | 9908ae067af59cb6e43997552cb0e03e8f082f31 (diff) | |
download | roux-64c79edda0bc29d11b7efaffa9d051f64ea431d0.tar.gz |
fix fp subtractions on amd64
The stashing of constants in gas.c was also changed to support 16-bytes constants.
-rw-r--r-- | all.h | 2 | ||||
-rw-r--r-- | amd64/emit.c | 22 | ||||
-rw-r--r-- | amd64/isel.c | 2 | ||||
-rw-r--r-- | arm64/isel.c | 2 | ||||
-rw-r--r-- | gas.c | 78 |
5 files changed, 60 insertions, 46 deletions
diff --git a/all.h b/all.h index 1abd23c..629fea3 100644 --- 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 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; diff --git a/arm64/isel.c b/arm64/isel.c index 7ab368f..59f1579 100644 --- 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 index c1fd6df..6c3317d 100644 --- 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); |