修正了 TPC 的一些错误,包括 Test 维护后 TPV 无法重新编译或重编译后越界的部分问题
This commit is contained in:
1 parent
ab73420b4f
commit
a277ded8d4
476 files changed
+4000
-3439
No files matched your search
@@ -1272,7 +1272,13 @@ class ExprCallHandle(BaseHandle):
|
||||
if expected_type.width < val.type.width:
|
||||
return Gen.builder.trunc(val, expected_type)
|
||||
else:
|
||||
return Gen.builder.zext(val, expected_type)
|
||||
if val.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
return Gen.builder.zext(val, expected_type, name="zext")
|
||||
is_unsigned: bool = id(val) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
return Gen.builder.zext(val, expected_type, name="zext")
|
||||
return Gen.builder.sext(val, expected_type, name="sext")
|
||||
if isinstance(val.type, ir.PointerType) and isinstance(expected_type, ir.IntType):
|
||||
if expected_type.width == 64:
|
||||
return Gen.builder.ptrtoint(val, expected_type)
|
||||
@@ -1625,7 +1631,14 @@ class ExprCallHandle(BaseHandle):
|
||||
return ArgVal
|
||||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType):
|
||||
if ArgVal.type.width < TargetType.width:
|
||||
return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast")
|
||||
if ArgVal.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast")
|
||||
# C cast 语义:源有符号 → sext;源无符号 → zext;目标符号性仅影响解释
|
||||
is_unsigned: bool = (Node.args and Gen._check_node_unsigned(Node.args[0])) or id(ArgVal) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast")
|
||||
return Gen.builder.sext(ArgVal, TargetType, name=f"sext_{TypedefName}_cast")
|
||||
elif ArgVal.type.width > TargetType.width:
|
||||
return Gen.builder.trunc(ArgVal, TargetType, name=f"trunc_{TypedefName}_cast")
|
||||
return ArgVal
|
||||
@@ -1754,7 +1767,15 @@ class ExprCallHandle(BaseHandle):
|
||||
if default_val.type != param_type:
|
||||
if isinstance(param_type, ir.IntType) and isinstance(default_val.type, ir.IntType):
|
||||
if default_val.type.width < param_type.width:
|
||||
default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
|
||||
if default_val.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
|
||||
else:
|
||||
is_unsigned: bool = Gen._check_node_unsigned(default_node) or id(default_val) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
|
||||
else:
|
||||
default_val = Gen.builder.sext(default_val, param_type, name=f"sext_default_{i}")
|
||||
elif default_val.type.width > param_type.width:
|
||||
default_val = Gen.builder.trunc(default_val, param_type, name=f"trunc_default_{i}")
|
||||
elif isinstance(param_type, ir.PointerType) and isinstance(default_val.type, ir.IntType):
|
||||
@@ -1823,7 +1844,16 @@ class ExprCallHandle(BaseHandle):
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
|
||||
adjusted.append(Gen.builder.ptrtoint(arg, param_type))
|
||||
elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
|
||||
adjusted.append(Gen.builder.zext(arg, param_type))
|
||||
if arg.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
adjusted.append(Gen.builder.zext(arg, param_type, name=f"zext_vararg_fixed_{i}"))
|
||||
else:
|
||||
arg_node = Node.args[i] if i < len(Node.args) else None
|
||||
is_unsigned: bool = (arg_node is not None and Gen._check_node_unsigned(arg_node)) or id(arg) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
adjusted.append(Gen.builder.zext(arg, param_type, name=f"zext_vararg_fixed_{i}"))
|
||||
else:
|
||||
adjusted.append(Gen.builder.sext(arg, param_type, name=f"sext_vararg_fixed_{i}"))
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType):
|
||||
adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}"))
|
||||
else:
|
||||
@@ -1994,6 +2024,23 @@ class ExprCallHandle(BaseHandle):
|
||||
else:
|
||||
# 跨模块基类 — 查找基类的 sha1
|
||||
base_sha1 = struct_sha1_map.get(base_name)
|
||||
# 回退:若 _struct_sha1_map 未命中(普通类导入时不填充),
|
||||
# 扫描 temp/ 下所有 .pyi 查找包含该基类定义的文件
|
||||
if base_sha1 is None:
|
||||
temp_dir = os.path.join(project_root, 'temp')
|
||||
try:
|
||||
pyi_files = os.listdir(temp_dir)
|
||||
except OSError:
|
||||
pyi_files = []
|
||||
for pyi_file in pyi_files:
|
||||
if not pyi_file.endswith('.pyi'):
|
||||
continue
|
||||
candidate_sha1 = pyi_file[:-4]
|
||||
candidate_map = load_pyi(candidate_sha1)
|
||||
if candidate_map and base_name in candidate_map:
|
||||
base_sha1 = candidate_sha1
|
||||
struct_sha1_map[base_name] = base_sha1
|
||||
break
|
||||
if base_sha1:
|
||||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, base_sha1, visited)
|
||||
if base_novtable:
|
||||
@@ -2049,6 +2096,63 @@ class ExprCallHandle(BaseHandle):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _try_complete_generic_specialization(self, ClassName: str, MethodName: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
"""泛型特化类方法按需完整特化。
|
||||
|
||||
当 ClassName 是泛型特化名(如 ndarray[double])且缓存中只有
|
||||
declare_only 版本时,补发方法体。这样方法调用能找到 define,
|
||||
避免链接时 undefined reference。
|
||||
|
||||
触发场景:numpy 模块内部函数(如 np_sum)调用 a.sum(),
|
||||
其中 a 的类型注解 ndarray[t.CDouble] | t.CPtr 在类型解析时
|
||||
只触发了 declare_only=True 特化(创建 struct + __before_init__),
|
||||
方法体(fill/delete/dot/sum/...)未被编译。
|
||||
"""
|
||||
# 仅对特化名(含 '[' 且以 ']' 结尾)触发
|
||||
if '[' not in ClassName or not ClassName.endswith(']'):
|
||||
return
|
||||
# 反推模板类名(如 ndarray[double] → ndarray)
|
||||
base_name: str = ClassName.split('[')[0]
|
||||
# 检查是否是已注册的泛型模板
|
||||
if not (hasattr(self.Trans.ClassHandler, '_generic_class_templates') and base_name in self.Trans.ClassHandler._generic_class_templates):
|
||||
return
|
||||
# 构造 spec_key(与 _specialize_generic_class 一致:ClassName<arg1,arg2,...>)
|
||||
spec_key: str = base_name + '<' + ','.join(ClassName[len(base_name) + 1:-1].split('][')) + '>'
|
||||
spec_cache = getattr(Gen, '_generic_class_specializations', {})
|
||||
cached = spec_cache.get(spec_key)
|
||||
if not isinstance(cached, tuple) or len(cached) < 2:
|
||||
return
|
||||
cached_name: str = cached[0]
|
||||
was_declare_only: bool = cached[1]
|
||||
# 仅当缓存是 declare_only 版本时才需要补发
|
||||
if not was_declare_only:
|
||||
return
|
||||
# 检查方法是否已有 define(blocks 非空表示已编译方法体)
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||||
class_sha1 = struct_sha1_map.get(cached_name)
|
||||
full_method_name: str = f'{class_sha1}.{cached_name}.{MethodName}' if class_sha1 else f'{cached_name}.{MethodName}'
|
||||
existing_func = Gen._find_function(full_method_name)
|
||||
if existing_func is not None:
|
||||
existing_blocks = getattr(existing_func, 'blocks', [])
|
||||
if existing_blocks:
|
||||
return # 方法体已编译
|
||||
# 从缓存获取 type_args/type_names
|
||||
type_info = getattr(Gen, '_generic_class_spec_type_info', {}).get(spec_key)
|
||||
if type_info is None:
|
||||
return
|
||||
cached_type_args, cached_type_names = type_info
|
||||
# 不预先标记:_specialize_generic_class 内部缓存逻辑会检测
|
||||
# cached_declare_only=True 且 declare_only=False,自动补发方法体
|
||||
# 并更新缓存为 (spec_name, False)。预注册机制(L117)防止递归。
|
||||
try:
|
||||
self.Trans.ClassHandler._specialize_generic_class(
|
||||
base_name, cached_type_args, Gen,
|
||||
type_names=cached_type_names, declare_only=False
|
||||
)
|
||||
except Exception:
|
||||
# 失败时恢复 declare_only 标记,避免后续调用跳过补发
|
||||
Gen._generic_class_specializations[spec_key] = (cached_name, True)
|
||||
|
||||
def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen = self.Trans.LlvmGen
|
||||
MethodName = Node.func.attr
|
||||
@@ -2425,6 +2529,25 @@ class ExprCallHandle(BaseHandle):
|
||||
break
|
||||
if not ClassName:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray',不含 '[')
|
||||
# 且注解未指定类型参数时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
|
||||
# (如 'ndarray[double]'),优先选有对应方法的特化。这样方法调用能正确分派到
|
||||
# 特化版本的方法(如 ndarray[double].delete),而非查找 opaque stub declare。
|
||||
if '[' not in ClassName:
|
||||
SpecClass: str | None = None
|
||||
for CN in Gen.structs.keys():
|
||||
if not CN.startswith(f'{ClassName}['):
|
||||
continue
|
||||
struct_sha1_tmp = getattr(Gen, '_struct_sha1_map', {}).get(CN)
|
||||
if struct_sha1_tmp:
|
||||
if Gen._has_function(f'{struct_sha1_tmp}.{CN}.{MethodName}'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if Gen._has_function(f'{CN}.{MethodName}'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if SpecClass:
|
||||
ClassName = SpecClass
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||||
class_sha1 = struct_sha1_map.get(ClassName)
|
||||
if class_sha1:
|
||||
@@ -2432,6 +2555,11 @@ class ExprCallHandle(BaseHandle):
|
||||
else:
|
||||
FullMethodName = f'{ClassName}.{MethodName}'
|
||||
|
||||
# 泛型特化类方法按需完整特化:当 ClassName 是特化名(如 ndarray[double])
|
||||
# 且缓存中只有 declare_only 版本时,补发方法体。否则方法调用会查找
|
||||
# stub declare(无 define),链接时报 undefined reference。
|
||||
self._try_complete_generic_specialization(ClassName, MethodName, Gen)
|
||||
|
||||
# 提前查找函数以获取参数信息
|
||||
func_for_kw = Gen._find_function(FullMethodName)
|
||||
if not func_for_kw:
|
||||
@@ -2505,6 +2633,22 @@ class ExprCallHandle(BaseHandle):
|
||||
if func:
|
||||
break
|
||||
p = Gen.class_parent.get(p)
|
||||
# 修复:vtable 分派需要 func 的函数类型。当 func=None 时(如 __new__
|
||||
# 编译较早,MemManager.alloc 的 declare 尚未加入 Gen.functions),
|
||||
# 从 stub 获取函数类型并创建 declare,确保 vtable 分派不被跳过
|
||||
# 回退到直接调用(直接调用基类 MemManager.alloc 返回 NULL → 段错误)。
|
||||
if not func and class_sha1:
|
||||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FullMethodName, Gen)
|
||||
if stub_func_type:
|
||||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||||
if not func and class_sha1:
|
||||
plain_name = f'{ClassName}.{MethodName}'
|
||||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen)
|
||||
if stub_func_type:
|
||||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||||
if not func:
|
||||
plain_name = f'{ClassName}.{MethodName}'
|
||||
func = Gen._find_function(plain_name)
|
||||
if func:
|
||||
VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
|
||||
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
|
||||
@@ -2790,8 +2934,18 @@ class ExprCallHandle(BaseHandle):
|
||||
return (ts, tn)
|
||||
# BinOp (如 AST | CPtr) 或 Attribute (如 t.CPtr / t.CInt)
|
||||
type_str: str = self._resolve_type_arg_str(sn)
|
||||
# type_name 取原始名称(不带模块前缀),用于 T 替换
|
||||
raw_name: str = self._get_raw_type_name(sn)
|
||||
# type_name 保留模块前缀(如 't.CUnsignedChar'),避免 T(0) 替换为
|
||||
# CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域而报
|
||||
# "Undefined function: 'CUnsignedChar'"。
|
||||
# t.CPtr 特殊处理:保留 'CPtr' 不带前缀,因为 cptr_params 检测依赖
|
||||
# _BUILTIN_TYPE_NAMES 中的 'CPtr' 来识别指针类型参数
|
||||
if isinstance(sn, ast.Attribute) and isinstance(sn.value, ast.Name):
|
||||
if sn.attr == 'CPtr':
|
||||
raw_name: str = 'CPtr'
|
||||
else:
|
||||
raw_name: str = f'{sn.value.id}.{sn.attr}'
|
||||
else:
|
||||
raw_name: str = self._get_raw_type_name(sn)
|
||||
return (type_str, raw_name)
|
||||
|
||||
def _ResolveGenericSlice(self, Sub: ast.Subscript) -> str | None:
|
||||
@@ -2823,7 +2977,13 @@ class ExprCallHandle(BaseHandle):
|
||||
while len(type_args) < len(type_param_names):
|
||||
type_args.append('int')
|
||||
type_names.append('CInt')
|
||||
return self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)
|
||||
# 类型注解解析(如 Float64Array: t.CTypedef = ndarray[t.CDouble])
|
||||
# 只需 struct 定义,不需方法体;使用 declare_only=True 避免过早触发
|
||||
# 完整特化(此时被引用的函数如 printf 可能尚未由 from X import Y 注册,
|
||||
# 导致 "Undefined function" 错误)。完整特化由后续类实例化
|
||||
# (_HandleClassNewLlvm → _specialize_generic_class(declare_only=False))
|
||||
# 触发,缓存机制会补发方法体。
|
||||
return self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names, declare_only=True)
|
||||
|
||||
@staticmethod
|
||||
def _AnnotationContainsCPtr(Node: ast.AST) -> bool:
|
||||
|
||||
Reference in new issue
Block a user