移除了在全局变量声明处理中对全局值向量的直接推送操作, 以优化内存管理和值引用的一致性。 fix(hir): 修复表达式索引类型检查中的空指针访问 修正了表达式处理中索引类型的获取方式,从使用类型指针改为使用类型引用, 并更新了空值检查条件以避免潜在的空指针解引用问题。 perf(hir): 优化类型大小计算性能 将类型大小计算逻辑从模块内部实现替换为使用HIR布局系统提供的统一接口, 提高计算效率和代码复用性。 refactor(hir): 统一字符串常量构建流程 重构了字符串常量的创建过程,简化了类型定义步骤并确保包含正确的空终止符。 fix(dump): 改进全局分配值转储的健壮性 添加了对空初始化值的检查,当全局分配没有初始值时显示零初始化器, 避免访问空指针导致的程序崩溃。 refactor(x86): 增强操作数编码的安全性 在x86指令编码中添加了对操作数字节对齐的断言检查,确保所有操作数都符合 字节边界对齐要求。 chore(build): 更新头文件包含路径和初始化参数 调整了头文件包含路径格式,并更新了HIR程序和模块的初始化函数签名, 传入ABI参数以支持更准确的目标平台特性。
708 lines
28 KiB
C
708 lines
28 KiB
C
#include <scc_ast2ir.h>
|
||
#include <scc_ast_def.h>
|
||
#include <scc_ast_utils.h>
|
||
#include <scc_hir_builder.h>
|
||
#include <scc_hir_def.h>
|
||
|
||
// static inline void parse_struct_union_layout(scc_ast_qual_type_t *type) {}
|
||
|
||
// 辅助函数:计算数组实际长度(如果原长度为0)
|
||
static void resolve_array_length(scc_ast2ir_ctx_t *ctx,
|
||
const scc_hir_type_t *orig_array_type,
|
||
scc_hir_type_t *resolved_array_type,
|
||
const scc_ast_expr_t *init_expr) {
|
||
*resolved_array_type = *orig_array_type; // 拷贝
|
||
Assert(orig_array_type->tag == SCC_HIR_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;
|
||
}
|
||
|
||
scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||
const scc_ast_qual_type_t *ast_type) {
|
||
if (ctx == nullptr || ast_type == nullptr) {
|
||
LOG_ERROR("args is nullptr");
|
||
return 0;
|
||
}
|
||
scc_hir_type_t ir_type;
|
||
|
||
switch (ast_type->base.type) {
|
||
case SCC_AST_TYPE_BUILTIN: {
|
||
return scc_ast2ir_parse_base_type(ctx, ast_type);
|
||
}
|
||
case SCC_AST_TYPE_POINTER: {
|
||
scc_hir_type_init(&ir_type, SCC_HIR_TYPE_PTR);
|
||
scc_hir_type_ref_t pointee_type =
|
||
scc_ast2ir_type(ctx, scc_ast_canon_type(ast_type)->pointer.pointee);
|
||
ir_type.data.pointer.base = pointee_type;
|
||
break;
|
||
}
|
||
case SCC_AST_TYPE_ARRAY: {
|
||
scc_hir_type_init(&ir_type, SCC_HIR_TYPE_ARRAY);
|
||
|
||
scc_hir_type_ref_t element_type =
|
||
scc_ast2ir_type(ctx, scc_ast_canon_type(ast_type)->array.element);
|
||
|
||
ir_type.data.array.base = element_type;
|
||
ir_type.data.array.len = 0;
|
||
if (scc_ast_canon_type(ast_type)->array.size) {
|
||
scc_ap_t value;
|
||
if (!scc_ast2ir_eval_constant_int(
|
||
ctx, &value, scc_ast_canon_type(ast_type)->array.size)) {
|
||
Panic("array size is not a constant expression");
|
||
}
|
||
ir_type.data.array.len = value.data.digit;
|
||
}
|
||
} break;
|
||
case SCC_AST_TYPE_FUNCTION: {
|
||
scc_hir_type_init(&ir_type, SCC_HIR_TYPE_FUNC);
|
||
|
||
// 处理返回类型
|
||
scc_hir_type_ref_t ret_type = scc_ast2ir_type(
|
||
ctx, scc_ast_canon_type(ast_type)->function.return_type);
|
||
|
||
// 将返回类型添加到程序的类型容器中
|
||
ir_type.data.function.ret_type = ret_type;
|
||
|
||
// 转换参数类型(跳过尾部的 ... 假参数)
|
||
scc_hir_type_ref_vec_t params;
|
||
scc_vec_init(params);
|
||
int n_fixed = fixed_param_count(scc_ast_canon_type(ast_type));
|
||
scc_ast_decl_vec_t *ast_params =
|
||
&scc_ast_canon_type(ast_type)->function.params;
|
||
for (int i = 0; i < n_fixed; i++) {
|
||
scc_ast_decl_t *decl_param = scc_vec_at(*ast_params, i);
|
||
Assert(decl_param->base.type == SCC_AST_DECL_PARAM);
|
||
scc_hir_type_ref_t tmp_type =
|
||
scc_ast2ir_type(ctx, decl_param->param.type);
|
||
scc_vec_push(params, tmp_type);
|
||
}
|
||
ir_type.data.function.params = params;
|
||
} break;
|
||
case SCC_AST_TYPE_STRUCT:
|
||
case SCC_AST_TYPE_UNION: {
|
||
const scc_ast_canon_type_t *canon = scc_ast_canon_type(ast_type);
|
||
|
||
// === 1. 查缓存,如果已存在则直接返回(递归时一定会命中) ===
|
||
scc_hir_type_ref_t cached =
|
||
(scc_hir_type_ref_t)(usize)scc_hashtable_get(&ctx->type_cache,
|
||
canon);
|
||
if (cached != 0) {
|
||
return cached;
|
||
}
|
||
|
||
// === 2. 创建占位类型(字段为空) ===
|
||
scc_hir_type_t placeholder;
|
||
scc_hir_type_init(&placeholder,
|
||
ast_type->base.type == SCC_AST_TYPE_STRUCT
|
||
? SCC_HIR_TYPE_STRUCT
|
||
: SCC_HIR_TYPE_UNION);
|
||
// 可以给占位符一个调试名
|
||
if (canon->record.name) {
|
||
placeholder.name = canon->record.name;
|
||
}
|
||
|
||
// === 3. 直接添加到模块,不经过 builder 的 uniquing ===
|
||
// 因为此时我们不需要类型去重,只需要一个确定不移的引用
|
||
scc_hir_type_ref_t place_ref =
|
||
scc_hir_module_add_type(scc_ast2ir_mir_module(ctx), &placeholder);
|
||
|
||
// === 4. 将映射写入缓存(关键!必须在递归前) ===
|
||
scc_hashtable_set(&ctx->type_cache, canon, (void *)(usize)place_ref);
|
||
|
||
// === 5. 递归解析所有字段 ===
|
||
// 此时若字段类型指回本结构体,将直接通过缓存返回 place_ref
|
||
scc_hir_type_ref_vec_t fields;
|
||
scc_vec_init(fields);
|
||
scc_ast_decl_t *decl = canon->record.decl;
|
||
if (decl == nullptr) {
|
||
Panic("struct/union declaration is missing");
|
||
}
|
||
scc_vec_foreach(decl->record.fields, i) {
|
||
scc_ast_decl_t *field_decl = scc_vec_at(decl->record.fields, i);
|
||
Assert(field_decl->base.type == SCC_AST_DECL_VAR);
|
||
scc_hir_type_ref_t field_ir_type =
|
||
scc_ast2ir_type(ctx, field_decl->var.type);
|
||
scc_vec_push(fields, field_ir_type);
|
||
}
|
||
|
||
// === 6. 将字段填入占位类型 ===
|
||
scc_hir_type_t *place_type =
|
||
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), place_ref);
|
||
// 注意:scc_hir_type_init 已经为 struct/union 初始化了 fields 空向量
|
||
// 这里直接 push 即可(也可以先 scc_vec_free 再 init,看需要)
|
||
scc_vec_foreach(fields, i) {
|
||
scc_vec_push(place_type->data.aggregate.fields,
|
||
scc_vec_at(fields, i));
|
||
}
|
||
scc_vec_free(fields); // 释放临时向量
|
||
|
||
// === 7. 返回占位符的引用(现在已经变成完整类型) ===
|
||
return place_ref;
|
||
} break;
|
||
case SCC_AST_TYPE_ENUM:
|
||
scc_ast_canon_type_t *int_canon_type = scc_ast_module_get_builtin_type(
|
||
ctx->ast_module, SCC_AST_BUILTIN_TYPE_INT);
|
||
scc_ast_qual_type_t int_type = {
|
||
.base.type = SCC_AST_TYPE_BUILTIN,
|
||
.type = int_canon_type,
|
||
};
|
||
return scc_ast2ir_parse_base_type(ctx, &int_type);
|
||
case SCC_AST_TYPE_TYPEDEF:
|
||
// TODO maybe using cache
|
||
return scc_ast2ir_type(
|
||
ctx,
|
||
scc_ast_canon_type(ast_type)->typedef_type.decl->typedef_decl.type);
|
||
default:
|
||
LOG_FATAL("Unsupported AST type: %d", ast_type->base.type);
|
||
return 0;
|
||
}
|
||
return scc_hir_builder_type(&ctx->builder, &ir_type);
|
||
}
|
||
|
||
/**
|
||
* @brief
|
||
*
|
||
* @param ctx
|
||
* @param stmt
|
||
*/
|
||
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
|
||
if (stmt == nullptr) {
|
||
return;
|
||
}
|
||
|
||
switch (stmt->base.type) {
|
||
case SCC_AST_STMT_COMPOUND: {
|
||
scc_vec_foreach(stmt->compound.block_items, i) {
|
||
scc_ast_node_t *child_stmt =
|
||
scc_vec_at(stmt->compound.block_items, i);
|
||
if (SCC_AST_IS_A(scc_ast_stmt_t, child_stmt)) {
|
||
scc_ast2ir_stmt(ctx,
|
||
SCC_AST_CAST_TO(scc_ast_stmt_t, child_stmt));
|
||
} else if (SCC_AST_IS_A(scc_ast_decl_t, child_stmt)) {
|
||
scc_ast2ir_decl(
|
||
ctx, SCC_AST_CAST_TO(scc_ast_decl_t, child_stmt), false);
|
||
} else {
|
||
UNREACHABLE();
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case SCC_AST_STMT_EXPR: {
|
||
scc_ast2ir_expr(ctx, stmt->expr.expr, false);
|
||
break;
|
||
}
|
||
case SCC_AST_STMT_IF: {
|
||
/*
|
||
branch cond
|
||
/ \
|
||
true_block false_block
|
||
\ /
|
||
merge_block
|
||
*/
|
||
scc_hir_value_ref_t true_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "if_true");
|
||
|
||
scc_hir_value_ref_t false_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "if_false");
|
||
|
||
scc_hir_value_ref_t merge_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "if_merge");
|
||
|
||
scc_hir_value_ref_t cond_node =
|
||
scc_ast2ir_expr(ctx, stmt->if_stmt.cond, false);
|
||
scc_hir_builder_branch(&ctx->builder, cond_node, true_block,
|
||
stmt->if_stmt.opt_else_stmt ? false_block
|
||
: merge_block);
|
||
|
||
// 生成true分支
|
||
scc_hir_builder_append_bblock(&ctx->builder, true_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
|
||
scc_ast2ir_stmt(ctx, stmt->if_stmt.then_stmt);
|
||
scc_hir_builder_jump(&ctx->builder, merge_block);
|
||
|
||
// 生成false分支
|
||
if (stmt->if_stmt.opt_else_stmt) {
|
||
scc_hir_builder_append_bblock(&ctx->builder, false_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
|
||
scc_ast2ir_stmt(ctx, stmt->if_stmt.opt_else_stmt);
|
||
scc_hir_builder_jump(&ctx->builder, merge_block);
|
||
}
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, merge_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, merge_block);
|
||
break;
|
||
}
|
||
case SCC_AST_STMT_WHILE: {
|
||
scc_hir_value_ref_t cond_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "while_cond");
|
||
scc_hir_value_ref_t body_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "while_body");
|
||
scc_hir_value_ref_t exit_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "while_exit");
|
||
|
||
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
||
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
|
||
|
||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||
scc_hir_value_ref_t cond_node =
|
||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
||
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
||
exit_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, body_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||
break;
|
||
}
|
||
case SCC_AST_STMT_DO_WHILE: {
|
||
scc_hir_value_ref_t cond_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "do_while_cond");
|
||
scc_hir_value_ref_t body_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "do_while_body");
|
||
scc_hir_value_ref_t exit_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "do_while_exit");
|
||
|
||
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
||
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
|
||
|
||
scc_hir_builder_jump(&ctx->builder, body_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, body_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||
scc_hir_value_ref_t cond_node =
|
||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
||
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
||
exit_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||
break;
|
||
}
|
||
case SCC_AST_STMT_FOR: {
|
||
scc_hir_value_ref_t cond_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "for_cond");
|
||
scc_hir_value_ref_t body_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "for_body");
|
||
scc_hir_value_ref_t incr_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "for_incr");
|
||
scc_hir_value_ref_t exit_block =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "for_exit");
|
||
|
||
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
||
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)incr_block);
|
||
|
||
if (stmt->for_stmt.init) {
|
||
if (SCC_AST_IS_A(scc_ast_decl_t, stmt->for_stmt.init)) {
|
||
scc_ast2ir_decl(
|
||
ctx, SCC_AST_CAST_TO(scc_ast_decl_t, stmt->for_stmt.init),
|
||
false);
|
||
} else if (SCC_AST_IS_A(scc_ast_expr_t, stmt->for_stmt.init)) {
|
||
scc_ast2ir_expr(
|
||
ctx, SCC_AST_CAST_TO(scc_ast_expr_t, stmt->for_stmt.init),
|
||
false);
|
||
} else {
|
||
LOG_FATAL("invalid for init statement");
|
||
}
|
||
}
|
||
|
||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||
if (stmt->for_stmt.cond) {
|
||
scc_hir_value_ref_t cond_node =
|
||
scc_ast2ir_expr(ctx, stmt->for_stmt.cond, false);
|
||
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
||
exit_block);
|
||
} else {
|
||
scc_hir_builder_jump(&ctx->builder, body_block);
|
||
}
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, body_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||
scc_ast2ir_stmt(ctx, stmt->for_stmt.body);
|
||
scc_hir_builder_jump(&ctx->builder, incr_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, incr_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, incr_block);
|
||
if (stmt->for_stmt.incr) {
|
||
scc_ast2ir_expr(ctx, stmt->for_stmt.incr, false);
|
||
}
|
||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||
|
||
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||
break;
|
||
}
|
||
case SCC_AST_STMT_SWITCH: {
|
||
scc_hir_value_ref_t exit_block =
|
||
scc_hir_builder_bblock(&ctx->builder, "switch_exit");
|
||
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
||
|
||
// TODO:
|
||
} break;
|
||
case SCC_AST_STMT_CASE:
|
||
case SCC_AST_STMT_DEFAULT:
|
||
UNREACHABLE();
|
||
break;
|
||
case SCC_AST_STMT_BREAK: {
|
||
scc_hir_bblock_ref_t target =
|
||
(usize)scc_hashtable_get(&ctx->break_cache, stmt->jump._target);
|
||
Assert(target != SCC_HIR_REF_nullptr);
|
||
scc_hir_builder_jump(&ctx->builder, target);
|
||
} break;
|
||
case SCC_AST_STMT_CONTINUE: {
|
||
scc_hir_bblock_ref_t target =
|
||
(usize)scc_hashtable_get(&ctx->continue_cache, stmt->jump._target);
|
||
Assert(target != SCC_HIR_REF_nullptr);
|
||
scc_hir_builder_jump(&ctx->builder, target);
|
||
} break;
|
||
case SCC_AST_STMT_RETURN: {
|
||
if (stmt->return_stmt.expr) {
|
||
scc_hir_value_ref_t ret_val_node =
|
||
scc_ast2ir_expr(ctx, stmt->return_stmt.expr, false);
|
||
// 将返回值转换为函数返回值类型
|
||
scc_hir_func_ref_t func = ctx->builder.current_func;
|
||
if (func != SCC_HIR_REF_nullptr) {
|
||
scc_hir_func_t *hir_func =
|
||
scc_hir_module_get_func(scc_ast2ir_mir_module(ctx), func);
|
||
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(hir_func);
|
||
if (meta->type != SCC_HIR_REF_nullptr) {
|
||
const scc_hir_type_t *func_type = scc_hir_module_get_type(
|
||
scc_ast2ir_mir_module(ctx), meta->type);
|
||
if (func_type != nullptr &&
|
||
func_type->tag == SCC_HIR_TYPE_FUNC) {
|
||
ret_val_node = scc_ast2ir_emit_conversion(
|
||
ctx, ret_val_node,
|
||
func_type->data.function.ret_type);
|
||
}
|
||
}
|
||
}
|
||
scc_hir_builder_ret(&ctx->builder, ret_val_node);
|
||
} else {
|
||
scc_hir_builder_ret_void(&ctx->builder);
|
||
}
|
||
break;
|
||
}
|
||
case SCC_AST_STMT_GOTO: {
|
||
scc_ast_stmt_t *target_label = stmt->goto_stmt._target;
|
||
Assert(target_label != nullptr);
|
||
scc_hir_bblock_ref_t target =
|
||
(usize)scc_hashtable_get(&ctx->ast2ir_cache, (void *)target_label);
|
||
if (target == SCC_HIR_REF_nullptr) {
|
||
// 前向引用:预创建块,等 label handler 复用
|
||
target =
|
||
scc_hir_builder_create_bblock(&ctx->builder, "goto_target");
|
||
scc_hashtable_set(&ctx->ast2ir_cache, (void *)target_label,
|
||
(void *)target);
|
||
}
|
||
scc_hir_builder_jump(&ctx->builder, target);
|
||
} break;
|
||
case SCC_AST_STMT_LABEL: {
|
||
scc_ast_stmt_t *label_stmt = stmt->label_stmt.stmt;
|
||
scc_hir_bblock_ref_t label_block =
|
||
(usize)scc_hashtable_get(&ctx->ast2ir_cache, (void *)stmt);
|
||
if (label_block == SCC_HIR_REF_nullptr) {
|
||
// goto 未预先创建,新建立即追加
|
||
label_block =
|
||
scc_hir_builder_bblock(&ctx->builder, stmt->label_stmt.label);
|
||
} else {
|
||
// goto 已预创建,只需追加
|
||
scc_hir_builder_append_bblock(&ctx->builder, label_block);
|
||
}
|
||
scc_hir_builder_set_current_bblock(&ctx->builder, label_block);
|
||
scc_hashtable_set(&ctx->ast2ir_cache, (void *)stmt,
|
||
(void *)label_block);
|
||
scc_ast2ir_stmt(ctx, label_stmt);
|
||
} break;
|
||
default:
|
||
LOG_FATAL("Unsupported statement type: %d", stmt->base.type);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief
|
||
*
|
||
* @param ctx
|
||
* @param 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");
|
||
return;
|
||
}
|
||
|
||
switch (decl->base.type) {
|
||
case SCC_AST_DECL_VAR: {
|
||
// 1. 获取原始类型(可能数组长度为0)
|
||
scc_hir_type_ref_t orig_type_ref = scc_ast2ir_type(ctx, decl->var.type);
|
||
// 借用指针并拷贝类型(避免悬空)
|
||
const scc_hir_type_t *orig_type;
|
||
SCC_HIR_BUILDER_BEGIN_BORROW(
|
||
&ctx->builder, orig_type,
|
||
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), orig_type_ref));
|
||
scc_hir_type_t final_type_desc = *orig_type;
|
||
SCC_HIR_BUILDER_END_BORROW(&ctx->builder);
|
||
|
||
// 2. 如果是未知长度数组且有初始化,解析实际长度
|
||
scc_hir_type_ref_t final_type_ref = orig_type_ref;
|
||
if (decl->var.init && final_type_desc.tag == SCC_HIR_TYPE_ARRAY &&
|
||
final_type_desc.data.array.len == 0) {
|
||
scc_hir_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_hir_builder_type(&ctx->builder, &final_type_desc);
|
||
// 此时 final_type_desc 中的长度已经确定
|
||
}
|
||
|
||
// 3. 分配变量(栈或全局)
|
||
scc_hir_value_ref_t alloc_val_node;
|
||
if (is_global) {
|
||
scc_hir_value_ref_t init_val = SCC_HIR_REF_nullptr;
|
||
if (decl->var.init) {
|
||
if (final_type_desc.tag == SCC_HIR_TYPE_ARRAY ||
|
||
final_type_desc.tag == SCC_HIR_TYPE_STRUCT ||
|
||
final_type_desc.tag == SCC_HIR_TYPE_UNION) {
|
||
// TODO: 聚合类型全局初始化(需生成 .data 段数据)
|
||
} else {
|
||
init_val = scc_ast2ir_expr(ctx, decl->var.init, false);
|
||
}
|
||
}
|
||
alloc_val_node = scc_hir_builder_global_alloca(
|
||
&ctx->builder, final_type_ref, init_val);
|
||
} else {
|
||
alloc_val_node = scc_hir_builder_alloca(&ctx->builder,
|
||
final_type_ref, decl->name);
|
||
}
|
||
scc_hashtable_set(&ctx->ast2ir_cache, decl,
|
||
(void *)(usize)alloc_val_node);
|
||
|
||
// 4. 处理初始化(全局变量由 global_alloca 的 init_val 处理,跳过)
|
||
if (!is_global && decl->var.init) {
|
||
// 再次借用 final_type 以判断是否为数组
|
||
const scc_hir_type_t *final_type;
|
||
SCC_HIR_BUILDER_BEGIN_BORROW(
|
||
&ctx->builder, final_type,
|
||
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx),
|
||
final_type_ref));
|
||
scc_hir_type_t type = *final_type;
|
||
SCC_HIR_BUILDER_END_BORROW(&ctx->builder);
|
||
if (type.tag == SCC_HIR_TYPE_ARRAY) {
|
||
emit_array_initialization(ctx, alloc_val_node, &type,
|
||
decl->var.init);
|
||
} else if (type.tag == SCC_HIR_TYPE_STRUCT ||
|
||
type.tag == SCC_HIR_TYPE_UNION) {
|
||
emit_aggregate_initialization(ctx, alloc_val_node, &type,
|
||
decl->var.init);
|
||
} else {
|
||
// 标量类型
|
||
scc_hir_value_ref_t init_val =
|
||
scc_ast2ir_expr(ctx, decl->var.init, false);
|
||
scc_hir_builder_store(&ctx->builder, alloc_val_node, init_val);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case SCC_AST_DECL_FUNC: {
|
||
scc_hir_type_ref_t func_type_ref =
|
||
scc_ast2ir_type(ctx, decl->func.type);
|
||
scc_hir_func_ref_t func_ref =
|
||
(usize)scc_hashtable_get(&ctx->symtab, decl->name);
|
||
|
||
if (func_ref == SCC_HIR_REF_nullptr) {
|
||
func_ref =
|
||
scc_hir_builder_func(&ctx->builder, func_type_ref, decl->name);
|
||
// TODO: add func to cache because function pointer is needed
|
||
scc_hashtable_set(&ctx->symtab, decl->name,
|
||
(void *)(usize)func_ref);
|
||
}
|
||
|
||
// 检测是否是可变参数函数(无论是否有函数体)
|
||
scc_hir_func_t *hir_func =
|
||
scc_hir_module_get_func(&ctx->builder.cprog->module, func_ref);
|
||
int n_fixed = fixed_param_count(scc_ast_canon_type(decl->func.type));
|
||
int n_total = (int)scc_vec_size(
|
||
scc_ast_canon_type(decl->func.type)->function.params);
|
||
if (n_total > n_fixed) {
|
||
SCC_HIR_FUNC_META(hir_func)->is_variadic = true;
|
||
}
|
||
|
||
if (decl->func.body == nullptr) {
|
||
// function decl
|
||
break;
|
||
}
|
||
|
||
// TODO this is double check defined
|
||
Assert(SCC_HIR_FUNC_META(hir_func)->defined == false);
|
||
SCC_HIR_FUNC_META(hir_func)->defined = true;
|
||
|
||
scc_hir_builder_begin_func(&ctx->builder, func_ref);
|
||
scc_hir_builder_begin_bblock(&ctx->builder, "entry");
|
||
|
||
// 只处理固定参数,跳过尾部的 ... 假参数
|
||
scc_ast_decl_vec_t *ast_params =
|
||
&scc_ast_canon_type(decl->func.type)->function.params;
|
||
for (int i = 0; i < n_fixed; i++) {
|
||
scc_ast_decl_t *param = scc_vec_at(*ast_params, i);
|
||
scc_ast2ir_decl(ctx, param, false);
|
||
}
|
||
|
||
scc_ast2ir_stmt(ctx, decl->func.body);
|
||
// FIXME need ret for none return or other default ret
|
||
scc_hir_builder_ret_void(&ctx->builder);
|
||
|
||
scc_hir_builder_end_bblock(&ctx->builder);
|
||
scc_hir_builder_end_func(&ctx->builder);
|
||
break;
|
||
}
|
||
case SCC_AST_DECL_LIST: {
|
||
scc_vec_foreach(decl->list.vars, i) {
|
||
scc_ast_decl_t *sub_decl = scc_vec_at(decl->list.vars, i);
|
||
scc_ast2ir_decl(ctx, sub_decl, is_global);
|
||
}
|
||
break;
|
||
}
|
||
case SCC_AST_DECL_PARAM: {
|
||
// 跳过 void 参数和 ... 假参数(无名 VA_LIST)
|
||
if (decl->param.type->base.type == SCC_AST_TYPE_BUILTIN &&
|
||
scc_ast_canon_type(decl->param.type)->builtin.type ==
|
||
SCC_AST_BUILTIN_TYPE_VOID) {
|
||
break;
|
||
}
|
||
if (is_variadic_marker(decl)) {
|
||
break;
|
||
}
|
||
scc_hir_type_ref_t parma_type_ref =
|
||
scc_ast2ir_type(ctx, decl->param.type);
|
||
scc_hir_value_ref_t param_ref = scc_hir_builder_func_arg_ref(
|
||
&ctx->builder, parma_type_ref, decl->name, decl->param.param_idx);
|
||
|
||
if (!ctx->hint_using_value) {
|
||
scc_hir_value_ref_t val_ref = scc_hir_builder_alloca(
|
||
&ctx->builder, parma_type_ref, decl->name);
|
||
scc_hir_builder_store(&ctx->builder, val_ref, param_ref);
|
||
scc_hashtable_set(&ctx->ast2ir_cache, decl, (void *)(usize)val_ref);
|
||
} else {
|
||
Panic("using value is not supported");
|
||
}
|
||
break;
|
||
}
|
||
case SCC_AST_DECL_STRUCT:
|
||
case SCC_AST_DECL_UNION: {
|
||
scc_ast_canon_type_t canon_type = {
|
||
.record.decl = decl,
|
||
.record.name = decl->name,
|
||
};
|
||
scc_ast_qual_type_t type = {
|
||
.base.type = decl->base.type == SCC_AST_DECL_STRUCT
|
||
? SCC_AST_TYPE_STRUCT
|
||
: SCC_AST_TYPE_UNION,
|
||
.type = &canon_type,
|
||
};
|
||
scc_hir_type_ref_t type_ref = scc_ast2ir_type(ctx, &type);
|
||
// scc_hir_builder_global_alloca(&ctx->builder, type_ref,
|
||
// SCC_HIR_REF_nullptr);
|
||
} break;
|
||
case SCC_AST_DECL_ENUM: {
|
||
scc_ap_t val;
|
||
scc_ap_set_int(&val, 0);
|
||
scc_vec_foreach(decl->record.fields, i) {
|
||
scc_ast_decl_t *item = scc_vec_at(decl->record.fields, i);
|
||
Assert(item->base.type == SCC_AST_DECL_VAR);
|
||
if (item->var.init) {
|
||
if (!scc_ast2ir_eval_constant_int(ctx, &val, item->var.init)) {
|
||
Panic("enum value is not a constant expression");
|
||
}
|
||
}
|
||
scc_hir_value_ref_t item_val_ref = scc_hir_builder_integer(
|
||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder), &val);
|
||
scc_hashtable_set(&ctx->ast2ir_cache, item,
|
||
(void *)(usize)item_val_ref);
|
||
/* next = val + 1 */
|
||
scc_ap_t one;
|
||
scc_ap_set_int(&one, 1);
|
||
scc_ap_add(&val, &val, &one);
|
||
}
|
||
} break;
|
||
case SCC_AST_DECL_TYPEDEF:
|
||
break;
|
||
default:
|
||
LOG_FATAL("Unsupported declaration type: %d", decl->base.type);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void scc_ast2ir_run(scc_ast2ir_ctx_t *ctx,
|
||
const scc_ast_translation_unit_t *tu) {
|
||
Assert(ctx != nullptr && tu != nullptr);
|
||
|
||
scc_vec_foreach(tu->declarations, i) {
|
||
scc_ast_decl_t *decl = scc_vec_at(tu->declarations, i);
|
||
scc_ast2ir_decl(ctx, decl, true);
|
||
}
|
||
}
|
||
|
||
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_type_abi_t *type_abi,
|
||
scc_ast_module_t *ast_module, scc_hir_cprog_t *cprog) {
|
||
Assert(ctx != nullptr);
|
||
Assert(type_abi != nullptr);
|
||
Assert(ast_module != nullptr);
|
||
Assert(cprog != nullptr);
|
||
ctx->type_abi = type_abi;
|
||
ctx->ast_module = ast_module;
|
||
scc_hir_builder_init(&ctx->builder, cprog);
|
||
scc_hashtable_usize_init(&ctx->ast2ir_cache);
|
||
scc_hashtable_usize_init(&ctx->break_cache);
|
||
scc_hashtable_usize_init(&ctx->continue_cache);
|
||
scc_hashtable_cstr_init(&ctx->symtab);
|
||
scc_hashtable_usize_init(&ctx->type_cache);
|
||
ctx->hint_using_value = false;
|
||
}
|
||
|
||
void scc_ast2ir_ctx_drop(scc_ast2ir_ctx_t *ctx) {
|
||
scc_hir_builder_drop(&ctx->builder);
|
||
scc_hashtable_drop(&ctx->ast2ir_cache);
|
||
scc_hashtable_drop(&ctx->break_cache);
|
||
scc_hashtable_drop(&ctx->continue_cache);
|
||
scc_hashtable_drop(&ctx->type_cache);
|
||
scc_hashtable_drop(&ctx->symtab);
|
||
}
|