refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建

删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
This commit is contained in:
TermiNexus committed 2026-10-18 13:00:58 +08:00
1 parent 8d27747c7c
commit f19d25782f
66 files changed
+2445 -3638

No files matched your search

+98 -98
View File
@@ -4,7 +4,7 @@ import re
import vast as ast
import llvmlite.ir as ir
from llvmlite.ir.values import _Undefined
from lib.includes import t as _t
from lib.core import TypeSystem as _t
from lib.core.VLogger import get_logger as _vlog
# vtable 槽类型 `i8*` 的共享实例:llvmlite 的类型是不可变值语义(`_TypedPointerType`
@@ -305,100 +305,100 @@ class StructGenMixin:
return ir_text
def _MemberSlotAccepts(self, Declared: Any, Slot: Any) -> bool:
"""声明类型能否**隐式写进**该 struct 槽(判据与存储侧同一套)。
用于判定已冻结的 struct body 是否与 `class_members` 自洽。判定放宽到与
存储侧一致,避免误清:通用指针槽(i8*/void*)照旧放行(历史 stub 普遍
如此),继承上转/数组退让亦放行;只有**存储时必被拒绝**的组合——层数
不同、指针与非指针混位——才判为不一致,触发重建。
"""
if Declared is None or Slot is None:
return True
# 同一对象直接放行:llvmlite 的 Type.__eq__ 走类型键比较(profile:
# 本函数被 _generate_structs 调 54.2M 次,其中 types.py __eq__ 合计 ~30s)
# ⇒ 先做身份判定短路,等价且避免绝大多数 __eq__/str() 开销。
if Declared is Slot:
return True
if Declared == Slot or str(Declared) == str(Slot):
return True
_d_ptr: bool = isinstance(Declared, ir.PointerType)
_s_ptr: bool = isinstance(Slot, ir.PointerType)
if _d_ptr != _s_ptr:
return False
if not _d_ptr:
# 数值/浮点宽度差异不在本次收紧范围:保持既有行为(不清 body)。
return True
try:
Allowed, _Reason = self._ClassifyPtrImplicitConvert(Declared, Slot)
return bool(Allowed)
except Exception:
# 判据不可用(缺上下文)时保守放行,避免误清已正确的布局。
return True
def _IsRenumLayoutClass(self, ClassName: str | None) -> bool:
"""该类是否属 **REnum 布局**(主 REnum 自身,或其变体嵌套结构体 `<REnum>_<Variant>`)。
REnum 的 struct body 是 **max-variant 镜像布局**:`class_members` 里那些名字是
*变体*(不是字段),变体嵌套结构体也必须逐字镜像主结构体。因此**一律不得**用
class_members 的"声明类型"去改写或校验它们的布局 —— 否则跨模块 GEP 偏移与
定义端失配(变体载荷槽本就允许与 max-variant 槽类型不同,取值处靠 bitcast)。
"""
if not ClassName:
return False
_tbl: Any = getattr(self, 'SymbolTable', None)
if _tbl is None:
return False
try:
_e: Any = _tbl.lookup(ClassName)
except Exception:
return False
if _e is not None and getattr(_e, 'IsRenum', False):
return True
if '_' in ClassName:
_prefix: str = ClassName.rsplit('_', 1)[0]
try:
_pe: Any = _tbl.lookup(_prefix)
except Exception:
_pe = None
if _pe is not None and getattr(_pe, 'IsRenum', False):
return True
return False
def _StructBodyHasPlaceholderT(self, St: Any) -> bool:
"""该 struct body 是否含未特化的 `T*` 占位字段(结果按 body 对象记忆)。
`_generate_structs` 里有两处对"全部类的全部元素"做这一扫描(Step 4 的完整性与
set_body 前的复核),每次调用都全量重扫 —— profile(2026-09-29 main_prof_72472):
这两处是本函数 62.5M 次 `isinstance`(6.20s)与 4.98M 次 `rsplit`(1.12s)的主源。
判定精确性:扫描是 `st.elements` 的**纯函数**,而 `elements` 在 llvmlite 里是
**整体替换**(`set_body` 赋新 tuple;作废时置 None;从不原地改元素)⇒ 用
`elements` 的**对象身份**当版本号即可精确判定"body 未变"。缓存条目**强引用**
struct 实例与 elements 对象,二者存活 ⇒ `id()` 不会被回收复用 ⇒ 不会误判命中。
(代价:被替换掉的旧 body tuple 会被缓存多留一份引用;量级 = 结构体数量级,可忽略。)
"""
_cache: dict | None = getattr(self, '_struct_t_placeholder_cache', None)
if _cache is None:
_cache = {}
self._struct_t_placeholder_cache = _cache
_key: int = id(St)
_elems: Any = getattr(St, 'elements', None)
_hit: Any = _cache.get(_key)
if _hit is not None and _hit[0] is St and _hit[1] is _elems:
return _hit[2]
_found: bool = False
if _elems:
for _elem in _elems:
if isinstance(_elem, ir.PointerType) and isinstance(_elem.pointee, ir.IdentifiedStructType):
_pname: str = _elem.pointee.name
_short: str = _pname.rsplit('.', 1)[-1] if '.' in _pname else _pname
if _short == 'T':
_found = True
break
_cache[_key] = (St, _elems, _found)
return _found
def _MemberSlotAccepts(self, Declared: Any, Slot: Any) -> bool:
"""声明类型能否**隐式写进**该 struct 槽(判据与存储侧同一套)。
用于判定已冻结的 struct body 是否与 `class_members` 自洽。判定放宽到与
存储侧一致,避免误清:通用指针槽(i8*/void*)照旧放行(历史 stub 普遍
如此),继承上转/数组退让亦放行;只有**存储时必被拒绝**的组合——层数
不同、指针与非指针混位——才判为不一致,触发重建。
"""
if Declared is None or Slot is None:
return True
# 同一对象直接放行:llvmlite 的 Type.__eq__ 走类型键比较(profile:
# 本函数被 _generate_structs 调 54.2M 次,其中 types.py __eq__ 合计 ~30s)
# ⇒ 先做身份判定短路,等价且避免绝大多数 __eq__/str() 开销。
if Declared is Slot:
return True
if Declared == Slot or str(Declared) == str(Slot):
return True
_d_ptr: bool = isinstance(Declared, ir.PointerType)
_s_ptr: bool = isinstance(Slot, ir.PointerType)
if _d_ptr != _s_ptr:
return False
if not _d_ptr:
# 数值/浮点宽度差异不在本次收紧范围:保持既有行为(不清 body)。
return True
try:
Allowed, _Reason = self._ClassifyPtrImplicitConvert(Declared, Slot)
return bool(Allowed)
except Exception:
# 判据不可用(缺上下文)时保守放行,避免误清已正确的布局。
return True
def _IsRenumLayoutClass(self, ClassName: str | None) -> bool:
"""该类是否属 **REnum 布局**(主 REnum 自身,或其变体嵌套结构体 `<REnum>_<Variant>`)。
REnum 的 struct body 是 **max-variant 镜像布局**:`class_members` 里那些名字是
*变体*(不是字段),变体嵌套结构体也必须逐字镜像主结构体。因此**一律不得**用
class_members 的"声明类型"去改写或校验它们的布局 —— 否则跨模块 GEP 偏移与
定义端失配(变体载荷槽本就允许与 max-variant 槽类型不同,取值处靠 bitcast)。
"""
if not ClassName:
return False
_tbl: Any = getattr(self, 'SymbolTable', None)
if _tbl is None:
return False
try:
_e: Any = _tbl.lookup(ClassName)
except Exception:
return False
if _e is not None and getattr(_e, 'IsRenum', False):
return True
if '_' in ClassName:
_prefix: str = ClassName.rsplit('_', 1)[0]
try:
_pe: Any = _tbl.lookup(_prefix)
except Exception:
_pe = None
if _pe is not None and getattr(_pe, 'IsRenum', False):
return True
return False
def _StructBodyHasPlaceholderT(self, St: Any) -> bool:
"""该 struct body 是否含未特化的 `T*` 占位字段(结果按 body 对象记忆)。
`_generate_structs` 里有两处对"全部类的全部元素"做这一扫描(Step 4 的完整性与
set_body 前的复核),每次调用都全量重扫 —— profile(2026-09-29 main_prof_72472):
这两处是本函数 62.5M 次 `isinstance`(6.20s)与 4.98M 次 `rsplit`(1.12s)的主源。
判定精确性:扫描是 `st.elements` 的**纯函数**,而 `elements` 在 llvmlite 里是
**整体替换**(`set_body` 赋新 tuple;作废时置 None;从不原地改元素)⇒ 用
`elements` 的**对象身份**当版本号即可精确判定"body 未变"。缓存条目**强引用**
struct 实例与 elements 对象,二者存活 ⇒ `id()` 不会被回收复用 ⇒ 不会误判命中。
(代价:被替换掉的旧 body tuple 会被缓存多留一份引用;量级 = 结构体数量级,可忽略。)
"""
_cache: dict | None = getattr(self, '_struct_t_placeholder_cache', None)
if _cache is None:
_cache = {}
self._struct_t_placeholder_cache = _cache
_key: int = id(St)
_elems: Any = getattr(St, 'elements', None)
_hit: Any = _cache.get(_key)
if _hit is not None and _hit[0] is St and _hit[1] is _elems:
return _hit[2]
_found: bool = False
if _elems:
for _elem in _elems:
if isinstance(_elem, ir.PointerType) and isinstance(_elem.pointee, ir.IdentifiedStructType):
_pname: str = _elem.pointee.name
_short: str = _pname.rsplit('.', 1)[-1] if '.' in _pname else _pname
if _short == 'T':
_found = True
break
_cache[_key] = (St, _elems, _found)
return _found
def _generate_structs(self) -> None:
# 热路径局部化:profile 中本函数被调 35,240 次(cum 1893s),内部
# SymbolTable.lookup 15.9M 次(16.7s)+ 真值判断触发的 __len__ 15.9M 次
@@ -569,7 +569,7 @@ class StructGenMixin:
# 治本修复:检查 struct body 是否不完整(元素数少于 class_members + vtable 预期)。
# 常见于跨模块继承:子类 struct 在父类 class_members 加载前从 stub 生成,
# stub 中的定义可能不完整或类型不正确(如 GSList* 代替 AST*、i8* 代替 i32)。
# 此处检测到不完整后清除 elements(公开属性,见下方 Step 4 说明)和
# 此处检测到不完整后清除 elements(公开属性,见下方 Step 4 说明)和
# stub 缓存,让后续代码重新从 stub 加载。
_has_vtable_precheck: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
if not _has_vtable_precheck:
@@ -774,7 +774,7 @@ class StructGenMixin:
# 优先从 stub.ll 加载完整定义。set_body 只能对 opaque struct 调用一次,
# 若用不完整 class_members 设置 body,后续无法修正,会导致 GEP 越界。
# 但本地定义的类(_classes_in_progress)不从 stub 加载,因为 stub 可能
# 来自同名导入类,其 vtable 状态与本地定义不同(@t.NoVTable 冲突)
# 来自同名导入类,其 vtable 状态与本地定义不同(@NoVTable 冲突)
import_handler: Any = self._import_handler_ref
if import_handler is not None and ClassName not in self._classes_in_progress:
try:
@@ -924,7 +924,7 @@ class StructGenMixin:
needs_fix = True
elif isinstance(gv.initializer, ir.Constant):
if isinstance(gv.initializer.constant, list):
if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant):
if any(hasattr(c, 'constant') and isinstance(constant, _Undefined) for c in gv.initializer.constant):
needs_fix = True
if not needs_fix:
continue