修正了 TPC 的一些错误,包括 Test 维护后 TPV 无法重新编译或重编译后越界的部分问题

This commit is contained in:
2026-07-20 11:12:30 +08:00
parent ab73420b4f
commit a277ded8d4
476 changed files with 4000 additions and 3439 deletions

View File

@@ -87,15 +87,71 @@ class ExprAttrHandle(BaseHandle):
return (ST2, CN2)
return None
def _try_access_opaque_generic_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, opaque_struct: Any, Node: ast.Attribute, orig_CN: str) -> ir.Value | None:
"""通过特化版本访问 opaque 非特化泛型结构体成员。"""
spec_result: Any = self._find_specialized_struct_with_body(Gen, opaque_struct)
if spec_result is None:
def _try_access_opaque_generic_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, opaque_struct: Any, Node: ast.Attribute, orig_CN: str, parent_hint: str | None = None) -> ir.Value | None:
"""通过特化版本访问 opaque 非特化泛型结构体成员。
遍历所有候选特化版本(如 GSList[Param]/GSList[NameEntry]
优先选择 class_members 中包含 Node.attr 字段的版本,
避免选到错误特化版本(如 GSList[NameEntry] 而非 GSList[Param]
导致 _get_member_offset 返回 None 而生成 ret null。
parent_hint: 父上下文提供的特化提示(如 'GSList[BasicBlock]'
当所有候选都有目标字段(如 Head/Tail/Count
用此提示选择正确特化版本。"""
# 收集所有候选特化版本(有 body 的)
candidates: list[tuple[ir.IdentifiedStructType, str]] = []
if isinstance(opaque_struct, ir.IdentifiedStructType):
base_name: str = opaque_struct.name or ""
short_name: str = base_name.split('.')[-1] if '.' in base_name else base_name
if short_name and '[' not in short_name:
for CN2, ST2 in Gen.structs.items():
if not isinstance(ST2, ir.IdentifiedStructType):
continue
if ST2 is opaque_struct:
continue
if ST2.elements is None:
continue
st2_short: str = (ST2.name or "").split('.')[-1] if '.' in (ST2.name or "") else (ST2.name or "")
if st2_short.startswith(short_name + '['):
candidates.append((ST2, CN2))
if not candidates:
return None
# 优先级 1: parent_hint 精确匹配(如 'GSList[BasicBlock]'
# 当父对象字段声明记录了特化名时,直接使用,避免 Head/Tail/Count 等公共字段歧义
if parent_hint:
hint_short: str = parent_hint.split('.')[-1] if '.' in parent_hint else parent_hint
for spec_st, spec_CN in candidates:
spec_short: str = spec_CN.split('.')[-1] if '.' in spec_CN else spec_CN
if spec_short == hint_short:
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
for lookup_CN in (spec_CN, orig_CN):
bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {})
if Node.attr in bitfield_offsets:
return self._load_bitfield_member(CastedObj, lookup_CN, Node.attr)
offset: int | None = Gen._get_member_offset(Node.attr, lookup_CN)
if offset is not None:
return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, lookup_CN, spec_st)
break
# 优先级 2: class_members 中包含 Node.attr 字段的特化版本
best_candidate: tuple[ir.IdentifiedStructType, str] | None = None
for spec_st, spec_CN in candidates:
for lookup_CN in (spec_CN, orig_CN):
lookup_short: str = lookup_CN.split('.')[-1] if '.' in lookup_CN else lookup_CN
for chk_CN in (lookup_CN, lookup_short):
if chk_CN in Gen.class_members:
if any(name == Node.attr for name, _ in Gen.class_members[chk_CN]):
best_candidate = (spec_st, spec_CN)
break
if best_candidate:
break
if best_candidate:
break
if best_candidate is None:
best_candidate = candidates[0]
spec_st: ir.IdentifiedStructType
spec_CN: str
spec_st, spec_CN = spec_result
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
spec_st, spec_CN = best_candidate
CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
for lookup_CN in (spec_CN, orig_CN):
bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {})
if Node.attr in bitfield_offsets:
@@ -467,14 +523,33 @@ class ExprAttrHandle(BaseHandle):
ClassName = CN
struct_match = self._check_struct_match(Gen, ObjVal, ClassName)
# 最终回退var_struct_class 可能被前一个函数污染(如 cur 在不同函数中
# 分别是 Line/Param/BasicBlock通过 ObjVal 的实际 pointee 类型恢复正确类名
# 分别是 Line/Param/BasicBlock通过 ObjVal 的实际 pointee 类型恢复正确类名
# 但若 var_struct_class 已记录特化名(如 ndarray[double]),且 ObjVal 的
# pointee 是对应的 opaque 基础类型(如 ndarray则 bitcast 到特化版本,
# 不覆盖为裸模板名(否则后续方法调用会查找 ndarray.xxx 而非 ndarray[double].xxx
if not struct_match and isinstance(ObjVal.type, ir.PointerType):
found: Any = Gen.find_struct_by_pointee(ObjVal.type.pointee)
if found:
ClassName = found[0]
struct_match = True
if VarName:
Gen.var_struct_class[VarName] = ClassName
found_name: str = found[0]
# 检查 var_struct_class 是否已记录 found_name 的特化版本
preserved: bool = False
if VarName and VarName in Gen.var_struct_class:
cur_spec: str = Gen.var_struct_class[VarName]
if ('[' in cur_spec
and cur_spec.split('[')[0] == found_name
and cur_spec in Gen.structs):
# bitcast ObjVal (opaque base*) 到特化类型指针,保留特化名
ObjVal = Gen.builder.bitcast(
ObjVal, ir.PointerType(Gen.structs[cur_spec]),
name=f"cast_spec_{cur_spec}")
ClassName = cur_spec
struct_match = True
preserved = True
if not preserved:
ClassName = found_name
struct_match = True
if VarName:
Gen.var_struct_class[VarName] = ClassName
elif isinstance(ObjVal.type.pointee, ir.IdentifiedStructType):
# sha1 冲突 fallbackfind_struct_by_pointee 因 sha1 前缀不匹配失败时,
# 用短名匹配,优先选字段最多的完整版本
@@ -490,7 +565,17 @@ class ExprAttrHandle(BaseHandle):
best_elem_count = elem_count
struct_match = True
if struct_match and VarName:
Gen.var_struct_class[VarName] = ClassName
# 同样保护特化名:若已记录的特化名的短名基础部分与 ClassName 匹配,保留
cur_spec2: str = Gen.var_struct_class.get(VarName, '')
if ('[' in cur_spec2
and cur_spec2.split('[')[0] == ClassName
and cur_spec2 in Gen.structs):
ObjVal = Gen.builder.bitcast(
ObjVal, ir.PointerType(Gen.structs[cur_spec2]),
name=f"cast_spec_{cur_spec2}")
ClassName = cur_spec2
else:
Gen.var_struct_class[VarName] = ClassName
if not struct_match:
return None
@@ -611,11 +696,23 @@ class ExprAttrHandle(BaseHandle):
# 已知结构体类型 → 直接成员访问
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
# 提取父上下文特化提示:当 Node.value 是 Attribute(Name, attr) 时,
# 从 var_struct_class 和 class_member_element_class 获取字段声明的特化名。
# 例如 func.Blocks.Head 中func 是 FunctionBlocks 字段声明为 GSList[BasicBlock]
# 提示为 'GSList[BasicBlock]',避免在所有 GSList[T] 都有 Head 字段时选错特化版本。
parent_hint: str | None = None
if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name):
p_var: str = Node.value.value.id
p_attr: str = Node.value.attr
p_CN: str | None = Gen.var_struct_class.get(p_var)
if p_CN:
p_elem_map: Any = Gen.class_member_element_class.get(p_CN, {})
parent_hint = p_elem_map.get(p_attr)
for CN, ST in Gen.structs.items():
if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name):
st, ok = self._try_Load_struct_from_stub(Gen, CN)
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN)
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN, parent_hint)
if spec_val is not None:
return spec_val
break
@@ -824,12 +921,16 @@ class ExprAttrHandle(BaseHandle):
# 但 HandleExprLlvm 已自动 load 返回 AST*(一级指针),
# 需要检查 Gen.variables 中的原始 alloca 类型,
# 若是二级指针且存储的是结构体指针,应 bitcast ValueVal 为 AST** 后 GEP 再 load
# 避免 GEP AST 结构体数组返回错误的 AST*(指向存储位置而非实际对象)
# 避免 GEP AST 结构体数组返回错误的 AST*(指向存储位置而非实际对象)
# 仅当 var_ptr_element 标记为 True 时触发(由 AnnAssign 检测 (S|t.CPtr)|t.CPtr 注解设置),
# 防止 pts: Point | t.CPtr简单结构体指针错误走二级指针路径。
if (isinstance(Node.value, ast.Name)
and isinstance(ValueVal.type, ir.PointerType)
and isinstance(ValueVal.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))):
VarName: str = Node.value.id
if VarName in Gen.variables and Gen.variables[VarName] is not None:
_vpe_load: bool = (getattr(Gen, 'var_ptr_element', {}).get(VarName, False)
or getattr(Gen, 'global_var_ptr_element', {}).get(VarName, False))
if _vpe_load and VarName in Gen.variables and Gen.variables[VarName] is not None:
VarAlloca: ir.Value = Gen.variables[VarName]
if (isinstance(VarAlloca.type, ir.PointerType)
and isinstance(VarAlloca.type.pointee, ir.PointerType)):