diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 300699c..2a38412 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -42,8 +42,12 @@ typedef struct { LLVMTypeRef printf_ty; // 字符串拼接运行时支持 LLVMValueRef malloc_fn; + LLVMValueRef free_fn; // auto-free 需要 free() LLVMValueRef strlen_fn; LLVMValueRef memcpy_fn; + // 自动内存管理: 追踪需要 free 的 str alloca + LLVMValueRef cleanup_list[64]; + size_t cleanup_count; } CgCtx; // === 类型映射(需要 Context)=== @@ -340,6 +344,26 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) { } } +// === 自动内存管理: 作用域退出时释放 str 堆分配 === +static void cleanup_add(CgCtx* ctx, LLVMValueRef alloca) { + if (ctx->cleanup_count < 64) { + ctx->cleanup_list[ctx->cleanup_count++] = alloca; + } +} + +// 释放从 mark 位置开始的所有 str 变量 +static 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; +} + // === 语句代码生成 === static void codegen_stmt(CgCtx* ctx, AstNode* node) { if (!node) return; @@ -362,6 +386,17 @@ static void codegen_stmt(CgCtx* ctx, AstNode* node) { var_type, node->as.let_stmt.name); LLVMBuildStore(ctx->builder, init_val, alloca); add_var(ctx, node->as.let_stmt.name, alloca); + + // 自动内存管理: str 堆分配追踪 + // 只有 BINARY_EXPR (拼接) 和 STRUCT_INIT 产生堆内存 + 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_STRUCT_INIT || ik == AST_CALL_EXPR) { + cleanup_add(ctx, alloca); + } + } else if (node->as.let_stmt.init->type.kind == TYPE_STRUCT) { + cleanup_add(ctx, alloca); // struct 可能含 str 字段 + } break; } @@ -378,20 +413,30 @@ static void codegen_stmt(CgCtx* ctx, AstNode* node) { codegen_expr(ctx, node->as.expr_stmt.expr); break; - case AST_RETURN_STMT: - if (node->as.return_stmt.expr) { - LLVMValueRef val = codegen_expr(ctx, node->as.return_stmt.expr); - if (val) LLVMBuildRet(ctx->builder, val); - } else { - LLVMBuildRetVoid(ctx->builder); + 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; } + // return 前释放当前作用域所有 str 堆分配 + cleanup_emit(ctx, 0); + // 然后 emit ret + if (has_val) LLVMBuildRet(ctx->builder, ret_val); + else LLVMBuildRetVoid(ctx->builder); break; + } - case AST_BLOCK: + case AST_BLOCK: { + size_t block_mark = ctx->cleanup_count; for (size_t i = 0; i < node->as.block.stmt_count; i++) { codegen_stmt(ctx, node->as.block.stmts[i]); } + cleanup_emit(ctx, block_mark); // 作用域退出: 释放块内 str 堆分配 break; + } case AST_IF_STMT: { LLVMValueRef cond = codegen_expr(ctx, node->as.if_stmt.cond); @@ -478,6 +523,11 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena, 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( @@ -560,6 +610,8 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena, // 确保函数有终止指令(terminator) if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx.builder))) { + // 函数结尾隐式 return: 先释放所有 str 堆分配 + cleanup_emit(&ctx, 0); if (fn->as.function.return_type == TYPE_VOID) LLVMBuildRetVoid(ctx.builder); else