feat(ast2ir): 添加指针运算支持并修复整数字面量解析

- 实现了指针解引用(*)和取地址(&)操作符的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中添加对应的期望返回值
This commit is contained in:
zzy
2026-04-04 13:22:19 +08:00
parent ca187c78f1
commit 27d86d5685
11 changed files with 109 additions and 41 deletions

View File

@@ -1,5 +1,15 @@
#include <scc_ast2ir.h>
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;

View File

@@ -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), &param_node);
scc_vec_push(func_ptr->params, param_ref);
}
return;
}

View File

@@ -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, "<invalid block>\n");
scc_tree_dump_append(ctx->dump_ctx, "<invalid block>");
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 <unnamed>:", 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) {

View File

@@ -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__ */

View File

@@ -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))

View File

View File

@@ -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

View File

@@ -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);

1
src/target.c Normal file
View File

@@ -0,0 +1 @@

12
tests/simple/14_pointer.c Normal file
View File

@@ -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;
}

View File

@@ -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]