Files
scc/libs/ast2ir/src/scc_ast2ir.c
zzy be33eb3942 refactor(ast2ir): 移除全局值向量的直接推送
移除了在全局变量声明处理中对全局值向量的直接推送操作,
以优化内存管理和值引用的一致性。

fix(hir): 修复表达式索引类型检查中的空指针访问

修正了表达式处理中索引类型的获取方式,从使用类型指针改为使用类型引用,
并更新了空值检查条件以避免潜在的空指针解引用问题。

perf(hir): 优化类型大小计算性能

将类型大小计算逻辑从模块内部实现替换为使用HIR布局系统提供的统一接口,
提高计算效率和代码复用性。

refactor(hir): 统一字符串常量构建流程

重构了字符串常量的创建过程,简化了类型定义步骤并确保包含正确的空终止符。

fix(dump): 改进全局分配值转储的健壮性

添加了对空初始化值的检查,当全局分配没有初始值时显示零初始化器,
避免访问空指针导致的程序崩溃。

refactor(x86): 增强操作数编码的安全性

在x86指令编码中添加了对操作数字节对齐的断言检查,确保所有操作数都符合
字节边界对齐要求。

chore(build): 更新头文件包含路径和初始化参数

调整了头文件包含路径格式,并更新了HIR程序和模块的初始化函数签名,
传入ABI参数以支持更准确的目标平台特性。
2026-06-02 14:47:05 +08:00

708 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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);
}