kit

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

ir_print.c (10643B)


      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_STACK:
    205       strbuf_puts(&sb, "stack#");
    206       strbuf_put_u64(&sb, (u64)(unsigned)op->v.frame_slot);
    207       dump_sb(w, &sb);
    208       break;
    209     case OPK_FRAME_ADDR:
    210       strbuf_puts(&sb, "&frame#");
    211       strbuf_put_u64(&sb, (u64)(unsigned)op->v.frame_slot);
    212       dump_sb(w, &sb);
    213       break;
    214     case OPK_GLOBAL:
    215       strbuf_puts(&sb, "global#");
    216       strbuf_put_u64(&sb, (u64)(unsigned)op->v.global.sym);
    217       strbuf_put_i64_plus(&sb, (i64)op->v.global.addend);
    218       dump_sb(w, &sb);
    219       break;
    220     case OPK_INDIRECT:
    221       strbuf_putc(&sb, '[');
    222       if (op->v.ind.base_kind == OPT_INDIRECT_FRAME)
    223         strbuf_puts(&sb, "frame-value#");
    224       else if (op->v.ind.base_kind == OPT_INDIRECT_FRAME_ADDR)
    225         strbuf_puts(&sb, "frame#");
    226       else
    227         strbuf_putc(&sb, 'v');
    228       strbuf_put_u64(&sb, (u64)(unsigned)op->v.ind.base);
    229       if (op->v.ind.index_kind != OPT_INDIRECT_REG ||
    230           op->v.ind.index != (Reg)REG_NONE) {
    231         strbuf_puts(&sb, "+");
    232         if (op->v.ind.index_kind == OPT_INDIRECT_FRAME)
    233           strbuf_puts(&sb, "frame-value#");
    234         else if (op->v.ind.index_kind == OPT_INDIRECT_FRAME_ADDR)
    235           strbuf_puts(&sb, "frame#");
    236         else
    237           strbuf_putc(&sb, 'v');
    238         strbuf_put_u64(&sb, (u64)(unsigned)op->v.ind.index);
    239         if (op->v.ind.log2_scale) {
    240           strbuf_puts(&sb, "<<");
    241           strbuf_put_u64(&sb, op->v.ind.log2_scale);
    242         }
    243       }
    244       strbuf_put_i64_plus(&sb, (i64)(int)op->v.ind.ofs);
    245       strbuf_putc(&sb, ']');
    246       dump_sb(w, &sb);
    247       break;
    248     default:
    249       dump_write(w, "op?");
    250       break;
    251   }
    252 }
    253 
    254 static void dump_operands(Writer* w, const Inst* in) {
    255   dump_write(w, " opnds=[");
    256   for (u32 i = 0; i < in->nopnds; ++i) {
    257     if (i) dump_write(w, ",");
    258     dump_operand(w, &in->opnds[i]);
    259   }
    260   dump_write(w, "]");
    261 }
    262 
    263 static void dump_mem(Writer* w, const MemAccess* m) {
    264   char buf[128];
    265   StrBuf sb;
    266   strbuf_init(&sb, buf, sizeof buf);
    267   strbuf_puts(&sb, " mem=size");
    268   strbuf_put_u64(&sb, (u64)(unsigned)m->size);
    269   strbuf_puts(&sb, " align");
    270   strbuf_put_u64(&sb, (u64)(unsigned)m->align);
    271   strbuf_puts(&sb, " flags=");
    272   strbuf_put_hex_u64(&sb, (u64)(unsigned)m->flags);
    273   strbuf_puts(&sb, " alias=");
    274   dump_sb(w, &sb);
    275   dump_alias(w, &m->alias);
    276 }
    277 
    278 static void dump_phi(Writer* w, const Inst* in) {
    279   char buf[96];
    280   StrBuf sb;
    281   IRPhiAux* aux = (IRPhiAux*)in->extra.aux;
    282   strbuf_init(&sb, buf, sizeof buf);
    283   strbuf_puts(&sb, " slot=");
    284   strbuf_put_u64(&sb, aux ? (u64)(unsigned)aux->slot_id : 0u);
    285   strbuf_puts(&sb, " preds=[");
    286   dump_sb(w, &sb);
    287   if (aux) {
    288     for (u32 p = 0; p < aux->npreds; ++p) {
    289       strbuf_reset(&sb);
    290       if (p) strbuf_putc(&sb, ',');
    291       strbuf_putc(&sb, 'b');
    292       strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_blocks[p]);
    293       strbuf_puts(&sb, ":v");
    294       strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_vals[p]);
    295       dump_sb(w, &sb);
    296     }
    297   }
    298   dump_write(w, "]");
    299 }
    300 
    301 static void dump_ret(Writer* w, const Inst* in) {
    302   IRRetAux* aux = (IRRetAux*)in->extra.aux;
    303   if (!aux || !aux->present) {
    304     dump_write(w, " ret=void");
    305     return;
    306   }
    307   dump_write(w, " ret=");
    308   dump_operand(w, &aux->val.storage);
    309 }
    310 
    311 void opt_ir_dump(Func* f, Writer* w) {
    312   if (!f || !w) return;
    313   char buf[160];
    314   StrBuf sb;
    315   strbuf_init(&sb, buf, sizeof buf);
    316   strbuf_puts(&sb, "ir blocks=");
    317   strbuf_put_u64(&sb, (u64)(unsigned)f->nblocks);
    318   strbuf_puts(&sb, " vals=");
    319   strbuf_put_u64(&sb, (u64)(unsigned)f->nvals);
    320   strbuf_putc(&sb, '\n');
    321   dump_sb(w, &sb);
    322   for (u32 b = 0; b < f->nblocks; ++b) {
    323     Block* bl = &f->blocks[b];
    324     strbuf_reset(&sb);
    325     strbuf_puts(&sb, "block ");
    326     strbuf_put_u64(&sb, (u64)(unsigned)b);
    327     strbuf_puts(&sb, " preds=[");
    328     dump_sb(w, &sb);
    329     for (u32 p = 0; p < bl->npreds; ++p) {
    330       strbuf_reset(&sb);
    331       if (p) strbuf_putc(&sb, ',');
    332       strbuf_putc(&sb, 'b');
    333       strbuf_put_u64(&sb, (u64)(unsigned)bl->preds[p]);
    334       dump_sb(w, &sb);
    335     }
    336     dump_write(w, "] succs=[");
    337     for (u32 s = 0; s < bl->nsucc; ++s) {
    338       strbuf_reset(&sb);
    339       if (s) strbuf_putc(&sb, ',');
    340       strbuf_putc(&sb, 'b');
    341       strbuf_put_u64(&sb, (u64)(unsigned)bl->succ[s]);
    342       dump_sb(w, &sb);
    343     }
    344     strbuf_reset(&sb);
    345     strbuf_puts(&sb, "] insts=");
    346     strbuf_put_u64(&sb, (u64)(unsigned)bl->ninsts);
    347     strbuf_putc(&sb, '\n');
    348     dump_sb(w, &sb);
    349 
    350     for (u32 i = 0; i < bl->ninsts; ++i) {
    351       Inst* in = &bl->insts[i];
    352       strbuf_reset(&sb);
    353       strbuf_puts(&sb, "  ");
    354       strbuf_put_u64(&sb, (u64)(unsigned)i);
    355       strbuf_putc(&sb, ' ');
    356       strbuf_puts(&sb, op_name((IROp)in->op));
    357       dump_sb(w, &sb);
    358       if (in->def != VAL_NONE) {
    359         strbuf_reset(&sb);
    360         strbuf_puts(&sb, " def=v");
    361         strbuf_put_u64(&sb, (u64)(unsigned)in->def);
    362         dump_sb(w, &sb);
    363       }
    364       if (in->ndefs) {
    365         dump_write(w, " defs=[");
    366         for (u32 d = 0; d < in->ndefs; ++d) {
    367           strbuf_reset(&sb);
    368           if (d) strbuf_putc(&sb, ',');
    369           strbuf_putc(&sb, 'v');
    370           strbuf_put_u64(&sb, (u64)(unsigned)in->defs[d]);
    371           dump_sb(w, &sb);
    372         }
    373         dump_write(w, "]");
    374       }
    375       if (in->nopnds) dump_operands(w, in);
    376       if ((IROp)in->op == IR_LOAD || (IROp)in->op == IR_STORE)
    377         dump_mem(w, &in->extra.mem);
    378       if ((IROp)in->op == IR_LOAD_IMM || (IROp)in->op == IR_CONST_I) {
    379         strbuf_reset(&sb);
    380         strbuf_puts(&sb, " imm=");
    381         strbuf_put_i64(&sb, (i64)in->extra.imm);
    382         dump_sb(w, &sb);
    383       }
    384       if ((IROp)in->op == IR_PHI) dump_phi(w, in);
    385       if ((IROp)in->op == IR_RET) dump_ret(w, in);
    386       dump_write(w, "\n");
    387     }
    388   }
    389 }