Files
l-language/src/codegen/codegen.c
T
Serendipity 6ebe551ee3 fix: AST_PARAMETER 增加数组元素类型字段 + 五子棋集成测试
问题: 函数参数声明 i64[N] 只在 TypeInfo 存储数组信息, AST_PARAMETER
仅存 TypeKind(TYPE_ARRAY), 丢失元素类型和大小, 导致 sema 将参数
数组误判为 i32[N], codegen 生成 void GEP 而崩溃。

修复:
- AST_PARAMETER 新增 arr_elem_type/arr_elem_struct/arr_size 字段
- parser 传入 parse_type_expr 的完整数组信息
- sema 将数组信息从 AST 节点复制到 Symbol
- codegen 为数组参数生成正确的 LLVMArrayType

附加: 45_gomoku.l — 5x5 五子棋双AI对弈, 测试数组/函数/循环/字符串

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 18:48:04 +08:00

543 lines
23 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 "codegen_internal.h"
int codegen_depth = 0;
// === 变量表 ===
LLVMValueRef find_var(CgCtx* ctx, const char* name) {
for (VarEntry* e = ctx->var_table; e; e = e->next)
if (strcmp(e->name, name) == 0) return e->alloca;
return NULL;
}
VarEntry* add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca, LLVMTypeRef alloca_type) {
VarEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return NULL;
e->name = name; e->alloca = alloca; e->alloca_type = alloca_type;
e->closure_fn = NULL;
e->next = ctx->var_table;
ctx->var_table = e;
return e;
}
// === 函数表 ===
LLVMValueRef find_fn(CgCtx* ctx, const char* name) {
for (FnEntry* e = ctx->fn_table; e; e = e->next)
if (strcmp(e->name, name) == 0) return e->fn;
return NULL;
}
void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn, bool* out_params, size_t pc) {
FnEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return;
e->name = name; e->fn = fn;
e->ret = TYPE_VOID;
e->params = NULL;
e->out_params = out_params;
e->pc = pc;
e->next = ctx->fn_table;
ctx->fn_table = e;
}
FnEntry* find_fn_entry(CgCtx* ctx, const char* name) {
for (FnEntry* e = ctx->fn_table; e; e = e->next)
if (strcmp(e->name, name) == 0) return e;
return NULL;
}
// === 结构体类型表 ===
void add_struct_type(CgCtx* ctx, const char* name, LLVMTypeRef ty, size_t fc) {
StructTypeEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return;
e->name = name; e->llvm_type = ty; e->field_count = fc;
e->next = ctx->struct_table;
ctx->struct_table = e;
}
LLVMTypeRef find_struct_type(CgCtx* ctx, const char* name) {
for (StructTypeEntry* e = ctx->struct_table; e; e = e->next)
if (strcmp(e->name, name) == 0) return e->llvm_type;
return NULL;
}
// 将整数值强制转换到目标 LLVM 类型(sext/zext/trunc
// === 自动内存管理: 作用域退出时释放 str 堆分配 ===
void cleanup_add(CgCtx* ctx, LLVMValueRef alloca) {
if (ctx->cleanup_count >= ctx->cleanup_cap) {
size_t new_cap = ctx->cleanup_cap ? ctx->cleanup_cap * 2 : 16;
LLVMValueRef* new_list = arena_alloc(ctx->arena, new_cap * sizeof(LLVMValueRef));
if (!new_list) return;
if (ctx->cleanup_list)
memcpy(new_list, ctx->cleanup_list, ctx->cleanup_count * sizeof(LLVMValueRef));
ctx->cleanup_list = new_list;
ctx->cleanup_cap = new_cap;
}
ctx->cleanup_list[ctx->cleanup_count++] = alloca;
}
// 释放从 mark 位置开始的所有 str 变量
void cleanup_emit(CgCtx* ctx, size_t from_mark) {
for (size_t j = from_mark; j < ctx->cleanup_count; j++) {
LLVMValueRef ptr = ctx->cleanup_list[j];
LLVMValueRef val = LLVMBuildLoad2(ctx->builder,
LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0), ptr, "free_load");
LLVMBuildCall2(ctx->builder,
LLVMGlobalGetValueType(ctx->free_fn), ctx->free_fn,
(LLVMValueRef[]){val}, 1, "");
}
ctx->cleanup_count = from_mark;
}
// 发射所有 defer 语句(LIFO 顺序)
static void emit_deferred(CgCtx* ctx) {
for (size_t i = ctx->defer_count; i > 0; i--)
codegen_stmt(ctx, ctx->defer_exprs[i - 1]);
ctx->defer_count = 0;
}
// === 语句代码生成 ===
void codegen_stmt(CgCtx* ctx, AstNode* node) {
if (!node) return;
switch (node->kind) {
case AST_LET_STMT: {
// 使用节点的完整类型信息来确定 LLVM 类型
// 如果 sema 未运行 (node->type.kind == TYPE_UNKNOWN),回退到 init 的类型
LLVMTypeRef var_type;
if (node->type.kind == TYPE_UNKNOWN) {
// 回退到旧行为:使用 init 表达式的类型
AstNode* init_node = node->as.let_stmt.init;
if (init_node->type.kind == TYPE_STRUCT && init_node->type.struct_name) {
var_type = find_struct_type(ctx, init_node->type.struct_name);
if (!var_type) var_type = to_llvm_type(ctx, init_node->type.kind);
} else {
var_type = to_llvm_type(ctx, init_node->type.kind);
}
} else {
var_type = type_info_to_llvm(ctx, &node->type);
}
if (!var_type) return;
LLVMValueRef alloca = LLVMBuildAlloca(ctx->builder,
var_type, node->as.let_stmt.name);
// 尝试生成 init 值;数组类型可能 init 失败 (自引用占位符)
LLVMValueRef init_val = codegen_expr(ctx, node->as.let_stmt.init);
if (init_val) {
// 若 init LLVM 类型与 alloca 类型不同,强制转换(如 i64→i32)
LLVMTypeRef init_ty = LLVMTypeOf(init_val);
if (init_ty != var_type && LLVMGetTypeKind(init_ty) == LLVMIntegerTypeKind
&& LLVMGetTypeKind(var_type) == LLVMIntegerTypeKind) {
init_val = coerce_int(ctx, init_val, init_ty, var_type);
}
LLVMBuildStore(ctx->builder, init_val, alloca);
} else if (node->type.kind == TYPE_ARRAY) {
// 数组声明: init 失败是预期的 (自引用), 存储零初始化
LLVMValueRef zero_init = LLVMConstNull(var_type);
LLVMBuildStore(ctx->builder, zero_init, alloca);
} else {
return;
}
VarEntry* ve = add_var(ctx, node->as.let_stmt.name, alloca, var_type);
// 若 init 是 lambda, 记录闭包函数名供后续调用
if (node->as.let_stmt.init &&
node->as.let_stmt.init->kind == AST_LAMBDA && ve)
ve->closure_fn = node->as.let_stmt.init->as.lambda.generated_name;
// 自动内存管理: 只追踪 str 堆分配 (拼接/malloc)
// struct 是栈上值类型,不能 free();含 str 字段时 v0.5 扩展
if (node->as.let_stmt.init->type.kind == TYPE_STR) {
AstKind ik = node->as.let_stmt.init->kind;
if (ik == AST_BINARY_EXPR || ik == AST_CALL_EXPR) {
cleanup_add(ctx, alloca);
}
}
break;
}
case AST_ASSIGN_STMT: {
LLVMValueRef ptr = find_var(ctx, node->as.assign_stmt.name);
if (!ptr) return;
LLVMValueRef val = codegen_expr(ctx, node->as.assign_stmt.value);
if (!val) return;
LLVMBuildStore(ctx->builder, val, ptr);
break;
}
case AST_EXPR_STMT:
codegen_expr(ctx, node->as.expr_stmt.expr);
break;
case AST_DEFER_STMT:
if (ctx->defer_count < 64)
ctx->defer_exprs[ctx->defer_count++] = node->as.defer_stmt.body;
break;
case AST_RETURN_STMT: {
// 先计算返回值
LLVMValueRef ret_val = NULL;
bool has_val = node->as.return_stmt.expr != NULL;
if (has_val) {
ret_val = codegen_expr(ctx, node->as.return_stmt.expr);
if (!ret_val) return;
}
// 如果返回的是 str 类型的变量,从清理列表移除以防止 use-after-free
if (has_val && node->as.return_stmt.expr->type.kind == TYPE_STR &&
node->as.return_stmt.expr->kind == AST_IDENT_EXPR) {
LLVMValueRef alloca = find_var(ctx, node->as.return_stmt.expr->as.ident.name);
if (alloca) {
for (size_t i = 0; i < ctx->cleanup_count; i++) {
if (ctx->cleanup_list[i] == alloca) {
ctx->cleanup_list[i] = ctx->cleanup_list[ctx->cleanup_count - 1];
ctx->cleanup_count--;
break;
}
}
}
}
// defer → cleanup → ret 的顺序
emit_deferred(ctx);
cleanup_emit(ctx, 0);
if (has_val) LLVMBuildRet(ctx->builder, ret_val);
else LLVMBuildRetVoid(ctx->builder);
break;
}
case AST_BLOCK: {
if (++codegen_depth > MAX_CODEGEN_DEPTH) { codegen_depth--; return; }
size_t block_mark = ctx->cleanup_count;
VarEntry* saved_table = ctx->var_table;
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
codegen_stmt(ctx, node->as.block.stmts[i]);
}
ctx->var_table = saved_table;
cleanup_emit(ctx, block_mark);
codegen_depth--;
break;
}
case AST_IF_STMT: {
LLVMValueRef cond = codegen_expr(ctx, node->as.if_stmt.cond);
if (!cond) return;
LLVMBasicBlockRef cur_bb = LLVMGetInsertBlock(ctx->builder);
LLVMValueRef cur_fn = LLVMGetBasicBlockParent(cur_bb);
LLVMBasicBlockRef then_bb = LLVMAppendBasicBlockInContext(ctx->context, cur_fn, "then");
LLVMBasicBlockRef else_bb = node->as.if_stmt.else_block
? LLVMAppendBasicBlockInContext(ctx->context, cur_fn, "else") : NULL;
LLVMBasicBlockRef merge_bb = LLVMAppendBasicBlockInContext(ctx->context, cur_fn, "if_merge");
if (else_bb)
LLVMBuildCondBr(ctx->builder, cond, then_bb, else_bb);
else
LLVMBuildCondBr(ctx->builder, cond, then_bb, merge_bb);
LLVMPositionBuilderAtEnd(ctx->builder, then_bb);
codegen_stmt(ctx, node->as.if_stmt.then_block);
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx->builder)))
LLVMBuildBr(ctx->builder, merge_bb);
if (else_bb) {
LLVMPositionBuilderAtEnd(ctx->builder, else_bb);
codegen_stmt(ctx, node->as.if_stmt.else_block);
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx->builder)))
LLVMBuildBr(ctx->builder, merge_bb);
}
LLVMPositionBuilderAtEnd(ctx->builder, merge_bb);
break;
}
case AST_ARRAY_ASSIGN_STMT: {
LLVMValueRef arr_ptr = find_var(ctx, node->as.array_assign.name);
if (!arr_ptr) return;
// 获取数组的 LLVM 类型(从变量表中)
VarEntry* ve = NULL;
for (VarEntry* e = ctx->var_table; e; e = e->next)
if (strcmp(e->name, node->as.array_assign.name) == 0) { ve = e; break; }
LLVMValueRef idx_val = codegen_expr(ctx, node->as.array_assign.index);
if (!idx_val) return;
LLVMValueRef val_val = codegen_expr(ctx, node->as.array_assign.value);
if (!val_val) return;
// i64 → i32 截断
LLVMValueRef idx_i32 = LLVMBuildTrunc(ctx->builder, idx_val,
LLVMInt32TypeInContext(ctx->context), "idx32");
LLVMValueRef indices[] = {
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
idx_i32
};
LLVMValueRef elem_ptr = LLVMBuildGEP2(ctx->builder, ve->alloca_type, arr_ptr, indices, 2, "arr_assign_elem");
LLVMBuildStore(ctx->builder, val_val, elem_ptr);
break;
}
case AST_WHILE_STMT: {
LLVMBasicBlockRef cur_bb = LLVMGetInsertBlock(ctx->builder);
LLVMValueRef cur_fn = LLVMGetBasicBlockParent(cur_bb);
LLVMBasicBlockRef cond_bb = LLVMAppendBasicBlockInContext(ctx->context, cur_fn, "while_cond");
LLVMBasicBlockRef body_bb = LLVMAppendBasicBlockInContext(ctx->context, cur_fn, "while_body");
LLVMBasicBlockRef exit_bb = LLVMAppendBasicBlockInContext(ctx->context, cur_fn, "while_exit");
LLVMBuildBr(ctx->builder, cond_bb);
LLVMPositionBuilderAtEnd(ctx->builder, cond_bb);
LLVMValueRef cond = codegen_expr(ctx, node->as.while_stmt.cond);
if (!cond) return;
LLVMBuildCondBr(ctx->builder, cond, body_bb, exit_bb);
LLVMPositionBuilderAtEnd(ctx->builder, body_bb);
codegen_stmt(ctx, node->as.while_stmt.body);
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx->builder)))
LLVMBuildBr(ctx->builder, cond_bb);
LLVMPositionBuilderAtEnd(ctx->builder, exit_bb);
break;
}
default:
break;
}
}
// === 程序级代码生成 ===
LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
const char* name, const char** error_msg,
LLVMContextRef* out_context) {
CgCtx ctx = {0};
ctx.arena = codegen_arena;
ctx.context = LLVMContextCreate();
if (!ctx.context) {
*error_msg = "无法创建 LLVM Context";
*out_context = NULL;
return NULL;
}
ctx.module = LLVMModuleCreateWithNameInContext(name, ctx.context);
ctx.builder = LLVMCreateBuilderInContext(ctx.context);
codegen_expr_init();
// 声明 C 标准库 printf(内置 print 函数依赖它)
LLVMTypeRef printf_param_types[] = {
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0)
};
ctx.printf_ty = LLVMFunctionType(
LLVMInt32TypeInContext(ctx.context), printf_param_types, 1, true);
ctx.printf_fn = LLVMAddFunction(ctx.module, "printf", ctx.printf_ty);
// 声明 malloc: void* malloc(size_t)
LLVMTypeRef malloc_args[] = { LLVMInt64TypeInContext(ctx.context) };
LLVMTypeRef malloc_ty = LLVMFunctionType(
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0), malloc_args, 1, false);
ctx.malloc_fn = LLVMAddFunction(ctx.module, "malloc", malloc_ty);
// 声明 free: void free(void*)
LLVMTypeRef free_args[] = { LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0) };
LLVMTypeRef free_ty = LLVMFunctionType(LLVMVoidTypeInContext(ctx.context), free_args, 1, false);
ctx.free_fn = LLVMAddFunction(ctx.module, "free", free_ty);
// 声明 strlen: size_t strlen(const char*)
LLVMTypeRef strlen_args[] = { LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0) };
LLVMTypeRef strlen_ty = LLVMFunctionType(
LLVMInt64TypeInContext(ctx.context), strlen_args, 1, false);
ctx.strlen_fn = LLVMAddFunction(ctx.module, "strlen", strlen_ty);
// 声明 memcpy: void* memcpy(void*, const void*, size_t)
LLVMTypeRef memcpy_args[] = {
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0),
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0),
LLVMInt64TypeInContext(ctx.context),
};
LLVMTypeRef memcpy_ty = LLVMFunctionType(
LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0),
memcpy_args, 3, false);
ctx.memcpy_fn = LLVMAddFunction(ctx.module, "memcpy", memcpy_ty);
// __chkstk 桩:LLVM 在生成大栈帧代码时会引用此符号(MinGW x64: __chkstk
{
LLVMTypeRef chkstk_ty = LLVMFunctionType(LLVMVoidTypeInContext(ctx.context), NULL, 0, false);
LLVMValueRef chkstk_fn = LLVMAddFunction(ctx.module, "__chkstk", chkstk_ty);
LLVMBasicBlockRef chk_bb = LLVMAppendBasicBlockInContext(ctx.context, chkstk_fn, "entry");
LLVMPositionBuilderAtEnd(ctx.builder, chk_bb);
LLVMBuildRetVoid(ctx.builder);
}
// 第零遍:先创建所有命名结构体(占位符,未设置 body)
for (size_t i = 0; i < ast->as.program.struct_count; i++) {
AstNode* sd = ast->as.program.structs[i];
LLVMTypeRef llvm_st = LLVMStructCreateNamed(ctx.context, sd->as.struct_decl.name);
add_struct_type(&ctx, sd->as.struct_decl.name, llvm_st,
sd->as.struct_decl.field_count);
}
// 然后设置所有结构体的 body(此时所有结构体类型已注册,可互相引用)
for (size_t i = 0; i < ast->as.program.struct_count; i++) {
AstNode* sd = ast->as.program.structs[i];
LLVMTypeRef llvm_st = find_struct_type(&ctx, sd->as.struct_decl.name);
LLVMTypeRef* elem_types = arena_alloc(ctx.arena,
sd->as.struct_decl.field_count * sizeof(LLVMTypeRef));
for (size_t j = 0; j < sd->as.struct_decl.field_count; j++) {
AstNode* field = sd->as.struct_decl.fields[j];
if (field->as.parameter.type == TYPE_STRUCT &&
field->as.parameter.struct_type_name) {
elem_types[j] = find_struct_type(&ctx,
field->as.parameter.struct_type_name);
} else {
elem_types[j] = to_llvm_type(&ctx, field->as.parameter.type);
}
}
LLVMStructSetBody(llvm_st, elem_types,
(unsigned)sd->as.struct_decl.field_count, false);
}
// 第一遍:声明所有 L 函数
for (size_t i = 0; i < ast->as.program.fn_count; i++) {
AstNode* fn = ast->as.program.functions[i];
bool has_env = fn->as.function.cap_count > 0;
size_t total_params = fn->as.function.param_count + (has_env ? 1 : 0);
LLVMTypeRef* ptypes = arena_alloc(ctx.arena,
total_params * sizeof(LLVMTypeRef));
bool* out_params = NULL;
if (total_params > 0) {
out_params = arena_alloc(ctx.arena, total_params * sizeof(bool));
for (size_t j = 0; j < total_params; j++) out_params[j] = false;
}
// 若有捕获, 第一个参数是 env_ptr
size_t poff = 0;
if (has_env) {
ptypes[0] = LLVMPointerType(LLVMInt8TypeInContext(ctx.context), 0);
poff = 1;
}
for (size_t j = 0; j < fn->as.function.param_count; j++) {
AstNode* param = fn->as.function.params[j];
bool is_out = param->as.parameter.is_out;
if (out_params) out_params[j + poff] = is_out;
LLVMTypeRef inner_ty;
if (param->as.parameter.type == TYPE_STRUCT &&
param->as.parameter.struct_type_name) {
inner_ty = find_struct_type(&ctx, param->as.parameter.struct_type_name);
} else if (param->as.parameter.type == TYPE_ARRAY) {
LLVMTypeRef et = param->as.parameter.arr_elem_struct
? (find_struct_type(&ctx, param->as.parameter.arr_elem_struct) ?: LLVMInt64TypeInContext(ctx.context))
: to_llvm_type(&ctx, param->as.parameter.arr_elem_type);
inner_ty = LLVMArrayType(et, (unsigned)param->as.parameter.arr_size);
} else {
inner_ty = to_llvm_type(&ctx, param->as.parameter.type);
}
ptypes[j + poff] = is_out ? LLVMPointerType(inner_ty, 0) : inner_ty;
}
LLVMTypeRef ret_ty;
if (fn->as.function.return_type == TYPE_STRUCT &&
fn->as.function.return_struct_type_name) {
ret_ty = find_struct_type(&ctx, fn->as.function.return_struct_type_name);
} else {
ret_ty = to_llvm_type(&ctx, fn->as.function.return_type);
}
LLVMTypeRef fty = LLVMFunctionType(ret_ty,
ptypes, (unsigned)total_params, false);
LLVMValueRef lfn = LLVMAddFunction(ctx.module, fn->as.function.name, fty);
add_fn(&ctx, fn->as.function.name, lfn, out_params, total_params);
}
// 第二遍:生成函数体
for (size_t i = 0; i < ast->as.program.fn_count; i++) {
AstNode* fn = ast->as.program.functions[i];
LLVMValueRef lfn = find_fn(&ctx, fn->as.function.name);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(ctx.context, lfn, "entry");
LLVMPositionBuilderAtEnd(ctx.builder, entry);
// 清空变量表(每个函数独立作用域)
ctx.var_table = NULL;
// 捕获变量: 第一个参数是 env_ptr, 通过 GEP 注册捕获变量
bool has_env = fn->as.function.cap_count > 0;
LLVMValueRef env_ptr = NULL;
size_t param_offset = 0;
if (has_env) {
env_ptr = LLVMGetParam(lfn, 0);
param_offset = 1;
// 生成 env struct 类型并注册捕获变量
LLVMTypeRef* ef = arena_alloc(ctx.arena,
fn->as.function.cap_count * sizeof(LLVMTypeRef));
for (size_t ci = 0; ci < fn->as.function.cap_count; ci++)
ef[ci] = to_llvm_type(&ctx, fn->as.function.cap_types[ci]);
LLVMTypeRef env_ty = LLVMStructTypeInContext(ctx.context, ef,
(unsigned)fn->as.function.cap_count, false);
LLVMValueRef typed_env = LLVMBuildBitCast(ctx.builder, env_ptr,
LLVMPointerType(env_ty, 0), "env_typed");
for (size_t ci = 0; ci < fn->as.function.cap_count; ci++) {
LLVMValueRef gep_idx[] = {
LLVMConstInt(LLVMInt32TypeInContext(ctx.context), 0, false),
LLVMConstInt(LLVMInt32TypeInContext(ctx.context), (unsigned)ci, false)
};
LLVMValueRef field_ptr = LLVMBuildGEP2(ctx.builder, env_ty,
typed_env, gep_idx, 2, "cap_ptr");
add_var(&ctx, fn->as.function.captured[ci], field_ptr,
to_llvm_type(&ctx, fn->as.function.cap_types[ci]));
}
}
// 将参数注册为变量
for (size_t j = 0; j < fn->as.function.param_count; j++) {
LLVMValueRef param = LLVMGetParam(lfn, (unsigned)(j + param_offset));
AstNode* pnode = fn->as.function.params[j];
LLVMTypeRef param_ty;
if (pnode->as.parameter.type == TYPE_STRUCT &&
pnode->as.parameter.struct_type_name) {
param_ty = find_struct_type(&ctx, pnode->as.parameter.struct_type_name);
} else if (pnode->as.parameter.type == TYPE_ARRAY) {
LLVMTypeRef et = pnode->as.parameter.arr_elem_struct
? (find_struct_type(&ctx, pnode->as.parameter.arr_elem_struct) ?: LLVMInt64TypeInContext(ctx.context))
: to_llvm_type(&ctx, pnode->as.parameter.arr_elem_type);
param_ty = LLVMArrayType(et, (unsigned)pnode->as.parameter.arr_size);
} else {
param_ty = to_llvm_type(&ctx, pnode->as.parameter.type);
}
if (pnode->as.parameter.is_out) {
add_var(&ctx, pnode->as.parameter.name, param, param_ty);
} else {
LLVMValueRef alloca = LLVMBuildAlloca(ctx.builder,
param_ty, pnode->as.parameter.name);
LLVMBuildStore(ctx.builder, param, alloca);
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
}
}
ctx.defer_count = 0;
codegen_stmt(&ctx, fn->as.function.body);
// 确保函数有终止指令(terminator)
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx.builder))) {
emit_deferred(&ctx);
cleanup_emit(&ctx, 0);
if (fn->as.function.return_type == TYPE_VOID)
LLVMBuildRetVoid(ctx.builder);
else if (fn->as.function.return_type == TYPE_STRUCT &&
fn->as.function.return_struct_type_name) {
LLVMTypeRef st_ty = find_struct_type(&ctx, fn->as.function.return_struct_type_name);
LLVMBuildRet(ctx.builder, st_ty ? LLVMConstNull(st_ty) :
LLVMConstInt(to_llvm_type(&ctx, TYPE_I64), 0, false));
}
else
LLVMBuildRet(ctx.builder,
(fn->as.function.return_type == TYPE_F64
? LLVMConstReal(to_llvm_type(&ctx, TYPE_F64), 0.0)
: LLVMConstInt(to_llvm_type(&ctx, fn->as.function.return_type), 0, false)));
}
}
// 验证模块(使用 ReturnStatus 以获取完整错误消息)
char* verify_err = NULL;
if (LLVMVerifyModule(ctx.module, LLVMReturnStatusAction, &verify_err)) {
*error_msg = verify_err ? verify_err
: arena_strdup(ctx.arena, "LLVM 模块验证失败");
LLVMDisposeBuilder(ctx.builder);
*out_context = ctx.context;
return NULL;
}
LLVMDisposeBuilder(ctx.builder);
*out_context = ctx.context;
return ctx.module;
}