fix(tpv): vpi 注入完整类型定义 + list elem_size + 路径修复,清理临时诊断
- VpiReader: 值 struct 全局/数组元素/函数返回类型注册完整定义,修复 llc use of undefined type;vpi 注入类后补 add_field 字段表(LARGE_INTEGER.QuadPart 恒 0 根因) - TypeGenResolve: list[str](pool, elem_size) 语义修复(参数个数误当 elem_size,Mat4 崩溃根因);t/c 内置命名空间 Subscript 特判 - Config: _join_path 防双份路径 - GenApi: 新增 add_field 代理 - 移除 DBG-VK/PHASEADBG/GAP-DIAG/DBG-EMP 临时诊断
This commit is contained in:
1 parent
1fe7878074
commit
c2b9a26c62
7 files changed
+102
-40
No files matched your search
@@ -245,6 +245,14 @@ def _join_path(rel: str, project_dir: str) -> str:
|
||||
# 绝对路径(以 / 或 \ 开头)保持不变
|
||||
if rel[0] == '/' or rel[0] == '\\':
|
||||
return rel
|
||||
# [FIX] 命令行 --build-dir 按进程 cwd 给出的路径(如 ./TransPyV/.tpv_build2)
|
||||
# 已含 project_dir 前缀(./TransPyV)时不再拼接,避免双份路径
|
||||
# (./TransPyV/TransPyV/.tpv_build2)。边界取到目录分隔符或串尾。
|
||||
if project_dir is not None:
|
||||
pdl: t.CSizeT = string.strlen(project_dir)
|
||||
if pdl > 0 and string.strncmp(rel, project_dir, pdl) == 0:
|
||||
if rel[pdl] == '/' or rel[pdl] == '\\' or rel[pdl] == '\0':
|
||||
return rel
|
||||
|
||||
rel_len: t.CSizeT = string.strlen(rel)
|
||||
dir_len: t.CSizeT = string.strlen(project_dir)
|
||||
|
||||
@@ -1695,10 +1695,51 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
pool, cls_name, struct_ty_c, src_sha1)
|
||||
if entry_c is None:
|
||||
return 0
|
||||
# [FIX] vpi 注入类时同步注册字段到 StructEntry 字段表(名字+类型)。
|
||||
# 仅设置 Ty(LLVMType 含字段)而字段表空(FieldCount=0)时,使用端
|
||||
# lookup_field / lookup_field_by_class 按名字查字段失败 → 属性访问走
|
||||
# _deps_pending → Phase 1 includes 翻译无重译 → 失败版本落盘恒 0
|
||||
# (fileio.vp File.size 的 li.QuadPart → ret i64 zeroinitializer →
|
||||
# read_all=0 → 二代 Config 加载失败根因)。
|
||||
# add_field 内部按 StdlibAlloc 复制字段名到 perm_pool,跨 reset 存活。
|
||||
afi_c: int = 0
|
||||
for afi_c in range(field_count):
|
||||
af_name_c: str = (str)(t.CVoid(field_names_buf[afi_c], t.CPtr))
|
||||
af_ty_c: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
|
||||
t.CVoid(field_types_buf[afi_c], t.CPtr))
|
||||
GenApi.add_field(pool, entry_c, af_name_c, af_ty_c)
|
||||
GenApi.add_visible_struct(pool, cls_name)
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _ensure_full_value_types - 跨模块"值类型"引用注册完整定义
|
||||
#
|
||||
# opaque 不足以支撑 llc:值 struct global(@_per_cpu = global %per_cpu_data)、
|
||||
# [N x opaque] 数组(@gdt = global [7 x %gdt_entry])、值 struct 返回类型
|
||||
# (declare %Mat4 @Mat4_Identity())均报 "use of undefined type"(值类型大小
|
||||
# 需已知)。vpi 注入类已 add_field 含字段(完整 Ty),在注册表可查时注册完整
|
||||
# 定义。指针引用(Ptr(Struct))无需——_scan_type_for_cross_module_refs 的 Ptr
|
||||
# 分支添加 opaque 即可。
|
||||
# ============================================================
|
||||
def _ensure_full_value_types(mod: llvmlite.LLVMModule | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> None:
|
||||
"""递归为值 struct / 数组元素 struct 注册完整定义(递归深度守卫)"""
|
||||
if mod is None or pool is None or ty is None:
|
||||
return
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
full_se_h: GenTypes.StructEntry | t.CPtr = GenApi.find_struct_by_type(ty)
|
||||
if full_se_h is not None and full_se_h.Ty is not None:
|
||||
llvmlite.module_add_named_type(mod, pool, full_se_h.Ty)
|
||||
case llvmlite.LLVMType.Array(aelem_h, _):
|
||||
if aelem_h is not None:
|
||||
_ensure_full_value_types(mod, pool, aelem_h)
|
||||
case _:
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _inject_global_variable_declare - 从 vpi AnnAssign 创建模块级全局变量 declare
|
||||
#
|
||||
@@ -1792,6 +1833,8 @@ def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
# undefined type named 'sha1.gdt_entry'"(fpu/fat32 合并 IR 根因)。
|
||||
# 对齐 TranslatorGenMixin 创建全局前的 module_ensure_opaque_for_type
|
||||
# (_scan_type_for_cross_module_refs 递归 Array/Struct/Ptr)。
|
||||
# 值类型(struct 值 / 数组元素 struct)注册完整定义(见 _ensure_full_value_types)
|
||||
_ensure_full_value_types(mod, pool, gv_ty_v)
|
||||
llvmlite.module_ensure_opaque_for_type(mod, pool, gv_ty_v)
|
||||
gv_v: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_m, gv_ty_v)
|
||||
if gv_v is None:
|
||||
@@ -1889,6 +1932,11 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
if ret_ty is None:
|
||||
ret_ty = i32_ty
|
||||
|
||||
# 值 struct 返回类型(如 gfx.vp Mat4_Identity -> Mat4)需要完整定义:
|
||||
# declare %Mat4 opaque → llc "use of undefined type"。注册完整定义。
|
||||
_ensure_full_value_types(mod, pool, ret_ty)
|
||||
llvmlite.module_ensure_opaque_for_type(mod, pool, ret_ty)
|
||||
|
||||
# 创建 declare
|
||||
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, mangled_name, ret_ty)
|
||||
|
||||
@@ -5,7 +5,6 @@ import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
@@ -87,7 +86,6 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
if existing is not None:
|
||||
if existing.FieldCount == 0 and trans._declare_only == 0:
|
||||
if self.Gen.ClassGenBase._class_body_has_field(cd) != 0:
|
||||
VLogger.info(f"[DBG-EMP] class={class_name} FC=0 ty={t.CUInt64T(existing.Ty)} 类体有字段,中和重建", "DBG")
|
||||
if existing.Name is not None:
|
||||
existing.Name[0] = '\0'
|
||||
existing.Ty = None
|
||||
@@ -230,8 +228,6 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
# L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
# [PHASEADBG] 临时诊断:父类未注册即 pending 的根因(用后移除)
|
||||
stdio.printf("[PHASEADBG] 父类未注册: class=%s parent=%s\n", class_name, pname)
|
||||
return 0
|
||||
pfc: int = parent_entry.FieldCount
|
||||
for pfi in range(pfc):
|
||||
@@ -366,12 +362,6 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
# 翻译: <file>,请检查依赖模块是否已编译/注册"),不静默掩盖。
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
# [PHASEADBG] 临时诊断:字段注解类型未解析即 pending 的根因(用后移除)
|
||||
dbg_ak: t.CInt = -1
|
||||
if aa.annotation is not None:
|
||||
dbg_ak = aa.annotation.kind()
|
||||
stdio.printf("[PHASEADBG] 字段类型未解析: class=%s field=%s annot_kind=%d\n",
|
||||
class_name, tgt.id, dbg_ak)
|
||||
return 0
|
||||
# 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时
|
||||
# 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底)
|
||||
|
||||
@@ -807,18 +807,6 @@ class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# 查找字段索引和类型
|
||||
field_info: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||||
struct_ty, at.attr)
|
||||
# [GAP-DIAG] 定位 th.arg=arg 字段索引错(func/arg 都解析成 3)根因:
|
||||
# 打印字段名/结构体类型名/查到的索引与实际字段名
|
||||
if field_info is not None \
|
||||
and (string.strcmp(at.attr, "arg") == 0 or string.strcmp(at.attr, "func") == 0):
|
||||
dbg_gap: str = pool.alloc(200)
|
||||
if dbg_gap is not None:
|
||||
ty_nm_gap: str = self.Gen.StructGen._extract_struct_name(struct_ty)
|
||||
if ty_nm_gap is None:
|
||||
ty_nm_gap = "?"
|
||||
viperlib.snprintf(dbg_gap, 200, "[GAP] attr=%s ty=%s idx=%d fe_name=%s\n",
|
||||
at.attr, ty_nm_gap, field_info.Index, field_info.Name)
|
||||
stdio.printf("%s", dbg_gap)
|
||||
# REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名
|
||||
# REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee)
|
||||
if field_info is None:
|
||||
|
||||
@@ -398,6 +398,19 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr,
|
||||
return None
|
||||
|
||||
|
||||
# ---------------- add_field(委托 StructGenMixin.add_field) ----------------
|
||||
def add_field(pool: memhub.MemBuddy | t.CPtr,
|
||||
struct_entry: GenTypes.StructEntry | t.CPtr,
|
||||
field_name: str,
|
||||
field_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""委托到 gen.add_field(原 Handles 壳)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.StructGen.add_field(pool, struct_entry, field_name, field_ty)
|
||||
return -1
|
||||
|
||||
|
||||
# ---------------- register_struct_alias(委托 StructGenMixin.register_struct_alias) ----------------
|
||||
def register_struct_alias(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str,
|
||||
|
||||
@@ -221,14 +221,6 @@ class StructGenMixin:
|
||||
|
||||
entry.Ty = struct_ty
|
||||
entry.FieldCount = 0
|
||||
# [DBG-EMP] 临时诊断:定位空类注册来源(win32base SECURITY_ATTRIBUTES /
|
||||
# win32file WIN32_FIND_DATAA FieldCount=0)
|
||||
if name is not None and (string.strstr(name, "SECURITY_ATTRIBUTES") is not None
|
||||
or string.strstr(name, "WIN32_FIND_DATAA") is not None):
|
||||
sha1_s: str = "?"
|
||||
if sha1 is not None:
|
||||
sha1_s = sha1
|
||||
VLogger.info(f"[DBG-REG] {name} sha1={sha1_s} Ty={t.CUInt64T(struct_ty)}", "DBG")
|
||||
|
||||
# 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry)
|
||||
# SHA1 同样按 StdlibAlloc 选分配源(跨 1a/1b 存活,防 strcmp 悬空)
|
||||
@@ -359,11 +351,6 @@ class StructGenMixin:
|
||||
return -1
|
||||
|
||||
idx: int = struct_entry.FieldCount
|
||||
# [DBG-EMP] 临时诊断:定位空类字段添加(win32base SECURITY_ATTRIBUTES /
|
||||
# win32file WIN32_FIND_DATAA FieldCount=0)
|
||||
if struct_entry.Name is not None and (string.strstr(struct_entry.Name, "SECURITY_ATTRIBUTES") is not None
|
||||
or string.strstr(struct_entry.Name, "WIN32_FIND_DATAA") is not None):
|
||||
VLogger.info(f"[DBG-ADDF] {struct_entry.Name} field={field_name} idx={idx}", "DBG")
|
||||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(struct_entry, idx)
|
||||
if fe is None:
|
||||
return -1
|
||||
|
||||
@@ -230,6 +230,21 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
"""
|
||||
if type_name is None:
|
||||
return None
|
||||
# [FIX] 类型名指针越界(垃圾指针,ViperOS Mat4.m 嵌套泛型崩溃现场
|
||||
# strlen 收到 0x12124AE128712850 > x64 用户空间上限 2^47;低 16 位
|
||||
# 0x2850 残留 pool 偏移 → pool 越界写/寄存器破坏)。解引用前 fail-fast
|
||||
# 暴露根因(不静默 strlen 段错误)。
|
||||
if t.CUInt64T(type_name) > 0x00007FFFFFFFFFFF:
|
||||
VLogger.error(f"_norm_type_arg_name 类型名指针越界 (ptr={t.CUInt64T(type_name)}),疑似 pool 越界写破坏类型名指针", "TypeGen")
|
||||
stdlib.exit(1)
|
||||
# [FIX] 泛型实参分割(L341 "float, 4" → " 4")第二个参数带前导空格,
|
||||
# 空格开头的字符串作为类型名/查表 key 是脏数据(ViperOS Mat4.m 的
|
||||
# t.CArray[t.CArray[float, 4], 4] 崩溃现场:_norm_type_arg_name 收到
|
||||
# " 4")。跳过前导空格后再按规则规范化。
|
||||
while type_name[0] == ' ':
|
||||
type_name += 1
|
||||
if type_name[0] == '\0':
|
||||
return type_name
|
||||
# ---- 1. 顶层联合 "A|B"('|' 仅在括号外才分割)----
|
||||
# 括号感知:list[A|B] 的 '|' 在 '[' 内不是顶层联合,应留给第 1.5 步
|
||||
# 泛型 slice 递归处理;list[A]|t.CPtr 的 '|' 在括号外才是联合分割。
|
||||
@@ -316,7 +331,14 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
elif inner_buf_g[ci_g] == ',' and cur_dep_g == 0:
|
||||
arg_cnt_g += 1
|
||||
ci_g += 1
|
||||
arg_list_g: list[str] | t.CPtr = list[str](pool, arg_cnt_g)
|
||||
# [FIX] 第二参数是 elem_size(元素字节大小),不是参数个数!
|
||||
# str 是 i8*(8 字节)。此前误传 arg_cnt_g(参数个数,如 Mat4
|
||||
# 的 2)→ __elem_size__=2 → append 只写指针低 2 字节(高 48 位
|
||||
# 残留)→ get 读回垃圾指针(低 16 位=pool 偏移、高 48 位=相邻
|
||||
# 数据)→ _norm_type_arg_name 递归 strlen 崩(ViperOS Mat4.m
|
||||
# t.CArray[t.CArray[float, 4], 4] 崩溃根因:strlen 参数三次
|
||||
# 均为低 16 位 0x2850、高 48 位漂移)。
|
||||
arg_list_g: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if arg_list_g is not None:
|
||||
arg_start_g: t.CSizeT = 0
|
||||
cur_dep_g = 0
|
||||
@@ -1092,7 +1114,9 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
tp_elts = tp_tup.elts
|
||||
tp_count = len(tp_elts)
|
||||
else:
|
||||
tp_single: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 1)
|
||||
# [FIX] elem_size=8(ast.AST | t.CPtr 指针 8 字节),原传 1 → get 只读
|
||||
# 1 字节拼指针(高 56 位残留)→ tuple 元素解析垃圾
|
||||
tp_single: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8)
|
||||
if tp_single is not None:
|
||||
tp_single.append(sub.slice)
|
||||
tp_elts = tp_single
|
||||
@@ -1791,7 +1815,9 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 函数指针类型: t.Callable[[A, B], Ret] → i8*
|
||||
# 与 TPV 函数传指针惯例一致(函数值 bitcast 为 i8* 存储,调用时按实参重建签名)
|
||||
if string.strcmp(arr_at.attr, "Callable") == 0:
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
# t/c 是内置命名空间(不编译、不入 imported_modules),无需显式导入检查
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 \
|
||||
and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.Callable 模块未导入")
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# 指针类型: t.CPtr[T] → Ptr(T)(指向 T 的指针,T 自身可含指针层级)
|
||||
@@ -1800,7 +1826,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 此前缺失 → t.CUInt8T | t.CPtr[t.CPtr] 联合退化为左值 i8 →
|
||||
# c.Deref(out) 报"参数不是指针类型"(zdeflate.vp compress out 根因)
|
||||
if string.strcmp(arr_at.attr, "CPtr") == 0:
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 \
|
||||
and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CPtr 模块未导入")
|
||||
inner_cptr_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
@@ -1817,7 +1844,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return llvmlite.Ptr(pool, inner_cptr_ty)
|
||||
if string.strcmp(arr_at.attr, "CArray") != 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)")
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 \
|
||||
and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray 模块未导入")
|
||||
# 单参数形式: t.CArray[elem_ty] → Ptr(elem_ty)
|
||||
# 相当于 t.CArray[elem_ty, None],表示静态推导长度数组
|
||||
|
||||
Reference in new issue
Block a user