From 4f40f0d5e4a958236543f88caef7ec49f947b534 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Mon, 11 May 2026 13:18:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(mir):=20=E6=B7=BB=E5=8A=A0=E5=AF=84?= =?UTF-8?q?=E5=AD=98=E5=99=A8=E5=88=86=E9=85=8D=20pass=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了核心寄存器分配接口 scc_reg_alloc.h - 添加 x86_64 架构特定的寄存器分配实现 - 实现基础的虚拟寄存器到物理寄存器分配逻辑 - 支持栈槽分配和重载/存储指令生成 fix(argparse): 修复帮助信息打印中的枚举类型显示 - 将固定大小缓冲区改为动态字符串处理 - 正确显示枚举类型的选项值和可选值列表 - 使用 | 分隔符展示多个可选值 refactor(main): 调整编译流程中的 pass 阶段支持 - 更新配置文件中各编译阶段的名称定义 - 添加对寄存器分配、帧布局等中间表示 pass 的支持 - 重构主流程以支持不同 MIR 阶段的代码输出 --- libs/argparse/src/argparse_print.c | 40 +++++-- libs/ir/mir/include/core_pass/scc_reg_alloc.h | 45 +++++++ libs/ir/mir/src/arch/x86_64_reg_alloc.c | 86 ++++++++++++++ libs/ir/mir/src/reg_alloc/reg_alloc.c | 111 ++++++++++++++++++ libs/ir/mir/src/scc_mir_pass.c | 9 +- libs/mcode/cbuild.toml | 9 ++ src/config.c | 6 +- src/main.c | 24 +++- 8 files changed, 311 insertions(+), 19 deletions(-) create mode 100644 libs/ir/mir/include/core_pass/scc_reg_alloc.h create mode 100644 libs/ir/mir/src/arch/x86_64_reg_alloc.c create mode 100644 libs/ir/mir/src/reg_alloc/reg_alloc.c create mode 100644 libs/mcode/cbuild.toml diff --git a/libs/argparse/src/argparse_print.c b/libs/argparse/src/argparse_print.c index fc26fb7..0aa05b2 100644 --- a/libs/argparse/src/argparse_print.c +++ b/libs/argparse/src/argparse_print.c @@ -145,24 +145,42 @@ void scc_argparse_print_help(scc_argparse_t *parser, scc_argparse_cmd_t *cmd) { continue; if (opt->short_name == 'h') opt->description = lines[ARGPARSE_SHOW_HELP_MSG]; - char buf[64]; + scc_str_t buf; + scc_str_init(&buf); int pos = 0; if (opt->short_name) { - buf[pos++] = '-'; - buf[pos++] = opt->short_name; + scc_str_append_ch(&buf, '-'); + scc_str_append_ch(&buf, opt->short_name); if (opt->long_name) { - buf[pos++] = ','; - buf[pos++] = ' '; + scc_str_append_ch(&buf, ','); + scc_str_append_ch(&buf, ' '); } } if (opt->long_name) { - buf[pos++] = '-'; - buf[pos++] = '-'; - for (const char *p = opt->long_name; *p; ++p) - buf[pos++] = *p; + scc_str_append_ch(&buf, '-'); + scc_str_append_ch(&buf, '-'); + scc_str_append_cstr(&buf, opt->long_name, + scc_strlen(opt->long_name)); } - buf[pos] = '\0'; - scc_printf(" %-25s %s", buf, + if (opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_ENUM) { + scc_str_append_ch(&buf, '='); + scc_str_append_ch(&buf, '<'); + for (int j = 0; j < opt->spec.choices.count; j += 1) { + if (opt->spec.choices.values[j] == 0) { + continue; + } + + if (j != 0) { + scc_str_append_ch(&buf, '|'); + } + + scc_str_append_cstr( + &buf, opt->spec.choices.values[j], + scc_strlen(opt->spec.choices.values[j])); + } + scc_str_append_ch(&buf, '>'); + } + scc_printf(" %-25s %s", scc_str_as_cstr(&buf), opt->description ? opt->description : ""); // if (opt->spec.default_value) // scc_printf(" (default: %s)", opt->spec.default_value); diff --git a/libs/ir/mir/include/core_pass/scc_reg_alloc.h b/libs/ir/mir/include/core_pass/scc_reg_alloc.h new file mode 100644 index 0000000..2795c8e --- /dev/null +++ b/libs/ir/mir/include/core_pass/scc_reg_alloc.h @@ -0,0 +1,45 @@ +#ifndef __SCC_REG_ALLOC_H__ +#define __SCC_REG_ALLOC_H__ + +#include "../scc_mir_module.h" + +typedef enum { + SCC_REG_ALLOC_OP_ACCESS_READ = 0, + SCC_REG_ALLOC_OP_ACCESS_WRITE = 1, + SCC_REG_ALLOC_OP_ACCESS_READWRITE = 2, +} scc_op_access_t; + +typedef struct scc_reg_alloc_op { + // ---- 指令生成(纯动作,无状态) ---- + + // preg → [slot] + void (*emit_spill)(scc_mir_instr_vec_t *ctx, int preg, int slot); + // [slot] → preg + void (*emit_reload)(scc_mir_instr_vec_t *ctx, int preg, int slot); + // preg → preg + void (*emit_copy)(scc_mir_instr_vec_t *ctx, int dst_preg, int src_preg, + int size); + + // 通用寄存器申请 / 释放 + int (*acquire_reg)(void *ctx); // 返回一个物理寄存器编号 + void (*release_reg)(void *ctx, int preg); // 归还该寄存器 + + // 显式标记某个寄存器已占用 / 未占用(用于隐式寄存器、固定分配等) + void (*mark_reg_used)(void *ctx, int preg); + void (*mark_reg_unused)(void *ctx, int preg); + + // ---- 指令信息查询(只读) ---- + scc_op_access_t (*get_operand_access)(void *ctx, int opcode, int op_idx); + void (*get_implicit_regs)(void *ctx, int opcode, const int **out_uses, + const int **out_defs); +} scc_reg_alloc_op_t; + +typedef struct scc_reg_alloc_ctx { + const scc_reg_alloc_op_t *ops; + scc_mir_func_meta_t *func_meta; + scc_mir_instr_vec_t *instrs; +} scc_reg_alloc_ctx_t; + +void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module); + +#endif /* __SCC_REG_ALLOC__ */ diff --git a/libs/ir/mir/src/arch/x86_64_reg_alloc.c b/libs/ir/mir/src/arch/x86_64_reg_alloc.c new file mode 100644 index 0000000..72cf737 --- /dev/null +++ b/libs/ir/mir/src/arch/x86_64_reg_alloc.c @@ -0,0 +1,86 @@ +#include +#include + +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}, + {.kind = SCC_MIR_OP_PREG, .preg = preg}}}; + scc_vec_push(*ctx, ins); +} + +static void x86_emit_reload(scc_mir_instr_vec_t *ctx, int preg, int slot) { + scc_mir_instr_t ins = { + .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}}}; + scc_vec_push(*ctx, ins); +} + +static void x86_emit_copy(scc_mir_instr_vec_t *ctx, int dst_preg, int src_preg, + int size) { + scc_mir_instr_t ins = { + .opcode = SCC_X86_IFORM_MOV_GPRV_GPRV_89, + .num_operands = 2, + .operands = {{.kind = SCC_MIR_OP_PREG, .preg = dst_preg}, + {.kind = SCC_MIR_OP_PREG, .preg = src_preg}}}; + scc_vec_push(*ctx, ins); +} + +/* ---- 临时寄存器 ---- */ +static int x86_acquire_temp_reg(void *vctx) { return SCC_X86_REG_R11; } + +static void x86_release_temp_reg(void *vctx, int preg) { /* 简单模式无需操作 */ +} + +/* ---- 操作数读写属性 ---- */ +static scc_op_access_t x86_get_operand_access(void *vctx, int opcode, + int op_idx) { + switch (opcode) { + default: + return SCC_REG_ALLOC_OP_ACCESS_READWRITE; // 保守 + } +} + +/* ---- 隐式寄存器 ---- */ +static void x86_get_implicit_regs(void *vctx, int opcode, const int **uses, + const int **defs) { + static const int empty[] = {-1}; + static const int rax[] = {SCC_X86_REG_RAX, -1}; + static const int rdx[] = {SCC_X86_REG_RDX, -1}; + static const int rax_rdx[] = {SCC_X86_REG_RAX, SCC_X86_REG_RDX, -1}; + static const int cl[] = {SCC_X86_REG_CL, -1}; + + switch (opcode) { + case SCC_X86_IFORM_IDIV_GPRV: + case SCC_X86_IFORM_DIV_GPRV: + *uses = rax_rdx; + *defs = rax_rdx; + break; + case SCC_X86_IFORM_CQO: + *uses = rax; + *defs = rax_rdx; + break; + case SCC_X86_IFORM_SAR_GPRV_CL: + *uses = cl; + *defs = empty; + break; + default: + *uses = empty; + *defs = empty; + break; + } +} + +/* 组装 hooks 表 */ +scc_reg_alloc_op_t x86_reg_alloc_hooks = { + .emit_spill = x86_emit_spill, + .emit_reload = x86_emit_reload, + .emit_copy = x86_emit_copy, + .acquire_reg = x86_acquire_temp_reg, + .release_reg = x86_release_temp_reg, + .get_operand_access = x86_get_operand_access, + .get_implicit_regs = x86_get_implicit_regs, +}; \ No newline at end of file diff --git a/libs/ir/mir/src/reg_alloc/reg_alloc.c b/libs/ir/mir/src/reg_alloc/reg_alloc.c new file mode 100644 index 0000000..2287983 --- /dev/null +++ b/libs/ir/mir/src/reg_alloc/reg_alloc.c @@ -0,0 +1,111 @@ +#include +#include +#include + +static int ensure_slot(scc_reg_alloc_ctx_t *ctx, int vreg) { + void *key = (void *)(usize)vreg; + void *val = scc_hashtable_get(&ctx->func_meta->vreg2slot, key); + if (val != NULL) + return (int)(usize)val; + int new_slot = scc_vec_size(ctx->func_meta->stack_slots) + 1; // 1-based + scc_mir_stack_slot_t s = { + .slot_id = new_slot, .size = 8, .alignment = 8, .offset = 0}; + scc_vec_push(ctx->func_meta->stack_slots, s); + scc_hashtable_set(&ctx->func_meta->vreg2slot, key, (void *)(usize)new_slot); + return new_slot; +} + +static void alloc_instr(scc_reg_alloc_ctx_t *ctx, + scc_mir_instr_vec_t *instr_vec, + scc_mir_instr_t *instr) { + const scc_reg_alloc_op_t *ops = ctx->ops; + scc_mir_instr_vec_t before_instrs; + scc_vec_init(before_instrs); + scc_mir_instr_vec_t after_instrs; + scc_vec_init(after_instrs); + + for (int i = 0; i < instr->num_operands; i += 1) { + if (instr->operands[i].kind != SCC_MIR_OP_VREG) { + continue; + } + + int vreg = instr->operands[i].vreg; + scc_op_access_t op_access = + ops->get_operand_access(ctx, instr->opcode, i); + int slot = ensure_slot(ctx, vreg); + + int preg = -1; + // if (implicit_uses && implicit_uses[0] != -1) + // preg = implicit_uses[0]; + // else + preg = ops->acquire_reg(ctx); + + if (op_access == SCC_REG_ALLOC_OP_ACCESS_READ || + op_access == SCC_REG_ALLOC_OP_ACCESS_READWRITE) { + ops->emit_reload(&before_instrs, preg, slot); + } + instr->operands[i].kind = SCC_MIR_OP_PREG; + instr->operands[i].preg = preg; + if (op_access == SCC_REG_ALLOC_OP_ACCESS_WRITE || + op_access == SCC_REG_ALLOC_OP_ACCESS_READWRITE) { + ops->emit_spill(&after_instrs, preg, slot); + } + + ops->release_reg(ctx, preg); + } + + scc_vec_foreach(before_instrs, i) { + scc_vec_push(*instr_vec, scc_vec_at(before_instrs, i)); + } + scc_vec_push(*instr_vec, *instr); + // TODO reverse it + scc_vec_foreach(after_instrs, i) { + scc_vec_push(*instr_vec, scc_vec_at(after_instrs, i)); + } +} + +/* 对一个基本块执行分配 */ +static void alloc_bb(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module, + scc_cfg_bblock_id_t bb_id) { + 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); + + 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_vec_push(new_instrs, ins); + continue; + } + alloc_instr(ctx, &new_instrs, &ins); + } + + scc_vec_free(*old_instrs); + *old_instrs = new_instrs; +} + +/* 对一个函数运行分配 */ +static void alloc_func(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module, + scc_mir_func_t *func) { + + ctx->func_meta = SCC_MIR_FUNC_META(func); + scc_vec_foreach(func->bblocks, i) { + scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i); + alloc_bb(ctx, module, bb_id); + } + ctx->func_meta = nullptr; +} + +/* 公开入口 */ +void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module) { + Assert(ctx != nullptr && module != nullptr); + scc_vec_foreach(module->cfg_module.funcs, i) { + if (i == 0) + continue; + alloc_func(ctx, module, &scc_vec_at(module->cfg_module.funcs, i)); + } +} diff --git a/libs/ir/mir/src/scc_mir_pass.c b/libs/ir/mir/src/scc_mir_pass.c index 99eacff..ac4464e 100644 --- a/libs/ir/mir/src/scc_mir_pass.c +++ b/libs/ir/mir/src/scc_mir_pass.c @@ -1,8 +1,11 @@ #include #include +#include -extern scc_reg_alloc_t x86_reg_alloc_hooks; +extern scc_reg_alloc_op_t x86_reg_alloc_hooks; -void scc_mir_pass(scc_mir_module_t *mir_module) { - scc_reg_alloc(&x86_reg_alloc_hooks, mir_module); +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_meta = nullptr, .instrs = nullptr, .ops = &x86_reg_alloc_hooks}; + scc_reg_alloc(®_alloc_ctx, mir_module); } diff --git a/libs/mcode/cbuild.toml b/libs/mcode/cbuild.toml new file mode 100644 index 0000000..347f90c --- /dev/null +++ b/libs/mcode/cbuild.toml @@ -0,0 +1,9 @@ +[package] +name = "mcode" +version = "0.1.0" +authors = [] +description = "" + +dependencies = [{ name = "scc_core", path = "../../runtime/scc_core" }] +# features = {} +# default_features = [] diff --git a/src/config.c b/src/config.c index 9373cc7..fd63ac1 100644 --- a/src/config.c +++ b/src/config.c @@ -161,9 +161,9 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, [SCC_EMIT_STAGE_LIR] = "lir", // -L [SCC_EMIT_STAGE_MIR] = "mir", // -M - [SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC] = "", - [SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT] = "", - [SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG] = "", + [SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC] = "reg_alloc", + [SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT] = "frame_layout", + [SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG] = "prolog_epilog", [SCC_EMIT_STAGE_FLATBIN] = "flatbin", [SCC_EMIT_STAGE_SCCF] = "sccf", [SCC_EMIT_STAGE_TARGET] = "target", diff --git a/src/main.c b/src/main.c index aed0a98..df71c19 100644 --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,8 @@ #include #include +#include + #include #include #include @@ -271,7 +273,25 @@ sstream_drop: scc_mir_module_t mir_module; scc_mir_module_init(&mir_module); scc_lir2mir(&mir_module, &lir_module); - if (config.emit_stage == SCC_EMIT_STAGE_MIR) { + + switch (config.emit_stage) { + case SCC_EMIT_STAGE_MIR: + goto mir_dump; + case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC); + goto mir_dump; + case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_POST_REGALLOC); + goto mir_dump; + case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_POST_REGALLOC); + goto mir_dump; + break; + default: + break; + } + do { + mir_dump: scc_mir_dump_ctx_t mir_dump_ctx; scc_tree_dump_t tree_dump; if (fp == nullptr) { @@ -285,7 +305,7 @@ sstream_drop: 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};