kit

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

ir_dump.c (12780B)


      1 /* Textual dump of the semantic CG IR (the recorded CG-API tape).
      2  *
      3  * This renders CgIrFunc — the IR as recorded from the CG API, before any
      4  * lowering to the optimizer's CFG form. It is the only dumper for the Cg* IR;
      5  * the optimizer's Func IR is dumped separately by opt_ir_dump (opt/ir_print.c).
      6  *
      7  * The format is line-oriented and stable enough for golden-file diffs but
      8  * otherwise unspecified. Symbols are rendered by numeric id (sym#N) since the
      9  * dumper has no object-builder handle, matching opt_ir_dump's convention. */
     10 
     11 #include "cg/ir.h"
     12 #include "core/core.h"
     13 #include "core/pool.h"
     14 #include "core/slice.h"
     15 #include "core/strbuf.h"
     16 
     17 static void dump_write(Writer* w, const StrBuf* sb) {
     18   kit_writer_write(w, strbuf_cstr(sb), strbuf_len(sb));
     19 }
     20 
     21 static const char* cg_ir_op_name(CgIrOp op) {
     22   switch (op) {
     23     case CG_IR_NOP:
     24       return "nop";
     25     case CG_IR_LABEL:
     26       return "label";
     27     case CG_IR_LOAD_IMM:
     28       return "load_imm";
     29     case CG_IR_LOAD_CONST:
     30       return "load_const";
     31     case CG_IR_COPY:
     32       return "copy";
     33     case CG_IR_LOAD:
     34       return "load";
     35     case CG_IR_STORE:
     36       return "store";
     37     case CG_IR_ADDR_OF:
     38       return "addr_of";
     39     case CG_IR_TLS_ADDR_OF:
     40       return "tls_addr_of";
     41     case CG_IR_AGG_COPY:
     42       return "agg_copy";
     43     case CG_IR_AGG_SET:
     44       return "agg_set";
     45     case CG_IR_BITFIELD_LOAD:
     46       return "bitfield_load";
     47     case CG_IR_BITFIELD_STORE:
     48       return "bitfield_store";
     49     case CG_IR_BINOP:
     50       return "binop";
     51     case CG_IR_UNOP:
     52       return "unop";
     53     case CG_IR_CMP:
     54       return "cmp";
     55     case CG_IR_CONVERT:
     56       return "convert";
     57     case CG_IR_CALL:
     58       return "call";
     59     case CG_IR_RET:
     60       return "ret";
     61     case CG_IR_UNREACHABLE:
     62       return "unreachable";
     63     case CG_IR_BR:
     64       return "br";
     65     case CG_IR_CMP_BRANCH:
     66       return "cmp_branch";
     67     case CG_IR_SWITCH:
     68       return "switch";
     69     case CG_IR_INDIRECT_BRANCH:
     70       return "indirect_branch";
     71     case CG_IR_LOAD_LABEL_ADDR:
     72       return "load_label_addr";
     73     case CG_IR_LOCAL_STATIC_DATA_BEGIN:
     74       return "local_static_data_begin";
     75     case CG_IR_LOCAL_STATIC_DATA_WRITE:
     76       return "local_static_data_write";
     77     case CG_IR_LOCAL_STATIC_DATA_LABEL_ADDR:
     78       return "local_static_data_label_addr";
     79     case CG_IR_LOCAL_STATIC_DATA_END:
     80       return "local_static_data_end";
     81     case CG_IR_SCOPE_BEGIN:
     82       return "scope_begin";
     83     case CG_IR_SCOPE_END:
     84       return "scope_end";
     85     case CG_IR_BREAK_TO:
     86       return "break_to";
     87     case CG_IR_CONTINUE_TO:
     88       return "continue_to";
     89     case CG_IR_ALLOCA:
     90       return "alloca";
     91     case CG_IR_VA_START:
     92       return "va_start";
     93     case CG_IR_VA_ARG:
     94       return "va_arg";
     95     case CG_IR_VA_END:
     96       return "va_end";
     97     case CG_IR_VA_COPY:
     98       return "va_copy";
     99     case CG_IR_ATOMIC_LOAD:
    100       return "atomic_load";
    101     case CG_IR_ATOMIC_STORE:
    102       return "atomic_store";
    103     case CG_IR_ATOMIC_RMW:
    104       return "atomic_rmw";
    105     case CG_IR_ATOMIC_CAS:
    106       return "atomic_cas";
    107     case CG_IR_FENCE:
    108       return "fence";
    109     case CG_IR_INTRINSIC:
    110       return "intrinsic";
    111     case CG_IR_ASM_BLOCK:
    112       return "asm_block";
    113   }
    114   return "??";
    115 }
    116 
    117 static const char* cg_ir_binop_name(BinOp op) {
    118   switch (op) {
    119     case BO_IADD:
    120       return "iadd";
    121     case BO_ISUB:
    122       return "isub";
    123     case BO_IMUL:
    124       return "imul";
    125     case BO_SDIV:
    126       return "sdiv";
    127     case BO_UDIV:
    128       return "udiv";
    129     case BO_SREM:
    130       return "srem";
    131     case BO_UREM:
    132       return "urem";
    133     case BO_FADD:
    134       return "fadd";
    135     case BO_FSUB:
    136       return "fsub";
    137     case BO_FMUL:
    138       return "fmul";
    139     case BO_FDIV:
    140       return "fdiv";
    141     case BO_AND:
    142       return "and";
    143     case BO_OR:
    144       return "or";
    145     case BO_XOR:
    146       return "xor";
    147     case BO_SHL:
    148       return "shl";
    149     case BO_SHR_S:
    150       return "shr_s";
    151     case BO_SHR_U:
    152       return "shr_u";
    153   }
    154   return "??";
    155 }
    156 
    157 static const char* cg_ir_unop_name(UnOp op) {
    158   switch (op) {
    159     case UO_NEG:
    160       return "neg";
    161     case UO_FNEG:
    162       return "fneg";
    163     case UO_NOT:
    164       return "not";
    165     case UO_BNOT:
    166       return "bnot";
    167   }
    168   return "??";
    169 }
    170 
    171 static const char* cg_ir_cmp_name(CmpOp op) {
    172   switch (op) {
    173     case CMP_EQ:
    174       return "eq";
    175     case CMP_NE:
    176       return "ne";
    177     case CMP_LT_S:
    178       return "lt_s";
    179     case CMP_LE_S:
    180       return "le_s";
    181     case CMP_GT_S:
    182       return "gt_s";
    183     case CMP_GE_S:
    184       return "ge_s";
    185     case CMP_LT_U:
    186       return "lt_u";
    187     case CMP_LE_U:
    188       return "le_u";
    189     case CMP_GT_U:
    190       return "gt_u";
    191     case CMP_GE_U:
    192       return "ge_u";
    193     case CMP_OEQ_F:
    194       return "oeq_f";
    195     case CMP_ONE_F:
    196       return "one_f";
    197     case CMP_OLT_F:
    198       return "olt_f";
    199     case CMP_OLE_F:
    200       return "ole_f";
    201     case CMP_OGT_F:
    202       return "ogt_f";
    203     case CMP_OGE_F:
    204       return "oge_f";
    205     case CMP_UEQ_F:
    206       return "ueq_f";
    207     case CMP_UNE_F:
    208       return "une_f";
    209     case CMP_ULT_F:
    210       return "ult_f";
    211     case CMP_ULE_F:
    212       return "ule_f";
    213     case CMP_UGT_F:
    214       return "ugt_f";
    215     case CMP_UGE_F:
    216       return "uge_f";
    217   }
    218   return "??";
    219 }
    220 
    221 static const char* cg_ir_conv_name(ConvKind op) {
    222   switch (op) {
    223     case CV_SEXT:
    224       return "sext";
    225     case CV_ZEXT:
    226       return "zext";
    227     case CV_TRUNC:
    228       return "trunc";
    229     case CV_ITOF_S:
    230       return "itof_s";
    231     case CV_ITOF_U:
    232       return "itof_u";
    233     case CV_FTOI_S:
    234       return "ftoi_s";
    235     case CV_FTOI_U:
    236       return "ftoi_u";
    237     case CV_FEXT:
    238       return "fext";
    239     case CV_FTRUNC:
    240       return "ftrunc";
    241     case CV_BITCAST:
    242       return "bitcast";
    243   }
    244   return "??";
    245 }
    246 
    247 static void put_type(StrBuf* sb, KitCgTypeId type) {
    248   strbuf_putc(sb, 't');
    249   strbuf_put_u64(sb, (u64)type);
    250 }
    251 
    252 static void put_operand(StrBuf* sb, const Operand* op) {
    253   switch (op->kind) {
    254     case OPK_IMM:
    255       strbuf_put_slice(sb, SLICE_LIT("imm:"));
    256       strbuf_put_i64(sb, op->v.imm);
    257       break;
    258     case OPK_LOCAL:
    259       strbuf_putc(sb, 'L');
    260       strbuf_put_u64(sb, (u64)op->v.local);
    261       break;
    262     case OPK_GLOBAL:
    263       strbuf_put_slice(sb, SLICE_LIT("sym#"));
    264       strbuf_put_u64(sb, (u64)op->v.global.sym);
    265       if (op->v.global.addend) {
    266         strbuf_putc(sb, op->v.global.addend < 0 ? '-' : '+');
    267         strbuf_put_u64(sb, op->v.global.addend < 0
    268                                ? (u64)(-(op->v.global.addend + 1)) + 1u
    269                                : (u64)op->v.global.addend);
    270       }
    271       break;
    272     case OPK_INDIRECT:
    273       strbuf_putc(sb, '[');
    274       strbuf_putc(sb, 'L');
    275       strbuf_put_u64(sb, (u64)op->v.ind.base);
    276       if (op->v.ind.index != CG_LOCAL_NONE) {
    277         strbuf_put_slice(sb, SLICE_LIT("+L"));
    278         strbuf_put_u64(sb, (u64)op->v.ind.index);
    279         strbuf_putc(sb, '*');
    280         strbuf_put_u64(sb, (u64)(1u << op->v.ind.log2_scale));
    281       }
    282       if (op->v.ind.ofs) {
    283         strbuf_putc(sb, op->v.ind.ofs < 0 ? '-' : '+');
    284         strbuf_put_u64(sb, op->v.ind.ofs < 0
    285                                ? (u64)(-((i64)op->v.ind.ofs + 1)) + 1u
    286                                : (u64)op->v.ind.ofs);
    287       }
    288       strbuf_putc(sb, ']');
    289       break;
    290     default:
    291       strbuf_put_slice(sb, SLICE_LIT("?op"));
    292       break;
    293   }
    294   strbuf_putc(sb, ':');
    295   put_type(sb, op->type);
    296 }
    297 
    298 static void put_mem(StrBuf* sb, const MemAccess* m) {
    299   strbuf_put_slice(sb, SLICE_LIT(" mem{sz="));
    300   strbuf_put_u64(sb, (u64)m->size);
    301   strbuf_put_slice(sb, SLICE_LIT(" al="));
    302   strbuf_put_u64(sb, (u64)m->align);
    303   if (m->flags) {
    304     strbuf_put_slice(sb, SLICE_LIT(" fl="));
    305     strbuf_put_hex_u64(sb, (u64)m->flags);
    306   }
    307   strbuf_putc(sb, '}');
    308 }
    309 
    310 static void put_inst_extra(StrBuf* sb, const CgIrFunc* f, const CgIrInst* in) {
    311   switch (in->op) {
    312     case CG_IR_LOAD_IMM:
    313       strbuf_put_slice(sb, SLICE_LIT(" = "));
    314       strbuf_put_i64(sb, in->extra.imm);
    315       break;
    316     case CG_IR_BINOP:
    317       strbuf_putc(sb, ' ');
    318       strbuf_puts(sb, cg_ir_binop_name((BinOp)in->extra.imm));
    319       break;
    320     case CG_IR_UNOP:
    321       strbuf_putc(sb, ' ');
    322       strbuf_puts(sb, cg_ir_unop_name((UnOp)in->extra.imm));
    323       break;
    324     case CG_IR_CMP:
    325       strbuf_putc(sb, ' ');
    326       strbuf_puts(sb, cg_ir_cmp_name((CmpOp)in->extra.imm));
    327       break;
    328     case CG_IR_CONVERT:
    329       strbuf_putc(sb, ' ');
    330       strbuf_puts(sb, cg_ir_conv_name((ConvKind)in->extra.imm));
    331       break;
    332     case CG_IR_BR:
    333     case CG_IR_LABEL:
    334       strbuf_put_slice(sb, SLICE_LIT(" Lbl"));
    335       strbuf_put_u64(sb, (u64)in->extra.imm);
    336       break;
    337     case CG_IR_SCOPE_END:
    338     case CG_IR_BREAK_TO:
    339     case CG_IR_CONTINUE_TO:
    340       strbuf_put_slice(sb, SLICE_LIT(" scope"));
    341       strbuf_put_u64(sb, (u64)in->extra.imm);
    342       break;
    343     case CG_IR_SCOPE_BEGIN: {
    344       const CgIrScopeAux* aux = (const CgIrScopeAux*)in->extra.aux;
    345       if (aux) {
    346         strbuf_put_slice(sb, SLICE_LIT(" scope"));
    347         strbuf_put_u64(sb, (u64)aux->scope);
    348         strbuf_put_slice(sb, SLICE_LIT(" kind="));
    349         strbuf_put_u64(sb, (u64)aux->desc.kind);
    350       }
    351       break;
    352     }
    353     case CG_IR_CMP_BRANCH: {
    354       const CgIrCmpBranchAux* aux = (const CgIrCmpBranchAux*)in->extra.aux;
    355       if (aux) {
    356         strbuf_putc(sb, ' ');
    357         strbuf_puts(sb, cg_ir_cmp_name(aux->op));
    358         strbuf_put_slice(sb, SLICE_LIT(" -> Lbl"));
    359         strbuf_put_u64(sb, (u64)aux->target);
    360       }
    361       break;
    362     }
    363     case CG_IR_CALL: {
    364       const CgIrCallAux* aux = (const CgIrCallAux*)in->extra.aux;
    365       if (aux) {
    366         strbuf_put_slice(sb, SLICE_LIT(" callee="));
    367         put_operand(sb, &aux->desc.callee);
    368         strbuf_put_slice(sb, SLICE_LIT(" args=["));
    369         for (u32 i = 0; i < aux->desc.nargs; ++i) {
    370           if (i) strbuf_putc(sb, ' ');
    371           strbuf_putc(sb, 'L');
    372           strbuf_put_u64(sb, (u64)aux->desc.args[i]);
    373         }
    374         strbuf_put_slice(sb, SLICE_LIT("] result="));
    375         if (aux->desc.result != CG_LOCAL_NONE) {
    376           strbuf_putc(sb, 'L');
    377           strbuf_put_u64(sb, (u64)aux->desc.result);
    378         } else {
    379           strbuf_putc(sb, '-');
    380         }
    381         if (aux->desc.flags & CG_CALL_TAIL)
    382           strbuf_put_slice(sb, SLICE_LIT(" tail"));
    383       }
    384       break;
    385     }
    386     case CG_IR_RET: {
    387       const CgIrRetAux* aux = (const CgIrRetAux*)in->extra.aux;
    388       if (aux) {
    389         strbuf_put_slice(sb, SLICE_LIT(" value="));
    390         if (aux->present) {
    391           strbuf_putc(sb, 'L');
    392           strbuf_put_u64(sb, (u64)aux->value);
    393         } else {
    394           strbuf_putc(sb, '-');
    395         }
    396       }
    397       break;
    398     }
    399     case CG_IR_LOAD:
    400     case CG_IR_STORE:
    401       put_mem(sb, &in->extra.mem);
    402       break;
    403     default:
    404       break;
    405   }
    406   (void)f;
    407 }
    408 
    409 void cg_ir_func_dump(const CgIrFunc* f, Writer* w) {
    410   char buf[1024];
    411   StrBuf sb;
    412   if (!f || !w) return;
    413   strbuf_init(&sb, buf, sizeof buf);
    414 
    415   strbuf_put_slice(&sb, SLICE_LIT("func sym#"));
    416   strbuf_put_u64(&sb, (u64)f->desc.sym);
    417   strbuf_put_slice(&sb, SLICE_LIT(" params="));
    418   strbuf_put_u64(&sb, (u64)f->nparams);
    419   strbuf_put_slice(&sb, SLICE_LIT(" locals="));
    420   strbuf_put_u64(&sb, (u64)f->nlocals);
    421   strbuf_put_slice(&sb, SLICE_LIT(" labels="));
    422   strbuf_put_u64(&sb, (u64)f->nlabels);
    423   strbuf_put_slice(&sb, SLICE_LIT(" scopes="));
    424   strbuf_put_u64(&sb, (u64)f->nscopes);
    425   strbuf_put_slice(&sb, SLICE_LIT(" insts="));
    426   strbuf_put_u64(&sb, (u64)f->ninsts);
    427   strbuf_putc(&sb, '\n');
    428   dump_write(w, &sb);
    429 
    430   for (u32 i = 0; i < f->nlocals; ++i) {
    431     const CgIrLocal* l = &f->locals[i];
    432     strbuf_reset(&sb);
    433     strbuf_put_slice(&sb, SLICE_LIT("  local L"));
    434     strbuf_put_u64(&sb, (u64)l->id);
    435     strbuf_putc(&sb, ' ');
    436     put_type(&sb, l->desc.type);
    437     strbuf_put_slice(&sb, SLICE_LIT(" sz="));
    438     strbuf_put_u64(&sb, (u64)l->desc.size);
    439     strbuf_put_slice(&sb, SLICE_LIT(" al="));
    440     strbuf_put_u64(&sb, (u64)l->desc.align);
    441     if (l->desc.name) {
    442       Slice nm = pool_slice(f->c->global, l->desc.name);
    443       strbuf_put_slice(&sb, SLICE_LIT(" \""));
    444       strbuf_put_slice(&sb, nm);
    445       strbuf_putc(&sb, '"');
    446     }
    447     if (l->is_param) {
    448       strbuf_put_slice(&sb, SLICE_LIT(" param#"));
    449       strbuf_put_u64(&sb, (u64)l->param_index);
    450     }
    451     if (l->address_taken) strbuf_put_slice(&sb, SLICE_LIT(" addr_taken"));
    452     strbuf_putc(&sb, '\n');
    453     dump_write(w, &sb);
    454   }
    455 
    456   for (u32 i = 0; i < f->ninsts; ++i) {
    457     const CgIrInst* in = &f->insts[i];
    458     strbuf_reset(&sb);
    459     strbuf_put_slice(&sb, SLICE_LIT("  "));
    460     strbuf_put_u64(&sb, (u64)i);
    461     strbuf_put_slice(&sb, SLICE_LIT(": "));
    462     strbuf_puts(&sb, cg_ir_op_name((CgIrOp)in->op));
    463     for (u32 j = 0; j < in->nopnds; ++j) {
    464       strbuf_putc(&sb, ' ');
    465       put_operand(&sb, &in->opnds[j]);
    466     }
    467     put_inst_extra(&sb, f, in);
    468     strbuf_putc(&sb, '\n');
    469     dump_write(w, &sb);
    470   }
    471 }