From 27d86d568541a9fc91f4b8d1df6d10ee2f91e577 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Sat, 4 Apr 2026 13:22:19 +0800 Subject: [PATCH] =?UTF-8?q?feat(ast2ir):=20=E6=B7=BB=E5=8A=A0=E6=8C=87?= =?UTF-8?q?=E9=92=88=E8=BF=90=E7=AE=97=E6=94=AF=E6=8C=81=E5=B9=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=95=B4=E6=95=B0=E5=AD=97=E9=9D=A2=E9=87=8F=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了指针解引用(*)和取地址(&)操作符的IR转换 - 添加parse_lexme2const_int函数统一处理整数字面量解析 - 支持数组大小表达式的常量解析 - 修复函数缺少返回语句的问题,在函数末尾添加默认ret指令 refactor(ir_builder): 调整函数参数类型处理逻辑 - 修改函数参数以指针形式传递,更新参数类型处理方式 - 优化参数节点创建过程,将参数类型包装为指针类型 fix(ir_dump): 修正IR输出格式问题 - 调整基本块和函数的输出格式,确保正确的换行和缩进 - 统一输出格式,提升可读性 feat(ir2mcode): 添加帧管理器头文件定义 - 定义frame_manager.h接口,包含栈帧分配相关函数声明 - 提供栈槽分配、寄存器保存、偏移计算等功能接口 refactor(reg_alloc): 添加初始栈大小配置 - 在寄存器分配器中增加init_stack_size字段 - 支持初始化栈大小设置,为后续帧管理功能做准备 test: 添加指针操作测试用例 - 新增14_pointer.c测试文件,验证指针取地址和解引用功能 - 在expect.toml中添加对应的期望返回值 --- libs/ast2ir/src/scc_ast2ir.c | 67 ++++++++++++++++----------- libs/ir/src/ir_builder.c | 13 ++++-- libs/ir/src/ir_dump.c | 15 +++--- libs/ir2mcode/include/frame_manager.h | 27 +++++++++++ libs/ir2mcode/include/reg_alloc.h | 1 + libs/ir2mcode/src/frame_manager.c | 0 libs/ir2mcode/src/ir2amd64.c | 6 ++- libs/ir2mcode/src/reg_alloc.c | 3 +- src/target.c | 1 + tests/simple/14_pointer.c | 12 +++++ tests/simple/expect.toml | 5 +- 11 files changed, 109 insertions(+), 41 deletions(-) create mode 100644 libs/ir2mcode/include/frame_manager.h create mode 100644 libs/ir2mcode/src/frame_manager.c create mode 100644 src/target.c create mode 100644 tests/simple/14_pointer.c diff --git a/libs/ast2ir/src/scc_ast2ir.c b/libs/ast2ir/src/scc_ast2ir.c index d1971be..4f4a23a 100644 --- a/libs/ast2ir/src/scc_ast2ir.c +++ b/libs/ast2ir/src/scc_ast2ir.c @@ -1,5 +1,15 @@ #include +static inline void parse_lexme2const_int(const char *lexme, + scc_ir_const_int_t *value) { + // FIXME + usize int_lit = 0; + for (usize i = 0; i < scc_strlen(lexme); i++) { + int_lit = int_lit * 10 + (lexme[i] - '0'); + } + value->int64 = int_lit; +} + scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx, scc_ast_type_t *ast_type) { if (ctx == null || ast_type == null) { @@ -51,7 +61,16 @@ scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx, ir_type.data.array.base = element_type; // TODO: 处理数组大小表达式 - ir_type.data.array.len = 0; // 暂时设为0 + ir_type.data.array.len = 0; + if (ast_type->array.size) { + // TODO constant expression + if (ast_type->array.size->base.type != SCC_AST_EXPR_INT_LITERAL) { + Panic("TODO: array size expression"); + } + scc_ir_const_int_t value; + parse_lexme2const_int(ast_type->array.size->literal.lexme, &value); + ir_type.data.array.len = value.int32; + } break; } @@ -315,6 +334,20 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr, } case SCC_AST_EXPR_UNARY: { + if (expr->unary.op == SCC_AST_OP_ADDRESS_OF) { + return scc_ast2ir_expr(ctx, expr->unary.operand, true); + } else if (expr->unary.op == SCC_AST_OP_INDIRECTION) { + // 从地址取值 + scc_ir_value_ref_t ptr = + scc_ast2ir_expr(ctx, expr->unary.operand, false); + if (is_lvalue) { + // 作为左值使用(如 *ptr = ...),直接返回指针值(地址) + return ptr; + } else { + // 作为右值使用(如 x = *ptr),加载指针指向的值 + return scc_ir_builder_load(&ctx->builder, ptr); + } + } scc_ir_value_ref_t operand = scc_ast2ir_expr(ctx, expr->unary.operand, is_lvalue); // /* 一元操作符 */ @@ -344,27 +377,9 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr, operand); } case SCC_AST_OP_ADDRESS_OF: - // 取地址 - operand = - scc_ir_builder_get_ptr(&ctx->builder, operand, SCC_IR_REF_NULL); - Assert(operand != SCC_IR_REF_NULL); - return operand; case SCC_AST_OP_INDIRECTION: - // 从地址取值 - // FIXME - scc_ir_value_t *value = - scc_ir_module_get_value(ctx->builder.ctx.module, operand); - Assert(value != null); - scc_ir_type_t *type = - scc_ir_module_get_type(ctx->builder.ctx.module, value->type); - Assert(type != null); - if (type->tag != SCC_IR_TYPE_PTR) { - LOG_FATAL("Invalid type: %d", type->tag); - } - - operand = scc_ir_builder_load(&ctx->builder, operand); - Assert(operand != SCC_IR_REF_NULL); - return operand; + UNREACHABLE(); + break; case SCC_AST_OP_BITWISE_NOT: // 按位取反 return scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_NOT, operand, @@ -428,16 +443,11 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr, case SCC_AST_EXPR_INT_LITERAL: { // FIXME maybe using some array to int; - usize int_lit = 0; - for (usize i = 0; i < scc_strlen(expr->literal.lexme); i++) { - int_lit = int_lit * 10 + (expr->literal.lexme[i] - '0'); - } scc_ir_type_ref_t type_ref = scc_ir_builder_type_i32(&ctx->builder); scc_ir_const_int_t value; - value.int32 = int_lit; + parse_lexme2const_int(expr->literal.lexme, &value); return scc_ir_builder_const_int(&ctx->builder, type_ref, value); } - // SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量 case SCC_AST_EXPR_CHAR_LITERAL: { // FIXME just 'a' '\n' @@ -752,6 +762,9 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl) { (void *)(usize)param_node_ref); } scc_ast2ir_stmt(ctx, decl->func.body); + // FIXME need ret for none return or other default ret + scc_ir_builder_ret_void(&ctx->builder); + scc_ir_builder_end_bblock(&ctx->builder); scc_ir_builder_end_func(&ctx->builder); break; diff --git a/libs/ir/src/ir_builder.c b/libs/ir/src/ir_builder.c index 0b74697..778bb6a 100644 --- a/libs/ir/src/ir_builder.c +++ b/libs/ir/src/ir_builder.c @@ -56,13 +56,17 @@ void scc_ir_builder_begin_func(scc_ir_builder_t *builder, return; } - scc_vec_foreach(func_type->data.function.params, i) { - scc_ir_type_ref_t param_type = - scc_vec_at(func_type->data.function.params, i); + scc_ir_type_ref_vec_t params = func_type->data.function.params; + func_type = null; + scc_vec_foreach(params, i) { + scc_ir_type_ref_t param_type = scc_vec_at(params, i); scc_ir_value_t param_node = {0}; param_node.tag = SCC_IR_VALUE_TAG_FUNC_ARG_REF; // 参数节点标记 - param_node.type = param_type; + param_node.type = scc_ir_module_add_type( + GET_MODULE(builder), + &(scc_ir_type_t){.tag = SCC_IR_TYPE_PTR, + .data.pointer.base = param_type}); param_node.name = param_names ? param_names[i] : null; param_node.data.arg_ref.idx = i; scc_vec_init(param_node.used_by); @@ -71,7 +75,6 @@ void scc_ir_builder_begin_func(scc_ir_builder_t *builder, scc_ir_module_add_value(GET_MODULE(builder), ¶m_node); scc_vec_push(func_ptr->params, param_ref); } - return; } diff --git a/libs/ir/src/ir_dump.c b/libs/ir/src/ir_dump.c index 2313bdc..c0af6a7 100644 --- a/libs/ir/src/ir_dump.c +++ b/libs/ir/src/ir_dump.c @@ -597,10 +597,11 @@ void scc_ir_dump_node_linear(scc_ir_dump_ctx_t *ctx, void scc_ir_dump_bblock_linear(scc_ir_dump_ctx_t *ctx, scc_ir_bblock_ref_t bblock_ref) { + scc_tree_dump_begin_line(ctx->dump_ctx); scc_ir_bblock_t *bblock = scc_ir_module_get_bblock(GET_MODULE(ctx), bblock_ref); if (!bblock) { - scc_tree_dump_append(ctx->dump_ctx, "\n"); + scc_tree_dump_append(ctx->dump_ctx, ""); return; } if (bblock->label && bblock->label[0] != '\0') @@ -610,7 +611,8 @@ void scc_ir_dump_bblock_linear(scc_ir_dump_ctx_t *ctx, scc_tree_dump_append_fmt(ctx->dump_ctx, "%%L%d :", bblock_ref); for (usize i = 0; i < scc_vec_size(bblock->instrs); i++) { - scc_tree_dump_append(ctx->dump_ctx, "\n "); + scc_tree_dump_begin_line(ctx->dump_ctx); + scc_tree_dump_append(ctx->dump_ctx, " "); scc_ir_dump_node_linear(ctx, scc_vec_at(bblock->instrs, i)); } } @@ -651,16 +653,17 @@ void scc_ir_dump_func_linear(scc_ir_dump_ctx_t *ctx, scc_ir_func_ref_t func_ref, scc_ir_dump_type_linear(ctx, func->type); if (is_decl) { - scc_tree_dump_append(ctx->dump_ctx, ";\n"); + scc_tree_dump_append(ctx->dump_ctx, ";"); return; } - scc_tree_dump_append(ctx->dump_ctx, " {\n"); + scc_tree_dump_append(ctx->dump_ctx, " {"); for (usize i = 0; i < scc_vec_size(func->bblocks); i++) { scc_ir_dump_bblock_linear(ctx, scc_vec_at(func->bblocks, i)); - scc_tree_dump_append(ctx->dump_ctx, "\n"); + scc_tree_dump_append(ctx->dump_ctx, ""); } - scc_tree_dump_append(ctx->dump_ctx, "}\n"); + scc_tree_dump_begin_line(ctx->dump_ctx); + scc_tree_dump_append(ctx->dump_ctx, "}"); } void scc_ir_dump_cprog_linear(scc_ir_dump_ctx_t *ctx) { diff --git a/libs/ir2mcode/include/frame_manager.h b/libs/ir2mcode/include/frame_manager.h new file mode 100644 index 0000000..917aec0 --- /dev/null +++ b/libs/ir2mcode/include/frame_manager.h @@ -0,0 +1,27 @@ +#ifndef __SCC_FRAME_MANAGER_H__ +#define __SCC_FRAME_MANAGER_H__ + +typedef struct frame_manager frame_manager_t; + +// 初始化帧管理器,传入 ABI 参数(影子空间大小、栈对齐等) +void frame_manager_init(frame_manager_t *fm, int shadow_space, int align); + +// 分配一个栈槽(用于局部变量或临时值),返回虚拟槽索引(从0开始) +int frame_alloc_slot(frame_manager_t *fm, int size); + +// 分配一个保存的寄存器槽(用于被调用者保存的寄存器),返回虚拟槽索引 +int frame_alloc_saved_reg(frame_manager_t *fm, int reg_width); + +// 计算最终栈帧总大小(已对齐) +int frame_total_size(frame_manager_t *fm); + +// 将虚拟槽索引转换为相对于 RBP 的偏移(正数,表示从 RBP 向下的距离) +int frame_slot_offset(frame_manager_t *fm, int slot_idx); + +// 获取影子空间大小(固定) +int frame_shadow_space(frame_manager_t *fm); + +// 获取保存寄存器区域的总大小 +int frame_saved_reg_size(frame_manager_t *fm); + +#endif /* __SCC_FRAME_MANAGER_H__ */ diff --git a/libs/ir2mcode/include/reg_alloc.h b/libs/ir2mcode/include/reg_alloc.h index b0c54f6..5f3cf1b 100644 --- a/libs/ir2mcode/include/reg_alloc.h +++ b/libs/ir2mcode/include/reg_alloc.h @@ -37,6 +37,7 @@ typedef struct scc_reg_alloc { int gpr_callee_saved; ///< 函数必须保护这些寄存器的值. scc_reg_alloc_func_t reg_alloc_func; int alloc_stack_size; + int init_stack_size; } scc_reg_alloc_t; #define scc_reg_alloc(ctx, func) ((ctx)->reg_alloc_func(ctx, func)) diff --git a/libs/ir2mcode/src/frame_manager.c b/libs/ir2mcode/src/frame_manager.c new file mode 100644 index 0000000..e69de29 diff --git a/libs/ir2mcode/src/ir2amd64.c b/libs/ir2mcode/src/ir2amd64.c index cb27a58..dd034ff 100644 --- a/libs/ir2mcode/src/ir2amd64.c +++ b/libs/ir2mcode/src/ir2amd64.c @@ -198,9 +198,11 @@ static void parse_value(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref, scc_mcode_amd64_mov_r32_m32( &ctx->sect_mcode, SCC_AMD64_RAX, SCC_AMD64_RCX); // 32位加载自动清零高位 - } else { // 8 + } else if (width == 8) { // 8 scc_mcode_amd64_mov_r64_m64(&ctx->sect_mcode, SCC_AMD64_RAX, SCC_AMD64_RCX); + } else { + UNREACHABLE(); } // 存储结果 store_value_from_reg(&ctx->sect_mcode, &to, SCC_AMD64_RAX); @@ -503,6 +505,8 @@ static int equal_func(const void *key1, const void *key2) { } static void parse_function(scc_ir2mcode_ctx_t *ctx, scc_ir_func_t *func) { + // FIXME using API instead + ctx->reg_alloc.init_stack_size = 8; ctx->noderef2regloc = scc_reg_alloc(&ctx->reg_alloc, func); // 对齐到 16 字节 // FIXME diff --git a/libs/ir2mcode/src/reg_alloc.c b/libs/ir2mcode/src/reg_alloc.c index 68a0295..df852cd 100644 --- a/libs/ir2mcode/src/reg_alloc.c +++ b/libs/ir2mcode/src/reg_alloc.c @@ -13,13 +13,14 @@ void scc_reg_alloc_init(scc_reg_alloc_t *ctx, scc_reg_alloc_func_t func, ctx->reg_alloc_func = func; ctx->alloc_stack_size = 0; + ctx->init_stack_size = 0; scc_vec_init(ctx->reg_loc_vec); scc_hashtable_init(&ctx->node_ref2reg_loc, hash_func, equal_func); } scc_hashtable_t *scc_reg_alloc_with_stack(scc_reg_alloc_t *ctx, scc_ir_func_t *func) { - ctx->alloc_stack_size = 0; + ctx->alloc_stack_size = ctx->init_stack_size; scc_hashtable_drop(&ctx->node_ref2reg_loc); scc_vec_free(ctx->reg_loc_vec); scc_vec_init(ctx->reg_loc_vec); diff --git a/src/target.c b/src/target.c new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/target.c @@ -0,0 +1 @@ + diff --git a/tests/simple/14_pointer.c b/tests/simple/14_pointer.c new file mode 100644 index 0000000..3d496f7 --- /dev/null +++ b/tests/simple/14_pointer.c @@ -0,0 +1,12 @@ + +void exchange(int *a, int *b) { + int tmp = *a; + *a = *b; + *b = tmp; +} + +int main(void) { + int a = 1, b = 3; + exchange(&a, &b); + return a - b; +} diff --git a/tests/simple/expect.toml b/tests/simple/expect.toml index e225f7e..0fdbcb5 100644 --- a/tests/simple/expect.toml +++ b/tests/simple/expect.toml @@ -1,5 +1,7 @@ [return_val_cases] -# windows: echo $LASTEXITCODE +# windows powershell: echo $LASTEXITCODE +# nushell: echo $env.LAST_EXIT_CODE +# bash: echo $? "./01_return.c" = 65536 "./02_decl_expr.c" = 1 "./03_decl_init.c" = 11 @@ -13,4 +15,5 @@ "./11_recursive.c" = 120 "./12_logic.c" = 10 "./13_array.c" = 1198 +"./14_pointer.c" = 2 [stdout_val_cases]