diff --git a/libs/ir/hir/src/scc_hir_dump.c b/libs/ir/hir/src/scc_hir_dump.c index c66c3cf..a8d04b0 100644 --- a/libs/ir/hir/src/scc_hir_dump.c +++ b/libs/ir/hir/src/scc_hir_dump.c @@ -658,9 +658,9 @@ void scc_hir_dump_func_linear(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref, scc_tree_dump_append(ctx->dump_ctx, ""); return; } - scc_tree_dump_append_fmt(ctx->dump_ctx, "func @%s", - (func->name && func->name[0]) ? func->name - : ""); + scc_tree_dump_node(ctx->dump_ctx, "func @%s", + (func->name && func->name[0]) ? func->name + : ""); if (scc_vec_size(SCC_HIR_FUNC_META(func)->params) > 0) { scc_tree_dump_append(ctx->dump_ctx, "("); diff --git a/libs/ir/mir/include/core_pass/scc_frame_layout.h b/libs/ir/mir/include/core_pass/scc_frame_layout.h index 59c6535..70dcc35 100644 --- a/libs/ir/mir/include/core_pass/scc_frame_layout.h +++ b/libs/ir/mir/include/core_pass/scc_frame_layout.h @@ -3,10 +3,15 @@ #include "../scc_mir_module.h" -typedef struct scc_frame_layout { - scc_mir_func_t *func; -} scc_frame_layout_t; +struct scc_frame_layout; +typedef struct scc_frame_layout scc_frame_layout_t; +typedef void (*scc_frame_layout_impl_fn)(scc_frame_layout_t *ctx, + scc_mir_module_t *mir_module, + scc_mir_func_t *mir_func); -void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module); +struct scc_frame_layout { + scc_frame_layout_impl_fn impl_fn; + int offset; +}; #endif /* __SCC_FRAME_LAYOUT_H__ */ diff --git a/libs/ir/mir/include/core_pass/scc_prolog_epilog.h b/libs/ir/mir/include/core_pass/scc_prolog_epilog.h index 9d32b7e..00ba1f6 100644 --- a/libs/ir/mir/include/core_pass/scc_prolog_epilog.h +++ b/libs/ir/mir/include/core_pass/scc_prolog_epilog.h @@ -1,8 +1,9 @@ #ifndef __SCC_PROLOG_EPILOG_H__ #define __SCC_PROLOG_EPILOG_H__ +#include "../scc_mir_module.h" #include -#include + typedef void (*scc_prolog_epilog_fn)(void *userdata, const scc_mir_func_t *func); diff --git a/libs/ir/mir/include/scc_mir.h b/libs/ir/mir/include/scc_mir.h index 003c80b..8a653b1 100644 --- a/libs/ir/mir/include/scc_mir.h +++ b/libs/ir/mir/include/scc_mir.h @@ -7,12 +7,13 @@ typedef enum { SCC_MIR_OP_NONE, - SCC_MIR_OP_MEM, // 内存访问 - SCC_MIR_OP_VREG, // 虚拟寄存器 - SCC_MIR_OP_PREG, // 物理寄存器 - SCC_MIR_OP_IMM, // 立即数 - SCC_MIR_OP_SYMBOL, // 符号地址(用于重定位) - SCC_MIR_OP_BLOCK // 基本块引用(label) + SCC_MIR_OP_STACK_OFFSET, // 已分配的内存 + SCC_MIR_OP_STACK_SLOT, // 栈空间 + SCC_MIR_OP_VREG, // 虚拟寄存器 + SCC_MIR_OP_PREG, // 物理寄存器 + SCC_MIR_OP_IMM, // 立即数 + SCC_MIR_OP_SYMBOL, // 符号地址(用于重定位) + SCC_MIR_OP_BLOCK // 基本块引用(label) } scc_mir_op_kind_t; typedef struct scc_mir_operand { @@ -23,6 +24,7 @@ typedef struct scc_mir_operand { i64 imm; // 立即数 const char *symbol; // 符号名 int stack_slot; // 栈槽 ID (由 FrameLayout 分配) + int stack_offset; // 栈偏移 scc_lir_bblock_id_t block_id; // 目标基本块 }; } scc_mir_operand_t; @@ -78,5 +80,10 @@ void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg, void scc_mir_vreg_map2preg(scc_mir_func_t *func, int vreg, int preg); int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align); +static inline scc_mir_stack_slot_t * +scc_mir_unsafe_slot(const scc_mir_func_t *func, int slot) { + Assert(slot > 0); + return &scc_vec_at(SCC_MIR_FUNC_META(func)->stack_slots, slot); +} #endif /* __SCC_MIR_H__ */ diff --git a/libs/ir/mir/include/target/scc_win64.h b/libs/ir/mir/include/target/scc_win64.h index 9525af6..9fc9cb0 100644 --- a/libs/ir/mir/include/target/scc_win64.h +++ b/libs/ir/mir/include/target/scc_win64.h @@ -2,8 +2,13 @@ #define __SCC_WIN64_H__ #include "../arch/x86_64_isel.h" +#include "../core_pass/scc_frame_layout.h" +#include "../core_pass/scc_prolog_epilog.h" #include "../core_pass/scc_reg_alloc.h" + void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering); -void scc_reg_alloc_fill_win_x64(scc_reg_alloc_op_t *ops); +void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops); +void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx); +void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx); #endif diff --git a/libs/ir/mir/src/arch/x86_64_isel.c b/libs/ir/mir/src/arch/x86_64_isel.c index 0d40eea..ef6018e 100644 --- a/libs/ir/mir/src/arch/x86_64_isel.c +++ b/libs/ir/mir/src/arch/x86_64_isel.c @@ -36,9 +36,11 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) { case SCC_MIR_OP_SYMBOL: scc_tree_dump_append_fmt(td, "@%s", op->symbol); break; - case SCC_MIR_OP_MEM: + case SCC_MIR_OP_STACK_SLOT: scc_tree_dump_append_fmt(td, "[%d]", op->stack_slot); break; + case SCC_MIR_OP_STACK_OFFSET: + scc_tree_dump_append_fmt(td, "[sp, %d]", op->stack_offset); default: break; } @@ -99,12 +101,12 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst, dst, src); } else if (src.kind == SCC_MIR_OP_SYMBOL) { add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, dst, src); - } else if (src.kind == SCC_MIR_OP_MEM) { + } else if (src.kind == SCC_MIR_OP_STACK_SLOT) { add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src); } else { UNREACHABLE(); } - } else if (dst.kind == SCC_MIR_OP_MEM) { + } else if (dst.kind == SCC_MIR_OP_STACK_SLOT) { if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) { add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src); } else if (src.kind == SCC_MIR_OP_IMM) { @@ -113,7 +115,7 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst, scc_mir_operand_t temp = new_vreg_temp(isel); add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, temp, src); add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, temp); - } else if (src.kind == SCC_MIR_OP_MEM) { + } else if (src.kind == SCC_MIR_OP_STACK_SLOT) { scc_mir_operand_t temp = new_vreg_temp(isel); scc_x86_emit_move(isel, temp, src, size); scc_x86_emit_move(isel, dst, temp, size); @@ -209,7 +211,8 @@ static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op, } static scc_mir_operand_t stack_slot_op(int offset) { - return (scc_mir_operand_t){.kind = SCC_MIR_OP_MEM, .stack_slot = offset}; + return (scc_mir_operand_t){.kind = SCC_MIR_OP_STACK_SLOT, + .stack_slot = offset}; } static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int offset) { @@ -281,6 +284,11 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) { case SCC_LIR_MUL: // imul dst, src0, src1 → 需要 mov + imul emit_copy_if_needed(isel, dst, src0, size); + if (src1.kind == SCC_MIR_OP_IMM) { + scc_mir_operand_t op = new_vreg_temp(isel); + scc_x86_emit_move(isel, op, src1, size); + src1 = op; + } add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1); break; @@ -421,6 +429,8 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) { .imm = instr->size, }); Assert(op.kind == SCC_MIR_OP_VREG); + // FIXME + scc_mir_vreg_map2slot(isel->func, op.vreg, instr->size, 8); break; /* ---- 其他(占位) ---- */ diff --git a/libs/ir/mir/src/arch/x86_64_reg_alloc.c b/libs/ir/mir/src/arch/x86_64_reg_alloc.c index fbe24dd..4e3be5d 100644 --- a/libs/ir/mir/src/arch/x86_64_reg_alloc.c +++ b/libs/ir/mir/src/arch/x86_64_reg_alloc.c @@ -5,7 +5,7 @@ static void x86_emit_spill(scc_mir_instr_vec_t *ctx, int preg, int slot) { scc_mir_instr_t ins = { .opcode = SCC_X86_IFORM_MOV_MEMV_GPRV, .num_operands = 2, - .operands = {{.kind = SCC_MIR_OP_MEM, .stack_slot = slot}, + .operands = {{.kind = SCC_MIR_OP_STACK_SLOT, .stack_slot = slot}, {.kind = SCC_MIR_OP_PREG, .preg = preg}}}; scc_vec_push(*ctx, ins); } @@ -15,7 +15,7 @@ static void x86_emit_reload(scc_mir_instr_vec_t *ctx, int preg, int slot) { .opcode = SCC_X86_IFORM_MOV_GPRV_MEMV, .num_operands = 2, .operands = {{.kind = SCC_MIR_OP_PREG, .preg = preg}, - {.kind = SCC_MIR_OP_MEM, .stack_slot = slot}}}; + {.kind = SCC_MIR_OP_STACK_SLOT, .stack_slot = slot}}}; scc_vec_push(*ctx, ins); } diff --git a/libs/ir/mir/src/reg_alloc/frame_layout.c b/libs/ir/mir/src/reg_alloc/frame_layout.c deleted file mode 100644 index b6ee21c..0000000 --- a/libs/ir/mir/src/reg_alloc/frame_layout.c +++ /dev/null @@ -1,3 +0,0 @@ -#include - -void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {} diff --git a/libs/ir/mir/src/reg_alloc/reg_alloc.c b/libs/ir/mir/src/reg_alloc/reg_alloc.c index e9da1f3..2aa46cf 100644 --- a/libs/ir/mir/src/reg_alloc/reg_alloc.c +++ b/libs/ir/mir/src/reg_alloc/reg_alloc.c @@ -118,7 +118,7 @@ static void alloc_instr(scc_reg_alloc_ctx_t *ctx, slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8); } else { // 已经是 MEM,直接用它的 slot - Assert(op->kind == SCC_MIR_OP_MEM); + Assert(op->kind == SCC_MIR_OP_STACK_SLOT); slot = op->stack_slot; } @@ -192,6 +192,11 @@ static void alloc_bb(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module, scc_vec_foreach(*old_instrs, i) { scc_mir_instr_t ins = scc_vec_at(*old_instrs, i); + if (ins.opcode == SCC_MIR_PSUEDO_ALLOCA) { + scc_mir_vreg_op(ctx->func, ins.operands[0].vreg, &ins.operands[0]); + scc_vec_push(new_instrs, ins); + continue; + } alloc_instr(ctx, &new_instrs, &ins); } diff --git a/libs/ir/mir/src/scc_mir.c b/libs/ir/mir/src/scc_mir.c index 5ed64d1..7418f80 100644 --- a/libs/ir/mir/src/scc_mir.c +++ b/libs/ir/mir/src/scc_mir.c @@ -28,7 +28,7 @@ void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg, out->kind = SCC_MIR_OP_PREG; out->preg = (int)-idx; } else { - out->kind = SCC_MIR_OP_MEM; + out->kind = SCC_MIR_OP_STACK_SLOT; Assert(idx < scc_vec_size(meta->stack_slots)); out->stack_slot = (int)(usize)idx; } diff --git a/libs/ir/mir/src/scc_mir_dump.c b/libs/ir/mir/src/scc_mir_dump.c index d0c5b0c..1d1ddfd 100644 --- a/libs/ir/mir/src/scc_mir_dump.c +++ b/libs/ir/mir/src/scc_mir_dump.c @@ -16,7 +16,7 @@ void scc_mir_dump_instr(scc_mir_dump_ctx_t *ctx, const scc_mir_instr_t *ins) { scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm); if (ins->operands[0].kind == SCC_MIR_OP_VREG) { scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg); - } else if (ins->operands[0].kind == SCC_MIR_OP_MEM) { + } else if (ins->operands[0].kind == SCC_MIR_OP_STACK_SLOT) { scc_tree_dump_append_fmt(td, " [%d]", ins->operands[0].stack_slot); } else { scc_tree_dump_append(td, ""); @@ -33,7 +33,7 @@ void scc_mir_dump_bblock(scc_mir_dump_ctx_t *ctx, const scc_mir_bblock_t *bb) { // 基本块头部 scc_tree_dump_begin_line(td); - scc_tree_dump_node(td, "#BB%zu", bb->id); + scc_tree_dump_branch(td, "#BB%zu", bb->id); if (bb->name) { scc_tree_dump_append_fmt(td, " (%s)", bb->name); } diff --git a/libs/ir/mir/src/scc_mir_pass.c b/libs/ir/mir/src/scc_mir_pass.c index 809d275..3a04e2f 100644 --- a/libs/ir/mir/src/scc_mir_pass.c +++ b/libs/ir/mir/src/scc_mir_pass.c @@ -1,27 +1,78 @@ #include #include -#include -#include +// #include +// #include +// #include #include #include +void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) { + Assert(ctx && ctx->impl_fn && module); + scc_vec_foreach(module->cfg_module.funcs, i) { + if (i == 0) + continue; + ctx->impl_fn(ctx, module, &scc_vec_at(module->cfg_module.funcs, i)); + } +} + +void scc_prolog_epilog(scc_prolog_epilog_t *ctx, scc_mir_module_t *module) { + Assert(ctx && ctx->epilog && ctx->prolog && module); + scc_vec_foreach(module->cfg_module.funcs, i) { + if (i == 0) + continue; + scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i); + scc_vec_foreach(func->bblocks, i) { + scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i); + scc_cfg_bblock_t *bb = + scc_cfg_module_unsafe_get_bblock(&module->cfg_module, bb_id); + Assert(bb != nullptr); + scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES(bb); + scc_mir_instr_vec_t new_instrs; + scc_vec_init(new_instrs); + + if (i == 0) { + + } else if (i == scc_vec_size(func->bblocks) - 1) { + // FIXME epilog it maybe used in ret instr + } + + scc_vec_foreach(*old_instrs, i) { + scc_mir_instr_t ins = scc_vec_at(*old_instrs, i); + if (ins.opcode == SCC_MIR_PSUEDO_ALLOCA) { + continue; + } + scc_vec_push(new_instrs, ins); + } + + scc_vec_free(*old_instrs); + *old_instrs = new_instrs; + } + } +} + void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) { scc_reg_alloc_ctx_t reg_alloc_ctx = { .func = nullptr, .instrs = nullptr, .ops = {0}}; scc_reg_alloc_fill_arch_x86(®_alloc_ctx.ops); - scc_reg_alloc_fill_win_x64(®_alloc_ctx.ops); + scc_win_pc_x64_reg_alloc_fill(®_alloc_ctx.ops); scc_reg_alloc(®_alloc_ctx, mir_module); if (stage == SCC_MIR_STAGE_REGALLOC) { return; } + scc_frame_layout_t frame_layout_ctx = {0}; + scc_win_pc_x64_frame_alloc_init(&frame_layout_ctx); + scc_frame_layout(&frame_layout_ctx, mir_module); if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) { return; } + scc_prolog_epilog_t prolog_epilog_ctx = {0}; + scc_win_pc_x64_prolog_epilog_init(&prolog_epilog_ctx); + scc_prolog_epilog(&prolog_epilog_ctx, mir_module); if (stage == SCC_MIR_STAGE_PROLOGUE_EPILOGUE) { return; } diff --git a/libs/ir/mir/src/target/win64_abi.c b/libs/ir/mir/src/target/win64_abi.c index 70c3eae..146a4cb 100644 --- a/libs/ir/mir/src/target/win64_abi.c +++ b/libs/ir/mir/src/target/win64_abi.c @@ -2,30 +2,23 @@ #include #include -#include #include #include static const int WIN64_DEFAULT_ALIGN = 8; static const int WIN64_STACK_ALIGN = 16; -typedef struct { - scc_hashtable_t *vreg2slot; - int offset; -} frame_layout_ctx_t; - static void transit_vreg(scc_mir_func_meta_t *func, scc_mir_operand_t *op) { Assert(op->kind == SCC_MIR_OP_VREG); } -static void frame_alloc_impl(frame_layout_ctx_t *ctx, +static void frame_alloc_impl(scc_frame_layout_t *ctx, scc_mir_module_t *mir_module, scc_mir_func_t *mir_func) { /* WIN ABI */ - ctx->offset = 8; // called ret address - + ctx->offset = 8; scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func); scc_vec_foreach(mir_func->bblocks, i) { scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i); @@ -35,8 +28,19 @@ static void frame_alloc_impl(frame_layout_ctx_t *ctx, scc_vec_foreach(*instrs, j) { scc_mir_instr_t *ins = &scc_vec_at(*instrs, j); for (int k = 0; k < ins->num_operands; k += 1) { - if (ins->operands[k].kind == SCC_MIR_OP_VREG) { - transit_vreg(func_meta, &ins->operands[k]); + scc_mir_operand_t *op = &ins->operands[k]; + if (op->kind == SCC_MIR_OP_VREG) { + Panic("vreg not supported in frame layout"); + } else if (op->kind == SCC_MIR_OP_STACK_SLOT) { + scc_mir_stack_slot_t *slot = + scc_mir_unsafe_slot(mir_func, op->stack_slot); + op->kind = SCC_MIR_OP_STACK_OFFSET; + if (slot->offset == 0) { + // FIXME align + ctx->offset += slot->size; + slot->offset = ctx->offset; + } + op->stack_offset = slot->offset; } } } @@ -47,6 +51,11 @@ static void frame_alloc_impl(frame_layout_ctx_t *ctx, // 16 字节栈对齐 ctx->offset = (total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1); + func_meta->frame_size = ctx->offset; +} + +void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx) { + ctx->impl_fn = frame_alloc_impl; } /* @@ -99,6 +108,11 @@ static void epilogue(void *userdata, const scc_mir_func_t *func) { add_instr_1(isel, SCC_X86_IFORM_POP_GPRV_58, reg_operand(SCC_X86_REG_RBP)); } +void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx) { + ctx->prolog = prologue; + ctx->epilog = epilogue; +} + static void lower_call(void *userdata, const scc_lir_instr_t *instr) { scc_x86_64_isel_t *isel = userdata; /* @@ -174,7 +188,7 @@ static scc_mir_operand_t lower_param(void *userdata, const scc_lir_val_t *val) { case 3: return reg_operand(SCC_X86_REG_R9); default: - return (scc_mir_operand_t){.kind = SCC_MIR_OP_MEM, + return (scc_mir_operand_t){.kind = SCC_MIR_OP_STACK_SLOT, .stack_slot = -val->data.arg}; } } @@ -231,14 +245,9 @@ static void mark_reg_used(void *ctx, int preg) { } static void clean_mark_regs(void *ctx) { reg_mask = 0; } -void scc_reg_alloc_fill_win_x64(scc_reg_alloc_op_t *ops) { +void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops) { ops->acquire_reg = acquire_reg; ops->release_reg = release_reg; ops->mark_reg_used = mark_reg_used; ops->clean_mark_regs = clean_mark_regs; } - -void scc_win_pc_x64_prolog_epilog(scc_prolog_epilog_t *prolog_epilog) { - prolog_epilog->prolog = prologue; - prolog_epilog->epilog = epilogue; -} diff --git a/libs/ir2mcode/src/scc_ir2mcode.c b/libs/ir2mcode/src/scc_ir2mcode.c index 373653c..fd81588 100644 --- a/libs/ir2mcode/src/scc_ir2mcode.c +++ b/libs/ir2mcode/src/scc_ir2mcode.c @@ -17,9 +17,17 @@ void mir_x86_to_mcode(scc_mcode_t *mcode, const scc_mir_instr_t *ins) { ops[i].kind = SCC_X86_OPR_REG; ops[i].reg = ins->operands[i].preg; break; - case SCC_MIR_OP_MEM: + case SCC_MIR_OP_STACK_SLOT: Panic("can't convert mem to mcode"); break; + case SCC_MIR_OP_STACK_OFFSET: + // TODO + ops[i].kind = SCC_X86_OPR_MEM; + ops[i].mem.base = SCC_X86_REG_RSP; + ops[i].mem.index = SCC_X86_REG_INVALID; + ops[i].mem.scale = 1; + ops[i].mem.disp = -ins->operands[i].stack_offset; // 注意符号 + break; case SCC_MIR_OP_IMM: ops[i].kind = SCC_X86_OPR_IMM; ops[i].imm = ins->operands[i].imm; diff --git a/libs/ir2mcode/src/scc_ir2sccf.c b/libs/ir2mcode/src/scc_ir2sccf.c index 1c91430..ba98af4 100644 --- a/libs/ir2mcode/src/scc_ir2sccf.c +++ b/libs/ir2mcode/src/scc_ir2sccf.c @@ -5,12 +5,15 @@ static inline void scc_ir_sym_to_sccf_sym(const scc_cfg_symbol_t *symbol, switch (symbol->kind) { case SCC_CFG_SYMBOL_KIND_DATA: sym->sccf_sym_type = SCCF_SYM_TYPE_DATA; + sym->sccf_sect_type = SCCF_SECT_DATA; break; case SCC_CFG_SYMBOL_KIND_FUNC: sym->sccf_sym_type = SCCF_SYM_TYPE_FUNC; + sym->sccf_sect_type = SCCF_SECT_CODE; break; case SCC_CFG_SYMBOL_KIND_EXTERN: sym->sccf_sym_type = SCCF_SYM_TYPE_EXTERN; + sym->sccf_sect_type = SCCF_SECT_NONE; break; } @@ -42,6 +45,11 @@ void scc_ir2sccf(sccf_builder_t *builder, scc_mir_module_t *mir_module) { scc_vec_init(sect_data); scc_vec_foreach(mir_module->cfg_module.symbols, i) { + if (i == 0) { + // FIXME + continue; + } + scc_cfg_symbol_t *symbol = &scc_vec_at(mir_module->cfg_module.symbols, i); diff --git a/libs/mcode/include/x86/scc_x86_encode.h b/libs/mcode/include/x86/scc_x86_encode.h new file mode 100644 index 0000000..68de93c --- /dev/null +++ b/libs/mcode/include/x86/scc_x86_encode.h @@ -0,0 +1,28 @@ +#ifndef __SCC_X86_ENCODE_H__ +#define __SCC_X86_ENCODE_H__ + +#include "../scc_mcode.h" +#include "scc_x86_iform.h" +#include "scc_x86_reg.h" + +typedef struct { + scc_x86_reg_t base; + scc_x86_reg_t index; + u8 scale; /* 1,2,4,8 */ + i32 disp; +} scc_x86_mem_t; + +typedef struct { + scc_x86_operand_kind_t kind; + union { + scc_x86_reg_t reg; + i64 imm; + scc_x86_mem_t mem; + }; +} scc_x86_operand_value_t; + +/* 按 iform 发射一条指令,ops 数组长度需与 iform 定义的操作数数目一致 */ +int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, + const scc_x86_operand_value_t *ops); + +#endif /* __SCC_X86_ENCODE_H__ */ diff --git a/libs/mcode/src/scc_x86_encode.c b/libs/mcode/src/scc_x86_encode.c new file mode 100644 index 0000000..fb0c70e --- /dev/null +++ b/libs/mcode/src/scc_x86_encode.c @@ -0,0 +1,449 @@ +#include +#include +#include +#include +#include + +/* ---------- 内部辅助 ---------- */ +static inline void emit_u8(scc_mcode_t *m, uint8_t v) { + scc_mcode_add_u8(m, v); +} +static inline void emit_u16(scc_mcode_t *m, uint16_t v) { + scc_mcode_add_u16(m, v); +} +static inline void emit_u32(scc_mcode_t *m, uint32_t v) { + scc_mcode_add_u32(m, v); +} +static inline void emit_u64(scc_mcode_t *m, uint64_t v) { + scc_mcode_add_u64(m, v); +} + +/* ---------- 寄存器查询 ---------- */ +static inline uint16_t scc_reg_width(scc_x86_reg_t reg) { + if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID) + return 0; + return scc_x86_reg_table[reg].width; +} +static inline int scc_reg_ordinal(scc_x86_reg_t reg) { + if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID) + return 0; + return scc_x86_reg_table[reg].ordinal; +} +static int reg_low3(scc_x86_reg_t reg) { + if (reg == SCC_X86_REG_INVALID) + return 0; + return scc_reg_ordinal(reg) & 7; +} +static int reg_rex_bit(scc_x86_reg_t reg) { + if (reg == SCC_X86_REG_INVALID) + return 0; + if (reg >= SCC_X86_REG_AH && reg <= SCC_X86_REG_DH) + return 0; + return (scc_reg_ordinal(reg) >= 8) ? 1 : 0; +} + +/* ---------- 操作数宽度推导 ---------- */ +static int infer_operand_width(const scc_x86_iform_info_t *info, + const scc_x86_operand_value_t ops[]) { + for (int i = 0; i < info->num_explicit_ops; i++) { + if (ops[i].kind == SCC_X86_OPR_REG && !info->ops[i].is_implicit) { + uint16_t w = scc_reg_width(ops[i].reg); + if (w > 0) + return w; + } + } + const char *eosz = info->encode.eosz; + int default_64 = info->encode.default_64b; + if (!strcmp(eosz, "o16")) + return 16; + if (!strcmp(eosz, "o32")) + return 32; + if (!strcmp(eosz, "o64")) + return 64; + if (!strcmp(eosz, "oszall") || !strcmp(eosz, "osznot16")) + return default_64 ? 64 : 32; + return 32; +} + +/* ---------- 前缀决策 ---------- */ +static int need_rexw(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op, + scc_x86_reg_t rm_op, scc_x86_reg_t base, + scc_x86_reg_t idx) { + /* 强制要求 / 明确禁止 优先级最高 */ + if (enc->rex_w == 1) + return 1; + if (enc->rex_w == 0) + return 0; + + /* 指令已隐含 64 位语义(如 PUSH/POP),但仍可能被 64 位操作数需要 W?例如 + * PUSH r64 不需要 W,但 PUSH r/m64 也不需要。总之 default_64b + * 时一般无需额外 W,但若操作数明确是 64 位且模板没有禁止,我们仍加上以兼容 + * movabs 等 */ + int has_64bit_op = 0; + if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 64) + has_64bit_op = 1; + if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 64) + has_64bit_op = 1; + if (base != SCC_X86_REG_INVALID && scc_reg_width(base) == 64) + has_64bit_op = 1; + if (idx != SCC_X86_REG_INVALID && scc_reg_width(idx) == 64) + has_64bit_op = 1; + + if (enc->default_64b) { + /* 对于默认 64 位的指令(如 CALL, JMP),有些仍需要 REX.W + * 访问扩展寄存器,但若 reg/rm 本身是 64 位且需要 REX.B/R 则一并设置 W + * 来保证编码正确?这里简单处理:只要访问扩展寄存器就加 W */ + return (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op)) || + (rm_op != SCC_X86_REG_INVALID && reg_rex_bit(rm_op)) || + (base != SCC_X86_REG_INVALID && reg_rex_bit(base)) || + (idx != SCC_X86_REG_INVALID && reg_rex_bit(idx)) + ? 1 + : 0; + } + + /* 普通指令:有 64 位操作数即加 W */ + return has_64bit_op; +} + +static int need_66_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op, + scc_x86_reg_t rm_op) { + if (enc->osz_required) + return 1; + // 如果强制指定了操作大小,不自动加66 + if (!strcmp(enc->eosz, "o32") || !strcmp(enc->eosz, "o64")) + return 0; + if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 16) + return 1; + if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 16) + return 1; + return 0; +} +static int need_67_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t base, + scc_x86_reg_t idx) { + (void)enc; + (void)base; + (void)idx; + return 0; +} + +static void emit_legacy_prefixes(scc_mcode_t *m, const scc_x86_encoding_t *enc, + scc_x86_reg_t reg_op, scc_x86_reg_t rm_op, + scc_x86_reg_t base, scc_x86_reg_t idx) { + if (enc->has_lock) + emit_u8(m, 0xF0); + if (enc->f2_required) + emit_u8(m, 0xF2); + if (enc->f3_required) + emit_u8(m, 0xF3); + if (need_66_prefix(enc, reg_op, rm_op)) + emit_u8(m, 0x66); + if (need_67_prefix(enc, base, idx)) + emit_u8(m, 0x67); +} + +static void emit_rex(scc_mcode_t *m, const scc_x86_encoding_t *enc, + scc_x86_reg_t reg_op, scc_x86_reg_t rm_op, + scc_x86_reg_t base, scc_x86_reg_t idx) { + int rex = 0x40; + if (need_rexw(enc, reg_op, rm_op, base, idx)) + rex |= 8; + if (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op)) + rex |= 4; + if (idx != SCC_X86_REG_INVALID && reg_rex_bit(idx)) + rex |= 2; + scc_x86_reg_t b = (rm_op != SCC_X86_REG_INVALID) ? rm_op : base; + if (b != SCC_X86_REG_INVALID && reg_rex_bit(b)) + rex |= 1; + if (rex != 0x40) { + LOG_INFO("[REX] emit 0x%02x", (uint8_t)rex); + emit_u8(m, (uint8_t)rex); + } +} + +static void emit_escape_map(scc_mcode_t *m, const scc_x86_encoding_t *enc) { + if (enc->map == 1) { + emit_u8(m, 0x0F); + } else if (enc->map == 2) { + emit_u8(m, 0x0F); + emit_u8(m, 0x38); + } else if (enc->map == 3) { + emit_u8(m, 0x0F); + emit_u8(m, 0x3A); + } +} + +static void emit_opcode(scc_mcode_t *m, const scc_x86_encoding_t *enc, + scc_x86_reg_t rm_reg, scc_x86_reg_t base_reg) { + for (int i = 0; i < enc->opcode_len; i++) { + uint8_t byte = enc->opcode[i]; + if (enc->partial_opcode && i == enc->opcode_len - 1) { + scc_x86_reg_t target = + (rm_reg != SCC_X86_REG_INVALID) ? rm_reg : base_reg; + if (target != SCC_X86_REG_INVALID) + byte |= (reg_low3(target) & 7); + } + emit_u8(m, byte); + } +} + +static int scale_to_enc(uint8_t scale) { + switch (scale) { + case 1: + return 0; + case 2: + return 1; + case 4: + return 2; + case 8: + return 3; + default: + return -1; + } +} + +static int disp_size(int32_t disp, scc_x86_reg_t base) { + if (disp == 0 && base != SCC_X86_REG_RBP && base != SCC_X86_REG_R13) + return 0; + if (disp >= -128 && disp <= 127) + return 8; + return 32; +} + +/* ---------- 立即数发射(独立函数) ---------- */ +static void emit_immediate(scc_mcode_t *m, const scc_x86_encoding_t *enc, + const scc_x86_operand_t *tmpl, int imm_idx, + int64_t imm_val, int op_width) { + const char *oc2 = tmpl[imm_idx].oc2; + int imm_size = enc->imm_size; + if (!strcmp(oc2, "b")) + imm_size = 1; + else if (!strcmp(oc2, "w")) + imm_size = 2; + else if (!strcmp(oc2, "z")) + imm_size = (op_width <= 16) ? op_width / 8 : (op_width <= 32 ? 4 : 4); + else if (!strcmp(oc2, "v")) + imm_size = op_width / 8; + else if (!strcmp(oc2, "d") || !strcmp(oc2, "ss")) + imm_size = 4; + else if (!strcmp(oc2, "q")) + imm_size = 8; + + LOG_INFO("[IMM] val=%lld size=%d", imm_val, imm_size); + switch (imm_size) { + case 1: + emit_u8(m, (uint8_t)imm_val); + break; + case 2: + emit_u16(m, (uint16_t)imm_val); + break; + case 4: + emit_u32(m, (uint32_t)imm_val); + break; + case 8: + emit_u64(m, (uint64_t)imm_val); + break; + default: + break; + } +} + +/* ---------- ModR/M + SIB + 位移 + 立即数 ---------- */ +static void emit_modrm_sib_disp(scc_mcode_t *m, + const scc_x86_iform_info_t *info, + const scc_x86_operand_value_t ops[], + int op_width) { + const scc_x86_encoding_t *enc = &info->encode; + const scc_x86_operand_t *tmpl = info->ops; + int num_ops = info->num_explicit_ops; + + scc_x86_reg_t reg_r = SCC_X86_REG_INVALID; + scc_x86_reg_t reg_b = SCC_X86_REG_INVALID; + int has_mem = 0; + scc_x86_mem_t memdesc = {0}; + int64_t imm_val = 0; + int imm_idx = -1; + + for (int i = 0; i < num_ops; i++) { + const char *tname = tmpl[i].name; + if (ops[i].kind == SCC_X86_OPR_REG) { + LOG_INFO("[OPD] %d: REG kind, name=\"%s\" reg=%d", i, tname, + ops[i].reg); + if (strncmp(tname, "REG0", 4) == 0) + reg_r = ops[i].reg; + else if (strncmp(tname, "REG1", 4) == 0) + reg_b = ops[i].reg; + else { + if (reg_r == SCC_X86_REG_INVALID) + reg_r = ops[i].reg; + else if (reg_b == SCC_X86_REG_INVALID) + reg_b = ops[i].reg; + } + } else if (ops[i].kind == SCC_X86_OPR_MEM) { + has_mem = 1; + memdesc = ops[i].mem; + } else if (ops[i].kind == SCC_X86_OPR_IMM) { + imm_val = ops[i].imm; + imm_idx = i; + } + } + LOG_INFO("[MODRM] reg_r=%d (ord=%d) reg_b=%d (ord=%d)", reg_r, + scc_reg_ordinal(reg_r), reg_b, scc_reg_ordinal(reg_b)); + + uint8_t modrm = 0; + if (has_mem) { + if (reg_r != SCC_X86_REG_INVALID) + modrm |= (reg_low3(reg_r) & 7) << 3; + else if (enc->modrm_reg_fix >= 0) + modrm |= (enc->modrm_reg_fix & 7) << 3; + + int32_t disp = memdesc.disp; + int dsize = disp_size(disp, memdesc.base); + modrm |= (dsize == 0) ? 0 : (dsize == 8) ? 0x40 : 0x80; + + if (memdesc.index != SCC_X86_REG_INVALID) { + modrm |= 4; + int idx_ord = scc_reg_ordinal(memdesc.index); + int base_ord = scc_reg_ordinal(memdesc.base); + int scale_enc = scale_to_enc(memdesc.scale); + if (scale_enc < 0) + return; + uint8_t sib = (uint8_t)((scale_enc << 6) | ((idx_ord & 7) << 3) | + (base_ord & 7)); + emit_u8(m, modrm); + emit_u8(m, sib); + if (dsize == 8) + emit_u8(m, (uint8_t)disp); + else if (dsize == 32) + emit_u32(m, (uint32_t)disp); + } else if (memdesc.base == SCC_X86_REG_INVALID) { + modrm |= 5; + emit_u8(m, modrm); + emit_u32(m, (uint32_t)disp); + } else { + int base_ord = scc_reg_ordinal(memdesc.base); + if (memdesc.base == SCC_X86_REG_RSP || + memdesc.base == SCC_X86_REG_R12) { + modrm |= 4; + uint8_t sib = (uint8_t)((base_ord & 7) | (4 << 3)); + emit_u8(m, modrm); + emit_u8(m, sib); + if (dsize == 8) + emit_u8(m, (uint8_t)disp); + else if (dsize == 32) + emit_u32(m, (uint32_t)disp); + } else { + modrm |= (base_ord & 7); + emit_u8(m, modrm); + if (dsize == 8) + emit_u8(m, (uint8_t)disp); + else if (dsize == 32) + emit_u32(m, (uint32_t)disp); + } + } + } else { + modrm = 0xC0; + if (enc->modrm_reg_fix >= 0) + modrm |= (enc->modrm_reg_fix & 7) << 3; + else if (reg_r != SCC_X86_REG_INVALID) + modrm |= (reg_low3(reg_r) & 7) << 3; + + if (enc->modrm_rm_fix >= 0) { + modrm |= enc->modrm_rm_fix & 7; + } else if (reg_b != SCC_X86_REG_INVALID) { + modrm |= reg_low3(reg_b) & 7; + } else if (enc->modrm_reg_fix >= 0 && reg_r != SCC_X86_REG_INVALID) { + modrm |= reg_low3(reg_r) & 7; + } else if (reg_r != SCC_X86_REG_INVALID) { + modrm |= reg_low3(reg_r) & 7; + } + emit_u8(m, modrm); + } + LOG_INFO("[MODRM] emit byte 0x%02x", modrm); + + /* 立即数在 ModRM 后发射 */ + if (imm_idx >= 0) { + emit_immediate(m, enc, tmpl, imm_idx, imm_val, op_width); + } +} + +/* ---------- 主编码入口 ---------- */ +int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, + const scc_x86_operand_value_t *ops) { + if (!mcode || !ops) + return -1; + + if (iform >= SCC_X86_IFORM_COUNT || iform < 0) + Panic("invalid iform %d", iform); + + const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform]; + const scc_x86_encoding_t *enc = &info->encode; + const scc_x86_operand_t *tmpl = info->ops; + int num_ops = info->num_explicit_ops; + + LOG_INFO("[IFORM] %s, explicit_ops=%d (total=%d)", info->iform_name, + num_ops, info->num_ops); + + scc_x86_reg_t reg_field = SCC_X86_REG_INVALID; + scc_x86_reg_t rm_field = SCC_X86_REG_INVALID; + scc_x86_reg_t base_reg = SCC_X86_REG_INVALID; + scc_x86_reg_t idx_reg = SCC_X86_REG_INVALID; + + /* ---------- 收集立即数信息(用于无 ModRM 指令) ---------- */ + int64_t imm_val = 0; + int imm_idx = -1; + for (int i = 0; i < num_ops; i++) { + const char *tname = tmpl[i].name; + if (ops[i].kind == SCC_X86_OPR_REG) { + if (strncmp(tname, "REG0", 4) == 0) { + if (enc->modrm_reg_fix >= 0) + rm_field = ops[i].reg; // reg固定 → REG0为rm + else + reg_field = ops[i].reg; // 否则为reg + } else if (strncmp(tname, "REG1", 4) == 0) { + if (enc->modrm_rm_fix >= 0) + reg_field = ops[i].reg; // rm固定 → REG1为reg + else + rm_field = ops[i].reg; // 否则为rm + } else { + // 未命名的寄存器,按先 reg 后 rm 填充 + if (reg_field == SCC_X86_REG_INVALID) + reg_field = ops[i].reg; + else if (rm_field == SCC_X86_REG_INVALID) + rm_field = ops[i].reg; + } + } else if (ops[i].kind == SCC_X86_OPR_MEM) { + base_reg = ops[i].mem.base; + idx_reg = ops[i].mem.index; + } else if (ops[i].kind == SCC_X86_OPR_IMM || + ops[i].kind == SCC_X86_OPR_RELBR) { + imm_val = ops[i].imm; + imm_idx = i; + } + } + + int op_width = infer_operand_width(info, ops); + LOG_INFO("[OPWIDTH] %d bits", op_width); + + // +++ 新增:无 ModRM 时,寄存器用 REX.B 扩展 +++ + if (!enc->has_modrm) { + rm_field = reg_field; + reg_field = SCC_X86_REG_INVALID; + } + + emit_legacy_prefixes(mcode, enc, reg_field, rm_field, base_reg, idx_reg); + emit_rex(mcode, enc, reg_field, rm_field, base_reg, idx_reg); + emit_escape_map(mcode, enc); + + if (enc->has_modrm) { + emit_opcode(mcode, enc, rm_field, base_reg); + emit_modrm_sib_disp(mcode, info, ops, op_width); + } else { + // 无 ModRM:opcode 中的寄存器来自 rm_field + emit_opcode(mcode, enc, rm_field, base_reg); + if (imm_idx >= 0) { + emit_immediate(mcode, enc, tmpl, imm_idx, imm_val, op_width); + } + } + + return 0; +} \ No newline at end of file diff --git a/libs/tree_dump/include/scc_tree_dump.h b/libs/tree_dump/include/scc_tree_dump.h index b795b09..b312646 100644 --- a/libs/tree_dump/include/scc_tree_dump.h +++ b/libs/tree_dump/include/scc_tree_dump.h @@ -71,20 +71,17 @@ void scc_tree_dump_append(scc_tree_dump_t *td, const char *s); */ void scc_tree_dump_append_fmt(scc_tree_dump_t *td, const char *fmt, ...); -/** - * @brief 追加带节点颜色的文本 - */ #define scc_tree_dump_node(td, fmt, ...) \ scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->node_color, \ ##__VA_ARGS__, (td)->reset_color) -/** - * @brief 追加带值颜色的格式化文本 - */ #define scc_tree_dump_value(td, fmt, ...) \ scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->value_color, \ ##__VA_ARGS__, (td)->reset_color) +#define scc_tree_dump_branch(td, fmt, ...) \ + scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->branch_color, \ + ##__VA_ARGS__, (td)->reset_color) /** * @brief 推入新层级 * @param is_last 该层级是否是父节点的最后一个子节点 diff --git a/libs/tree_dump/src/scc_tree_dump.c b/libs/tree_dump/src/scc_tree_dump.c index 0e741e6..65262bc 100644 --- a/libs/tree_dump/src/scc_tree_dump.c +++ b/libs/tree_dump/src/scc_tree_dump.c @@ -4,10 +4,10 @@ #define DEFAULT_BRANCH "|-" #define DEFAULT_LAST_BRANCH "`-" #define DEFAULT_SPACE " " -#define NODE_COLOR "\033[34m" -#define VALUE_COLOR "\033[32m" -#define BRANCH_COLOR "\033[33m" -#define RESET_COLOR "\033[0m" +#define NODE_COLOR ANSI_FG_GREEN +#define VALUE_COLOR ANSI_FG_YELLOW +#define BRANCH_COLOR ANSI_FG_CYAN +#define RESET_COLOR ANSI_NONE void scc_tree_dump_init(scc_tree_dump_t *td, cbool use_color) { scc_str_init(&td->buf); diff --git a/src/main.c b/src/main.c index 26f86d2..975a03f 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,8 @@ #include #include "config.h" +void init_platform(void); +#define GET_VALID_FP(fp) (fp == nullptr ? scc_stdout : fp) static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) { scc_lexer_tok_t tok = {0}; @@ -66,10 +68,21 @@ static void print_file(scc_lexer_tok_ring_t *ring, scc_file_t fp) { static void tree_dump_output(const char *str, usize len, void *user) { scc_fprintf(user, "%.*s", (int)len, str); } +static inline int mir_dump(scc_file_t fp, scc_mir_module_t *mir_module) { + scc_tree_dump_t tree_dump; + scc_mir_dump_ctx_t mir_dump_ctx; + if (fp == nullptr) { + scc_tree_dump_init(&tree_dump, true); + } else { + scc_tree_dump_init(&tree_dump, false); + } + scc_mir_dump_init(&mir_dump_ctx, &tree_dump, mir_module); + scc_mir_dump_module(&mir_dump_ctx); -void init_platform(void); - -#define GET_VALID_FP(fp) (fp == nullptr ? scc_stdout : fp) + scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); + scc_tree_dump_drop(&tree_dump); + return 0; +} int main(int argc, const char **argv, const char **envp) { init_platform(); @@ -276,36 +289,20 @@ sstream_drop: switch (config.emit_stage) { case SCC_EMIT_STAGE_MIR: - goto mir_dump; + return mir_dump(fp, &mir_module); case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC: scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC); - goto mir_dump; + return mir_dump(fp, &mir_module); case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT: scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT); - goto mir_dump; + return mir_dump(fp, &mir_module); case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG: scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE); - goto mir_dump; - break; + return mir_dump(fp, &mir_module); default: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY); break; } - do { - mir_dump: - scc_mir_dump_ctx_t mir_dump_ctx; - scc_tree_dump_t tree_dump; - if (fp == nullptr) { - scc_tree_dump_init(&tree_dump, true); - } else { - scc_tree_dump_init(&tree_dump, false); - } - scc_mir_dump_init(&mir_dump_ctx, &tree_dump, &mir_module); - scc_mir_dump_module(&mir_dump_ctx); - - scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); - scc_tree_dump_drop(&tree_dump); - return 0; - } while (0); if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) { scc_mcode_t mcode = {0};