feat(ast2ir): 添加数组初始化支持和AST转IR优化

添加了对未知长度数组的自动长度推导功能,支持字符串字面量和复合
初始化的数组长度计算。新增辅助函数resolve_array_length用于计算
数组实际长度,以及emit_array_initialization用于生成数组初始化
代码。

同时将AST转IR过程中的参数改为const引用,提高代码安全性。
新增IR构建器的借用检查机制,防止在借用期间进行重分配操作。

fix(ast): 为AST结构体添加详细注释说明字段用途
This commit is contained in:
zzy
2026-04-13 11:36:52 +08:00
parent 694778e4a0
commit ffb23afaf4
13 changed files with 480 additions and 220 deletions

View File

@@ -19,13 +19,13 @@ void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_abi_type_calc_t *abi,
void scc_ast2ir_ctx_drop(scc_ast2ir_ctx_t *ctx);
void scc_ast2ir_translation_unit(scc_ast2ir_ctx_t *ctx,
scc_ast_translation_unit_t *tu);
void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl,
const scc_ast_translation_unit_t *tu);
void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
cbool is_global);
scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
cbool is_lvalue);
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, scc_ast_stmt_t *stmt);
scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
const scc_ast_expr_t *expr, cbool is_lvalue);
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt);
scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
scc_ast_type_t *ast_type);
const scc_ast_type_t *ast_type);
#endif /* __SCC_AST2IR_H__ */

View File

@@ -5,7 +5,7 @@
#include <scc_ast2ir.h>
static scc_ir_type_ref_t parse_base_type(scc_ast2ir_ctx_t *ctx,
scc_ast_type_t *ast_type) {
const scc_ast_type_t *ast_type) {
scc_abi_type_layout_t layout;
// 映射内置类型
ctx->abi->compute_type_layout(ctx->abi, ast_type, &layout);
@@ -37,8 +37,100 @@ static inline void parse_lexme2const_int(const char *lexme,
value->int64 = int_lit;
}
// 辅助函数计算数组实际长度如果原长度为0
static void resolve_array_length(scc_ast2ir_ctx_t *ctx,
const scc_ir_type_t *orig_array_type,
scc_ir_type_t *resolved_array_type,
const scc_ast_expr_t *init_expr) {
*resolved_array_type = *orig_array_type; // 拷贝
Assert(orig_array_type->tag == SCC_IR_TYPE_ARRAY);
if (orig_array_type->data.array.len != 0)
return; // 长度已知,无需推断
usize new_len = 0;
switch (init_expr->base.type) {
case SCC_AST_EXPR_STRING_LITERAL:
// 字符串字面量:长度 = 字符串字符数 + 1'\0'
// TODO: L"" \n \r 计算 暂不支持
new_len = scc_strlen(init_expr->literal.lexme) + 1;
break;
case SCC_AST_EXPR_COMPOUND: {
// 复合初始化:元素个数 = 初始化列表长度
scc_vec_foreach(init_expr->compound.lhs_exprs, i) {
scc_ast_expr_t *elem = scc_vec_at(init_expr->compound.lhs_exprs, i);
// TODO: 支持嵌套的多维数组初始化(递归)
// 这里简化:只统计顶层元素个数,假设是一维数组
new_len++;
}
break;
}
default:
Panic("unsupported initializer for zero-length array");
}
resolved_array_type->data.array.len = new_len;
}
// 辅助函数:生成数组初始化代码
static void emit_array_initialization(scc_ast2ir_ctx_t *ctx,
scc_ir_value_ref_t array_ptr,
const scc_ir_type_t *array_type,
const scc_ast_expr_t *init_expr) {
Assert(array_type->tag == SCC_IR_TYPE_ARRAY);
scc_ir_type_ref_t elem_type_ref = array_type->data.array.base;
const scc_ir_type_t *elem_type =
scc_ir_module_get_type(ctx->builder.ctx.module, elem_type_ref);
usize array_len = array_type->data.array.len;
// 字符串字面量初始化:直接 memcpy
if (init_expr->base.type == SCC_AST_EXPR_STRING_LITERAL) {
scc_ir_value_ref_t str_val = scc_ast2ir_expr(ctx, init_expr, false);
scc_ir_const_int_t len_const = {.int64 = array_len};
scc_ir_value_ref_t len_ref = scc_ir_builder_const_int(
&ctx->builder, scc_ir_builder_type_u64(&ctx->builder), len_const);
scc_ir_builder_builtin_memcpy(&ctx->builder, array_ptr, str_val,
len_ref);
return;
}
// 复合初始化:逐个元素 store
if (init_expr->base.type != SCC_AST_EXPR_COMPOUND) {
Panic("unsupported initializer for array");
}
// 遍历初始化列表
usize idx = 0;
scc_vec_foreach(init_expr->compound.rhs_exprs, i) {
scc_ast_expr_t *elem_expr =
scc_vec_at(init_expr->compound.rhs_exprs, i);
Assert(elem_expr != nullptr);
if (idx >= array_len)
break; // 防止溢出
// 生成元素地址array_ptr + idx * elem_size
scc_ir_value_ref_t idx_val = scc_ir_builder_const_int(
&ctx->builder, scc_ir_builder_type_u64(&ctx->builder),
(scc_ir_const_int_t){.int64 = idx});
scc_ir_value_ref_t elem_ptr =
scc_ir_builder_get_elem_ptr(&ctx->builder, array_ptr, idx_val);
// 递归处理:如果元素本身是数组且初始化表达式是复合初始化,需要嵌套处理
if (elem_type->tag == SCC_IR_TYPE_ARRAY &&
elem_expr->base.type == SCC_AST_EXPR_COMPOUND) {
// 递归调用自身,但注意 elem_ptr 已经是子数组的首地址
emit_array_initialization(ctx, elem_ptr, elem_type, elem_expr);
} else {
// 标量元素:计算右值并 store
scc_ir_value_ref_t val = scc_ast2ir_expr(ctx, elem_expr, false);
scc_ir_builder_store(&ctx->builder, elem_ptr, val);
}
idx++;
}
// 如果初始化列表元素少于数组长度剩余元素默认零初始化C 标准要求)
// 这里简单忽略,实际可生成 memset 循环,但为简化暂不处理
}
scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
scc_ast_type_t *ast_type) {
const scc_ast_type_t *ast_type) {
if (ctx == nullptr || ast_type == nullptr) {
LOG_ERROR("args is nullptr");
return 0;
@@ -104,6 +196,7 @@ scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
scc_ir_type_init(&ir_type, ast_type->base.type == SCC_AST_TYPE_STRUCT
? SCC_IR_TYPE_STRUCT
: SCC_IR_TYPE_UNION);
Assert(ast_type->record.decl != nullptr);
scc_vec_foreach(ast_type->record.decl->record.fields, i) {
scc_ast_decl_t *decl_field =
scc_vec_at(ast_type->record.decl->record.fields, i);
@@ -119,7 +212,9 @@ scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
ctx, &(scc_ast_type_t){.base.type = SCC_AST_TYPE_BUILTIN,
.builtin = SCC_AST_BUILTIN_TYPE_INT});
case SCC_AST_TYPE_TYPEDEF:
return 0;
// TODO maybe using cache
return scc_ast2ir_type(ctx,
ast_type->typedef_type.decl->typedef_decl.type);
default:
LOG_FATAL("Unsupported AST type: %d", ast_type->base.type);
return 0;
@@ -128,7 +223,7 @@ scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
}
scc_ir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
scc_ast_expr_t *expr,
const scc_ast_expr_t *expr,
scc_ir_value_ref_t lhs,
scc_ir_value_ref_t rhs) {
// scc_ir_bblock_ref_t start_block =
@@ -220,7 +315,8 @@ scc_ir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
* @param expr
* @return scc_ir_value_ref_t
*/
scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
const scc_ast_expr_t *expr,
cbool is_lvalue) {
if (ctx == nullptr || expr == nullptr) {
LOG_ERROR("args is nullptr");
@@ -466,7 +562,8 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
break;
case SCC_AST_EXPR_PTR_MEMBER:
break;
// SCC_AST_EXPR_CAST, // 类型转换
case SCC_AST_EXPR_CAST:
break;
case SCC_AST_EXPR_SIZE_OF: {
scc_ir_const_int_t val;
// FIXME
@@ -577,7 +674,7 @@ scc_ir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
* @param ctx
* @param stmt
*/
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, scc_ast_stmt_t *stmt) {
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
if (stmt == nullptr) {
return;
}
@@ -757,7 +854,7 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, scc_ast_stmt_t *stmt) {
* @param ctx
* @param decl
*/
void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl,
void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
cbool is_global) {
if (ctx == nullptr || decl == nullptr) {
LOG_ERROR("Invalid argument");
@@ -766,58 +863,64 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl,
switch (decl->base.type) {
case SCC_AST_DECL_VAR: {
// 转换类型
scc_ir_type_ref_t ir_type_ref = scc_ast2ir_type(ctx, decl->var.type);
// 1. 获取原始类型可能数组长度为0
scc_ir_type_ref_t orig_type_ref = scc_ast2ir_type(ctx, decl->var.type);
// 借用指针并拷贝类型(避免悬空)
const scc_ir_type_t *orig_type;
SCC_IR_BUILDER_BEGIN_BORROW(
&ctx->builder, orig_type,
scc_ir_module_get_type(ctx->builder.ctx.module, orig_type_ref));
scc_ir_type_t final_type_desc = *orig_type;
SCC_IR_BUILDER_END_BORROW(&ctx->builder);
// 创建分配节点
scc_ir_value_ref_t alloc_val_node = SCC_IR_REF_nullptr;
// 2. 如果是未知长度数组且有初始化,解析实际长度
scc_ir_type_ref_t final_type_ref = orig_type_ref;
if (decl->var.init && final_type_desc.tag == SCC_IR_TYPE_ARRAY &&
final_type_desc.data.array.len == 0) {
scc_ir_type_t tmp_type_desc;
resolve_array_length(ctx, &final_type_desc, &tmp_type_desc,
decl->var.init);
final_type_desc = tmp_type_desc;
final_type_ref =
scc_ir_builder_type(&ctx->builder, &final_type_desc);
// 此时 final_type_desc 中的长度已经确定
}
// 3. 分配变量(栈或全局)
scc_ir_value_ref_t alloc_val_node;
if (is_global) {
// alloc_val_node = scc_ir_builder_global_alloca(
// &ctx->builder, ir_type_ref, decl->name);
// 全局变量:需要生成全局分配,当前代码暂未实现,保留 TODO
// alloc_val_node = scc_ir_builder_global_alloca(&ctx->builder,
// final_type_ref, decl->name);
// scc_vec_push(builder->cprog->global_vals, alloc_val_node);
// 这里先返回,后续补充
return;
} else {
alloc_val_node =
scc_ir_builder_alloca(&ctx->builder, ir_type_ref, decl->name);
alloc_val_node = scc_ir_builder_alloca(&ctx->builder,
final_type_ref, decl->name);
}
Assert(alloc_val_node != SCC_IR_REF_nullptr);
scc_hashtable_set(&ctx->ast2ir_cache, decl,
(void *)(usize)alloc_val_node);
// 如果有初始化表达式
if (!decl->var.init) {
break;
}
scc_ir_value_ref_t init_val_node =
scc_ast2ir_expr(ctx, decl->var.init, false);
Assert(init_val_node != SCC_IR_REF_nullptr);
// FIXME array auto calucate size
scc_ir_type_t *ir_type =
scc_ir_module_get_type(ctx->builder.ctx.module, ir_type_ref);
if (ir_type->tag == SCC_IR_TYPE_ARRAY) {
if (ir_type->data.array.len == 0) {
scc_ast_expr_t *init_expr = decl->var.init;
if (init_expr->base.type == SCC_AST_EXPR_COMPOUND) {
Panic(
"TODO: init_expr->base.type == SCC_AST_EXPR_COMPOUND");
} else if (init_expr->base.type ==
SCC_AST_EXPR_STRING_LITERAL) {
ir_type->data.array.len =
scc_strlen(init_expr->literal.lexme) + 1;
scc_ir_const_int_t len = {.int64 = ir_type->data.array.len};
scc_ir_value_ref_t len_ref = scc_ir_builder_const_int(
&ctx->builder, scc_ir_builder_type_u64(&ctx->builder),
len);
scc_ir_builder_builtin_memcpy(&ctx->builder, alloc_val_node,
init_val_node, len_ref);
} else {
Panic("unknown init expr in array decl");
}
// 4. 处理初始化
if (decl->var.init) {
// 再次借用 final_type 以判断是否为数组
const scc_ir_type_t *final_type;
SCC_IR_BUILDER_BEGIN_BORROW(
&ctx->builder, final_type,
scc_ir_module_get_type(ctx->builder.ctx.module,
final_type_ref));
scc_ir_type_t type = *final_type;
SCC_IR_BUILDER_END_BORROW(&ctx->builder);
if (type.tag == SCC_IR_TYPE_ARRAY) {
emit_array_initialization(ctx, alloc_val_node, &type,
decl->var.init);
} else {
// 标量类型
scc_ir_value_ref_t init_val =
scc_ast2ir_expr(ctx, decl->var.init, false);
scc_ir_builder_store(&ctx->builder, alloc_val_node, init_val);
}
} else {
scc_ir_builder_store(&ctx->builder, alloc_val_node, init_val_node);
}
break;
}
@@ -881,8 +984,8 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl,
.record.name = decl->name,
};
scc_ir_type_ref_t type_ref = scc_ast2ir_type(ctx, &type);
scc_ir_builder_global_alloca(&ctx->builder, type_ref,
SCC_IR_REF_nullptr);
// scc_ir_builder_global_alloca(&ctx->builder, type_ref,
// SCC_IR_REF_nullptr);
break;
case SCC_AST_DECL_ENUM:
scc_ir_const_int_t val;
@@ -910,7 +1013,7 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl,
}
void scc_ast2ir_translation_unit(scc_ast2ir_ctx_t *ctx,
scc_ast_translation_unit_t *tu) {
const scc_ast_translation_unit_t *tu) {
Assert(ctx != nullptr && tu != nullptr);
scc_vec_foreach(tu->declarations, i) {