import "ir.hff"; import "common.hff"; import "map.hff"; fn dump(fmt *const u8, ...) void { let ap va_list #?; ap->start(fmt); for let c = *fmt; c != 0; c = *++fmt { if c != '%' { fputc(c, stderr); continue; } switch (c = *++fmt) { case '%'; fputc('%', stderr); case 'd'; efmt("%d", ap->arg(int)); case 'a'; let arg = ap->arg(IRArg); switch arg { case Val val; switch val.u { case IImm i; efmt("%I", i); case FImm f; efmt("%f", f); case SImm s; efmt("%S", s); case BImm b; efmt("%s", b ? "#t" : "#f"); case Null; efmt("#null"); case Tmp t; efmt("%%%d", t); case Local l; efmt("$%s.%d", l.name, l.u.Let.id); case Global g; efmt("@%s.%d", g.name, g.u.Static.id); } case Ty ty; efmt("%t", ty); case Fn decl; efmt("@%s", decl.name); case else assert(#f, "arg? %d", arg.#tag); } case 't'; efmt("%t", ap->arg(*Type)); case else assert(#f, "bad fmt %c", c); } } ap->end(); } extern fn irdump(inst *IRInst) void { let labels Map<*IRInst, int, struct { fn hash(a *IRInst) u32 { return as(iptrint)a; } fn eq(a *IRInst, b *IRInst) bool { return a == b; } }> = {}; defer labels->clear(); let labid = 0; for let a = inst; a; a = a.next { if a.branch { let slot = labels->get_slot(a.branch); if *slot == 0 { *slot = ++labid; } } } #'dump for ; inst; inst = inst.next { let label = labels->get(inst); if label { dump(".L%d:\t", *label); } else { dump("\t"); } defmacro exprinst(tag, nam, n) [ if inst.t == (tag) { dump("%%%d(%t) = " ## nam ## " ", inst.args[0].Val.u.Tmp, inst.args[0].Val.ty); for let $i = 1; $i < (n); ++$i { dump("%a", inst.args[$i]); if $i < (n) - 1 { dump(", "); } } dump("\n"); continue #'dump; } ] defmacro stmtinst(tag, nam, n) [ if inst.t == (tag) { dump(nam##" "); for let $i = 0; $i < (n); ++$i { dump("%a", inst.args[$i]); if $i < (n) - 1 { dump(", "); } } dump("\n"); continue #'dump; } ] exprinst(:neg, "neg", 2) exprinst(:not, "not", 2) exprinst(:compl, "compl", 2) exprinst(:fneg, "fneg", 2) exprinst(:add, "add", 3); exprinst(:sub, "sub", 3); exprinst(:mul, "mul", 3); exprinst(:div, "div", 3); exprinst(:mod, "mod", 3); exprinst(:band, "band", 3); exprinst(:bor, "bor", 3); exprinst(:xor, "xor", 3); exprinst(:lsl, "lsl", 3); exprinst(:lsr, "lsr", 3); exprinst(:asr, "asr", 3); exprinst(:eq, "eq", 3); exprinst(:neq, "neq", 3); exprinst(:lt, "lt", 3); exprinst(:lteq, "lteq", 3); exprinst(:fadd, "fadd", 3); exprinst(:fsub, "fsub", 3); exprinst(:fmul, "fmul", 3); exprinst(:fdiv, "fdiv", 3); if inst.t == :call { let fnty = inst.args[1].Fn.u.Fn.ty.u.Fn; dump("%%%d(%t) = call %a, ", inst.args[0].Val.u.Tmp, inst.args[0].Val.ty, inst.args[1]); let n = inst.call_nargs; for let i = 0; i < n; ++i { dump("%a(%t)", inst.args[i + 2], i < fnty.params.#len ? fnty.params[i] : inst.args[i + 2].Val.ty); if i < n - 1 { dump(", "); } } dump("\n"); continue #'dump; } exprinst(:ftrunc, "ftrunc", 2); exprinst(:itof, "itof", 2); exprinst(:getelem, "getelem", 4); exprinst(:pgetelem, "pgetelem", 4); stmtinst(:nop, "nop", 0); exprinst(:copy, "copy", 2); if inst.t == :setvar { dump("set %a, %a\n", inst.args[0], inst.args[1]); continue #'dump; } if inst.t == :load { dump("%a(%t) = load %a[%a]\n", inst.args[0], inst.args[0].Val.ty, inst.args[1], inst.args[2]); continue #'dump; } if inst.t == :store { dump("store %a[%a], %a\n", inst.args[0], inst.args[1], inst.args[2]); continue #'dump; } stmtinst(:ret0, "ret", 0); stmtinst(:ret, "ret", 1); if inst.t == :beqz { dump("beqz %a, .L%d\n", inst.args[0], *labels->get(inst.branch)); continue #'dump; } if inst.t == :b { dump("b .L%d\n", *labels->get(inst.branch)); continue #'dump; } assert(#f, "inst? %d\n", inst.t); }; }