kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

ir_print.c (9547B)


      1 #include "core/slice.h"
      2 #include "core/strbuf.h"
      3 #include "opt/opt.h"
      4 
      5 static void dump_write(Writer* w, const char* s) {
      6   kit_writer_write(w, s, slice_from_cstr(s).len);
      7 }
      8 
      9 static void dump_sb(Writer* w, const StrBuf* sb) {
     10   kit_writer_write(w, strbuf_cstr(sb), strbuf_len(sb));
     11 }
     12 
     13 /* Append a signed value with an explicit leading sign, matching printf's
     14  * "%+lld"/"%+d" formatting (forced '+' on non-negative values). */
     15 static void strbuf_put_i64_plus(StrBuf* sb, i64 v) {
     16   if (v < 0) {
     17     strbuf_putc(sb, '-');
     18     strbuf_put_u64(sb, (u64)(-(v + 1)) + 1u);
     19   } else {
     20     strbuf_putc(sb, '+');
     21     strbuf_put_u64(sb, (u64)v);
     22   }
     23 }
     24 
     25 static const char* op_name(IROp op) {
     26   switch (op) {
     27     case IR_NOP:
     28       return "nop";
     29     case IR_CONST_I:
     30       return "const_i";
     31     case IR_CONST_BYTES:
     32       return "const_bytes";
     33     case IR_PARAM_DECL:
     34       return "param_decl";
     35     case IR_LOAD_IMM:
     36       return "load_imm";
     37     case IR_LOAD_CONST:
     38       return "load_const";
     39     case IR_COPY:
     40       return "copy";
     41     case IR_LOAD:
     42       return "load";
     43     case IR_STORE:
     44       return "store";
     45     case IR_ADDR_OF:
     46       return "addr_of";
     47     case IR_TLS_ADDR_OF:
     48       return "tls_addr_of";
     49     case IR_AGG_COPY:
     50       return "agg_copy";
     51     case IR_AGG_SET:
     52       return "agg_set";
     53     case IR_BITFIELD_LOAD:
     54       return "bitfield_load";
     55     case IR_BITFIELD_STORE:
     56       return "bitfield_store";
     57     case IR_BINOP:
     58       return "binop";
     59     case IR_UNOP:
     60       return "unop";
     61     case IR_CMP:
     62       return "cmp";
     63     case IR_CONVERT:
     64       return "convert";
     65     case IR_CALL:
     66       return "call";
     67     case IR_PHI:
     68       return "phi";
     69     case IR_BR:
     70       return "br";
     71     case IR_CONDBR:
     72       return "condbr";
     73     case IR_CMP_BRANCH:
     74       return "cmp_branch";
     75     case IR_SWITCH:
     76       return "switch";
     77     case IR_INDIRECT_BRANCH:
     78       return "indirect_branch";
     79     case IR_LOAD_LABEL_ADDR:
     80       return "load_label_addr";
     81     case IR_LOCAL_STATIC_DATA_BEGIN:
     82       return "local_static_data_begin";
     83     case IR_LOCAL_STATIC_DATA_WRITE:
     84       return "local_static_data_write";
     85     case IR_LOCAL_STATIC_DATA_LABEL_ADDR:
     86       return "local_static_data_label_addr";
     87     case IR_LOCAL_STATIC_DATA_END:
     88       return "local_static_data_end";
     89     case IR_RET:
     90       return "ret";
     91     case IR_UNREACHABLE:
     92       return "unreachable";
     93     case IR_SCOPE_BEGIN:
     94       return "scope_begin";
     95     case IR_SCOPE_END:
     96       return "scope_end";
     97     case IR_BREAK_TO:
     98       return "break_to";
     99     case IR_CONTINUE_TO:
    100       return "continue_to";
    101     case IR_ALLOCA:
    102       return "alloca";
    103     case IR_VA_START:
    104       return "va_start";
    105     case IR_VA_ARG:
    106       return "va_arg";
    107     case IR_VA_END:
    108       return "va_end";
    109     case IR_VA_COPY:
    110       return "va_copy";
    111     case IR_ATOMIC_LOAD:
    112       return "atomic_load";
    113     case IR_ATOMIC_STORE:
    114       return "atomic_store";
    115     case IR_ATOMIC_RMW:
    116       return "atomic_rmw";
    117     case IR_ATOMIC_CAS:
    118       return "atomic_cas";
    119     case IR_FENCE:
    120       return "fence";
    121     case IR_ASM_BLOCK:
    122       return "asm_block";
    123     case IR_INTRINSIC:
    124       return "intrinsic";
    125     default:
    126       return "unknown";
    127   }
    128 }
    129 
    130 static const char* alias_name(u8 kind) {
    131   switch ((AliasKind)kind) {
    132     case ALIAS_UNKNOWN:
    133       return "unknown";
    134     case ALIAS_LOCAL:
    135       return "local";
    136     case ALIAS_GLOBAL:
    137       return "global";
    138     case ALIAS_PARAM:
    139       return "param";
    140     case ALIAS_HEAP:
    141       return "heap";
    142     case ALIAS_STRING:
    143       return "string";
    144     default:
    145       return "alias?";
    146   }
    147 }
    148 
    149 static void dump_alias(Writer* w, const AliasRoot* a) {
    150   char buf[64];
    151   StrBuf sb;
    152   dump_write(w, alias_name(a->kind));
    153   strbuf_init(&sb, buf, sizeof buf);
    154   switch ((AliasKind)a->kind) {
    155     case ALIAS_LOCAL:
    156       strbuf_putc(&sb, '#');
    157       strbuf_put_i64(&sb, (i64)(int)a->v.local_id);
    158       dump_sb(w, &sb);
    159       break;
    160     case ALIAS_GLOBAL:
    161       strbuf_putc(&sb, '#');
    162       strbuf_put_u64(&sb, (u64)(unsigned)a->v.global);
    163       dump_sb(w, &sb);
    164       break;
    165     case ALIAS_PARAM:
    166       strbuf_putc(&sb, '#');
    167       strbuf_put_u64(&sb, (u64)(unsigned)a->v.param_idx);
    168       dump_sb(w, &sb);
    169       break;
    170     case ALIAS_STRING:
    171       strbuf_putc(&sb, '#');
    172       strbuf_put_u64(&sb, (u64)(unsigned)a->v.string_id);
    173       dump_sb(w, &sb);
    174       break;
    175     default:
    176       break;
    177   }
    178 }
    179 
    180 static void dump_operand(Writer* w, const Operand* op) {
    181   char buf[96];
    182   StrBuf sb;
    183   if (!op) {
    184     dump_write(w, "-");
    185     return;
    186   }
    187   strbuf_init(&sb, buf, sizeof buf);
    188   switch ((OptOperandKind)op->kind) {
    189     case OPK_IMM:
    190       strbuf_puts(&sb, "imm:");
    191       strbuf_put_i64(&sb, (i64)op->v.imm);
    192       dump_sb(w, &sb);
    193       break;
    194     case OPK_REG:
    195       strbuf_putc(&sb, 'v');
    196       strbuf_put_u64(&sb, (u64)(unsigned)op->v.reg);
    197       dump_sb(w, &sb);
    198       break;
    199     case OPK_LOCAL:
    200       strbuf_puts(&sb, "local#");
    201       strbuf_put_u64(&sb, (u64)(unsigned)op->v.frame_slot);
    202       dump_sb(w, &sb);
    203       break;
    204     case OPK_GLOBAL:
    205       strbuf_puts(&sb, "global#");
    206       strbuf_put_u64(&sb, (u64)(unsigned)op->v.global.sym);
    207       strbuf_put_i64_plus(&sb, (i64)op->v.global.addend);
    208       dump_sb(w, &sb);
    209       break;
    210     case OPK_INDIRECT:
    211       strbuf_putc(&sb, '[');
    212       strbuf_putc(&sb, 'v');
    213       strbuf_put_u64(&sb, (u64)(unsigned)op->v.ind.base);
    214       strbuf_put_i64_plus(&sb, (i64)(int)op->v.ind.ofs);
    215       strbuf_putc(&sb, ']');
    216       dump_sb(w, &sb);
    217       break;
    218     default:
    219       dump_write(w, "op?");
    220       break;
    221   }
    222 }
    223 
    224 static void dump_operands(Writer* w, const Inst* in) {
    225   dump_write(w, " opnds=[");
    226   for (u32 i = 0; i < in->nopnds; ++i) {
    227     if (i) dump_write(w, ",");
    228     dump_operand(w, &in->opnds[i]);
    229   }
    230   dump_write(w, "]");
    231 }
    232 
    233 static void dump_mem(Writer* w, const MemAccess* m) {
    234   char buf[128];
    235   StrBuf sb;
    236   strbuf_init(&sb, buf, sizeof buf);
    237   strbuf_puts(&sb, " mem=size");
    238   strbuf_put_u64(&sb, (u64)(unsigned)m->size);
    239   strbuf_puts(&sb, " align");
    240   strbuf_put_u64(&sb, (u64)(unsigned)m->align);
    241   strbuf_puts(&sb, " flags=");
    242   strbuf_put_hex_u64(&sb, (u64)(unsigned)m->flags);
    243   strbuf_puts(&sb, " alias=");
    244   dump_sb(w, &sb);
    245   dump_alias(w, &m->alias);
    246 }
    247 
    248 static void dump_phi(Writer* w, const Inst* in) {
    249   char buf[96];
    250   StrBuf sb;
    251   IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    252   strbuf_init(&sb, buf, sizeof buf);
    253   strbuf_puts(&sb, " slot=");
    254   strbuf_put_u64(&sb, aux ? (u64)(unsigned)aux->slot_id : 0u);
    255   strbuf_puts(&sb, " preds=[");
    256   dump_sb(w, &sb);
    257   if (aux) {
    258     for (u32 p = 0; p < aux->npreds; ++p) {
    259       strbuf_reset(&sb);
    260       if (p) strbuf_putc(&sb, ',');
    261       strbuf_putc(&sb, 'b');
    262       strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_blocks[p]);
    263       strbuf_puts(&sb, ":v");
    264       strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_vals[p]);
    265       dump_sb(w, &sb);
    266     }
    267   }
    268   dump_write(w, "]");
    269 }
    270 
    271 static void dump_ret(Writer* w, const Inst* in) {
    272   IRRetAux* aux = (IRRetAux*)in->extra.aux;
    273   if (!aux || !aux->present) {
    274     dump_write(w, " ret=void");
    275     return;
    276   }
    277   dump_write(w, " ret=");
    278   dump_operand(w, &aux->val.storage);
    279 }
    280 
    281 void opt_ir_dump(Func* f, Writer* w) {
    282   if (!f || !w) return;
    283   char buf[160];
    284   StrBuf sb;
    285   strbuf_init(&sb, buf, sizeof buf);
    286   strbuf_puts(&sb, "ir blocks=");
    287   strbuf_put_u64(&sb, (u64)(unsigned)f->nblocks);
    288   strbuf_puts(&sb, " vals=");
    289   strbuf_put_u64(&sb, (u64)(unsigned)f->nvals);
    290   strbuf_putc(&sb, '\n');
    291   dump_sb(w, &sb);
    292   for (u32 b = 0; b < f->nblocks; ++b) {
    293     Block* bl = &f->blocks[b];
    294     strbuf_reset(&sb);
    295     strbuf_puts(&sb, "block ");
    296     strbuf_put_u64(&sb, (u64)(unsigned)b);
    297     strbuf_puts(&sb, " preds=[");
    298     dump_sb(w, &sb);
    299     for (u32 p = 0; p < bl->npreds; ++p) {
    300       strbuf_reset(&sb);
    301       if (p) strbuf_putc(&sb, ',');
    302       strbuf_putc(&sb, 'b');
    303       strbuf_put_u64(&sb, (u64)(unsigned)bl->preds[p]);
    304       dump_sb(w, &sb);
    305     }
    306     dump_write(w, "] succs=[");
    307     for (u32 s = 0; s < bl->nsucc; ++s) {
    308       strbuf_reset(&sb);
    309       if (s) strbuf_putc(&sb, ',');
    310       strbuf_putc(&sb, 'b');
    311       strbuf_put_u64(&sb, (u64)(unsigned)bl->succ[s]);
    312       dump_sb(w, &sb);
    313     }
    314     strbuf_reset(&sb);
    315     strbuf_puts(&sb, "] insts=");
    316     strbuf_put_u64(&sb, (u64)(unsigned)bl->ninsts);
    317     strbuf_putc(&sb, '\n');
    318     dump_sb(w, &sb);
    319 
    320     for (u32 i = 0; i < bl->ninsts; ++i) {
    321       Inst* in = &bl->insts[i];
    322       strbuf_reset(&sb);
    323       strbuf_puts(&sb, "  ");
    324       strbuf_put_u64(&sb, (u64)(unsigned)i);
    325       strbuf_putc(&sb, ' ');
    326       strbuf_puts(&sb, op_name((IROp)in->op));
    327       dump_sb(w, &sb);
    328       if (in->def != VAL_NONE) {
    329         strbuf_reset(&sb);
    330         strbuf_puts(&sb, " def=v");
    331         strbuf_put_u64(&sb, (u64)(unsigned)in->def);
    332         dump_sb(w, &sb);
    333       }
    334       if (in->ndefs) {
    335         dump_write(w, " defs=[");
    336         for (u32 d = 0; d < in->ndefs; ++d) {
    337           strbuf_reset(&sb);
    338           if (d) strbuf_putc(&sb, ',');
    339           strbuf_putc(&sb, 'v');
    340           strbuf_put_u64(&sb, (u64)(unsigned)in->defs[d]);
    341           dump_sb(w, &sb);
    342         }
    343         dump_write(w, "]");
    344       }
    345       if (in->nopnds) dump_operands(w, in);
    346       if ((IROp)in->op == IR_LOAD || (IROp)in->op == IR_STORE)
    347         dump_mem(w, &in->extra.mem);
    348       if ((IROp)in->op == IR_LOAD_IMM || (IROp)in->op == IR_CONST_I) {
    349         strbuf_reset(&sb);
    350         strbuf_puts(&sb, " imm=");
    351         strbuf_put_i64(&sb, (i64)in->extra.imm);
    352         dump_sb(w, &sb);
    353       }
    354       if ((IROp)in->op == IR_PHI) dump_phi(w, in);
    355       if ((IROp)in->op == IR_RET) dump_ret(w, in);
    356       dump_write(w, "\n");
    357     }
    358   }
    359 }