fix(gen): Gargantua 编译修复——循环 alloca 入入口块 + 跨模块 CDefine 拼路径/门控

- translate_for 循环计数 alloca 改回 _alloca_at_entry(入口块生成),
  修复分支内 for 循环(Terminal _cmd_cd 的 for i in range(1,64))产生
  "Instruction does not dominate all uses! %197 = alloca i32"
- _build_source_path_from_sha1 优先用条目存储的 IncDir(绝对 includes 根,
  多目录支持)拼路径,修复 Gargantua 多 includes 目录下 stdint.vp 拼到
  首目录 ViperOS → 文件不存在 → XMOD-CD 误报
- translate_name_value 对 ALL_CAPS 名先查 lookup_var:当前作用域已有
  同名变量(如 Gargantua CAM/FWD/RIGHT/UP 模块全局)则跳过跨模块
  CDefine 查找,避免 star-import 误命中 stdint
This commit is contained in:
TermiNexus committed 2026-08-26 16:14:05 +08:00
1 parent bd3705d68b
commit f2bfe82834
3 files changed
+99 -22

No files matched your search

+18 -7
View File
@@ -78,15 +78,26 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
rel_path: str = rel_arr_ptr + ridx
if rel_path[0] == '\0':
return None
# 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir);
# 以 "includes/" 开头 → includes 文件(去掉 "includes/" 前缀)。
# 其他 rel_path(如 VKernel 的 "drivers/core/cpu/cpu.vp")无前缀,
# 无法从 rel_path 判断归属:先试 SourceDir(App 文件),文件不存在
# 再试 IncludesDir(includes 文件的 RelPath 同样无前缀存储)。
# 避免路径构建错误导致跨模块 CDefine 查找静默失败。
# 选择基础目录(优先级):
# 1. 条目存储的 includes 根目录 IncDir(绝对路径,多 includes 目录
# 支持):PopulateSha1MapStore 按每条目保存所属根目录,跨模块
# CDefine 查找回退读源时按 IncDir 直接拼路径,避免"首 includes
# 目录"启发式对非首目录文件失效(Gargantua 多 includes 目录:
# stdint.vp 属于 TransPyC/includes,而 IncludesDir=首目录 ViperOS
# → 拼错路径 → 文件不存在 → XMOD-CD 误报根因)。
# 2. rel_path 前缀启发式:以 "lib/" 开头 → App 源文件(SourceDir);
# "includes/" 开头 → includes 文件(去掉前缀);其他无前缀路径
# (如 VKernel 的 "drivers/core/cpu/cpu.vp")先试 SourceDir,
# 文件不存在再试 IncludesDir。
base_dir: str = None
rel_used: str = rel_path
if string.strlen(rel_path) >= 4:
inc_arr_ptr: bytes = StubMergerStore.GetSha1StoreIncdirArrPtr()
if inc_arr_ptr is not None:
iidx: t.CSizeT = t.CSizeT(idx_s) * StubMerger.MAX_INC_DIR_LEN
inc_dir: str = inc_arr_ptr + iidx
if inc_dir[0] != '\0':
base_dir = inc_dir
if base_dir is None and string.strlen(rel_path) >= 4:
if (rel_path[0] == 'l' and rel_path[1] == 'i' and
rel_path[2] == 'b' and rel_path[3] == '/'):
base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir
+70 -14
View File
@@ -101,20 +101,28 @@ class ExprGenName(ExprGenBase.ExprGenBase):
# 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0:
if trans is not None:
cdef_val: t.CInt64T = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(
pool, nm_id, trans._from_imports, trans._imported_modules, 0, node)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id)
if cdef_sv2 is not None:
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv2, trans)
self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
# 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double),
# 需返回浮点常量而非截断的整数
dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id)
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm)
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val)
# ALL_CAPS 也可能是普通变量(如 Gargantua 的
# CAM/FWD/RIGHT/UP: V3|t.CPtr 模块级全局)。若当前作用域
# (含模块级 Root,lookup_var 逐级上溯)已存在同名变量,
# 优先按变量处理,跳过跨模块 CDefine 查找——否则 ALL_CAPS
# 命中 star-import 模块(from stdint import *)→ 无谓读源
# 文件,且多 includes 目录下还可能触发 XMOD-CD 误报
# (ExprGenCdef._build_source_path_from_sha1 拼错路径)。
if self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) is None:
cdef_val: t.CInt64T = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(
pool, nm_id, trans._from_imports, trans._imported_modules, 0, node)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id)
if cdef_sv2 is not None:
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv2, trans)
self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
# 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double),
# 需返回浮点常量而非截断的整数
dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id)
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm)
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val)
# CDefine 查找失败:from-import 的模块级全局变量(如
# from Phase1 import PYI_BUF_SIZE;PYI_BUF_SIZE: t.CSizeT = 262144 是
@@ -632,6 +640,33 @@ class ExprGenName(ExprGenBase.ExprGenBase):
if idx_val is None:
return None
# 嵌套下标读取: a[i][j] —— 递归取内层指针后 load
# (与 get_subscript_ptr 嵌套分支对称;如 gfx.vp 的
# a.m[i][k] * b.m[k][j],内层 translate_value 会把行加载为
# Array 值(非指针)→ 通用路径失败 → "rhs 翻译失败")
if sub.value is not None and sub.value.kind() == ast.ASTKind.Subscript:
inner_ptr_r: llvmlite.Value | t.CPtr = self.get_subscript_ptr(
builder, pool, mod, sub.value, trans)
if inner_ptr_r is None or inner_ptr_r.Ty is None:
return None
inner_elem_r: llvmlite.LLVMType | t.CPtr = inner_ptr_r.Ty.Pointee
if inner_elem_r is None:
return None
match inner_elem_r:
case llvmlite.LLVMType.Array(arr_ie_r, _):
elem_ptr_r: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, inner_elem_r, arr_ie_r, inner_ptr_r,
self._zext_index_to_i32(builder, idx_val))
if elem_ptr_r is not None:
return llvmlite.build_load(builder, arr_ie_r, elem_ptr_r)
return None
case _:
elem_ptr_r2: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, inner_elem_r, inner_ptr_r, idx_val)
if elem_ptr_r2 is not None:
return llvmlite.build_load(builder, inner_elem_r, elem_ptr_r2)
return None
# 如果 value 是 Name,尝试从 alloca 类型推断
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
@@ -912,6 +947,27 @@ class ExprGenName(ExprGenBase.ExprGenBase):
if idx_val is None:
return None
# 嵌套下标: a[i][j] = v —— 递归解析内层下标指针后 GEP
# (如 gfx.vp Mat4.m: t.CArray[t.CArray[float, 4], 4] 的 m.m[0][0] = 1;
# 外层 Subscript 的 value 是内层 Subscript,通用路径 translate_value
# 会把内层元素加载为值(Array 类型)→ is_ptr_type 失败 → 返回 None →
# "subscript ptr is None" fail-fast。递归取内层指针再 GEP 根治。)
if sub.value is not None and sub.value.kind() == ast.ASTKind.Subscript:
inner_ptr: llvmlite.Value | t.CPtr = self.get_subscript_ptr(
builder, pool, mod, sub.value, trans)
if inner_ptr is None or inner_ptr.Ty is None:
return None
inner_elem: llvmlite.LLVMType | t.CPtr = inner_ptr.Ty.Pointee
if inner_elem is None:
return None
match inner_elem:
case llvmlite.LLVMType.Array(arr_ie, _):
return llvmlite.build_gep_array(
builder, inner_elem, arr_ie, inner_ptr,
self._zext_index_to_i32(builder, idx_val))
case _:
return llvmlite.build_gep(builder, inner_elem, inner_ptr, idx_val)
# 如果 value 是 Name,尝试从 alloca 类型推断
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
+11 -1
View File
@@ -1211,10 +1211,20 @@ class StmtGenCifMixin:
step_neg_const = 1
# 4. 创建/查找循环变量 alloca
var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
# 必须用 lookup_current(仅当前作用域):闭包内 lookup_var 会跨函数
# 命中父函数同名变量(如父函数自己的循环计数器 i)→ 循环计数写到
# 父函数存储 → 跨函数 SSA 错乱(llc "instruction expected to be
# numbered",Terminal _cmd_cd 的 for i in range(1,64) 根因)。
var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
# 用 _alloca_at_entry:alloca 放函数入口块,保证支配性
# (内联 build_alloca 若 preheader 是分支块(如 if.then),
# 循环三块跨块使用 → llc "Instruction does not dominate all
# uses!",Terminal _cmd_cd 的 for i in range(1,64) 根因)。
# 闭包跨函数命中父函数变量的根因已由 lookup_current 修复,
# 故 entry 插入路径安全。
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i32_ty)
if self.Gen.VarGen.define_var(
trans.SymTab, var_name, var_alloca) == 0: