diff --git a/cbuild.toml b/cbuild.toml index 3267a41..24edc60 100644 --- a/cbuild.toml +++ b/cbuild.toml @@ -11,6 +11,7 @@ dependencies = [ { name = "ast2ir", path = "./libs/ast2ir" }, { name = "hir", path = "./libs/ir/hir" }, { name = "lir", path = "./libs/ir/lir" }, + { name = "mir", path = "./libs/ir/mir" }, # { name = "ir2mcode", path = "./libs/ir2mcode" }, # { name = "sccf2target", path = "./libs/target/sccf2target" }, diff --git a/libs/ir/lir/include/scc_lir.h b/libs/ir/lir/include/scc_lir.h index f3bdc84..2fc6322 100644 --- a/libs/ir/lir/include/scc_lir.h +++ b/libs/ir/lir/include/scc_lir.h @@ -31,9 +31,9 @@ typedef enum scc_lir_attr { } scc_lir_attr_t; typedef enum { - SCC_LIR_INSTR_KIND_NONE, // 无操作数 - SCC_LIR_INSTR_KIND_VREG, // 虚拟寄存器 - SCC_LIR_INSTR_KIND_PREG, // 物理寄存器 (后端定义编号) + SCC_LIR_INSTR_KIND_NONE, // 无操作数 + SCC_LIR_INSTR_KIND_VREG, // 虚拟寄存器 + // SCC_LIR_INSTR_KIND_PREG, // 物理寄存器 (后端定义编号) SCC_LIR_INSTR_KIND_IMM, // 整数立即数 SCC_LIR_INSTR_KIND_FIMM, // 浮点立即数 SCC_LIR_INSTR_KIND_SYMBOL, // 全局符号 (函数名、全局变量、字符串常量) diff --git a/libs/ir/lir/include/scc_lir_dump.h b/libs/ir/lir/include/scc_lir_dump.h index f8e14b6..b485c68 100644 --- a/libs/ir/lir/include/scc_lir_dump.h +++ b/libs/ir/lir/include/scc_lir_dump.h @@ -7,7 +7,7 @@ typedef struct { scc_tree_dump_t *dump_ctx; - scc_lir_module_t *module; + scc_lir_module_t *lir_module; } scc_lir_dump_ctx_t; static inline void scc_lir_dump_init(scc_lir_dump_ctx_t *ctx, @@ -15,7 +15,7 @@ static inline void scc_lir_dump_init(scc_lir_dump_ctx_t *ctx, scc_lir_module_t *module) { Assert(ctx != nullptr && dump_ctx != nullptr && module != nullptr); ctx->dump_ctx = dump_ctx; - ctx->module = module; + ctx->lir_module = module; } void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins); void scc_lir_dump_bblock(scc_lir_dump_ctx_t *ctx, const scc_lir_bblock_t *bb); diff --git a/libs/ir/lir/include/scc_lir_module.h b/libs/ir/lir/include/scc_lir_module.h index 8835cb3..a9a2872 100644 --- a/libs/ir/lir/include/scc_lir_module.h +++ b/libs/ir/lir/include/scc_lir_module.h @@ -22,12 +22,12 @@ typedef struct scc_lir_module { /** * @brief 初始化 LIR 模块 */ -void scc_lir_module_init(scc_lir_module_t *module); +void scc_lir_module_init(scc_lir_module_t *lir_module); /** * @brief 销毁 LIR 模块,释放所有函数和符号资源 */ -void scc_lir_module_drop(scc_lir_module_t *module); +void scc_lir_module_drop(scc_lir_module_t *lir_module); /** * @brief 添加一个函数声明(外部或未定义) @@ -36,7 +36,7 @@ void scc_lir_module_drop(scc_lir_module_t *module); * @param attr 属性 * @return 符号指针 */ -scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module, +scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module, const char *name); /** @@ -50,7 +50,7 @@ scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module, * @param attr 属性 * @return 符号指针 */ -scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *module, +scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *lir_module, const char *name, scc_cfg_symbol_kind_t kind, const u8 *init_data, usize size, diff --git a/libs/ir/lir/src/scc_hir2lir.c b/libs/ir/lir/src/scc_hir2lir.c index 9dfa788..b9d275b 100644 --- a/libs/ir/lir/src/scc_hir2lir.c +++ b/libs/ir/lir/src/scc_hir2lir.c @@ -14,7 +14,6 @@ typedef struct { scc_lir_func_t *current_func; scc_lir_instr_vec_t instrs; - scc_hashtable_t bb_map; // ir_bblock_ref_t -> scc_lir_bblock_id_t scc_hashtable_t value_to_vreg; // ir_value_ref_t -> unsigned int vreg scc_hashtable_t func_decl_map; // ir_func_ref_t -> const char* (用于调用) } ir2lir_ctx_t; @@ -23,13 +22,11 @@ static void ir2lir_ctx_init(ir2lir_ctx_t *ctx, scc_lir_module_t *lir_module, scc_hir_module_t *hir_module) { ctx->hir_module = hir_module; ctx->lir_module = lir_module; - scc_hashtable_usize_init(&ctx->bb_map); scc_hashtable_usize_init(&ctx->value_to_vreg); scc_hashtable_usize_init(&ctx->func_decl_map); } static void ir2lir_ctx_drop(ir2lir_ctx_t *ctx) { - scc_hashtable_drop(&ctx->bb_map); scc_hashtable_drop(&ctx->value_to_vreg); scc_hashtable_drop(&ctx->func_decl_map); } @@ -107,7 +104,8 @@ static int get_vreg_for_value(ir2lir_ctx_t *ctx, scc_hir_value_ref_t val_ref) { if (found) return (int)(usize)found; - int vreg = SCC_LIR_FUNC_META(ctx->current_func)->vregs_count++; + int vreg = ++(SCC_LIR_FUNC_META(ctx->current_func)->vregs_count); + Assert(vreg != 0); scc_hashtable_set(&ctx->value_to_vreg, (void *)(usize)val_ref, (void *)(usize)vreg); return vreg; @@ -386,25 +384,18 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, case SCC_HIR_VALUE_TAG_BRANCH: { scc_lir_val_t cond = ir_value_to_lir_operand(ctx, value->data.branch.cond); - scc_lir_bblock_id_t true_bb = - (scc_lir_bblock_id_t)(uintptr_t)scc_hashtable_get( - &ctx->bb_map, - (void *)(uintptr_t)value->data.branch.true_bblock); - scc_lir_bblock_id_t false_bb = - (scc_lir_bblock_id_t)(uintptr_t)scc_hashtable_get( - &ctx->bb_map, - (void *)(uintptr_t)value->data.branch.false_bblock); scc_lir_instr_t instr = { - .op = SCC_LIR_BR, .arg0 = cond, .metadata.br = {true_bb, false_bb}}; + .op = SCC_LIR_BR, + .arg0 = cond, + .metadata.br = {value->data.branch.true_bblock, + value->data.branch.false_bblock}}; scc_lir_builder_add_instr(ctx, &instr); break; } case SCC_HIR_VALUE_TAG_JUMP: { - scc_lir_bblock_id_t target = - (scc_lir_bblock_id_t)(usize)scc_hashtable_get( - &ctx->bb_map, (void *)(usize)value->data.jump.target_bblock); scc_lir_instr_t instr = {.op = SCC_LIR_JMP, - .metadata.jmp_target = target}; + .metadata.jmp_target = + value->data.jump.target_bblock}; scc_lir_builder_add_instr(ctx, &instr); break; } @@ -487,7 +478,6 @@ static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) { } // 清理本次函数翻译的临时映射 - scc_hashtable_drop(&ctx->bb_map); scc_hashtable_drop(&ctx->value_to_vreg); } diff --git a/libs/ir/lir/src/scc_lir_dump.c b/libs/ir/lir/src/scc_lir_dump.c index 263c316..b40e72a 100644 --- a/libs/ir/lir/src/scc_lir_dump.c +++ b/libs/ir/lir/src/scc_lir_dump.c @@ -144,9 +144,9 @@ static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) { 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_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); @@ -295,7 +295,7 @@ void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) { break; case SCC_LIR_JMP: - scc_tree_dump_append_fmt(td, "BB#%zu", ins->metadata.jmp_target); + scc_tree_dump_append_fmt(td, "#BB%d", ins->metadata.jmp_target); break; case SCC_LIR_JMP_INDIRECT: @@ -395,7 +395,7 @@ void scc_lir_dump_bblock(scc_lir_dump_ctx_t *ctx, const scc_lir_bblock_t *bb) { // 基本块头部 scc_tree_dump_begin_line(td); - scc_tree_dump_node(td, "BB%zu", bb->id); + scc_tree_dump_node(td, "#BB%zu", bb->id); if (bb->name) { scc_tree_dump_append_fmt(td, " (%s)", bb->name); } @@ -430,10 +430,10 @@ void scc_lir_dump_func(scc_lir_dump_ctx_t *ctx, const scc_lir_func_t *func) { scc_tree_dump_append(td, " {"); // 输出所有基本块 - for (usize i = 0; i < scc_vec_size(func->bblocks); ++i) { + 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->module->cfg_module, id); + scc_cfg_module_unsafe_get_bblock(&ctx->lir_module->cfg_module, id); scc_lir_dump_bblock(ctx, bb); } @@ -442,18 +442,20 @@ void scc_lir_dump_func(scc_lir_dump_ctx_t *ctx, const scc_lir_func_t *func) { } void scc_lir_dump_module(scc_lir_dump_ctx_t *ctx) { - scc_vec_foreach(ctx->module->cfg_module.symbols, i) { + 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->module->cfg_module.symbols, i); + 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_tree_dump_append_fmt(ctx->dump_ctx, " %s", sym->name); } - scc_vec_foreach(ctx->module->cfg_module.funcs, i) { + scc_vec_foreach(ctx->lir_module->cfg_module.funcs, i) { if (i == 0) continue; - scc_lir_dump_func(ctx, &scc_vec_at(ctx->module->cfg_module.funcs, i)); + scc_lir_dump_func(ctx, + &scc_vec_at(ctx->lir_module->cfg_module.funcs, i)); } } diff --git a/libs/ir/lir/src/scc_lir_module.c b/libs/ir/lir/src/scc_lir_module.c index 187f886..8f3aafd 100644 --- a/libs/ir/lir/src/scc_lir_module.c +++ b/libs/ir/lir/src/scc_lir_module.c @@ -1,21 +1,22 @@ #include -void scc_lir_module_init(scc_lir_module_t *module) { +void scc_lir_module_init(scc_lir_module_t *lir_module) { // FIXME - // module->module + // lir_module->lir_module - scc_vec_init(module->func_metas); - scc_vec_init(module->symbol_metas); + scc_vec_init(lir_module->func_metas); + scc_vec_init(lir_module->symbol_metas); } -void scc_lir_module_drop(scc_lir_module_t *module) { - scc_vec_free(module->func_metas); - scc_vec_free(module->symbol_metas); +void scc_lir_module_drop(scc_lir_module_t *lir_module) { + // FIXME memory leak + scc_vec_free(lir_module->func_metas); + scc_vec_free(lir_module->symbol_metas); } -scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module, +scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module, const char *name) { - if (!module || !name) + if (!lir_module || !name) return SCC_CFG_ID_nullptr; scc_lir_symbol_meta_t *meta = scc_malloc(sizeof(scc_lir_symbol_meta_t)); @@ -26,21 +27,21 @@ scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module, .meta = meta}; meta->func.func = nullptr; - scc_vec_push(module->symbol_metas, meta); + scc_vec_push(lir_module->symbol_metas, meta); scc_cfg_symbol_id_t id = - scc_cfg_module_add_symbol(&module->cfg_module, &sym); + scc_cfg_module_add_symbol(&lir_module->cfg_module, &sym); if (id == SCC_CFG_ID_nullptr) { Panic("scc_lir: add func decl '%s' failed", name); } return id; } -scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *module, +scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *lir_module, const char *name, scc_cfg_symbol_kind_t kind, const u8 *init_data, usize size, u32 align) { - if (!module || !name) + if (!lir_module || !name) return SCC_CFG_ID_nullptr; if (kind != SCC_CFG_SYMBOL_KIND_DATA && kind != SCC_CFG_SYMBOL_KIND_EXTERN) return SCC_CFG_ID_nullptr; @@ -67,9 +68,9 @@ scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *module, } } - scc_vec_push(module->symbol_metas, meta); + scc_vec_push(lir_module->symbol_metas, meta); scc_cfg_symbol_id_t id = - scc_cfg_module_add_symbol(&module->cfg_module, &sym); + scc_cfg_module_add_symbol(&lir_module->cfg_module, &sym); if (id = SCC_CFG_ID_nullptr) { /* 冲突时释放已分配的数据 */ scc_free(meta->data.init_data); diff --git a/libs/ir/mir/cbuild.toml b/libs/ir/mir/cbuild.toml new file mode 100644 index 0000000..729e764 --- /dev/null +++ b/libs/ir/mir/cbuild.toml @@ -0,0 +1,15 @@ +[package] +name = "scc_mir" +version = "0.1.0" +authors = [] +description = "" + +dependencies = [ + { name = "scc_cfg", path = "../cfg" }, + { name = "scc_lir", path = "../lir" }, + { name = "scc_utils", path = "../../../runtime/scc_utils" }, + { name = "tree_dump", path = "../../tree_dump" }, + { name = "scc_mcode", path = "../../mcode" }, +] +# features = {} +# default_features = [] diff --git a/libs/ir/mir/include/scc_lir2mir.h b/libs/ir/mir/include/scc_lir2mir.h new file mode 100644 index 0000000..dd6d522 --- /dev/null +++ b/libs/ir/mir/include/scc_lir2mir.h @@ -0,0 +1,10 @@ +#ifndef __SCC_LIR2MIR_H__ +#define __SCC_LIR2MIR_H__ + +#include "scc_mir_module.h" +#include + +void scc_lir2mir(scc_mir_module_t *mir_module, + const scc_lir_module_t *lir_module); + +#endif /* __SCC_LIR2MIR_H__ */ diff --git a/libs/ir/mir/include/scc_mir.h b/libs/ir/mir/include/scc_mir.h new file mode 100644 index 0000000..ab165f2 --- /dev/null +++ b/libs/ir/mir/include/scc_mir.h @@ -0,0 +1,60 @@ +// scc_mir.h (示意) + +#ifndef __SCC_MIR_H__ +#define __SCC_MIR_H__ + +#include // 复用 VREG 概念和一些基础类型 +// #include "scc_target_desc.h" // 目标架构描述(寄存器文件、指令编码) + +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_kind_t; + +typedef struct scc_mir_operand { + scc_mir_op_kind_t kind; + union { + int vreg; // 虚拟寄存器索引 + int preg; // 物理寄存器 + i64 imm; // 立即数 + const char *symbol; // 符号名 + int stack_slot; // 栈槽 ID (由 FrameLayout 分配) + scc_lir_bblock_id_t block_id; // 目标基本块 + }; +} scc_mir_operand_t; + +typedef enum { + SCC_MIR_PSUEDO_ALLOCA = -1, +} scc_mir_psuedo_op_t; + +typedef struct scc_mir_instr { + int opcode; // 目标特定的指令编码 (如 X86::ADD32rr) + int num_operands; // 实际使用的操作数个数 + scc_mir_operand_t + operands[8]; // 固定小数组,RISC 风格指令通常不超过 4 操作数 + scc_pos_t src_loc; // 调试信息 (继承自 LIR) +} scc_mir_instr_t; +typedef SCC_VEC(scc_mir_instr_t) scc_mir_instr_vec_t; + +typedef scc_cfg_bblock_t scc_mir_bblock_t; +typedef struct scc_mir_bblock_meta { +} scc_mir_bblock_meta_t; +#define SCC_MIR_BBLOCK_VALUES(bblock) \ + ((scc_mir_instr_vec_t *)&((bblock)->values)) + +typedef scc_cfg_func_t scc_mir_func_t; +typedef struct scc_mir_func_meta { + // 栈帧信息 (由 FrameLayout Pass 填充) + int frame_size; + int stack_alignment; + // 寄存器分配信息 + SCC_VEC(int) vreg_alloc; // vreg -> phys reg 映射 +} scc_mir_func_meta_t; +#define SCC_MIR_FUNC_META(func) ((scc_mir_func_meta_t *)(func)->meta) + +#endif /* __SCC_MIR_H__ */ diff --git a/libs/ir/mir/include/scc_mir_dump.h b/libs/ir/mir/include/scc_mir_dump.h new file mode 100644 index 0000000..01b380e --- /dev/null +++ b/libs/ir/mir/include/scc_mir_dump.h @@ -0,0 +1,22 @@ +#ifndef __SCC_MIR_DUMP_H__ +#define __SCC_MIR_DUMP_H__ + +#include "scc_mir.h" +#include "scc_mir_module.h" +#include +typedef struct { + scc_tree_dump_t *dump_ctx; + scc_mir_module_t *mir_module; +} scc_mir_dump_ctx_t; + +static inline void scc_mir_dump_init(scc_mir_dump_ctx_t *ctx, + scc_tree_dump_t *dump_ctx, + scc_mir_module_t *module) { + Assert(ctx != nullptr && dump_ctx != nullptr && module != nullptr); + ctx->dump_ctx = dump_ctx; + ctx->mir_module = module; +} + +void scc_mir_dump_module(scc_mir_dump_ctx_t *ctx); + +#endif /* __SCC_MIR_DUMP_H__*/ diff --git a/libs/ir/mir/include/scc_mir_module.h b/libs/ir/mir/include/scc_mir_module.h new file mode 100644 index 0000000..0f047d0 --- /dev/null +++ b/libs/ir/mir/include/scc_mir_module.h @@ -0,0 +1,18 @@ +#ifndef __SCC_MIR_MODULE_H__ +#define __SCC_MIR_MODULE_H__ + +#include "scc_mir.h" +#include + +typedef scc_lir_symbol_meta_vec_t scc_mir_symbol_meta_vec_t; +typedef SCC_VEC(scc_mir_func_meta_t *) scc_mir_func_meta_vec_t; +typedef struct scc_mir_module { + scc_cfg_module_t cfg_module; + scc_mir_func_meta_vec_t func_metas; + scc_mir_symbol_meta_vec_t symbol_metas; +} scc_mir_module_t; + +void scc_mir_module_init(scc_mir_module_t *mir_module); +void scc_mir_module_drop(scc_mir_module_t *mir_module); + +#endif /* __SCC_MIR_MODULE_H__ */ diff --git a/libs/ir/mir/include/scc_mir_pass.h b/libs/ir/mir/include/scc_mir_pass.h new file mode 100644 index 0000000..1c5b9ca --- /dev/null +++ b/libs/ir/mir/include/scc_mir_pass.h @@ -0,0 +1,131 @@ +#ifndef __SCC_MIR_PASS_H__ +#define __SCC_MIR_PASS_H__ + +#include "scc_mir.h" + +/** Pass 的唯一标识符 (枚举) */ +typedef enum { + SCC_MIR_PASS_ABI_LOWERING, // ABI 物理化 (核心) + SCC_MIR_PASS_REG_ALLOC, // 寄存器分配 (核心) + SCC_MIR_PASS_FRAME_LAYOUT, // 栈帧布局 (核心) + SCC_MIR_PASS_PROLOGUE_EPILOGUE, // 序言/尾声插入 (核心) + SCC_MIR_PASS_DEAD_CODE_ELIM, // 死代码消除 (优化) + SCC_MIR_PASS_CONST_PROP, // 常量传播 (优化) + SCC_MIR_PASS_PEEPHOLE, // 窥孔优化 (优化) + SCC_MIR_PASS_CFG_SIMPLIFY, // CFG 简化 (优化) + SCC_MIR_PASS_COPY_PROP, // 复制传播 (优化) + SCC_MIR_PASS_COUNT +} scc_mir_pass_id_t; + +/** Pass 运行阶段 (用于自动排序) */ +typedef enum { + SCC_MIR_STAGE_ANY, // 无特殊阶段要求 + SCC_MIR_STAGE_PRE_REGALLOC, // 寄存器分配前 + SCC_MIR_STAGE_REGALLOC, // 寄存器分配本身 + SCC_MIR_STAGE_POST_REGALLOC // 寄存器分配后 +} scc_mir_pass_stage_t; + +/** + * @brief Pass 执行函数原型 + * @param func 输入的 MIR 函数 (Pass 可修改或替换) + * @param ctx 可选的上下文指针 (如目标机器信息、调试标志) + * @return 执行后的 MIR 函数指针 (若未修改可返回原指针,若需替换可返回新指针) + * @warning Pass 应负责释放不再使用的旧函数资源 + */ +typedef scc_mir_func_t *(*scc_mir_pass_fn_t)(scc_mir_func_t *func, void *ctx); + +typedef struct scc_lir_pass_desc { + scc_mir_pass_id_t id; // 唯一标识 + const char *name; // 可读名称 + scc_mir_pass_stage_t stage; // 所属阶段 + scc_mir_pass_id_t *deps; // 依赖的 Pass ID 数组 (可为 NULL) + usize num_deps; // 依赖数量 + scc_mir_pass_fn_t run; // 执行函数 + cbool required; // 是否为核心必需 Pass +} scc_mir_pass_desc_t; + +/* -------------------------------------------------------------------------- + * Pass 管理器 + * -------------------------------------------------------------------------- */ + +typedef struct scc_lir_pass_manager { + SCC_VEC(scc_mir_pass_desc_t) passes; // 所有已注册 Pass + SCC_VEC(scc_mir_pass_id_t) pipeline; // 当前流水线顺序 + void *ctx; // 传递给每个 Pass 的上下文 +} scc_mir_pass_manager_t; + +/** + * @brief 初始化 Pass 管理器 + * @param pm 管理器指针 + * @param ctx 全局上下文 (如 scc_target_t*) + */ +void scc_mir_pass_manager_init(scc_mir_pass_manager_t *pm, void *ctx); + +/** + * @brief 销毁 Pass 管理器,释放资源 + */ +void scc_mir_pass_manager_drop(scc_mir_pass_manager_t *pm); + +/** + * @brief 注册一个 Pass (通常在编译器初始化时调用) + * @param pm 管理器 + * @param desc Pass 描述符 + */ +void scc_mir_pass_register(scc_mir_pass_manager_t *pm, + const scc_mir_pass_desc_t *desc); + +/** + * @brief 构建默认的核心流水线 (仅包含 required=true 的 Pass) + * @param pm 管理器 + * + * 自动按阶段排序并解析依赖。 + */ +void scc_mir_pass_build_core_pipeline(scc_mir_pass_manager_t *pm); + +/** + * @brief 向流水线追加一个可选 Pass + * @param pm 管理器 + * @param id 要添加的 Pass ID + * @return 成功返回 true,若依赖不满足或 ID 无效返回 false + */ +cbool scc_mir_pass_add_to_pipeline(scc_mir_pass_manager_t *pm, + scc_mir_pass_id_t id); + +/** + * @brief 对指定函数运行当前流水线中的所有 Pass + * @param pm 管理器 + * @param func 要处理的 LIR 函数 + * @return 最终处理后的函数指针 + */ +scc_lir_func_t *scc_mir_pass_run_pipeline(scc_mir_pass_manager_t *pm, + scc_lir_func_t *func); + +/* -------------------------------------------------------------------------- + * 便捷宏:声明并注册一个 Pass + * -------------------------------------------------------------------------- */ + +/** + * @brief 在模块内部声明并注册一个 Pass + * @param pm 管理器指针 + * @param id Pass ID 枚举值 + * @param name_str Pass 名称字符串 + * @param stage 运行阶段 + * @param deps_arr 依赖数组 (可为 NULL) + * @param num_deps 依赖数量 + * @param fn 执行函数 + * @param req 是否必需 + */ +#define SCC_MIR_REGISTER_PASS(pm, id, name_str, stage, deps_arr, num_deps, fn, \ + req) \ + do { \ + scc_mir_pass_desc_t desc = {.id = (id), \ + .name = (name_str), \ + .stage = (stage), \ + .deps = (deps_arr), \ + .num_deps = (num_deps), \ + .run = (fn), \ + .required = (req)}; \ + scc_mir_pass_register((pm), &desc); \ + } while (0) + +#endif /* __SCC_LIR_PASS_H__ */ diff --git a/libs/ir/mir/src/mir_x86.c b/libs/ir/mir/src/mir_x86.c new file mode 100644 index 0000000..59bb0d9 --- /dev/null +++ b/libs/ir/mir/src/mir_x86.c @@ -0,0 +1,393 @@ +#include +#include +#include + +#include +#include + +static const char *preg_name(int preg_id) { + if (preg_id < 1 || preg_id >= SCC_X86_REG_COUNT) + return "???"; + return scc_x86_reg_table[preg_id].name; +} + +void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) { + scc_x86_iform_t iform = instr->opcode; + const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform]; + scc_tree_dump_append_fmt(td, " %s", info->iform_name); + // Assert(instr->num_operands == info->num_ops); + for (int i = 0; i < instr->num_operands; i += 1) { + if (i == 0) + scc_tree_dump_append(td, " "); + else + scc_tree_dump_append_fmt(td, ", "); + scc_mir_operand_t *op = &instr->operands[i]; + switch (op->kind) { + case SCC_MIR_OP_VREG: + scc_tree_dump_append_fmt(td, "$%d", op->vreg); + break; + case SCC_MIR_OP_PREG: + scc_tree_dump_append_fmt(td, "$%s", preg_name(op->preg)); + break; + case SCC_MIR_OP_IMM: + scc_tree_dump_append_fmt(td, "%ld", op->imm); + break; + case SCC_MIR_OP_BLOCK: + scc_tree_dump_append_fmt(td, "#BB%d", op->block_id); + break; + case SCC_MIR_OP_SYMBOL: + scc_tree_dump_append_fmt(td, "@%s", op->symbol); + break; + default: + break; + } + } +} + +typedef struct x86_isel { + scc_mir_instr_vec_t instrs; +} x86_isel_t; + +static void add_instr(x86_isel_t *isel, const scc_mir_instr_t *instr) { + scc_vec_push(isel->instrs, *instr); +} + +static inline void add_instr_0(x86_isel_t *isel, scc_x86_iform_t opcode) { + scc_mir_instr_t out = {.opcode = opcode, .num_operands = 0}; + add_instr(isel, &out); +} +static inline void add_instr_1(x86_isel_t *isel, scc_x86_iform_t opcode, + scc_mir_operand_t op1) { + scc_mir_instr_t out = {.opcode = opcode, .num_operands = 1}; + out.operands[0] = op1; + add_instr(isel, &out); +} +static inline void add_instr_2(x86_isel_t *isel, scc_x86_iform_t opcode, + scc_mir_operand_t op1, scc_mir_operand_t op2) { + scc_mir_instr_t out = {.opcode = opcode, .num_operands = 2}; + out.operands[0] = op1; + out.operands[1] = op2; + add_instr(isel, &out); +} + +// 将 LIR 值转换为 MIR 操作数 +static scc_mir_operand_t lir_val_to_mir_op(const scc_lir_val_t *val) { + scc_mir_operand_t op = {0}; + switch (val->kind) { + case SCC_LIR_INSTR_KIND_NONE: + op.kind = SCC_MIR_OP_NONE; + break; + case SCC_LIR_INSTR_KIND_VREG: + op.kind = SCC_MIR_OP_VREG; + op.vreg = val->data.reg; + break; + case SCC_LIR_INSTR_KIND_IMM: + op.kind = SCC_MIR_OP_IMM; + // FIXME hack ap + op.imm = val->data.imm.data.digit; + break; + case SCC_LIR_INSTR_KIND_FIMM: + // 浮点立即数暂时作为普通立即数处理(后端需特殊处理) + op.kind = SCC_MIR_OP_IMM; + op.imm = *(i64 *)&val->data.fimm; + break; + case SCC_LIR_INSTR_KIND_SYMBOL: + op.kind = SCC_MIR_OP_SYMBOL; + op.symbol = val->data.symbol; + break; + default: + UNREACHABLE(); + } + return op; +} + +static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) { + switch (instr->op) { + case SCC_LIR_MOV: { + add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89, + lir_val_to_mir_op(&instr->to), + lir_val_to_mir_op(&instr->arg0)); + } break; + case SCC_LIR_LOAD: { + add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, + lir_val_to_mir_op(&instr->to), + lir_val_to_mir_op(&instr->arg0)); + } break; + case SCC_LIR_LOAD_ADDR: { + add_instr_2(isel, SCC_X86_IFORM_LEA_GPRV_AGEN, + lir_val_to_mir_op(&instr->to), + lir_val_to_mir_op(&instr->arg0)); + } break; + case SCC_LIR_STORE: + case SCC_LIR_STORE_ADDR: { + add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, + lir_val_to_mir_op(&instr->arg1), + lir_val_to_mir_op(&instr->arg0)); + } break; + // case SCC_LIR_LEA: + // case SCC_LIR_NEG: + // case SCC_LIR_NOT: + // case SCC_LIR_FNEG: + // case SCC_LIR_FCVT: + case SCC_LIR_ALLOCA: { + add_instr_2(isel, SCC_MIR_PSUEDO_ALLOCA, lir_val_to_mir_op(&instr->to), + (scc_mir_operand_t){ + .kind = SCC_MIR_OP_IMM, + .imm = instr->size, + }); + } break; + + case SCC_LIR_ADD: + case SCC_LIR_SUB: + case SCC_LIR_MUL: + case SCC_LIR_AND: + case SCC_LIR_OR: + case SCC_LIR_XOR: + case SCC_LIR_SHL: + case SCC_LIR_SHR: + case SCC_LIR_SAR: { + int base; + bool is_commutative = + (instr->op != SCC_LIR_SUB && instr->op != SCC_LIR_SHL && + instr->op != SCC_LIR_SHR && instr->op != SCC_LIR_SAR); + switch (instr->op) { + case SCC_LIR_ADD: + base = SCC_X86_IFORM_ADD_GPRV_GPRV_01; + break; + case SCC_LIR_SUB: + base = SCC_X86_IFORM_SUB_GPRV_GPRV_29; + break; + case SCC_LIR_AND: + base = SCC_X86_IFORM_AND_GPRV_GPRV_21; + break; + case SCC_LIR_OR: + base = SCC_X86_IFORM_OR_GPRV_GPRV_09; + break; + case SCC_LIR_XOR: + base = SCC_X86_IFORM_XOR_GPRV_GPRV_31; + break; + case SCC_LIR_MUL: + base = SCC_X86_IFORM_IMUL_GPRV_GPRV; + break; + case SCC_LIR_SHL: + base = SCC_X86_IFORM_SHR_GPRV_IMMB; + break; // 简化,实际应处理 CL 移位 + case SCC_LIR_SHR: + base = SCC_X86_IFORM_SHR_GPRV_IMMB; + break; + case SCC_LIR_SAR: + base = SCC_X86_IFORM_SAR_GPRV_IMMB; + break; + default: + return; + } + + if (instr->arg0.kind == SCC_LIR_INSTR_KIND_IMM) { + add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMV, + lir_val_to_mir_op(&instr->to), + lir_val_to_mir_op(&instr->arg0)); + } + + // 三地址转两地址:若 to != arg0,需先 mov to, arg0 + if (instr->to.kind == SCC_LIR_INSTR_KIND_VREG && + instr->arg0.kind == SCC_LIR_INSTR_KIND_VREG && + instr->to.data.reg != instr->arg0.data.reg) { + add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89, + lir_val_to_mir_op(&instr->to), + lir_val_to_mir_op(&instr->arg0)); + } + + // 如果是立即数,使用 RI 变体 + if (instr->arg1.kind == SCC_LIR_INSTR_KIND_IMM) { + // 需要根据立即数大小选择 RI8/RI32 + add_instr_2(isel, base, lir_val_to_mir_op(&instr->to), + lir_val_to_mir_op(&instr->arg1)); + break; + } + + // 生成两地址运算指令 + add_instr_2(isel, base, lir_val_to_mir_op(&instr->to), + lir_val_to_mir_op(&instr->arg1)); + } break; + // case SCC_LIR_DIV_S: + // case SCC_LIR_DIV_U: + // case SCC_LIR_REM_S: + // case SCC_LIR_REM_U: + // case SCC_LIR_FADD: + // case SCC_LIR_FSUB: + // case SCC_LIR_FMUL: + // case SCC_LIR_FDIV: + // dump_operand(ctx, &instr->to); + // scc_tree_dump_append(td, ", "); + // dump_operand(ctx, &instr->arg0); + // scc_tree_dump_append(td, ", "); + // dump_operand(ctx, &instr->arg1); + // break; + + // case SCC_LIR_CMP: + // dump_operand(ctx, &instr->to); + // scc_tree_dump_append_fmt(td, ", %s, ", + // cond_to_string(instr->metadata.cond)); + // dump_operand(ctx, &instr->arg0); + // scc_tree_dump_append(td, ", "); + // dump_operand(ctx, &instr->arg1); + // break; + + // case SCC_LIR_BR: + // dump_operand(ctx, &instr->arg0); + // scc_tree_dump_append_fmt(td, ", BB#%zu, BB#%zu", + // instr->metadata.br.true_target, + // instr->metadata.br.false_target); + // break; + + case SCC_LIR_JMP: { + add_instr_1(isel, SCC_X86_IFORM_JMP_GPRV, + (scc_mir_operand_t){ + .kind = SCC_MIR_OP_BLOCK, + .block_id = instr->metadata.jmp_target, + }); + } break; + + // case SCC_LIR_JMP_INDIRECT: + // dump_operand(ctx, &instr->arg0); + // break; + + case SCC_LIR_CALL: { + const struct scc_lir_call *c = &instr->metadata.call; + Assert(c->callee != nullptr); + add_instr_1(isel, SCC_X86_IFORM_CALL_NEAR_GPRV, + (scc_mir_operand_t){ + .kind = SCC_MIR_OP_SYMBOL, + .symbol = c->callee, + }); + } break; + // case SCC_LIR_CALL: { + // const struct scc_lir_call *c = &instr->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 = + // &instr->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 (instr->metadata.ret_val.kind != SCC_LIR_INSTR_KIND_NONE) { + // FIXME target ABI + add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89, + (scc_mir_operand_t){ + .kind = SCC_MIR_OP_PREG, + .preg = SCC_X86_REG_RAX, + }, + lir_val_to_mir_op(&instr->metadata.ret_val)); + } + + add_instr_0(isel, SCC_X86_IFORM_RET_FAR); + } break; + + // case SCC_LIR_PARALLEL_COPY: { + // const struct scc_lir_parallel_copy *pc = + // &instr->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, &instr->metadata.va_start.ap); + // scc_tree_dump_append(td, ", "); + // dump_operand(ctx, &instr->metadata.va_start.last); + // break; + + // case SCC_LIR_VA_ARG: + // dump_operand(ctx, &instr->metadata.va_arg.to); + // scc_tree_dump_append(td, " = va_arg "); + // dump_operand(ctx, &instr->metadata.va_arg.ap); + // scc_tree_dump_append_fmt(td, ", size=%u, align=%u, float=%d", + // instr->metadata.va_arg.type_size, + // instr->metadata.va_arg.type_align, + // instr->metadata.va_arg.is_float); + // break; + + // case SCC_LIR_VA_END: + // dump_operand(ctx, &instr->metadata.va_end.ap); + // break; + + // case SCC_LIR_VA_COPY: + // dump_operand(ctx, &instr->metadata.va_copy.dest); + // scc_tree_dump_append(td, ", "); + // dump_operand(ctx, &instr->metadata.va_copy.src); + // break; + + // case SCC_LIR_NOP: + // break; + // + default: + break; + UNREACHABLE(); + break; + } +} +static void sel_func(scc_lir_module_t *lir_module, const scc_lir_func_t *func) { + x86_isel_t isel; + + scc_vec_foreach(func->bblocks, i) { + scc_vec_init(isel.instrs); + + scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i); + scc_cfg_bblock_t *bb = + scc_cfg_module_unsafe_get_bblock(&lir_module->cfg_module, id); + 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); + sel_mir(&isel, ins); + } + + bb->values = *(scc_cfg_value_vec_t *)&isel.instrs; + scc_vec_init(isel.instrs); + } +} + +void scc_isel_x86_64(scc_mir_module_t *mir_module, + scc_lir_module_t *lir_module) { + scc_vec_foreach(lir_module->cfg_module.funcs, i) { + if (i == 0) + continue; + scc_lir_func_t *func = &scc_vec_at(lir_module->cfg_module.funcs, i); + sel_func(lir_module, func); + } +} diff --git a/libs/ir/mir/src/scc_lir2mir.c b/libs/ir/mir/src/scc_lir2mir.c new file mode 100644 index 0000000..150a422 --- /dev/null +++ b/libs/ir/mir/src/scc_lir2mir.c @@ -0,0 +1,12 @@ +#include + +extern void scc_isel_x86_64(scc_mir_module_t *mir_module, + scc_lir_module_t *lir_module); + +void scc_lir2mir(scc_mir_module_t *mir_module, + const scc_lir_module_t *lir_module) { + // FIXME hack cfg module + mir_module->cfg_module = lir_module->cfg_module; + // TODO using target ABI choice it + scc_isel_x86_64(mir_module, lir_module); +} diff --git a/libs/ir/mir/src/scc_mir.c b/libs/ir/mir/src/scc_mir.c new file mode 100644 index 0000000..e69de29 diff --git a/libs/ir/mir/src/scc_mir_dump.c b/libs/ir/mir/src/scc_mir_dump.c new file mode 100644 index 0000000..0af4434 --- /dev/null +++ b/libs/ir/mir/src/scc_mir_dump.c @@ -0,0 +1,80 @@ +#include + +void scc_x86_instr_dump(scc_tree_dump_t *dump, const scc_mir_instr_t *instr); + +void scc_mir_dump_instr(scc_mir_dump_ctx_t *ctx, const scc_mir_instr_t *ins) { + scc_tree_dump_t *td = ctx->dump_ctx; + scc_tree_dump_begin_line(td); + if (ins->opcode >= 0) { + scc_x86_instr_dump(td, ins); + return; + } + + switch (ins->opcode) { + case SCC_MIR_PSUEDO_ALLOCA: + scc_tree_dump_node(td, " @alloca"); + scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm); + Assert(ins->operands[0].kind == SCC_MIR_OP_VREG); + scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg); + break; + default: + break; + } +} + +void scc_mir_dump_bblock(scc_mir_dump_ctx_t *ctx, const scc_mir_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_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb); + scc_vec_foreach(*instrs, i) { + const scc_mir_instr_t *ins = &scc_vec_at(*instrs, i); + scc_mir_dump_instr(ctx, ins); + } +} + +void scc_mir_dump_func(scc_mir_dump_ctx_t *ctx, const scc_mir_func_t *func) { + Assert(ctx != nullptr && func != nullptr); + scc_tree_dump_t *td = ctx->dump_ctx; + + scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func); + // 函数头部 + scc_tree_dump_begin_line(td); + scc_tree_dump_node(td, "func @%s", func->name ? func->name : ""); + + // 输出所有基本块 + 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->mir_module->cfg_module, id); + scc_mir_dump_bblock(ctx, bb); + } +} + +void scc_mir_dump_module(scc_mir_dump_ctx_t *ctx) { + scc_vec_foreach(ctx->mir_module->cfg_module.symbols, i) { + // FIXME 0 is null + if (i == 0) + continue; + scc_cfg_symbol_t *sym = + &scc_vec_at(ctx->mir_module->cfg_module.symbols, i); + scc_tree_dump_begin_line(ctx->dump_ctx); + scc_tree_dump_node(ctx->dump_ctx, "symbol"); + scc_tree_dump_append_fmt(ctx->dump_ctx, " %s", sym->name); + } + scc_vec_foreach(ctx->mir_module->cfg_module.funcs, i) { + if (i == 0) + continue; + scc_mir_dump_func(ctx, + &scc_vec_at(ctx->mir_module->cfg_module.funcs, i)); + } +} diff --git a/libs/ir/mir/src/scc_mir_module.c b/libs/ir/mir/src/scc_mir_module.c new file mode 100644 index 0000000..f628c90 --- /dev/null +++ b/libs/ir/mir/src/scc_mir_module.c @@ -0,0 +1,12 @@ +#include "scc_mir_module.h" + +void scc_mir_module_init(scc_mir_module_t *mir_module) { + scc_vec_init(mir_module->func_metas); + scc_vec_init(mir_module->symbol_metas); +} + +void scc_mir_module_drop(scc_mir_module_t *mir_module) { + // FIXME memory leak + scc_vec_free(mir_module->func_metas); + scc_vec_free(mir_module->symbol_metas); +} diff --git a/libs/ir/mir/src/scc_mir_pass.c b/libs/ir/mir/src/scc_mir_pass.c new file mode 100644 index 0000000..e69de29 diff --git a/src/config.h b/src/config.h index fd493ce..1a7d050 100644 --- a/src/config.h +++ b/src/config.h @@ -16,6 +16,7 @@ typedef struct { cbool emit_ast; cbool emit_hir; cbool emit_lir; + cbool emit_mir; } scc_config_t; static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, @@ -183,6 +184,13 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, scc_hints[SCC_HINT_EMIT_LIR]); scc_argparse_spec_setup_bool(&opt_lir.spec, &(config->emit_lir)); scc_argparse_cmd_add_opt(root, &opt_lir); + + // -M, --emit-mir + scc_argparse_opt_t opt_mir; + scc_argparse_opt_init(&opt_mir, 'M', "emit-mir", + scc_hints[SCC_HINT_EMIT_MIR]); + scc_argparse_spec_setup_bool(&opt_mir.spec, &(config->emit_mir)); + scc_argparse_cmd_add_opt(root, &opt_mir); } #endif /* __SCC_CONFIG_H___ */ diff --git a/src/main.c b/src/main.c index 4d03e82..3c171d2 100644 --- a/src/main.c +++ b/src/main.c @@ -7,8 +7,9 @@ #include #include #include +#include #include - +#include // #include // #include @@ -262,6 +263,26 @@ sstream_drop: return 0; } + scc_mir_module_t mir_module; + scc_mir_module_init(&mir_module); + scc_lir2mir(&mir_module, &lir_module); + if (config.emit_mir) { + 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, + fp == nullptr ? scc_stdout : fp); + scc_tree_dump_drop(&tree_dump); + return 0; + } + // scc_ir2mcode_ctx_t ir2mcode_ctx; // sccf_builder_t sccf_builder; // scc_ir2mcode_init(&ir2mcode_ctx, &cprog, &sccf_builder,