aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir/ir.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-03-17 13:22:00 +0100
committerlemon <lsof@mailbox.org>2026-03-17 13:22:00 +0100
commita8d6f8bf30c07edb775e56889f568ca20240bedf (patch)
treeb5a452b2675b2400f15013617291fe6061180bbf /ir/ir.c
parent24f14b7ad1af08d872971d72ce089a529911f657 (diff)
REFACTOR: move sources to src/
Diffstat (limited to 'ir/ir.c')
-rw-r--r--ir/ir.c689
1 files changed, 0 insertions, 689 deletions
diff --git a/ir/ir.c b/ir/ir.c
deleted file mode 100644
index b612143..0000000
--- a/ir/ir.c
+++ /dev/null
@@ -1,689 +0,0 @@
-#include "ir.h"
-#include "../obj/obj.h"
-
-uchar type2cls[NTYPETAG];
-uchar cls2siz[] = { [KI32] = 4, [KI64] = 8, [KF32] = 4, [KF64] = 8 };
-uchar cls2load[] = {
- [KI32] = Oloadu32, [KI64] = Oloadi64,
- [KF32] = Oloadf32, [KF64] = Oloadf64, [KPTR] = -1
-}, cls2store[] = {
- [KI32] = Ostorei32, [KI64] = Ostorei64,
- [KF32] = Ostoref32, [KF64] = Ostoref64, [KPTR] = -1
-};
-const uchar siz2intcls[] = { [1] = KI32, [2] = KI32, [4] = KI32, [8] = KI64 };
-
-const char *opnames[] = {
- "?\??",
-#define _(o,...) #o,
-#include "op.def"
-#undef _
-};
-
-const uchar opnarg[] = {
- 0,
-#define _(o,n) n,
-#include "op.def"
-#undef _
-};
-
-struct instr instrtab[MAXINSTR];
-struct use *instruse[MAXINSTR];
-int ninstr;
-static int instrfreelist;
-static struct use *usefreelist;
-static struct arena **usearena;
-struct calltab calltab;
-struct phitab phitab;
-struct dattab dattab;
-struct contab contab;
-struct addrtab addrtab;
-static ushort *addrht;
-static int naddrht;
-int visitmark;
-
-void
-irinit(struct function *fn)
-{
- static struct call callsbuf[64];
- static union ref *phisbuf[64];
- static struct irdat datsbuf[64];
- static struct xcon consbuf[64];
- static struct addr addrsbuf[64];
-
- assert(fn->arena && !fn->passarena);
-
- ninstr = 0;
- instrfreelist = -1;
- usefreelist = NULL;
- usearena = fn->arena;
- vinit(&calltab, callsbuf, countof(callsbuf));
- for (int i = 0; i < phitab.n; ++i) xbfree(phitab.p[i]);
- vinit(&phitab, phisbuf, countof(phisbuf));
- vinit(&contab, consbuf, countof(consbuf));
- if (!dattab.p) vinit(&dattab, datsbuf, countof(datsbuf));
- naddrht = 128;
- if (!addrht) xbgrowz(&addrht, naddrht);
- else if (addrtab.n) memset(addrht, 0, xbcap(addrht) * sizeof *addrht);
- vinit(&addrtab, addrsbuf, countof(addrsbuf));
-
- if (!type2cls[TYINT]) {
- for (int i = TYBOOL; i <= TYUVLONG; ++i) {
- int siz = targ_primsizes[i];
- type2cls[i] = siz < 8 ? KI32 : KI64;
- }
- type2cls[TYFLOAT] = KF32;
- type2cls[TYDOUBLE] = KF64;
- type2cls[TYLDOUBLE] = KF64;
- type2cls[TYPTR] = KPTR;
- type2cls[TYARRAY] = KPTR;
- cls2siz[KPTR] = targ_primsizes[TYPTR];
- cls2load[KPTR] = targ_64bit ? Oloadi64 : Oloads32;
- cls2store[KPTR] = targ_64bit ? Ostorei64 : Ostorei32;
- }
- fn->entry = fn->curblk = allocz(fn->arena, sizeof(struct block), 0);
- fn->nblk = 1;
- fn->entry->lprev = fn->entry->lnext = fn->entry;
- fn->prop = FNUSE; /* builder keeps this */
-}
-
-static int
-newaddr(const struct addr *addr)
-{
- if (addrtab.n >= naddrht/4*3 /*75% load factor */) {
- xbgrowz(&addrht, naddrht*2);
- memset(addrht, 0, naddrht * sizeof *addrht);
- naddrht *= 2;
- for (int i = 0; i < addrtab.n; ++i) { /* rehash */
- const struct addr *addr = &addrtab.p[i];
- for (uint h = hashb(0, addr, sizeof *addr), j = h;; ++j) {
- if (!addrht[j &= naddrht - 1]) {
- addrht[j] = i+1;
- break;
- }
- }
- }
- }
- for (uint h = hashb(0, addr, sizeof *addr), i = h;; ++i) {
- i &= naddrht - 1;
- if (!addrht[i]) {
- vpush(&addrtab, *addr);
- return (addrht[i] = addrtab.n) - 1;
- } else if (!memcmp(&addrtab.p[addrht[i]-1], addr, sizeof *addr)) {
- return addrht[i] - 1;
- }
- }
-}
-
-union ref
-newxcon(const struct xcon *con)
-{
- assert((con->issym ^ con->isdat) || con->cls);
- vpush(&contab, *con);
- return mkref(RXCON, contab.n-1);
-}
-
-union irtype
-mkirtype(union type t)
-{
- if (t.t == TYVOID || isscalar(t))
- return (union irtype) { .cls = type2cls[scalartypet(t)] };
- assert(isagg(t));
- return (union irtype) { .isagg = 1, .dat = t.dat };
-}
-
-union ref
-mkintcon(enum irclass k, vlong i)
-{
- if (i < 1l << 28 && i >= -(1l << 28)) {
- return mkref(RICON, i);
- } else {
- struct xcon con = { .cls = k, .i = i };
- if (cls2siz[k] == 4) /* check upper half is zero or -1 */
- assert(in_range((i >> 32) + 1, 0, 1));
- return newxcon(&con);
- }
-}
-
-union ref
-mkfltcon(enum irclass k, double f)
-{
- struct xcon con = { .cls = k, .f = k == KF32 ? (float) f : f };
- return newxcon(&con);
-}
-
-union ref
-mksymref(internstr s, enum symflags symflags)
-{
- struct xcon con = { .issym = 1, .sym = s, .flag = symflags };
- return newxcon(&con);
-}
-
-union ref
-mkdatref(internstr name, union type ctype, uint siz, uint align,
- const void *bytes, uint n, bool deref, bool funclocal)
-{
- struct irdat dat = { .ctype = ctype, .align = align, .siz = siz, .name = name, .section = Srodata };
- if (funclocal && objout.code && align >= 4 && align <= targ_primsizes[TYPTR] && siz <= 16)
- dat.section = Stext;
-
- assert(n <= siz && siz && align);
- if (!name) {
- char buf[32];
- struct wbuf wbuf = MEMBUF(buf, sizeof buf);
-
- bfmt(&wbuf, ".L%c.%d", dat.section == Stext ? 'L' : 'D', dattab.n);
- ioputc(&wbuf, 0);
- assert(!wbuf.err);
- dat.name = name = intern(buf);
- }
- dat.off = objnewdat(name, dat.section, 0, siz, align);
- uchar *p = (dat.section == Stext ? objout.textbegin : objout.rodata.p) + dat.off;
- if (n) memcpy(p, bytes, n);
- if (dat.section != Stext) memset(p+n, 0, siz - n);
- vpush(&dattab, dat);
- return newxcon(&(struct xcon){.isdat = 1, .deref = deref, .dat = dattab.n - 1, .flag = SLOCAL});
-}
-
-internstr
-xcon2sym(int ref)
-{
- struct xcon con = contab.p[ref];
- assert(con.issym ^ con.isdat);
- return con.issym ? con.sym : dattab.p[con.dat].name;
-}
-
-struct instr
-mkalloca(uint siz, uint align)
-{
- struct instr ins = { .cls = KPTR };
- assert(ispo2(align) && align <= 16);
- ins.op = Oalloca1 + ilog2(align);
- ins.l = mkref(RICON, siz/align + (siz%align != 0));
- return ins;
-}
-
-union ref
-mkcallarg(union irtype ret, uint narg, int vararg)
-{
- struct call call = { .ret=ret, .narg=narg, .vararg=vararg };
- assert(vararg == -1 || (uint)vararg <= narg);
- vpush(&calltab, call);
- return mkref(RXXX, calltab.n-1);
-}
-
-union ref
-mkaddr(struct addr addr)
-{
- return mkref(RADDR, newaddr(&addr));
-}
-
-void
-addpred(struct block *blk, struct block *p)
-{
- if (blk->npred == 0) {
- blk->_pred0 = p;
- ++blk->npred;
- return;
- }
- if (blk->npred == 1) {
- struct block *p0 = blk->_pred0;
- blk->_pred = NULL;
- xbgrow(&blk->_pred, 4);
- *blk->_pred = p0;
- }
- xbpush(&blk->_pred, &blk->npred, p);
-}
-
-void
-delpred(struct block *blk, struct block *p)
-{
- for (int i = 0; i < blk->npred; ++i) {
- if (blkpred(blk, i) == p) {
- for (int j = 0; j < blk->phi.n; ++j) {
- union ref *phiargs = phitab.p[instrtab[blk->phi.p[j]].l.i];
- for (int k = i; k < blk->npred - 1; ++k) {
- phiargs[k] = phiargs[k + 1];
- }
- }
- for (int k = i; k < blk->npred - 1; ++k) {
- blkpred(blk, k) = blkpred(blk, k + 1);
- }
- if (--blk->npred == 1) {
- struct block *p0 = blk->_pred[0];
- xbfree(blk->_pred);
- blk->_pred0 = p0;
- }
- return;
- }
- }
- //assert(0&&"blk not in p");
-}
-
-struct block *
-newblk(struct function *fn)
-{
- struct block *blk = allocz(fn->arena, sizeof(struct block), 0);
- blk->id = -1;
- return blk;
-}
-
-void
-freeblk(struct function *fn, struct block *blk)
-{
- if (blk->npred > 1)
- xbfree(blk->_pred);
- blk->npred = 0;
- blk->_pred = NULL;
-
- for (int i = 0; i < blk->phi.n; ++i) {
- int ui = blk->phi.p[i];
- union ref *r = phitab.p[instrtab[ui].l.i];
- for (int j = 0; j < blk->npred; ++j) {
- deluse(blk, ui, *r);
- }
- }
- for (int i = 0; i < blk->ins.n; ++i) {
- int ui = blk->ins.p[i];
- struct instr *ins = &instrtab[ui];
- if (ins->l.t == RTMP) deluse(blk, ui, ins->l);
- if (ins->r.t == RTMP) deluse(blk, ui, ins->r);
- }
- for (int i = 0; i < 2; ++i) {
- if (blk->jmp.arg[i].t == RTMP) deluse(blk, USERJUMP, blk->jmp.arg[i]);
- }
- if (blk->s1) delpred(blk->s1, blk);
- if (blk->s2) delpred(blk->s2, blk);
- vfree(&blk->phi);
- vfree(&blk->ins);
- if (blk->id != -1)
- --fn->nblk;
- if (blk->lprev) blk->lprev->lnext = blk->lnext;
- if (blk->lnext) blk->lnext->lprev = blk->lprev;
- blk->id = 1u<<31;
-}
-
-struct block *
-insertblk(struct function *fn, struct block *pred, struct block *subst)
-{
- struct block *new = newblk(fn);
- struct block **s = pred->s1 == subst ? &pred->s1 : &pred->s2;
- assert(*s == subst);
- new->lnext = pred->lnext;
- new->lprev = pred;
- pred->lnext->lprev = new;
- pred->lnext = new;
- *s = new;
- new->jmp.t = Jb;
- new->s1 = subst;
- addpred(new, pred);
- for (int i = 0; i < subst->npred; ++i) {
- if (blkpred(subst, i) == pred) {
- blkpred(subst, i) = new;
- ++fn->nblk;
- return new;
- }
- }
- assert(0);
-}
-
-struct block *
-blksplitafter(struct function *fn, struct block *blk, int idx)
-{
- struct block *new = newblk(fn);
- ++fn->nblk;
- new->lprev = blk;
- new->lnext = blk->lnext;
- blk->lnext = new;
- new->lnext->lprev = new;
- if (idx == -1) {
- new->ins = blk->ins;
- memset(&blk->ins, 0, sizeof blk->ins);
- } else {
- if (idx < blk->ins.n-1)
- vpushn(&new->ins, &blk->ins.p[idx+1], blk->ins.n-idx-1);
- blk->ins.n -= new->ins.n;
- }
- new->jmp = blk->jmp;
- blk->jmp.t = Jb;
- memset(blk->jmp.arg, 0, sizeof blk->jmp.arg);
- for (int i = 0; i < 2; ++i) {
- struct block *s = (&blk->s1)[i];
- if (s) for (int i = 0; i < s->npred; ++i) {
- if (blkpred(s, i) == blk)
- blkpred(s, i) = new;
- }
- }
- new->s1 = blk->s1, new->s2 = blk->s2;
- blk->s1 = new, blk->s2 = NULL;
- addpred(new, blk);
- fn->prop &= ~FNUSE;
- return new;
-}
-
-int
-allocinstr(void)
-{
- int t;
- if (instrfreelist != -1) {
- t = instrfreelist;
- memcpy(&instrfreelist, &instrtab[t], sizeof(int));
- if (instruse[t]) deluses(t);
- } else {
- assert(ninstr < countof(instrtab));
- t = ninstr++;
- instruse[t] = NULL;
- }
- return t;
-}
-
-void
-adduse(struct block *ublk, int ui, union ref r) {
- if (r.t != RTMP) return;
- struct use *use;
- if (usefreelist) {
- use = usefreelist;
- usefreelist = usefreelist->next;
- } else {
- use = alloc(usearena, sizeof *use, 0);
- }
- assert(use != instruse[r.i]);
- use->next = instruse[r.i];
- use->blk = ublk,
- use->u = ui;
- instruse[r.i] = use;
-}
-
-bool
-deluse(struct block *ublk, int ui, union ref r) {
- if (r.t != RTMP) return 0;
-
- for (struct use **puse = &instruse[r.i]; *puse; puse = &(*puse)->next) {
- struct use *use = *puse;
- if (use->blk == ublk && use->u == ui) {
- *puse = use->next;
- use->blk = 0;
- use->u = 0;
- use->next = usefreelist;
- usefreelist = use;
- return 1;
- }
- }
- return 0;
-}
-
-void
-filluses(struct function *fn)
-{
- struct block *blk = fn->entry;
-
- for (int i = 0; i < ninstr; ++i)
- deluses(i);
-
- do {
- for (int i = 0; i < blk->phi.n; ++i) {
- int ins = blk->phi.p[i];
- union ref *phi = phitab.p[instrtab[ins].l.i];
- for (int i = 0; i < blk->npred; ++i)
- adduse(blk, ins, phi[i]);
- }
- for (int i = 0; i < blk->ins.n; ++i) {
- int ins = blk->ins.p[i];
- adduse(blk, ins, instrtab[ins].l);
- adduse(blk, ins, instrtab[ins].r);
- }
- adduse(blk, USERJUMP, blk->jmp.arg[0]);
- adduse(blk, USERJUMP, blk->jmp.arg[1]);
- } while ((blk = blk->lnext) != fn->entry);
-
- fn->prop |= FNUSE;
-}
-
-int
-newinstr(struct block *at, struct instr ins)
-{
- int new = allocinstr();
- instrtab[new] = ins;
- if (at) {
- adduse(at, new, ins.l);
- adduse(at, new, ins.r);
- }
- return new;
-}
-
-union ref
-insertinstr(struct block *blk, int idx, struct instr ins)
-{
- int new = newinstr(blk, ins);
- if (idx == blk->ins.n) vpush(&blk->ins, new);
- else {
- assert(idx >= 0 && idx < blk->ins.n);
- vpush_(&blk->ins._vb, sizeof *blk->ins.p);
- vresize(&blk->ins, blk->ins.n);
- for (int i = blk->ins.n++; i > idx; --i)
- blk->ins.p[i] = blk->ins.p[i - 1];
- blk->ins.p[idx] = new;
- }
- return mkref(RTMP, new);
-}
-
-union ref
-insertphi(struct block *blk, enum irclass cls)
-{
- int new = allocinstr();
- union ref *refs = NULL;
- assert(blk->npred > 0);
- xbgrowz(&refs, blk->npred);
- vpush(&phitab, refs);
- instrtab[new] = mkinstr(Ophi, cls, mkref(RXXX, phitab.n - 1));
- vpush(&blk->phi, new);
- return mkref(RTMP, new);
-}
-
-uint
-numberinstrs(struct function *fn)
-{
- struct block *blk = fn->entry;
- int start = 0;
- do {
- blk->inumstart = start;
- start += blk->ins.n+2;
- } while ((blk = blk->lnext) != fn->entry);
- return start-1;
-}
-
-static bool
-reachablerec(struct function *fn, struct block *blk)
-{
- if (blk == fn->entry) return 1;
- markvisited(blk);
- if (blk->npred == 1 && !wasvisited(blkpred(blk, 0)))
- return reachablerec(fn, blkpred(blk, 0));
- else for (int i = 0; i < blk->npred; ++i) {
- struct block *p = blkpred(blk, i);
- if (!wasvisited(p) && reachablerec(fn, p)) return 1;
- }
- return 0;
-}
-
-bool
-blkreachable(struct function *fn, struct block *blk)
-{
- startbbvisit();
- return reachablerec(fn, blk);
-}
-
-/* require use */
-void
-replcuses(union ref from, union ref to)
-{
- assert(from.t == RTMP);
- for (struct use *use = instruse[from.i], *next; use; use = next) {
- union ref *u;
- int n, j;
- next = use->next;
- if (use->u == from.i) continue;
- if (use->u == USERJUMP) {
- u = &use->blk->jmp.arg[0];
- n = 2;
- } else if (instrtab[use->u].op == Ophi) {
- u = phitab.p[instrtab[use->u].l.i];
- n = use->blk->npred;
- if (use->blk->phi.n == 0) continue; /* shouldn't happen */
- } else {
- u = &instrtab[use->u].l;
- n = 2;
- }
-
- for (j = 0; j < n; ++j) {
- if (u[j].bits == from.bits) {
- u[j].bits = to.bits;
- adduse(use->blk, use->u, to);
- next = use;
- break;
- }
- }
- }
-}
-
-void
-deluses(int ins)
-{
- for (struct use *use = instruse[ins], *next; use; use = next) {
- next = use->next;
- use->blk = 0;
- use->u = 0;
- use->next = usefreelist;
- usefreelist = use;
- }
- instruse[ins] = NULL;
-}
-
-void
-delinstr(struct block *blk, int idx)
-{
- int t = blk->ins.p[idx];
- assert(idx >= 0 && idx < blk->ins.n);
- for (int i = 0; i < 2; ++i) {
- deluse(blk, t, (&instrtab[t].l)[i]);
- }
- memcpy(&instrtab[t], &instrfreelist, sizeof(int));
- instrfreelist = t;
- deluses(t);
- for (int i = idx; i < blk->ins.n - 1; ++i)
- blk->ins.p[i] = blk->ins.p[i + 1];
- --blk->ins.n;
-}
-
-void
-delphi(struct block *blk, int idx)
-{
- int t = blk->phi.p[idx];
- assert(idx >= 0 && idx < blk->phi.n);
- memcpy(&instrtab[t], &instrfreelist, sizeof(int));
- instrfreelist = t;
- deluses(t);
- for (int i = idx; i < blk->phi.n - 1; ++i)
- blk->phi.p[i] = blk->phi.p[i + 1];
- --blk->phi.n;
-}
-
-void
-delnops(struct block *blk)
-{
- int i, n, t;
- /* delete trailing nops */
- while (blk->ins.n > 0 && instrtab[t = blk->ins.p[blk->ins.n - 1]].op == Onop) {
- --blk->ins.n;
- deluses(t);
- memcpy(&instrtab[t], &instrfreelist, sizeof(int));
- instrfreelist = t;
- }
- /* delete rest of nops */
- for (i = blk->ins.n - 2, n = 0; i >= 0; --i) {
- if (instrtab[t = blk->ins.p[i]].op == Onop) {
- deluses(t);
- memcpy(&instrtab[t], &instrfreelist, sizeof(int));
- instrfreelist = t;
- ++n;
- } else if (n) {
- memmove(blk->ins.p+i+1, blk->ins.p+i+1+n, (blk->ins.n - n - i - 1)*sizeof *blk->ins.p);
- blk->ins.n -= n;
- n = 0;
- }
- }
- if (n)
- memmove(blk->ins.p, blk->ins.p + n, (blk->ins.n -= n)*sizeof *blk->ins.p);
-}
-
-void
-fillblkids(struct function *fn)
-{
- int i = 0;
- struct block *blk = fn->entry;
- do blk->id = i++; while ((blk = blk->lnext) != fn->entry);
-
- fn->prop |= FNBLKID;
-}
-
-/** Misc **/
-
-static void
-freefn(struct function *fn)
-{
- struct block *blk = fn->entry;
- do {
- if (blk->npred > 1) xbfree(blk->_pred);
- vfree(&blk->phi);
- vfree(&blk->ins);
- } while ((blk = blk->lnext) != fn->entry);
-}
-
-void
-irfini(struct function *fn)
-{
- extern int nerror;
- static union { char m[sizeof(struct arena) + (4<<10)]; struct arena *_align; } amem;
- struct arena *passarena = (void *)&amem.m;
- fn->passarena = &passarena;
- if (nerror) {
- freefn(fn);
- return;
- }
-
- abi0(fn);
- lowerintrin(fn);
- if (ccopt.o > OPT0) {
- mem2reg(fn);
- freearena(fn->passarena);
- copyopt(fn);
- }
- if (ccopt.o >= OPT1) {
- doinline(fn);
- filldom(fn);
- if (!(fn->prop & FNUSE)) filluses(fn);
- cselim(fn);
- freearena(fn->passarena);
- simpl(fn);
- freearena(fn->passarena);
- }
- if (maybeinlinee(fn)) {
- // goto Fin; XXX do this by having inline function rematerialization when symbol is actually referenced
- }
- lowerstack(fn);
- freearena(fn->passarena);
- if (ccopt.dbg.o) {
- bfmt(ccopt.dbgout, "<< Before isel >>\n");
- irdump(fn);
- }
- mctarg->isel(fn);
- regalloc(fn);
- freearena(fn->passarena);
- if (objout.code)
- mctarg->emit(fn);
-
-//Fin:
- freearena(fn->passarena);
- freefn(fn);
-}
-
-/* vim:set ts=3 sw=3 expandtab: */