#include #include #include #include #include // 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); }