fix: 技术债修复 — codegen malloc→arena + .codegraphignore

- codegen.c: VarEntry/FnEntry/ptypes 全部改用 arena_alloc,消除 malloc/free
- codegen_module 新增 Arena* 参数,main.c 传入主 arena
- 新增 .codegraphignore 排除 build/ 和 .codegraph/
- 基于 Codex 分析报告第7节技术债务
This commit is contained in:
2026-06-05 00:37:54 +08:00
parent 3b7bab1e1b
commit f8c5e18188
5 changed files with 353 additions and 9 deletions
+10 -6
View File
@@ -3,7 +3,6 @@
#include <llvm-c/Types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// === 内部状态 ===
typedef struct VarEntry {
@@ -22,6 +21,7 @@ typedef struct FnEntry {
} FnEntry;
typedef struct {
Arena* arena; // 代码生成阶段分配器
LLVMContextRef context; // LLVM 19+ 需要显式 Context
LLVMModuleRef module;
LLVMBuilderRef builder;
@@ -60,7 +60,8 @@ static LLVMValueRef find_var(CgCtx* ctx, const char* name) {
}
static void add_var(CgCtx* ctx, const char* name, LLVMValueRef alloca) {
VarEntry* e = malloc(sizeof(*e));
VarEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return;
e->name = name; e->alloca = alloca; e->next = ctx->var_table;
ctx->var_table = e;
}
@@ -73,7 +74,8 @@ static LLVMValueRef find_fn(CgCtx* ctx, const char* name) {
}
static void add_fn(CgCtx* ctx, const char* name, LLVMValueRef fn) {
FnEntry* e = malloc(sizeof(*e));
FnEntry* e = arena_alloc(ctx->arena, sizeof(*e));
if (!e) return;
e->name = name; e->fn = fn;
e->ret = TYPE_VOID;
e->params = NULL;
@@ -305,8 +307,10 @@ static void codegen_stmt(CgCtx* ctx, AstNode* node) {
}
// === 程序级代码生成 ===
LLVMModuleRef codegen_module(AstNode* ast, const char* name, const char** error_msg) {
LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
const char* name, const char** error_msg) {
CgCtx ctx = {0};
ctx.arena = codegen_arena;
ctx.context = LLVMContextCreate();
if (!ctx.context) {
*error_msg = "无法创建 LLVM Context";
@@ -326,7 +330,8 @@ LLVMModuleRef codegen_module(AstNode* ast, const char* name, const char** error_
// 第一遍:声明所有 L 函数
for (size_t i = 0; i < ast->as.program.fn_count; i++) {
AstNode* fn = ast->as.program.functions[i];
LLVMTypeRef* ptypes = malloc(fn->as.function.param_count * sizeof(LLVMTypeRef));
LLVMTypeRef* ptypes = arena_alloc(ctx.arena,
fn->as.function.param_count * sizeof(LLVMTypeRef));
for (size_t j = 0; j < fn->as.function.param_count; j++)
ptypes[j] = to_llvm_type(&ctx, fn->as.function.params[j]->as.parameter.type);
LLVMTypeRef fty = LLVMFunctionType(
@@ -334,7 +339,6 @@ LLVMModuleRef codegen_module(AstNode* ast, const char* name, const char** error_
ptypes, (unsigned)fn->as.function.param_count, false);
LLVMValueRef lfn = LLVMAddFunction(ctx.module, fn->as.function.name, fty);
add_fn(&ctx, fn->as.function.name, lfn);
free(ptypes);
}
// 第二遍:生成函数体
+4 -2
View File
@@ -2,11 +2,13 @@
#define CODEGEN_H
#include "ast.h"
#include "arena.h"
#include <llvm-c/Core.h>
// 生成 LLVM Module。模块已 verify,可直接 dump 或写入文件。
// codegen_arena 用于内部分配(VarEntry/FnEntry 等),需在整个 Module 生命周期保持存活。
// 出错时返回 NULL 并设置 *error_msg。
LLVMModuleRef codegen_module(AstNode* ast, const char* module_name,
const char** error_msg);
LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
const char* module_name, const char** error_msg);
#endif
+1 -1
View File
@@ -95,7 +95,7 @@ int main(int argc, char** argv) {
// 6. LLVM IR 生成
const char* codegen_error = NULL;
LLVMModuleRef module = codegen_module(ast, "l_module", &codegen_error);
LLVMModuleRef module = codegen_module(ast, &arena, "l_module", &codegen_error);
if (!module) {
fprintf(stderr, "IR 生成错误: %s\n", codegen_error);
free(source); arena_destroy(&arena);