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 }