aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir/builder.c
diff options
context:
space:
mode:
Diffstat (limited to 'ir/builder.c')
-rw-r--r--ir/builder.c307
1 files changed, 0 insertions, 307 deletions
diff --git a/ir/builder.c b/ir/builder.c
deleted file mode 100644
index 206e66d..0000000
--- a/ir/builder.c
+++ /dev/null
@@ -1,307 +0,0 @@
-#include "ir.h"
-
-/* binary arithmetic builder with peephole optimizations */
-union ref
-irbinop(struct function *fn, enum op op, enum irclass k, union ref l, union ref r)
-{
- static const union ref ONE = {.t=RICON, .i=1};
- vlong iv;
- union ref c;
-
- if (foldbinop(&c, op, k, l, r))
- return c;
-
- switch (op) {
- case Oadd:
- if (l.bits == ZEROREF.bits) return r; /* 0 + x ==> x */
- if (r.bits == ZEROREF.bits) return l; /* x + 0 ==> x */
- break;
- case Osub:
- if (r.bits == ZEROREF.bits) return l; /* x - 0 ==> x */
- if (kisint(k) && l.bits == r.bits) return ZEROREF; /* x - x ==> 0 */
- break;
- case Omul:
- if (isnumcon(l)) rswap(l, r); /* put const in rhs */
- if (kisflt(k)) break;
- if (r.bits == ZEROREF.bits) /* x * 0 ==> 0 */
- return ZEROREF;
- if (r.bits == ONE.bits) /* x * 1 ==> x */
- return l;
- if (isintcon(r) && ispo2(iv = intconval(r))) {
- /* x * 2^y ==> x << y */
- op = Oshl;
- r = mkref(RICON, ilog2(iv));
- }
- break;
- case Odiv:
- break;
- case Oudiv:
- if (kisflt(k)) break;
- if (isintcon(r) && ispo2(iv = intconval(r))) {
- /* x / 2^y ==> x >> y */
- op = Oslr;
- r = mkref(RICON, ilog2(iv));
- }
- break;
- case Orem:
- break;
- case Ourem:
- if (kisflt(k)) break;
- if (isintcon(r) && ispo2(iv = intconval(r))) {
- /* x % 2^y ==> x & 2^y-1 */
- op = Oand;
- r = mkintcon(k, iv - 1);
- }
- break;
- case Oand:
- if (isnumcon(l)) rswap(l, r); /* put const in rhs */
- if (r.bits == ZEROREF.bits) /* x & 0 ==> 0 */
- return ZEROREF;
- break;
- case Oior:
- if (isnumcon(l)) rswap(l, r); /* put const in rhs */
- if (r.bits == ZEROREF.bits) /* x | 0 ==> x */
- return l;
- case Oxor:
- if (isnumcon(l)) rswap(l, r); /* put const in rhs */
- if (r.bits == ZEROREF.bits) /* x ^ 0 ==> x */
- return l;
- case Oshl: case Osar: case Oslr:
- if (r.bits == ZEROREF.bits) /* x shift 0 ==> x */
- return l;
- break;
- case Oequ:
- if (r.bits == l.bits && kisint(k))
- return ONE;
- break;
- case Oneq:
- if (r.bits == l.bits && kisint(k))
- return ZEROREF;
- break;
- case Olth: case Ogth:
- case Olte: case Ogte:
- break;
- case Oulth:
- if (r.bits == ZEROREF.bits) /* x u< 0 ==> f */
- return ZEROREF;
- break;
- case Ougth:
- if (l.bits == ZEROREF.bits) /* 0 u> x ==> f */
- return ZEROREF;
- break;
- case Oulte:
- if (l.bits == ZEROREF.bits) /* 0 u<= x ==> t */
- return ONE;
- break;
- case Ougte:
- if (r.bits == ZEROREF.bits) /* x u>= 0 ==> t */
- return ONE;
- break;
- default:
- assert(!"binop?");
- }
- return fn ? addinstr(fn, mkinstr(op, k, l, r)) : NOREF;
-}
-
-/* implements f32/f64 -> u64 conversion */
-static union ref
-cvtfu64(struct function *fn, enum irclass from, union ref x)
-{
- struct block *t, *f, *merge;
- union ref tmp, phiarg[2];
- /* if (x < 2p63) cvtfXs(x) else (cvtfXs(x - 2p63) | (1<<63)) */
- union ref max = mkfltcon(from, 0x1.0p63);
- enum op cvt = from == KF32 ? Ocvtf32s : Ocvtf64s;
- putcondbranch(fn, irbinop(fn, Olth, from, x, max), t = newblk(fn), f = newblk(fn));
-
- useblk(fn, t);
- phiarg[0] = irunop(fn, cvt, KI64, x);
- putbranch(fn, merge = newblk(fn));
-
- useblk(fn, f);
- tmp = irbinop(fn, Osub, from, x, max);
- tmp = irunop(fn, cvt, KI64, tmp);
- phiarg[1] = irbinop(fn, Oior, KI64, tmp, mkintcon(KI64, 1ull<<63));
- putbranch(fn, merge);
-
- useblk(fn, merge);
- return addphi(fn, KI64, phiarg);
-}
-
-/* implements u64 -> f32/f64 conversion */
-static union ref
-cvtu64f(struct function *fn, enum irclass to, union ref x)
-{
- struct block *t, *f, *merge;
- union ref t1, t2, phiarg[2];
-
- /* if ((s64)x >= 0) cvts64f(x) else cvts64f((x>>1)|(x&1))*2 */
-
- putcondbranch(fn, irbinop(fn, Ogte, KI64, x, ZEROREF), t = newblk(fn), f = newblk(fn));
-
- useblk(fn, t);
- phiarg[0] = irunop(fn, Ocvts64f, to, x);
- putbranch(fn, merge = newblk(fn));
-
- useblk(fn, f);
- t1 = irbinop(fn, Oslr, KI64, x, mkref(RICON, 1));
- t2 = irbinop(fn, Oand, KI64, x, mkref(RICON, 1));
- t1 = irbinop(fn, Oior, KI64, t1, t2);
- t1 = irunop(fn, Ocvts64f, to, t1);
- phiarg[1] = irbinop(fn, Oadd, to, t1, t1);
- putbranch(fn, merge);
-
- useblk(fn, merge);
- return addphi(fn, to, phiarg);
-}
-
-union ref
-irunop(struct function *fn, enum op op, enum irclass k, union ref a)
-{
- union ref c;
- struct instr *ins = NULL;
- if (foldunop(&c, op, k, a))
- return c;
- if (a.t == RTMP) ins = &instrtab[a.i];
- switch (op) {
- case Oneg:
- if (ins && ins->op == Oneg) /* -(-x) ==> x */
- return ins->l;
- break;
- case Onot:
- if (ins && ins->op == Onot) /* ~(~x) ==> x */
- return ins->l;
- break;
- case Ocvtf32s: case Ocvtf32f64: case Ocvtf64s:
- case Ocvtf64f32: case Ocvts32f: case Ocvtu32f:
- case Ocvts64f:
- break;
- case Ocvtf32u: case Ocvtf64u:
- if (target.arch == ISx86_64 && k == KI64 && fn) {
- /* this should probably be handled in a separate "arithmetic-lowering" pass, earlier than isel
- */
- return cvtfu64(fn, op == Ocvtf32u ? KF32 : KF64, a);
- }
- break;
- case Ocvtu64f:
- /* XXX see above */
- if (target.arch == ISx86_64 && fn)
- return cvtu64f(fn, k, a);
- case Oexts8: case Oextu8: case Oexts16: case Oextu16:
- case Oexts32: case Oextu32:
- case Ocopy:
- break;
- case Obswap16: case Obswap32: case Obswap64:
- break;
- default: assert(!"unop?");
- }
- return fn ? addinstr(fn, mkinstr(op, k, a)) : NOREF;
-}
-
-int allocinstr(void);
-
-union ref
-addinstr(struct function *fn, struct instr ins)
-{
- int new = allocinstr();
- assert(fn->curblk != NULL);
- instrtab[new] = ins;
- adduse(fn->curblk, new, ins.l);
- adduse(fn->curblk, new, ins.r);
- vpush(&fn->curblk->ins, new);
- return mkref(RTMP, new);
-}
-
-void
-useblk(struct function *fn, struct block *blk)
-{
- extern int nerror;
- if (fn->curblk && nerror == 0) assert(fn->curblk->jmp.t && "never finished block");
- if (blk) assert(!blk->jmp.t && "reusing built block");
- if (blk && !blk->lprev) { /* initialize */
- blk->lnext = fn->entry;
- blk->lprev = fn->entry->lprev;
- blk->lprev->lnext = blk;
- blk->id = fn->nblk++;
- fn->entry->lprev = blk;
- }
- fn->curblk = blk;
-}
-
-union ref
-addphi(struct function *fn, enum irclass cls, union ref *r)
-{
- assert(fn->curblk);
- if (fn->curblk->npred == 0) return UNDREF;
- if (fn->curblk->npred == 1) /* 1-argument phi is identity */
- return *r;
-
- union ref *refs = NULL;
- xbgrow(&refs, fn->curblk->npred);
- memcpy(refs, r, fn->curblk->npred * sizeof *r);
- vpush(&phitab, refs);
- /*assert(fn->curblk->ins.n == 0);*/
- int new = allocinstr();
- instrtab[new] = mkinstr(Ophi, cls, .l.i = phitab.n-1);
- for (int i = 0; i < fn->curblk->npred; ++i) {
- adduse(fn->curblk, new, r[i]);
- }
- vpush(&fn->curblk->phi, new);
- return mkref(RTMP, new);
-}
-
-#define putjump(fn, j, arg0, arg1, T, F) \
- fn->curblk->jmp.t = j; \
- fn->curblk->jmp.arg[0] = arg0; \
- fn->curblk->jmp.arg[1] = arg1; \
- fn->curblk->s1 = T; \
- fn->curblk->s2 = F; \
- fn->curblk = NULL;
-
-void
-putbranch(struct function *fn, struct block *blk)
-{
- assert(fn->curblk && blk);
- addpred(blk, fn->curblk);
- putjump(fn, Jb, NOREF, NOREF, blk, NULL);
-}
-
-void
-putcondbranch(struct function *fn, union ref arg, struct block *t, struct block *f)
-{
- assert(fn->curblk && t && f);
- if (iscon(arg)) {
- bool truthy;
- if (isintcon(arg)) truthy = intconval(arg) != 0;
- else if (isfltcon(arg)) truthy = fltconval(arg) != 0.0;
- else if (isaddrcon(arg,0)) truthy = 1; /* XXX ok to assume symbols have non null addresses? */
- else goto Cond;
- putbranch(fn, truthy ? t : f);
- } else {
- Cond:
- adduse(fn->curblk, USERJUMP, arg);
- addpred(t, fn->curblk);
- addpred(f, fn->curblk);
- putjump(fn, Jb, arg, NOREF, t, f);
- }
-}
-
-void
-putreturn(struct function *fn, union ref r0, union ref r1)
-{
- assert(fn->curblk);
- adduse(fn->curblk, USERJUMP, r0);
- adduse(fn->curblk, USERJUMP, r1);
- putjump(fn, Jret, r0, r1, NULL, NULL);
-}
-
-void
-puttrap(struct function *fn)
-{
- assert(fn->curblk);
- putjump(fn, Jtrap, NOREF, NOREF, NULL, NULL);
-}
-
-#undef putjump
-
-/* vim:set ts=3 sw=3 expandtab: */