feat(ast2ir): 添加数组初始化支持和AST转IR优化
添加了对未知长度数组的自动长度推导功能,支持字符串字面量和复合 初始化的数组长度计算。新增辅助函数resolve_array_length用于计算 数组实际长度,以及emit_array_initialization用于生成数组初始化 代码。 同时将AST转IR过程中的参数改为const引用,提高代码安全性。 新增IR构建器的借用检查机制,防止在借用期间进行重分配操作。 fix(ast): 为AST结构体添加详细注释说明字段用途
This commit is contained in:
@@ -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__ */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user