6ebe551ee3
问题: 函数参数声明 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>
543 lines
23 KiB
C
543 lines
23 KiB
C
#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;
|
||
}
|