diff options
author | Quentin Carbonneaux <quentin@c9x.me> | 2017-04-08 21:31:59 -0400 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2017-04-08 22:09:55 -0400 |
commit | 61090c758d36f3919a222efe01c9794fdf7987ef (patch) | |
tree | b7329a9a5ef93cff5d4a96daf0cfed0e4c8247dd /arm64/isel.c | |
parent | 96836855a55cd28f1449b4a58d1e5301669350c0 (diff) | |
download | roux-61090c758d36f3919a222efe01c9794fdf7987ef.tar.gz |
new arm64 backend, yeepee
Diffstat (limited to 'arm64/isel.c')
-rw-r--r-- | arm64/isel.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/arm64/isel.c b/arm64/isel.c new file mode 100644 index 0000000..2d4e995 --- /dev/null +++ b/arm64/isel.c @@ -0,0 +1,266 @@ +#include "all.h" + +enum Imm { + Iother, + Iplo12, + Iphi12, + Iplo24, + Inlo12, + Inhi12, + Inlo24 +}; + +static enum Imm +imm(Con *c, int k, int64_t *pn) +{ + int64_t n; + int i; + + if (c->type != CBits) + return Iother; + n = c->bits.i; + if (k == Kw) + n = (int32_t)n; + i = Iplo12; + if (n < 0) { + i = Inlo12; + n = -n; + } + *pn = n; + if ((n & 0x000fff) == n) + return i; + if ((n & 0xfff000) == n) + return i + 1; + if ((n & 0xffffff) == n) + return i + 2; + return Iother; +} + +int +arm64_logimm(uint64_t x, int k) +{ + uint64_t n; + + if (k == Kw) + x = (x & 0xffffffff) | x << 32; + if (x & 1) + x = ~x; + if (x == 0) + return 0; + if (x == 0xaaaaaaaaaaaaaaaa) + return 1; + n = x & 0xf; + if (0x1111111111111111 * n == x) + goto Check; + n = x & 0xff; + if (0x0101010101010101 * n == x) + goto Check; + n = x & 0xffff; + if (0x0001000100010001 * n == x) + goto Check; + n = x & 0xffffffff; + if (0x0000000100000001 * n == x) + goto Check; + n = x; +Check: + return (n & (n + (n & -n))) == 0; +} + +static void +fixarg(Ref *pr, int k, int phi, Fn *fn) +{ + Ref r0, r1, r2; + int s, n; + Con *c; + + r0 = *pr; + switch (rtype(r0)) { + case RCon: + if (KBASE(k) == 0 && phi) + return; + r1 = newtmp("isel", k, fn); + if (KBASE(k) == 0) { + emit(Ocopy, k, r1, r0, R); + } else { + c = &fn->con[r0.val]; + n = gasstashfp(c->bits.i, KWIDE(k)); + vgrow(&fn->con, ++fn->ncon); + c = &fn->con[fn->ncon-1]; + *c = (Con){.type = CAddr, .local = 1}; + sprintf(c->label, "fp%d", n); + r2 = newtmp("isel", Kl, fn); + emit(Oload, k, r1, r2, R); + emit(Ocopy, Kl, r2, CON(c-fn->con), R); + } + *pr = r1; + break; + case RTmp: + s = fn->tmp[r0.val].slot; + if (s == -1) + break; + r1 = newtmp("isel", Kl, fn); + emit(Oaddr, Kl, r1, SLOT(s), R); + *pr = r1; + break; + } +} + +static int +selcmp(Ref arg[2], int k, Fn *fn) +{ + Ref r, *iarg; + Con *c; + int swap, cmp, fix; + int64_t n; + + if (KBASE(k) == 1) { + emit(Oafcmp, k, R, arg[0], arg[1]); + iarg = curi->arg; + fixarg(&iarg[0], k, 0, fn); + fixarg(&iarg[1], k, 0, fn); + return 0; + } + swap = rtype(arg[0]) == RCon; + if (swap) { + r = arg[1]; + arg[1] = arg[0]; + arg[0] = r; + } + fix = 1; + cmp = Oacmp; + r = arg[1]; + if (rtype(r) == RCon) { + c = &fn->con[r.val]; + switch (imm(c, k, &n)) { + default: + break; + case Iplo12: + case Iphi12: + fix = 0; + break; + case Inlo12: + case Inhi12: + cmp = Oacmn; + r = getcon(n, fn); + fix = 0; + break; + } + } + emit(cmp, k, R, arg[0], r); + iarg = curi->arg; + fixarg(&iarg[0], k, 0, fn); + if (fix) + fixarg(&iarg[1], k, 0, fn); + return swap; +} + +static void +sel(Ins i, Fn *fn) +{ + Ref *iarg; + Ins *i0; + int ck, cc; + + if (iscmp(i.op, &ck, &cc)) { + emit(Oflag, i.cls, i.to, R, R); + i0 = curi; + if (selcmp(i.arg, ck, fn)) + i0->op += cmpop(cc); + else + i0->op += cc; + } else if (i.op != Onop) { + emiti(i); + iarg = curi->arg; /* fixarg() can change curi */ + fixarg(&iarg[0], argcls(&i, 0), 0, fn); + fixarg(&iarg[1], argcls(&i, 1), 0, fn); + } +} + +static void +seljmp(Blk *b, Fn *fn) +{ + Ref r; + Ins *i, *ir; + int ck, cc, use; + + switch (b->jmp.type) { + default: + assert(0 && "TODO 2"); + break; + case Jret0: + case Jjmp: + return; + case Jjnz: + break; + } + r = b->jmp.arg; + use = -1; + b->jmp.arg = R; + ir = 0; + i = &b->ins[b->nins]; + while (i > b->ins) + if (req((--i)->to, r)) { + use = fn->tmp[r.val].nuse; + ir = i; + break; + } + if (ir && use == 1 + && iscmp(ir->op, &ck, &cc)) { + if (selcmp(ir->arg, ck, fn)) + cc = cmpop(cc); + b->jmp.type = Jjf + cc; + *ir = (Ins){.op = Onop}; + } + else { + selcmp((Ref[]){r, CON_Z}, Kw, fn); + b->jmp.type = Jjfine; + } +} + +void +arm64_isel(Fn *fn) +{ + Blk *b, **sb; + Ins *i; + Phi *p; + uint n, al; + int64_t sz; + + /* assign slots to fast allocs */ + b = fn->start; + /* specific to NAlign == 3 */ /* or change n=4 and sz /= 4 below */ + for (al=Oalloc, n=4; al<=Oalloc1; al++, n*=2) + for (i=b->ins; i-b->ins < b->nins; i++) + if (i->op == al) { + if (rtype(i->arg[0]) != RCon) + break; + sz = fn->con[i->arg[0].val].bits.i; + if (sz < 0 || sz >= INT_MAX-15) + err("invalid alloc size %"PRId64, sz); + sz = (sz + n-1) & -n; + sz /= 4; + fn->tmp[i->to.val].slot = fn->slot; + fn->slot += sz; + *i = (Ins){.op = Onop}; + } + + for (b=fn->start; b; b=b->link) { + curi = &insb[NIns]; + for (sb=(Blk*[3]){b->s1, b->s2, 0}; *sb; sb++) + for (p=(*sb)->phi; p; p=p->link) { + for (n=0; p->blk[n] != b; n++) + assert(n+1 < p->narg); + fixarg(&p->arg[n], p->cls, 1, fn); + } + seljmp(b, fn); + for (i=&b->ins[b->nins]; i!=b->ins;) + sel(*--i, fn); + b->nins = &insb[NIns] - curi; + idup(&b->ins, curi, b->nins); + } + + if (debug['I']) { + fprintf(stderr, "\n> After instruction selection:\n"); + printfn(fn, stderr); + } +} |