aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ir_dump.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 /src/ir_dump.c
parent24f14b7ad1af08d872971d72ce089a529911f657 (diff)
REFACTOR: move sources to src/
Diffstat (limited to 'src/ir_dump.c')
-rw-r--r--src/ir_dump.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/src/ir_dump.c b/src/ir_dump.c
new file mode 100644
index 0000000..b0ce603
--- /dev/null
+++ b/src/ir_dump.c
@@ -0,0 +1,319 @@
+#include "ir.h"
+#include "../obj/obj.h"
+#include "../endian.h"
+
+static int nextdat;
+
+static struct wbuf *out = &bstdout;
+
+static bool
+prilitdat(const struct irdat *dat, const char *prefix)
+{
+ uchar *p;
+ switch (dat->section) {
+ default: assert(0);
+ case Sdata: p = objout.data.p + dat->off; break;
+ case Srodata: p = objout.rodata.p + dat->off; break;
+ case Stext: p = objout.textbegin + dat->off; break;
+ }
+ if (dat->ctype.t == TYARRAY && typechild(dat->ctype).t == TYCHAR && dat->siz-1 < 60 && p[dat->siz-1] == 0) {
+ bfmt(out, "%s%'S", prefix, p, dat->siz-1);
+ } else if (dat->ctype.t == TYFLOAT) {
+ bfmt(out, "%s%f", prefix, rdf32targ(p));
+ } else if (dat->ctype.t == TYDOUBLE) {
+ bfmt(out, "%s%f", prefix, rdf64targ(p));
+ } else if (dat->ctype.t == TYVLONG) {
+ bfmt(out, "%s0x%lx", prefix, rd64targ(p));
+ } else return 0;
+ return 1;
+}
+
+static void
+pridat(const struct irdat *dat)
+{
+ static const char *snames[] = { [Sdata] = ".data", [Srodata] = ".rodata", [Stext] = ".text" };
+ uchar *p;
+ switch (dat->section) {
+ default: assert(0);
+ case Sdata: p = objout.data.p + dat->off; break;
+ case Srodata: p = objout.rodata.p + dat->off; break;
+ case Stext: p = objout.textbegin + dat->off; break;
+ }
+ enum {
+ MINZERO = 4,
+ MAXLINE = 60,
+ };
+ int npri = 0;
+ int strbegin = 0, nstr = 0;
+ bfmt(out, "%s %ty %y(align %d, size %d):\n\t", snames[dat->section], dat->ctype, dat->name, dat->align, dat->siz);
+ if (!prilitdat(dat, "lit: ")) {
+ for (int i = 0; i < dat->siz; ++i) {
+ int c = p[i];
+ if (npri > MAXLINE) {
+ npri = 0;
+ bfmt(out, "\n\t");
+ }
+ if (aisprint(c)) {
+ if (!nstr++) strbegin = i;
+ } else {
+ if (nstr) {
+ npri += bfmt(out, "asc %'S,", p+strbegin, nstr);
+ nstr = 0;
+ bfmt(out, "b ");
+ }
+ npri += bfmt(out, "%d,", c);
+ }
+ }
+ if (nstr) npri += bfmt(out, "asc %'S,", p+strbegin, nstr);
+ }
+ bfmt(out, "\n");
+}
+
+static const char *clsname[] = {
+ "?", "i32", "i64", "ptr", "f32", "f64"
+};
+
+static void
+prityp(union irtype typ)
+{
+ if (!typ.isagg)
+ bfmt(out, clsname[typ.cls]);
+ else {
+ const struct typedata *td = &typedata[typ.dat];
+ const char *tag = td->t == TYSTRUCT ? "struct" : "union";
+ if (ttypenames[td->id])
+ bfmt(out, "%s.%s.%d", tag, ttypenames[td->id], td->id);
+ else
+ bfmt(out, "%s.%d", tag, td->id);
+ }
+}
+
+static const char *intrinname[] = {
+ "?\??",
+#define _(b,...) #b,
+#include "intrin.def"
+#undef _
+};
+
+static void
+dumpref(enum op o, union ref ref)
+{
+ struct xcon *con;
+ switch (ref.t) {
+ case RXXX:
+ if (ref.bits == UNDREF.bits)
+ bfmt(out, "undef");
+ else
+ bfmt(out, "??");
+ break;
+ case RTMP:
+ bfmt(out, "%%%d", ref.i);
+ if (instrtab[ref.i].reg)
+ bfmt(out, "(%s)", mctarg->rnames[instrtab[ref.i].reg-1]);
+ break;
+ case RREG:
+ bfmt(out, "%s", mctarg->rnames[ref.i]);
+ break;
+ case RICON:
+ if (o == Ointrin) bfmt(out, "\"%s\"", intrinname[ref.i]);
+ else bfmt(out, "%d", ref.i);
+ break;
+ case RXCON:
+ con = &contab.p[ref.i];
+ if (con->deref) bfmt(out, "*[");
+ if (con->issym || con->isdat) {
+ bfmt(out, "$%y", xcon2sym(ref.i));
+ if (con->isdat) {
+ struct irdat *dat = &dattab.p[con->dat];
+ if (prilitdat(dat, " (= ")) {
+ if (isscalar(dat->ctype)) {
+ struct wbuf tmp = MEMBUF((char [1]){0}, 1);
+ bfmt(&tmp, "%ty", dat->ctype);
+ ioputc(out, *tmp.buf);
+ }
+ ioputc(out, ')');
+ }
+ }
+ } else switch (con->cls) {
+ case KI32: bfmt(out, "%d", (int)con->i); break;
+ case KI64: bfmt(out, "%ld", con->i); break;
+ case KPTR: bfmt(out, "%'lx", con->i); break;
+ case KF32: bfmt(out, "%fs", con->f); break;
+ case KF64: bfmt(out, "%fd", con->f); break;
+ default: assert(0);
+ }
+ if (con->deref) bfmt(out, "]");
+ break;
+ case RTYPE:
+ prityp(ref2type(ref));
+ break;
+ case RADDR:
+ {
+ const struct addr *addr = &addrtab.p[ref.i];
+ bool k = 0;
+ bfmt(out, "addr [");
+ if ((k = addr->base.bits)) dumpref(0, addr->base);
+ if (addr->index.bits) {
+ if (k) bfmt(out, " + ");
+ dumpref(0, addr->index);
+ if (addr->shift)
+ bfmt(out, " * %d", 1<<addr->shift);
+ k = 1;
+ }
+ if (k && addr->disp) {
+ bfmt(out, " %c %d", "-+"[addr->disp > 0], addr->disp < 0 ? -addr->disp : addr->disp);
+ }
+ assert(k);
+ bfmt(out, "]");
+ }
+ break;
+ case RSTACK:
+ bfmt(out, "[stack %d]", ref.i);
+ break;
+ default: assert(!"ref");
+ }
+}
+
+static void
+dumpcall(struct call *call)
+{
+ if (call->ret.isagg) {
+ bfmt(out, "sret ");
+ prityp(call->ret);
+ bfmt(out, ", ");
+ }
+ if (call->vararg < 0) {
+ bfmt(out, "#%d", call->narg);
+ } else {
+ assert(call->vararg <= call->narg);
+ bfmt(out, "#%d, ... #%d", call->vararg, call->narg - call->vararg);
+ }
+}
+
+static void
+dumpinst(const struct instr *ins)
+{
+ int i;
+ if (ins->op == Omove) {
+ bfmt(out, "move %s ", clsname[ins->cls]);
+ } else {
+ enum irclass cls = insrescls(*ins);
+ if (ins->reg) {
+ if (cls)
+ bfmt(out, "%s ", clsname[cls]);
+ bfmt(out, "(%%%d)%s = ", ins - instrtab, mctarg->rnames[ins->reg - 1]);
+ } else if (cls) {
+ bfmt(out, "%s %%%d", clsname[cls], ins - instrtab);
+ bfmt(out, " = ");
+ }
+ bfmt(out, "%s ", opnames[ins->op]);
+ if (oiscmp(ins->op))
+ bfmt(out, "%s ", clsname[ins->cls]);
+ }
+ for (i = 0; i < opnarg[ins->op]; ++i) {
+ if (i) bfmt(out, ", ");
+ if (i == 1 && (ins->op == Ocall || ins->op == Ointrin)) {
+ dumpcall(&calltab.p[ins->r.i]);
+ } else {
+ dumpref(ins->op, (&ins->l)[i]);
+ }
+ }
+ if (oisalloca(ins->op) && ins->l.t == RICON) {
+ bfmt(out, " \t; %d bytes", ins->l.i << (ins->op - Oalloca1));
+ }
+ bfmt(out, "\n");
+}
+
+void
+dumpblk(struct function *fn, struct block *blk)
+{
+ static const char *jnames[] = { 0, "b", "ret", "trap" };
+ int i;
+ bfmt(out, " @%d:", blk->id);
+ if (blk->npred) {
+ bfmt(out, " \t; preds:");
+ for (i = 0; i < blk->npred; ++i) {
+ if (i) ioputc(out, ',');
+ bfmt(out, " @%d", blkpred(blk, i)->id);
+ }
+ }
+ if (fn->prop & FNDOM && blk->idom)
+ bfmt(out, "\t; idom: @%d", blk->idom->id);
+ if (blk->loop)
+ bfmt(out, "\t; loop depth: %d", blk->loop);
+ ioputc(out, '\n');
+ for (i = 0; i < blk->phi.n; ++i) {
+ struct instr *phi = &instrtab[blk->phi.p[i]];
+ union ref *refs = phitab.p[phi->l.i];
+ if (i == 0) bfmt(out, "%-4d", blk->inumstart);
+ else bfmt(out, " |> ");
+ bfmt(out, " %s ", clsname[phi->cls]);
+ if (!phi->reg) bfmt(out, "%%%d = %s ", blk->phi.p[i], opnames[phi->op]);
+ else bfmt(out, "(%%%d)%s = %s ", phi - instrtab, mctarg->rnames[phi->reg-1], opnames[phi->op]);
+ for (int i = 0; i < blk->npred; ++i) {
+ if (i) bfmt(out, ", ");
+ bfmt(out, "@%d ", blkpred(blk, i)->id);
+ dumpref(0, refs[i]);
+ }
+ ioputc(out, '\n');
+ }
+ for (i = 0; i < blk->ins.n; ++i) {
+ bfmt(out, "%-4d ", blk->inumstart + 1 + i);
+ dumpinst(&instrtab[blk->ins.p[i]]);
+ }
+ bfmt(out, "%-4d %s ", blk->inumstart + 1 + i, jnames[blk->jmp.t]);
+ if (blk->jmp.t == Jret && blk->jmp.arg[0].bits && !fn->nabiret && isagg(fn->retty)) {
+ /* un-lowered struct return */
+ dumpref(0, mktyperef(mkirtype(fn->retty)));
+ bfmt(out, " ");
+ }
+ for (i = 0; i < 2; ++i) {
+ if (!blk->jmp.arg[i].bits) break;
+ if (i > 0) bfmt(out, ", ");
+ dumpref(0, blk->jmp.arg[i]);
+ }
+ if (i && blk->s1) bfmt(out, ", ");
+ if (blk->s1 && blk->s2) bfmt(out, "@%d, @%d", blk->s1->id, blk->s2->id);
+ else if (blk->s1) bfmt(out, "@%d", blk->s1->id);
+ bfmt(out, "\n");
+}
+
+void
+irdump(struct function *fn)
+{
+ struct block *blk;
+
+ /* print datas that have never been printed before */
+ while (nextdat < dattab.n) pridat(&dattab.p[nextdat++]);
+
+ bfmt(out, "function %s : %ty\n", fn->name, fn->fnty);
+ if (fn->abiarg || fn->nabiret) {
+ bfmt(out, "abi: (");
+ for (int i = 0; i < fn->nabiarg; ++i) {
+ if (i > 0) bfmt(out, ", ");
+ if (!fn->abiarg[i].isstk) {
+ bfmt(out, "%s", mctarg->rnames[fn->abiarg[i].reg]);
+ } else {
+ prityp(fn->abiarg[i].ty);
+ bfmt(out, " <stk>");
+ }
+ }
+ bfmt(out, ")");
+ if (fn->retty.t != TYVOID) {
+ bfmt(out, " -> %s", mctarg->rnames[fn->abiret[0].reg]);
+ if (fn->nabiret > 1)
+ bfmt(out, ", %s", mctarg->rnames[fn->abiret[1].reg]);
+ }
+ bfmt(out, "\n");
+ }
+ numberinstrs(fn);
+ blk = fn->entry;
+ do {
+ assert(blk->lprev->lnext == blk);
+ dumpblk(fn, blk);
+ assert(blk->lnext != NULL);
+ } while ((blk = blk->lnext) != fn->entry);
+ bfmt(out, "\n");
+}
+
+/* vim:set ts=3 sw=3 expandtab: */