fix(compiler,peephole): TPC 属性链解析与窥孔输出瘦身
- TPC(lib/core): 任意级属性链按链前向类解析恢复 stub 退化字段; cast 局部 rowptr[X] 登记回填; 通用指针槽按静态类名 bitcast 兜底; 赋值 RHS 求值失败 fail-fast 防未初始化变量; 报错行按源码文本锚定并附 ATTR-DIAG 现场 - 窥孔(includes/llvmlite/__function.vp): 成员访问单级链模式; 窥孔移至 Renumber 前使 SSA 编号连续; T3 no-op bitcast 消除; 替换缓冲按最坏上界分配 - __builder/__module/string.vp 配套; 清理 Test 构建产物与 PROF 杂项
This commit is contained in:
1 parent
45e78ad107
commit
76d1ee6076
173 files changed
+1104
-3090
No files matched your search
@@ -558,6 +558,56 @@ class AnnAssignHandle(BaseHandle):
|
||||
Gen.var_struct_class[VarName] = _union_struct_name2
|
||||
if getattr(Gen, 'global_struct_class', None) is not None:
|
||||
Gen.global_struct_class[VarName] = _union_struct_name2
|
||||
# Subscript rowptr[X] / t.CPtr[X] 注解的本地结构指针变量(如
|
||||
# includes/ast/parser.vp _fix_store_ctx 里 `tp: rowptr[Tuple] =
|
||||
# (rowptr[Tuple])(node)`,随后 `tp_elts = tp.elts`):TypeMerge 的
|
||||
# builtins 分支把 rowptr[X] 折叠为 i8*(PtrCount=1/CVoid),既不登记
|
||||
# var_struct_class 也不保留内层 X —— 单级 Name 字段取值(tp.elts)
|
||||
# 在属性访问层 ClassName 解析为 None → 求值 None → 赋值被 fail-fast
|
||||
# 拦截(parser.vp L427 bootstrap 根因)。与上方 BinOp 联合的短名回退
|
||||
# 对称:把内层 X 解析为真实 struct 键(兼容短名 / 带 class_sha1 前缀
|
||||
# 的键)并登记;仅在缺失或指针占位(rowptr…)时覆盖,不碰已精确登记值。
|
||||
_rst_sub: ast.AST | None = None
|
||||
if isinstance(Node.annotation, ast.Subscript):
|
||||
_rst_v: ast.expr = Node.annotation.value
|
||||
_rst_nm: str = ''
|
||||
if isinstance(_rst_v, ast.Name):
|
||||
_rst_nm = _rst_v.id
|
||||
elif isinstance(_rst_v, ast.Attribute) and isinstance(_rst_v.value, ast.Name):
|
||||
_rst_nm = f'{_rst_v.value.id}.{_rst_v.attr}'
|
||||
if _rst_nm in ('rowptr', 't.CPtr'):
|
||||
_rst_sub = Node.annotation
|
||||
if _rst_sub is not None:
|
||||
_rst_sl: ast.AST = _rst_sub.slice
|
||||
if hasattr(ast, 'Index') and isinstance(_rst_sl, ast.Index):
|
||||
_rst_sl = _rst_sl.value
|
||||
_rst_tn: str = ''
|
||||
if isinstance(_rst_sl, ast.Name):
|
||||
_rst_tn = _rst_sl.id
|
||||
elif isinstance(_rst_sl, ast.Attribute) and isinstance(_rst_sl.value, ast.Name):
|
||||
_rst_tn = _rst_sl.attr
|
||||
_rst_tk: str | None = None
|
||||
if _rst_tn:
|
||||
if _rst_tn in Gen.structs:
|
||||
_rst_tk = _rst_tn
|
||||
else:
|
||||
_rst_sha: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(_rst_tn)
|
||||
if _rst_sha and f'{_rst_sha}.{_rst_tn}' in Gen.structs:
|
||||
_rst_tk = f'{_rst_sha}.{_rst_tn}'
|
||||
else:
|
||||
for _rst_k3 in Gen.structs:
|
||||
_rst_short3: str = _rst_k3.split('.')[-1] if '.' in _rst_k3 else _rst_k3
|
||||
if _rst_short3 == _rst_tn:
|
||||
_rst_tk = _rst_k3
|
||||
break
|
||||
if _rst_tk:
|
||||
_rst_cur: str | None = Gen.var_struct_class.get(VarName)
|
||||
_rst_need: bool = (not _rst_cur or _rst_cur == 'rowptr' or '.rowptr' in _rst_cur
|
||||
or _rst_cur.startswith('rowptr['))
|
||||
if _rst_need and _rst_cur != _rst_tk:
|
||||
Gen.var_struct_class[VarName] = _rst_tk
|
||||
if getattr(Gen, 'global_struct_class', None) is not None:
|
||||
Gen.global_struct_class[VarName] = _rst_tk
|
||||
# 检测指针到指针缓冲区变量:注解为 StructName | t.CPtr,且赋值来自 t.CPtr(...) 调用。
|
||||
# 这种变量(如 list[T].__getitem__ 中的 elem_ptr: T | t.CPtr = t.CPtr(...))
|
||||
# 实际指向存储结构体指针的缓冲区(T=AST|t.CPtr 时特化为 AST*,缓冲区存 AST* 数组)。
|
||||
@@ -598,6 +648,10 @@ class AnnAssignHandle(BaseHandle):
|
||||
InitValue: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=VarType)
|
||||
if InitValue:
|
||||
self._StoreOrStrCopy(VarName, var, InitValue)
|
||||
elif isinstance(Node.value, ast.Attribute):
|
||||
# 防静默:带值带注解属性链求值失败禁止跳过(见 __function.vp
|
||||
# 两级链 blk = func.Blocks.Head 编译产物 store 丢失根因)。
|
||||
self._RaiseUnresolvedExpr("带注解赋值", Node.value, Gen)
|
||||
Gen._record_var_signedness(VarName, IsUnsigned)
|
||||
return
|
||||
del Gen._reg_values[VarName]
|
||||
@@ -609,6 +663,10 @@ class AnnAssignHandle(BaseHandle):
|
||||
CalledName: str = Node.value.func.id
|
||||
if CalledName in Gen._closure_return_types:
|
||||
Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName]
|
||||
if InitValue is None and Node.value is not None and isinstance(Node.value, ast.Attribute):
|
||||
# 防静默:带值带注解的属性链求值失败(返回 None)必须报编译错误,
|
||||
# 否则变量 alloca 已创建却无 store → 后续 load 未初始化栈变量。
|
||||
self._RaiseUnresolvedExpr("带注解赋值", Node.value, Gen)
|
||||
if VarName in Gen._reg_values:
|
||||
del Gen._reg_values[VarName]
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
@@ -853,6 +911,10 @@ class AnnAssignHandle(BaseHandle):
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=AttrVarType)
|
||||
if Value:
|
||||
self._HandleAttributeStoreLlvm(Node.target, Value)
|
||||
elif isinstance(Node.value, ast.Attribute):
|
||||
# 防静默:self 字段带注解赋值右侧属性链求值失败必须报错
|
||||
self._RaiseUnresolvedExpr("self 字段带注解赋值", Node.value, Gen)
|
||||
if Value:
|
||||
AttrName: str = Node.target.attr
|
||||
len_name: str = f'{AttrName}__len'
|
||||
ClassName: str | None = self._CurrentCpythonObjectClass
|
||||
|
||||
@@ -173,6 +173,10 @@ class AssignHandle(BaseHandle):
|
||||
if CalledName in Gen._closure_return_types:
|
||||
Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName]
|
||||
if not Value:
|
||||
# 防静默:右侧是属性链(如 blk = func.Blocks.Head)却求值失败时
|
||||
# 必须报错,禁止跳过 store 留下未初始化变量(随机崩溃)。
|
||||
if isinstance(Node.value, ast.Attribute):
|
||||
self._RaiseUnresolvedExpr("赋值", Node.value, Gen)
|
||||
return
|
||||
if isinstance(Value.type, ir.VoidType):
|
||||
return
|
||||
@@ -447,8 +451,11 @@ class AssignHandle(BaseHandle):
|
||||
TargetType = m_type
|
||||
break
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType)
|
||||
if Value:
|
||||
self._HandleAttributeStoreLlvm(Target, Value)
|
||||
if not Value:
|
||||
if isinstance(Node.value, ast.Attribute):
|
||||
self._RaiseUnresolvedExpr("属性写入", Node.value, Gen)
|
||||
return
|
||||
self._HandleAttributeStoreLlvm(Target, Value)
|
||||
elif isinstance(Target, ast.Subscript):
|
||||
TargetType: ir.Type | None = None
|
||||
SubVarName: str | None = None
|
||||
@@ -480,8 +487,11 @@ class AssignHandle(BaseHandle):
|
||||
elif isinstance(var_type, ir.ArrayType):
|
||||
TargetType = var_type.element
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType)
|
||||
if Value:
|
||||
self._HandleSubscriptStoreLlvm(Target, Value)
|
||||
if not Value:
|
||||
if isinstance(Node.value, ast.Attribute):
|
||||
self._RaiseUnresolvedExpr("下标写入", Node.value, Gen)
|
||||
return
|
||||
self._HandleSubscriptStoreLlvm(Target, Value)
|
||||
elif isinstance(Target, ast.Tuple):
|
||||
if isinstance(Node.value, ast.Call):
|
||||
FuncName: str | None = None
|
||||
|
||||
@@ -525,6 +525,124 @@ class BaseHandle:
|
||||
def HandleExprLlvm(self, Node: ast.AST, VarType: _ir.Type | str | None = None) -> _ir.Value | None:
|
||||
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
|
||||
|
||||
@staticmethod
|
||||
def _ExprText(Node: ast.AST) -> str:
|
||||
"""把属性链/名字节点渲染成源码文本(如 func.Blocks.Head),供错误信息使用"""
|
||||
if isinstance(Node, ast.Attribute):
|
||||
parts: list[str] = []
|
||||
cur: ast.AST = Node
|
||||
while isinstance(cur, ast.Attribute):
|
||||
parts.append(cur.attr)
|
||||
cur = cur.value
|
||||
if isinstance(cur, ast.Name):
|
||||
parts.append(cur.id)
|
||||
if parts:
|
||||
return '.'.join(reversed(parts))
|
||||
if isinstance(Node, ast.Name):
|
||||
return Node.id
|
||||
return getattr(Node, 'attr', '') or '<expr>'
|
||||
|
||||
def _RaiseUnresolvedExpr(self, What: str, Node: ast.AST, Gen: Any) -> None:
|
||||
"""fail-fast:属性/成员访问表达式在编译期求值失败(返回 None)时终止。
|
||||
|
||||
属性链(含两级自动解引用链,如 blk = func.Blocks.Head)若解析不出
|
||||
目标类型,_handle_attr_nested 会返回 None;赋值调用方若静默跳过
|
||||
store,目标 alloca 永不初始化 → 运行期读未初始化栈变量(随机崩溃)。
|
||||
此处用 VLogger 输出 文件名:行:列 + 表达式源码后退出(严格模式语义)。
|
||||
"""
|
||||
import sys
|
||||
raw_lineno: int = getattr(Node, 'lineno', 0) or 0
|
||||
lineno: int = raw_lineno or getattr(Gen, '_current_lineno', 0) or 0
|
||||
col: int = getattr(Node, 'col_offset', -1)
|
||||
src_file: str = getattr(Gen, '_current_source_file', '') or ''
|
||||
expr_text: str = self._ExprText(Node)
|
||||
code_line: str = ''
|
||||
if lineno > 0 and src_file:
|
||||
# 行号基准修正(vasts AST 行号 vs 磁盘原文件行号偏差):
|
||||
# Phase2Translator._inject_auto_imports 会在解析前向源码头部注入
|
||||
# 1~3 行 "import _list/_dict/json",使 AST 节点 lineno 比磁盘原文件
|
||||
# 真实行号大 N(实测 CallGenCBuiltin.vp 真实 1409 报 1410、
|
||||
# FuncGenMixin.vp 真实 514 报 515)。而 _get_source_line 基于
|
||||
# _current_source_lines(原文件),导致报错行号偏大且"代码行"
|
||||
# 取错行。修正:以表达式文本为锚,从原始行号向上(至多 8 行)
|
||||
# 回溯取"最近且包含该表达式文本"的源码行作为真实行号。
|
||||
if expr_text and '.' in expr_text and hasattr(Gen, '_get_source_line'):
|
||||
_src_lines: Any = getattr(Gen, '_current_source_lines', None)
|
||||
if isinstance(_src_lines, list) and _src_lines:
|
||||
for cand in range(lineno, max(0, lineno - 8), -1):
|
||||
if 0 < cand <= len(_src_lines) and expr_text in _src_lines[cand - 1]:
|
||||
lineno = cand
|
||||
break
|
||||
try:
|
||||
code_line = (Gen._get_source_line(lineno) or '').strip()
|
||||
except Exception:
|
||||
code_line = ''
|
||||
loc: str = src_file
|
||||
if lineno > 0:
|
||||
loc += f":{lineno}"
|
||||
if col >= 0:
|
||||
loc += f":{col}"
|
||||
msg: str = (f"{What}表达式 '{expr_text}' 编译期求值为空(属性访问未能解析出"
|
||||
f"目标类型/成员),赋值将被跳过、变量保持未初始化。位置 {loc}"
|
||||
f"{(',源码: ' + code_line) if code_line else ''}")
|
||||
# 现场诊断:dump 最内层基变量在各类注册表/存储中的状态,定位属性解析
|
||||
# 在哪一级断裂(var_struct_class 缺失 / struct 键形态不匹配 / 存储退化)。
|
||||
diag: str = self._AttrFailDiag(Node, Gen)
|
||||
if diag:
|
||||
msg += f"\n[ATTR-DIAG]{diag}"
|
||||
_vlog().compile_error(msg, src_file, lineno, code_line)
|
||||
sys.exit(1)
|
||||
|
||||
@staticmethod
|
||||
def _AttrFailDiag(Node: ast.AST, Gen: Any) -> str:
|
||||
"""提取属性链失败现场:最内层 Name 变量的类登记与存储状态"""
|
||||
try:
|
||||
inner: ast.AST = Node
|
||||
while isinstance(inner, ast.Attribute):
|
||||
inner = inner.value
|
||||
if not isinstance(inner, ast.Name):
|
||||
return ''
|
||||
var: str = inner.id
|
||||
seg: list[str] = []
|
||||
seg.append(f"var={var}")
|
||||
vsc: Any = getattr(Gen, 'var_struct_class', {}) or {}
|
||||
gsc: Any = getattr(Gen, 'global_struct_class', {}) or {}
|
||||
seg.append(f"var_struct_class[{var}]={vsc.get(var)!r}")
|
||||
seg.append(f"global_struct_class[{var}]={gsc.get(var)!r}")
|
||||
def _ty_str(ptr: Any) -> str:
|
||||
try:
|
||||
if ptr is None:
|
||||
return 'None'
|
||||
return str(ptr.type)
|
||||
except Exception:
|
||||
return '?'
|
||||
for _tab_name, _tab in (('variables', getattr(Gen, 'variables', {}) or {}),
|
||||
('_reg_values', getattr(Gen, '_reg_values', {}) or {}),
|
||||
('_direct_values', getattr(Gen, '_direct_values', {}) or {}),
|
||||
('global_vars', getattr(Gen, 'global_vars', {}) or {})):
|
||||
if var in _tab:
|
||||
seg.append(f"{_tab_name}[{var}]={_ty_str(_tab[var])}")
|
||||
# 最内层类名 → 是否在 class_member_element_class 登记字段
|
||||
cn: Any = vsc.get(var) or gsc.get(var)
|
||||
cmap: Any = getattr(Gen, 'class_member_element_class', {}) or {}
|
||||
import re as _re
|
||||
def _short(k: str) -> str:
|
||||
return _re.sub(r'^[0-9a-fA-F]{16}\.', '', k)
|
||||
if cn:
|
||||
hit: list[str] = []
|
||||
for key, sub in cmap.items():
|
||||
if _short(key) == _short(cn):
|
||||
hit.append(f"{key}:{sub}")
|
||||
seg.append(f"elem_class_map_hits={hit or 'NONE'}")
|
||||
# Gen.structs 中含 cn 短名的键(供键形态比对)
|
||||
if cn:
|
||||
struct_keys: list[str] = [k for k in (getattr(Gen, 'structs', {}) or {})
|
||||
if _short(k) == _short(cn)]
|
||||
seg.append(f"structs_keys={struct_keys or 'NONE'}")
|
||||
return '\n'.join(seg)
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
def HandleBodyLlvm(self, Body: ast.AST | list[ast.stmt]) -> Any:
|
||||
return self.Trans.BodyHandler.HandleBodyLlvm(Body)
|
||||
|
||||
|
||||
@@ -444,6 +444,14 @@ class ExprAttrHandle(BaseHandle):
|
||||
# 解析结构体类名:若 VarName 是结构体变量,优先走结构体字段访问路径
|
||||
# 避免结构体字段名(如 stdout)与全局变量名冲突时被误解析为全局变量
|
||||
ClassName: str | None = self._resolve_var_classname(Gen, VarName)
|
||||
# 查找端键归一:var_struct_class 可能记录裸短名('Tuple'),而 Gen.structs
|
||||
# 的键是带 class_sha1 前缀的全名(如 '43ec967d0517abc1.Tuple'),或反之。
|
||||
# 单级 Name 字段取值(tp.elts)要求 ClassName 能直接定位 Gen.structs 并
|
||||
# 加载 stub body 后才能 GEP —— 与 _handle_attr_nested 各分支一致先归一。
|
||||
if ClassName and ClassName not in Gen.structs:
|
||||
_cn_key: str | None = self._find_struct_key_for_class_hint(Gen, ClassName)
|
||||
if _cn_key:
|
||||
ClassName = _cn_key
|
||||
|
||||
# 尝试 attr 直接作为全局变量(仅当 VarName 不是结构体变量时)
|
||||
if not ClassName and AttrName in Gen.module.globals:
|
||||
@@ -455,6 +463,20 @@ class ExprAttrHandle(BaseHandle):
|
||||
return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr")
|
||||
return Gen.builder.load(gv, name=AttrName)
|
||||
|
||||
if not ClassName:
|
||||
# 单级 Name 字段取值的类名恢复(跨模块 stub 下 var_struct_class 缺失的
|
||||
# 兜底):本地变量(如 `tp: rowptr[Tuple] = (rowptr[Tuple])(node)`)可能
|
||||
# 因 rowptr[X] 被折叠为 i8* 而漏登记。若变量 alloca / 值本身可辨识为
|
||||
# 结构体指针,按实际 pointee 恢复真实 Gen.structs 键并回填,避免属性
|
||||
# 访问求值 None 被 fail-fast 拦截(parser.vp `tp_elts = tp.elts` 根因)。
|
||||
if (VarName in Gen.variables or VarName in Gen._reg_values
|
||||
or VarName in Gen._direct_values or VarName in Gen.global_vars):
|
||||
_recovered: str | None = self._recover_struct_class(Gen, VarName)
|
||||
if _recovered:
|
||||
ClassName = _recovered
|
||||
Gen.var_struct_class[VarName] = _recovered
|
||||
if getattr(Gen, 'global_struct_class', None) is not None:
|
||||
Gen.global_struct_class[VarName] = _recovered
|
||||
if not ClassName:
|
||||
return None
|
||||
|
||||
@@ -591,6 +613,19 @@ class ExprAttrHandle(BaseHandle):
|
||||
ClassName = cur_spec2
|
||||
else:
|
||||
Gen.var_struct_class[VarName] = ClassName
|
||||
# 通用指针槽兜底:静态类名(var_struct_class/键归一后)有效且 ObjVal 是指针,
|
||||
# 但 pointee 非 struct(如 cast 局部变量 tp: rowptr[Tuple] 的槽被建为 i32**,
|
||||
# Name 求值 load 一次得到 i32*,上述 struct 匹配/回退均不命中 → return None)。
|
||||
# 此时按静态类名信任 bitcast 到 struct* 再走成员 GEP(tp.elts 根因,ATTR-DIAG
|
||||
# 实证 var_struct_class='Tuple'、structs 有 'Tuple',仅槽位为通用指针形态)。
|
||||
if (not struct_match and ClassName and ClassName in Gen.structs
|
||||
and isinstance(ObjVal.type, ir.PointerType)
|
||||
and not isinstance(ObjVal.type.pointee, ir.IdentifiedStructType)
|
||||
and not isinstance(ObjVal.type.pointee, ir.LiteralStructType)):
|
||||
ObjVal = Gen.builder.bitcast(
|
||||
ObjVal, ir.PointerType(Gen.structs[ClassName]),
|
||||
name=f"cast_slot_{ClassName}")
|
||||
struct_match = True
|
||||
if not struct_match:
|
||||
return None
|
||||
|
||||
@@ -637,6 +672,45 @@ class ExprAttrHandle(BaseHandle):
|
||||
result = self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st)
|
||||
return result
|
||||
|
||||
def _recover_struct_class(self, Gen: LlvmCodeGenerator, VarName: str) -> str | None:
|
||||
"""由变量的 LLVM 存储类型恢复结构体类键(var_struct_class 缺失时兜底)。
|
||||
|
||||
单级 Name 字段取值(如 tp.elts)的本地变量,若其注解 rowptr[X] 被 TypeMerge
|
||||
builtins 分支折叠成 i8*、且 var_struct_class 未登记 X,属性访问层无法解析
|
||||
类名。此处直接检查 Gen.variables / _reg_values / _direct_values /
|
||||
global_vars 中该变量的 alloca(或值)指针 pointee:能辨识出
|
||||
IdentifiedStruct 就按 pointee 恢复真实 Gen.structs 键(精确匹配失败时按
|
||||
短名找元素最多的完整版本),供调用方回填并继续 GEP 成员访问。不发射任何
|
||||
额外 IR(纯查表)。
|
||||
"""
|
||||
if not VarName:
|
||||
return None
|
||||
probe: ir.Type | None = None
|
||||
vp: Any = Gen.variables.get(VarName)
|
||||
if vp is not None and isinstance(vp.type, ir.PointerType):
|
||||
probe = vp.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
if probe is None:
|
||||
for reg in (Gen._reg_values.get(VarName), Gen._direct_values.get(VarName)):
|
||||
if reg is not None and isinstance(reg.type, ir.PointerType):
|
||||
probe = reg.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
break
|
||||
if probe is None and VarName in Gen.global_vars and hasattr(Gen, 'module') and VarName in Gen.module.globals:
|
||||
gv: Any = Gen.module.globals[VarName]
|
||||
if isinstance(gv, ir.GlobalVariable) and isinstance(gv.type, ir.PointerType):
|
||||
probe = gv.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
if probe is None or not isinstance(probe, ir.IdentifiedStructType):
|
||||
return None
|
||||
found: Any = Gen.find_struct_by_pointee(probe)
|
||||
if found:
|
||||
return found[0]
|
||||
return self._pointee_llvm_to_struct_key(Gen, probe)
|
||||
|
||||
def _handle_attr_nested(self, Node: ast.Attribute) -> ir.Value | None:
|
||||
"""处理 a.b.c 嵌套属性访问"""
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
@@ -694,35 +768,60 @@ class ExprAttrHandle(BaseHandle):
|
||||
|
||||
# char* → struct* cast + 成员访问
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
AttrClassName: str | None = self._get_attr_class(Node.value, Gen)
|
||||
if AttrClassName and AttrClassName in Gen.structs:
|
||||
st: Any
|
||||
ok: bool
|
||||
st, ok = self._try_Load_struct_from_stub(Gen, AttrClassName)
|
||||
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||||
return None
|
||||
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}")
|
||||
offset: int | None = Gen._get_member_offset(Node.attr, AttrClassName)
|
||||
if offset is None:
|
||||
return None
|
||||
if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
|
||||
return None
|
||||
return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, AttrClassName, st)
|
||||
# 两级自动解引用链(变量 = 指针.字段.成员,如 blk = func.Blocks.Head)
|
||||
# 根因修复:跨模块 stub 会把容器/类内指针字段(rowptr[GSList[BasicBlock]]
|
||||
# 等)退化为 i8*,此处 ObjVal 是刚从结构体字段 load 出的 i8*。必须恢复
|
||||
# 该字段声明的元素/特化类(如 'GSList[BasicBlock]')才能
|
||||
# bitcast + GEP + load 出成员。否则本函数返回 None → AnnAssign/Assign
|
||||
# 静默跳过 store → 目标 alloca 永不初始化(_peephole_opt 读未初始化
|
||||
# 栈变量随机崩溃,见 __function.vp L783 注释)。
|
||||
# 解析顺序:_resolve_chain_result_class 沿链前向解析父表达式(可为任意
|
||||
# 级数,如 ve.Alloca.Ty)的结果类;失败回退 _get_attr_class 直查
|
||||
# class_member_element_class;再回退 _resolve_attr_parent_hint(与下方
|
||||
# struct 分支同一 parent_hint 机制:func 的 var_struct_class +
|
||||
# class_member_element_class 给出 GSList[BasicBlock] 提示);三者都兼容
|
||||
# 裸名/带 sha1 前缀的键。
|
||||
AttrClassName: str | None = self._resolve_chain_result_class(Node.value, Gen)
|
||||
if not AttrClassName:
|
||||
AttrClassName = self._get_attr_class(Node.value, Gen)
|
||||
if not AttrClassName:
|
||||
AttrClassName = self._resolve_attr_parent_hint(Node.value, Gen)
|
||||
ResolvedKey: str | None = self._find_struct_key_for_class_hint(Gen, AttrClassName)
|
||||
if ResolvedKey is None or ResolvedKey not in Gen.structs:
|
||||
return None
|
||||
st: Any
|
||||
ok: bool
|
||||
st, ok = self._try_Load_struct_from_stub(Gen, ResolvedKey)
|
||||
if not isinstance(st, ir.IdentifiedStructType):
|
||||
return None
|
||||
if st.elements is None:
|
||||
# stub 仍 opaque(如跨模块泛型仅声明):走泛型特化候选访问
|
||||
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st, Node, ResolvedKey, AttrClassName)
|
||||
if spec_val is not None:
|
||||
return spec_val
|
||||
return None
|
||||
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{ResolvedKey}")
|
||||
if Node.attr in Gen.class_member_bitoffsets.get(ResolvedKey, {}):
|
||||
return self._load_bitfield_member(CastedObj, ResolvedKey, Node.attr)
|
||||
offset: int | None = Gen._get_member_offset(Node.attr, ResolvedKey)
|
||||
if offset is None:
|
||||
return None
|
||||
if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
|
||||
return None
|
||||
return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, ResolvedKey, st)
|
||||
|
||||
# 已知结构体类型 → 直接成员访问
|
||||
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)
|
||||
# 父上下文特化提示:Node.value 是 Attribute(Name, attr)(如
|
||||
# func.Blocks)时,从 var_struct_class/global_struct_class +
|
||||
# class_member_element_class 取字段声明的特化名(如 'GSList[BasicBlock]'),
|
||||
# 避免在所有 GSList[T] 都有 Head/Tail/Count 字段时选错特化版本。
|
||||
# 与 char* 分支共用 _resolve_attr_parent_hint(兼容裸名/sha1 前缀键);
|
||||
# 父表达式为多级链(Node.value 是 Attribute)时 _resolve_attr_parent_hint
|
||||
# 无法取提示,用 _resolve_chain_result_class 沿链前向解析补充。
|
||||
parent_hint: str | None = self._resolve_attr_parent_hint(Node, Gen)
|
||||
if not parent_hint and isinstance(Node.value, ast.Attribute):
|
||||
parent_hint = self._resolve_chain_result_class(Node.value, Gen) or parent_hint
|
||||
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)
|
||||
@@ -1584,23 +1683,251 @@ class ExprAttrHandle(BaseHandle):
|
||||
return ir.Constant(ir.IntType(32), info.value)
|
||||
return None
|
||||
|
||||
def _lookup_member_elem_class(self, Gen: LlvmCodeGenerator, OwnerClass: str | None, FieldName: str) -> str | None:
|
||||
"""在 class_member_element_class 中按"属主类 + 字段名"查找元素/特化类。
|
||||
|
||||
class_member_element_class 的 key 与调用方持有的类名(var_struct_class /
|
||||
_CurrentCpythonObjectClass 等)可能存在"裸名 vs 带 sha1 前缀"的不一致
|
||||
(如 key='Function',而持有者是 '732a8c24abb9b516.Function')。先精确
|
||||
匹配,再按短名(剥离 16 位 hex 前缀)遍历所有 key 匹配,确保能恢复
|
||||
字段声明的特化类(如 rowptr[GSList[BasicBlock]] → 'GSList[BasicBlock]')。
|
||||
"""
|
||||
if not OwnerClass or not FieldName:
|
||||
return None
|
||||
elem_map: Any = getattr(Gen, 'class_member_element_class', {}) or {}
|
||||
if OwnerClass in elem_map:
|
||||
sub_map: Any = elem_map[OwnerClass]
|
||||
if FieldName in sub_map:
|
||||
return sub_map[FieldName]
|
||||
owner_short: str = Gen._extract_short_name(OwnerClass)
|
||||
for key, sub_map in elem_map.items():
|
||||
if Gen._extract_short_name(key) != owner_short:
|
||||
continue
|
||||
if FieldName in sub_map:
|
||||
return sub_map[FieldName]
|
||||
return None
|
||||
|
||||
def _resolve_attr_parent_hint(self, Node: ast.Attribute, Gen: LlvmCodeGenerator) -> str | None:
|
||||
"""从父对象上下文解析字段的元素/容器特化提示(parent_hint)。
|
||||
|
||||
例:func.Blocks.Head —— Node.value 是 func.Blocks,父变量 func 的
|
||||
var_struct_class/global_struct_class 是 'Function',Blocks 字段声明为
|
||||
rowptr[GSList[BasicBlock]],class_member_element_class 记录元素提示
|
||||
'GSList[BasicBlock]'。该提示用于把退化为 i8* 的字段指针恢复成目标
|
||||
特化类(char* 分支),或在所有 GSList[T] 都有 Head/Tail/Count 时
|
||||
选择正确特化版本(struct 分支)。兼容裸名/带 sha1 前缀键。
|
||||
"""
|
||||
if not (isinstance(Node, ast.Attribute) and isinstance(Node.value, ast.Name)):
|
||||
return None
|
||||
p_var: str = Node.value.id
|
||||
p_attr: str = Node.attr
|
||||
p_CN: str | None = Gen.var_struct_class.get(p_var)
|
||||
if not p_CN and getattr(Gen, 'global_struct_class', None):
|
||||
p_CN = Gen.global_struct_class.get(p_var)
|
||||
if not p_CN:
|
||||
return None
|
||||
return self._lookup_member_elem_class(Gen, p_CN, p_attr)
|
||||
|
||||
def _find_struct_key_for_class_hint(self, Gen: LlvmCodeGenerator, ClassHint: str | None) -> str | None:
|
||||
"""把 class_member_element_class 记录的类/特化名解析为 Gen.structs 的真实键。
|
||||
|
||||
记录值可能是裸名('GSList[BasicBlock]')或带 sha1 前缀
|
||||
('8e92345fd262a343.GSList[BasicBlock]'),而 Gen.structs 的键可能是
|
||||
另一种形态。依次尝试:精确键 → 短名键 → class_sha1_map 重建前缀键 →
|
||||
遍历 Gen.structs 按短名匹配。
|
||||
"""
|
||||
if not ClassHint:
|
||||
return None
|
||||
if ClassHint in Gen.structs:
|
||||
return ClassHint
|
||||
short: str = Gen._extract_short_name(ClassHint)
|
||||
if short in Gen.structs:
|
||||
return short
|
||||
expected_sha1: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(short)
|
||||
if expected_sha1:
|
||||
prefixed: str = f"{expected_sha1}.{short}"
|
||||
if prefixed in Gen.structs:
|
||||
return prefixed
|
||||
for key in Gen.structs:
|
||||
if Gen._extract_short_name(key) == short:
|
||||
return key
|
||||
return None
|
||||
|
||||
def _get_attr_class(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||||
if isinstance(Node, ast.Attribute):
|
||||
# 注: 不再硬编码 ZLIB_VERSION / C_OK,它们应从符号表查找
|
||||
if isinstance(Node.value, ast.Name) and Node.value.id == 'self':
|
||||
ClassName: str | None = self.Trans._CurrentCpythonObjectClass
|
||||
if ClassName and ClassName in Gen.class_member_element_class:
|
||||
return Gen.class_member_element_class[ClassName].get(Node.attr)
|
||||
return self._lookup_member_elem_class(Gen, ClassName, Node.attr)
|
||||
if isinstance(Node.value, ast.Name):
|
||||
VarName: str = Node.value.id
|
||||
if VarName in Gen.var_struct_class:
|
||||
ParentClass: str = Gen.var_struct_class[VarName]
|
||||
if ParentClass in Gen.class_member_element_class:
|
||||
return Gen.class_member_element_class[ParentClass].get(Node.attr)
|
||||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||||
if not ClassName and getattr(Gen, 'global_struct_class', None):
|
||||
ClassName = Gen.global_struct_class.get(VarName)
|
||||
if ClassName:
|
||||
return self._lookup_member_elem_class(Gen, ClassName, Node.attr)
|
||||
if isinstance(Node.value, ast.Attribute):
|
||||
ParentClass = self._get_attr_class(Node.value, Gen)
|
||||
if ParentClass and ParentClass in Gen.class_member_element_class:
|
||||
return Gen.class_member_element_class[ParentClass].get(Node.attr)
|
||||
ParentClass: str | None = self._get_attr_class(Node.value, Gen)
|
||||
if ParentClass:
|
||||
return self._lookup_member_elem_class(Gen, ParentClass, Node.attr)
|
||||
return None
|
||||
|
||||
# ========== 任意级属性链:逐段前向类解析 ==========
|
||||
|
||||
def _pointee_llvm_to_struct_key(self, Gen: LlvmCodeGenerator, llvm_type: ir.Type) -> str | None:
|
||||
"""把 LLVM 成员类型(Ptr->IdentifiedStruct / IdentifiedStruct)解析为
|
||||
Gen.structs 的真实键。
|
||||
|
||||
先精确匹配(find_struct_by_pointee),失败再按短名匹配(优先选择
|
||||
有完整 elements 的定义),兼容 sha1 前缀冲突/泛型特化场景。
|
||||
"""
|
||||
cand: ir.Type = llvm_type
|
||||
if isinstance(cand, ir.PointerType):
|
||||
cand = cand.pointee
|
||||
if not isinstance(cand, ir.IdentifiedStructType):
|
||||
return None
|
||||
found: Any = Gen.find_struct_by_pointee(cand)
|
||||
if found:
|
||||
return found[0]
|
||||
cand_short: str = Gen._extract_short_name(cand.name)
|
||||
best_key: str | None = None
|
||||
best_elems: int = -1
|
||||
for k in Gen.structs:
|
||||
if Gen._extract_short_name(k) != cand_short:
|
||||
continue
|
||||
st_v: Any = Gen.structs[k]
|
||||
if not isinstance(st_v, ir.IdentifiedStructType):
|
||||
continue
|
||||
n_elems: int = len(st_v.elements) if st_v.elements is not None else 0
|
||||
if n_elems > best_elems:
|
||||
best_elems = n_elems
|
||||
best_key = k
|
||||
return best_key
|
||||
|
||||
def _owner_member_llvm_types(self, Gen: LlvmCodeGenerator, OwnerClass: str) -> list[tuple[str, ir.Type]]:
|
||||
"""收集 OwnerClass(含继承父类)的成员 (名, LLVM 类型) 列表。
|
||||
|
||||
class_members 的键可能是带 sha1 前缀全名,此处按短名/剥 '[' 泛型
|
||||
参数后的基名匹配,并沿 class_parents 继承链向上补充父类字段。
|
||||
"""
|
||||
owner_short: str = Gen._extract_short_name(OwnerClass)
|
||||
base_short: str = owner_short.split('[')[0] if '[' in owner_short else owner_short
|
||||
members_map: dict[str, list] = {}
|
||||
for k, v in getattr(Gen, 'class_members', {}).items():
|
||||
k_short: str = Gen._extract_short_name(k)
|
||||
k_base: str = k_short.split('[')[0] if '[' in k_short else k_short
|
||||
if k_short == owner_short or k_base == base_short:
|
||||
members_map[k] = list(v)
|
||||
ordered: list[tuple[str, ir.Type]] = []
|
||||
seen: set[str] = set()
|
||||
for m in self._class_and_parents(Gen, OwnerClass):
|
||||
m_short: str = Gen._extract_short_name(m)
|
||||
for k, v in members_map.items():
|
||||
if Gen._extract_short_name(k) != m_short:
|
||||
continue
|
||||
for name, ty in v:
|
||||
if name not in seen:
|
||||
seen.add(name)
|
||||
ordered.append((name, ty))
|
||||
return ordered
|
||||
|
||||
def _class_and_parents(self, Gen: LlvmCodeGenerator, OwnerClass: str) -> list[str]:
|
||||
"""OwnerClass 自身 + 全部父类短名链(子类在前)"""
|
||||
chain: list[str] = []
|
||||
seen: set[str] = set()
|
||||
cur: str = Gen._extract_short_name(OwnerClass)
|
||||
parents_map: Any = getattr(Gen, 'class_parents', {}) or {}
|
||||
single_parent: Any = getattr(Gen, 'class_parent', {}) or {}
|
||||
while cur and cur not in seen:
|
||||
seen.add(cur)
|
||||
chain.append(cur)
|
||||
nxt: list[str] = parents_map.get(cur, [])
|
||||
if not nxt and cur in single_parent and single_parent[cur]:
|
||||
nxt = [single_parent[cur]]
|
||||
if not nxt:
|
||||
break
|
||||
# 多继承:只取第一条链向上(深度优先声明顺序)保持与
|
||||
# _get_member_offset 的继承链回退一致
|
||||
cur = Gen._extract_short_name(nxt[0])
|
||||
return chain
|
||||
|
||||
def _field_element_key(self, Gen: LlvmCodeGenerator, OwnerClass: str | None, AttrName: str) -> str | None:
|
||||
"""解析 OwnerClass 上 AttrName 字段的"元素 struct 键"(可在 Gen.structs 定位)。
|
||||
|
||||
供任意级链(ve.Alloca.Ty.Pointee)逐段恢复目标类:跨模块 stub 会把
|
||||
rowptr[X] 指针字段退化为 i8*,load 出的值丢失 struct 身份;此处综合
|
||||
class_member_element_class(登记的元素/特化类)→ class_members LLVM
|
||||
成员类型 → struct elements 字段类型 推断该字段指向的 struct 键,
|
||||
兼容裸名/sha1 前缀/泛型特化名。
|
||||
"""
|
||||
if not OwnerClass or not AttrName:
|
||||
return None
|
||||
# 1) class_member_element_class 直查(含短名模糊匹配)
|
||||
hint: str | None = self._lookup_member_elem_class(Gen, OwnerClass, AttrName)
|
||||
if hint:
|
||||
k: str | None = self._find_struct_key_for_class_hint(Gen, hint)
|
||||
if k:
|
||||
return k
|
||||
# 2) class_members 成员 LLVM 类型
|
||||
for m_name, m_type in self._owner_member_llvm_types(Gen, OwnerClass):
|
||||
if m_name != AttrName:
|
||||
continue
|
||||
k2: str | None = self._pointee_llvm_to_struct_key(Gen, m_type)
|
||||
if k2:
|
||||
return k2
|
||||
break
|
||||
# 3) struct elements 字段类型(加载 stub 后按偏移取值)
|
||||
owner_key: str | None = self._find_struct_key_for_class_hint(Gen, OwnerClass)
|
||||
if owner_key and owner_key in Gen.structs:
|
||||
st_v: Any
|
||||
ok_v: bool
|
||||
st_v, ok_v = self._try_Load_struct_from_stub(Gen, owner_key)
|
||||
if isinstance(st_v, ir.IdentifiedStructType) and st_v.elements is not None:
|
||||
off: int | None = Gen._get_member_offset(AttrName, owner_key)
|
||||
if off is not None and off < len(st_v.elements):
|
||||
k3: str | None = self._pointee_llvm_to_struct_key(Gen, st_v.elements[off])
|
||||
if k3:
|
||||
return k3
|
||||
# 4) 继承父类 class_members 兜底(_owner_member_llvm_types 已含继承链,
|
||||
# 此处仅处理父类 struct elements 的字段类型)
|
||||
for parent_short in self._class_and_parents(Gen, OwnerClass)[1:]:
|
||||
p_key: str | None = self._find_struct_key_for_class_hint(Gen, parent_short)
|
||||
if not p_key or p_key not in Gen.structs:
|
||||
continue
|
||||
p_st: Any
|
||||
p_ok: bool
|
||||
p_st, p_ok = self._try_Load_struct_from_stub(Gen, p_key)
|
||||
if isinstance(p_st, ir.IdentifiedStructType) and p_st.elements is not None:
|
||||
p_off: int | None = Gen._get_member_offset(AttrName, p_key)
|
||||
if p_off is not None and p_off < len(p_st.elements):
|
||||
k4: str | None = self._pointee_llvm_to_struct_key(Gen, p_st.elements[p_off])
|
||||
if k4:
|
||||
return k4
|
||||
return None
|
||||
|
||||
def _resolve_chain_result_class(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||||
"""沿链前向解析表达式(Name 或任意级 Attribute 链)的最终 struct 键。
|
||||
|
||||
例如 ve.Alloca.Ty.Pointee:最内层 Name ve 查 var_struct_class /
|
||||
global_struct_class / 模块全局 / 变量 alloca pointee 得首个类(Value),
|
||||
之后每段用 _field_element_key 在当前类上取字段的元素类推进,直到最外层。
|
||||
对自指/REnum(如 LLVMType.Pointee → LLVMType)或 class_member_element_class
|
||||
缺项的字段,由 _field_element_key 的 class_members / struct elements 兜底。
|
||||
"""
|
||||
if isinstance(Node, ast.Name):
|
||||
if Node.id == 'self':
|
||||
return self.Trans._CurrentCpythonObjectClass
|
||||
return self._resolve_var_classname(Gen, Node.id)
|
||||
if isinstance(Node, ast.Attribute):
|
||||
ParentKey: str | None = self._resolve_chain_result_class(Node.value, Gen)
|
||||
if not ParentKey:
|
||||
return None
|
||||
if ParentKey not in Gen.structs:
|
||||
resolved_parent: str | None = self._find_struct_key_for_class_hint(Gen, ParentKey)
|
||||
if not resolved_parent:
|
||||
return None
|
||||
ParentKey = resolved_parent
|
||||
return self._field_element_key(Gen, ParentKey, Node.attr)
|
||||
return None
|
||||
|
||||
def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None:
|
||||
|
||||
Reference in new issue
Block a user