/** * @file scc_lir_dump.c * @brief LIR 文本 dump 实现 */ #include "scc_lir_dump.h" #include static const char *op_to_string(scc_lir_op_t op) { switch (op) { case SCC_LIR_MOV: return "mov"; case SCC_LIR_LOAD: return "load"; case SCC_LIR_LOAD_ADDR: return "load.addr"; case SCC_LIR_STORE: return "store"; // case SCC_LIR_STORE_ADDR: // return "store.addr"; case SCC_LIR_ADD: return "add"; case SCC_LIR_SUB: return "sub"; case SCC_LIR_MUL: return "mul"; case SCC_LIR_DIV_S: return "div.s"; case SCC_LIR_DIV_U: return "div.u"; case SCC_LIR_REM_S: return "rem.s"; case SCC_LIR_REM_U: return "rem.u"; case SCC_LIR_AND: return "and"; case SCC_LIR_OR: return "or"; case SCC_LIR_XOR: return "xor"; case SCC_LIR_SHL: return "shl"; case SCC_LIR_SHR: return "shr"; case SCC_LIR_SAR: return "sar"; case SCC_LIR_NEG: return "neg"; case SCC_LIR_NOT: return "not"; case SCC_LIR_FADD: return "fadd"; case SCC_LIR_FSUB: return "fsub"; case SCC_LIR_FMUL: return "fmul"; case SCC_LIR_FDIV: return "fdiv"; case SCC_LIR_FNEG: return "fneg"; case SCC_LIR_FCVT: return "fcvt"; case SCC_LIR_CMP: return "cmp"; case SCC_LIR_BR: return "br"; case SCC_LIR_JMP: return "jmp"; case SCC_LIR_JMP_INDIRECT: return "jmp.indirect"; case SCC_LIR_CALL: return "call"; case SCC_LIR_CALL_INDIRECT: return "call.indirect"; case SCC_LIR_RET: return "ret"; case SCC_LIR_PARALLEL_COPY: return "parallel_copy"; case SCC_LIR_VA_START: return "va_start"; case SCC_LIR_VA_ARG: return "va_arg"; case SCC_LIR_VA_END: return "va_end"; case SCC_LIR_VA_COPY: return "va_copy"; case SCC_LIR_ALLOCA: return "alloca"; case SCC_LIR_MEMCPY: return "memcpy"; case SCC_LIR_MEMSET: return "memset"; case SCC_LIR_NOP: return "nop"; default: return "???"; } } static const char *cond_to_string(scc_lir_cond_t cond) { switch (cond) { case SCC_LIR_COND_EQ: return "eq"; case SCC_LIR_COND_NE: return "ne"; case SCC_LIR_COND_SLT: return "slt"; case SCC_LIR_COND_SLE: return "sle"; case SCC_LIR_COND_SGT: return "sgt"; case SCC_LIR_COND_SGE: return "sge"; case SCC_LIR_COND_ULT: return "ult"; case SCC_LIR_COND_ULE: return "ule"; case SCC_LIR_COND_UGT: return "ugt"; case SCC_LIR_COND_UGE: return "uge"; case SCC_LIR_COND_FEQ: return "feq"; case SCC_LIR_COND_FNE: return "fne"; case SCC_LIR_COND_FLT: return "flt"; case SCC_LIR_COND_FLE: return "fle"; case SCC_LIR_COND_FGT: return "fgt"; case SCC_LIR_COND_FGE: return "fge"; default: return "???"; } } static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) { scc_tree_dump_t *td = ctx->dump_ctx; switch (op->kind) { case SCC_LIR_INSTR_KIND_NONE: scc_tree_dump_append(td, "_"); break; case SCC_LIR_INSTR_KIND_ARG: scc_tree_dump_append_fmt(td, "arg[%u]", op->data.arg); break; case SCC_LIR_INSTR_KIND_VREG: scc_tree_dump_append_fmt(td, "%%%u", op->data.reg); break; // case SCC_LIR_INSTR_KIND_PREG: // scc_tree_dump_append_fmt(td, "Phy%u", op->data.reg); // break; case SCC_LIR_INSTR_KIND_IMM: // TODO hack ap scc_tree_dump_append_fmt(td, "%lld", op->data.imm.data.digit); break; case SCC_LIR_INSTR_KIND_FIMM: TODO(); scc_tree_dump_append_fmt(td, "%lf", op->data.fimm); break; case SCC_LIR_INSTR_KIND_SYMBOL: scc_tree_dump_append_fmt(td, "@%s", op->data.symbol ? op->data.symbol : ""); break; default: scc_tree_dump_append(td, ""); } } static void dump_size_ext(scc_lir_dump_ctx_t *ctx, u8 size, scc_lir_ext_t ext) { scc_tree_dump_t *td = ctx->dump_ctx; const char *size_str = ""; if (size == SCC_LIR_SIZE_8) size_str = "8"; else if (size == SCC_LIR_SIZE_16) size_str = "16"; else if (size == SCC_LIR_SIZE_32) size_str = "32"; else if (size == SCC_LIR_SIZE_64) size_str = "64"; else size_str = "sz(?)"; const char *ext_str = ""; if (ext == SCC_LIR_EXT_SEXT) ext_str = ".s"; else if (ext == SCC_LIR_EXT_ZEXT) ext_str = ".u"; else if (ext == SCC_LIR_EXT_FLOAT) ext_str = ".f"; if (size_str[0] || ext_str[0]) { scc_tree_dump_append_fmt(td, ".%s%s", size_str, ext_str); } } void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) { Assert(ctx != nullptr && ins != nullptr); scc_tree_dump_t *td = ctx->dump_ctx; scc_tree_dump_begin_line(td); scc_tree_dump_append(td, " "); // 输出操作码(带节点颜色) scc_tree_dump_node(td, "%s", op_to_string(ins->op)); // 输出宽度和扩展标志 dump_size_ext(ctx, ins->size, ins->ext); scc_tree_dump_append(td, " "); switch (ins->op) { case SCC_LIR_MOV: case SCC_LIR_LOAD: dump_operand(ctx, &ins->to); scc_tree_dump_append(td, " <- "); dump_operand(ctx, &ins->arg0); break; case SCC_LIR_LOAD_ADDR: // base + index * scale + offset dump_operand(ctx, &ins->to); scc_tree_dump_append(td, " <- ("); dump_operand(ctx, &ins->arg0); // base scc_tree_dump_append(td, " + "); dump_operand(ctx, &ins->arg1); // index scc_tree_dump_append_fmt(td, " * %d + %lld)", ins->metadata.addr.scale, ins->metadata.addr.offset); break; case SCC_LIR_NEG: case SCC_LIR_NOT: case SCC_LIR_FNEG: case SCC_LIR_FCVT: dump_operand(ctx, &ins->to); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->arg0); break; case SCC_LIR_ALLOCA: scc_tree_dump_append_fmt(td, "(sz=%zd,al=%zd) => ", ins->metadata.alloca.size_bytes, ins->metadata.alloca.align_bytes); dump_operand(ctx, &ins->to); break; // case SCC_LIR_STORE_ADDR: case SCC_LIR_STORE: dump_operand(ctx, &ins->arg0); scc_tree_dump_append(td, " -> "); dump_operand(ctx, &ins->arg1); break; case SCC_LIR_ADD: case SCC_LIR_SUB: case SCC_LIR_MUL: case SCC_LIR_DIV_S: case SCC_LIR_DIV_U: case SCC_LIR_REM_S: case SCC_LIR_REM_U: case SCC_LIR_AND: case SCC_LIR_OR: case SCC_LIR_XOR: case SCC_LIR_SHL: case SCC_LIR_SHR: case SCC_LIR_SAR: case SCC_LIR_FADD: case SCC_LIR_FSUB: case SCC_LIR_FMUL: case SCC_LIR_FDIV: dump_operand(ctx, &ins->to); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->arg0); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->arg1); break; case SCC_LIR_CMP: dump_operand(ctx, &ins->to); scc_tree_dump_append_fmt(td, ", %s, ", cond_to_string(ins->metadata.cond)); dump_operand(ctx, &ins->arg0); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->arg1); break; case SCC_LIR_BR: dump_operand(ctx, &ins->arg0); scc_tree_dump_append_fmt(td, ", BB#%zu, BB#%zu", ins->metadata.br.true_target, ins->metadata.br.false_target); break; case SCC_LIR_JMP: scc_tree_dump_append_fmt(td, "#BB%d", ins->metadata.jmp_target); break; case SCC_LIR_JMP_INDIRECT: dump_operand(ctx, &ins->arg0); break; case SCC_LIR_CALL: { const struct scc_lir_call *c = &ins->metadata.call; if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) { dump_operand(ctx, &c->ret_vreg); scc_tree_dump_append(td, " = "); } scc_tree_dump_append_fmt(td, "call @%s(", c->callee ? c->callee : ""); for (u8 i = 0; i < c->arg_count; i++) { if (i > 0) scc_tree_dump_append(td, ", "); dump_operand(ctx, &c->args[i]); } scc_tree_dump_append_fmt(td, ") clobber=0x%llx", (unsigned long long)c->clobber_mask); } break; case SCC_LIR_CALL_INDIRECT: { const struct scc_lir_call_indirect *c = &ins->metadata.call_indirect; if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) { dump_operand(ctx, &c->ret_vreg); scc_tree_dump_append(td, " = "); } scc_tree_dump_append(td, "call "); dump_operand(ctx, &c->target); scc_tree_dump_append(td, "("); for (u8 i = 0; i < c->arg_count; i++) { if (i > 0) scc_tree_dump_append(td, ", "); dump_operand(ctx, &c->args[i]); } scc_tree_dump_append_fmt(td, ") clobber=0x%llx", (unsigned long long)c->clobber_mask); } break; case SCC_LIR_RET: if (ins->metadata.ret_val.kind != SCC_LIR_INSTR_KIND_NONE) { dump_operand(ctx, &ins->metadata.ret_val); } break; case SCC_LIR_PARALLEL_COPY: { const struct scc_lir_parallel_copy *pc = &ins->metadata.parallel_copy; scc_tree_dump_append(td, "["); for (u8 i = 0; i < pc->num_copies; i++) { if (i > 0) scc_tree_dump_append(td, ", "); dump_operand(ctx, &pc->dests[i]); scc_tree_dump_append(td, " <- "); dump_operand(ctx, &pc->srcs[i]); } scc_tree_dump_append(td, "]"); break; } case SCC_LIR_VA_START: dump_operand(ctx, &ins->metadata.va_start.ap); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->metadata.va_start.last); break; case SCC_LIR_VA_ARG: dump_operand(ctx, &ins->metadata.va_arg.to); scc_tree_dump_append(td, " = va_arg "); dump_operand(ctx, &ins->metadata.va_arg.ap); scc_tree_dump_append_fmt( td, ", size=%u, align=%u, float=%d", ins->metadata.va_arg.type_size, ins->metadata.va_arg.type_align, ins->metadata.va_arg.is_float); break; case SCC_LIR_VA_END: dump_operand(ctx, &ins->metadata.va_end.ap); break; case SCC_LIR_VA_COPY: dump_operand(ctx, &ins->metadata.va_copy.dest); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->metadata.va_copy.src); break; case SCC_LIR_MEMCPY: dump_operand(ctx, &ins->metadata.memcpy.dest); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->metadata.memcpy.src); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->metadata.memcpy.size); break; case SCC_LIR_MEMSET: dump_operand(ctx, &ins->metadata.memset.dest); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->metadata.memset.value); scc_tree_dump_append(td, ", "); dump_operand(ctx, &ins->metadata.memset.size); break; case SCC_LIR_NOP: break; } } void scc_lir_dump_bblock(scc_lir_dump_ctx_t *ctx, const scc_lir_bblock_t *bb) { Assert(ctx != nullptr && bb != nullptr); scc_tree_dump_t *td = ctx->dump_ctx; // 基本块头部 scc_tree_dump_begin_line(td); scc_tree_dump_node(td, "#BB%zu", bb->id); if (bb->name) { scc_tree_dump_append_fmt(td, " (%s)", bb->name); } scc_tree_dump_append(td, ":"); // 输出每条指令 scc_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb); scc_vec_foreach(*instrs, i) { const scc_lir_instr_t *ins = &scc_vec_at(*instrs, i); scc_lir_dump_ins(ctx, ins); } } void scc_lir_dump_func(scc_lir_dump_ctx_t *ctx, const scc_lir_func_t *func) { Assert(ctx != nullptr && func != nullptr); scc_tree_dump_t *td = ctx->dump_ctx; scc_lir_func_meta_t *meta = SCC_LIR_FUNC_META(func); // 函数头部 scc_tree_dump_begin_line(td); scc_tree_dump_node(td, "func @%s%s", func->name ? func->name : "", meta->is_va_arg ? "(...)" : "()"); scc_tree_dump_append_fmt(td, " (vregs: %u, frame: %d)", meta->vregs_count, meta->frame_size); if (meta->attr != SCC_LIR_ATTR_NONE) { scc_tree_dump_append(td, " [attr:"); if (meta->attr & SCC_LIR_ATTR_STATIC) scc_tree_dump_append(td, " static"); if (meta->attr & SCC_LIR_ATTR_WEAK) scc_tree_dump_append(td, " weak"); scc_tree_dump_append(td, " ]"); } scc_tree_dump_append(td, " {"); // 输出所有基本块 scc_vec_foreach(func->bblocks, i) { scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i); const scc_cfg_bblock_t *bb = scc_cfg_module_unsafe_get_bblock(&ctx->lir_module->cfg_module, id); scc_lir_dump_bblock(ctx, bb); } scc_tree_dump_begin_line(td); scc_tree_dump_append(td, "}"); } void scc_lir_dump_module(scc_lir_dump_ctx_t *ctx) { scc_vec_foreach(ctx->lir_module->cfg_module.symbols, i) { // FIXME 0 is null if (i == 0) continue; scc_lir_symbol_t *sym = &scc_vec_at(ctx->lir_module->cfg_module.symbols, i); scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "symbol"); scc_lir_symbol_meta_t *meta = SCC_LIR_SYMBOL_META(sym); scc_tree_dump_append_fmt(ctx->dump_ctx, " %s", sym->name); if (sym->kind == SCC_CFG_SYMBOL_KIND_DATA) { scc_tree_dump_append_fmt(ctx->dump_ctx, "(size=%zu)", meta->data.size); } } scc_vec_foreach(ctx->lir_module->cfg_module.funcs, i) { if (i == 0) continue; scc_lir_dump_func(ctx, &scc_vec_at(ctx->lir_module->cfg_module.funcs, i)); } }