#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; }