修正了 TPC 的一些错误,包括 Test 维护后 TPV 无法重新编译或重编译后越界的部分问题
This commit is contained in:
@@ -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 冲突 fallback:find_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 是 Function,Blocks 字段声明为 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)):
|
||||
|
||||
Reference in New Issue
Block a user