refactor(llvmlite): P0 对象化 - IRBuilder/LLVMModule 方法化(70 方法+一行委托兼容)
- IRBuilder 新增 62 个实例方法(load/store/gep/call/binop/cast 等), 顶层函数保留为一行委托, 调用方零改动 - LLVMModule 新增 8 个实例方法(add_function/add_global/add_named_type/PrintModule 等) - 类字段/硬编码 SIZE/逻辑/IR 输出零变化, GetDiagnostics 无错误 - 新增 wiki/14-oo-refactor.md 对象化重构方案(P0-P6)
This commit is contained in:
1 parent
e1cb560df0
commit
fc93a28ec6
3 files changed
+1620
-873
No files matched your search
+1155
-668
File diff suppressed because it is too large.
Load diff
+240
-205
@@ -61,6 +61,238 @@ class LLVMModule:
|
||||
NamedTypeCount: t.CSizeT # 命名结构体类型计数
|
||||
# 总计: 12 字段 * 8 = 96 字节(无 vtable)
|
||||
|
||||
# ============================================================
|
||||
# 实例方法(对象化重构:原 module_* 顶层函数改写为方法,
|
||||
# 原顶层函数保留为一行委托)
|
||||
# ============================================================
|
||||
|
||||
# ---- 链表操作 ----
|
||||
def add_function(self, func: Function | t.CPtr):
|
||||
"""将函数追加到模块函数链表(O(1))"""
|
||||
if self is None or func is None: return
|
||||
func.Next = None
|
||||
if self.FuncHead is None:
|
||||
self.FuncHead = func
|
||||
else:
|
||||
self.FuncTail.Next = func
|
||||
self.FuncTail = func
|
||||
self.FuncCount += 1
|
||||
|
||||
def add_global(self, gv: GlobalVariable | t.CPtr):
|
||||
"""将全局变量追加到模块全局变量链表(O(1))"""
|
||||
if self is None or gv is None: return
|
||||
gv.Next = None
|
||||
if self.GlobalHead is None:
|
||||
self.GlobalHead = gv
|
||||
else:
|
||||
self.GlobalTail.Next = gv
|
||||
self.GlobalTail = gv
|
||||
self.GlobalCount += 1
|
||||
|
||||
# ---- 目标属性 ----
|
||||
def set_target(self, triple: t.CChar | t.CPtr):
|
||||
"""设置目标三元组"""
|
||||
if self is None: return
|
||||
self.TargetTriple = triple
|
||||
|
||||
def set_datalayout(self, layout: t.CChar | t.CPtr):
|
||||
"""设置数据布局"""
|
||||
if self is None: return
|
||||
self.DataLayout = layout
|
||||
|
||||
# ---- 命名结构体类型管理 ----
|
||||
def add_named_type(self, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr):
|
||||
"""将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行)
|
||||
|
||||
非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。
|
||||
按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。
|
||||
"""
|
||||
if self is None or pool is None or ty is None:
|
||||
return
|
||||
name: t.CChar | t.CPtr = get_struct_name(ty)
|
||||
if name is None:
|
||||
return
|
||||
# 去重检查(opaque 声明可被完整定义替换)
|
||||
cur: NamedTypeNode | t.CPtr = self.NamedTypeHead
|
||||
while cur is not None:
|
||||
if cur.Ty is not None:
|
||||
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
|
||||
if existing_name is not None:
|
||||
if string.strcmp(existing_name, name) == 0:
|
||||
# 已有完整定义则无需替换
|
||||
if _is_opaque_struct(cur.Ty) == 0:
|
||||
return
|
||||
# 已有 opaque,新类型也是 opaque 则不重复
|
||||
if _is_opaque_struct(ty) != 0:
|
||||
return
|
||||
# 用完整定义替换 opaque 声明(原地替换 Ty 指针)
|
||||
cur.Ty = ty
|
||||
return
|
||||
cur = cur.Next
|
||||
# 创建新节点
|
||||
node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE)
|
||||
if node is None:
|
||||
return
|
||||
string.memset(node, 0, NAMED_TYPE_NODE_SIZE)
|
||||
node.Ty = ty
|
||||
# opaque 类型插入链表头部,确保在引用它的完整定义之前声明。
|
||||
# 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明
|
||||
# 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。
|
||||
# 完整定义追加到链表尾部,保持原有顺序。
|
||||
if _is_opaque_struct(ty) != 0:
|
||||
node.Next = self.NamedTypeHead
|
||||
if self.NamedTypeHead is None:
|
||||
self.NamedTypeTail = node
|
||||
self.NamedTypeHead = node
|
||||
else:
|
||||
node.Next = None
|
||||
if self.NamedTypeHead is None:
|
||||
self.NamedTypeHead = node
|
||||
else:
|
||||
self.NamedTypeTail.Next = node
|
||||
self.NamedTypeTail = node
|
||||
self.NamedTypeCount += 1
|
||||
|
||||
def _is_type_defined_in_module(self, name: t.CChar | t.CPtr) -> int:
|
||||
"""检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义"""
|
||||
if self is None or name is None:
|
||||
return 0
|
||||
cur: NamedTypeNode | t.CPtr = self.NamedTypeHead
|
||||
while cur is not None:
|
||||
if cur.Ty is not None:
|
||||
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
|
||||
if existing_name is not None:
|
||||
if string.strcmp(existing_name, name) == 0:
|
||||
return 1
|
||||
cur = cur.Next
|
||||
return 0
|
||||
|
||||
def ensure_opaque_for_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr):
|
||||
"""为类型中的跨模块结构体引用添加 opaque 声明
|
||||
|
||||
当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时,
|
||||
如果该名称未在模块中定义,则添加 opaque 声明。
|
||||
"""
|
||||
_scan_type_for_cross_module_refs(pool, self, ty)
|
||||
|
||||
# ---- 打印 ----
|
||||
def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
pool: memhub.MemBuddy | t.CPtr, mode: t.CInt):
|
||||
"""将模块序列化为 .ll 文本写入 buf"""
|
||||
if self is None or buf is None or size == 0: return
|
||||
|
||||
# 头部注释(stub 和 full 模式输出,text 模式不输出)
|
||||
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
|
||||
_append_cstr(buf, size, "; ModuleID = '")
|
||||
if self.Name is not None:
|
||||
_append_cstr(buf, size, self.Name)
|
||||
_append_cstr(buf, size, "'\n")
|
||||
|
||||
# 目标三元组
|
||||
if self.TargetTriple is not None:
|
||||
_append_cstr(buf, size, "target triple = \"")
|
||||
_append_cstr(buf, size, self.TargetTriple)
|
||||
_append_cstr(buf, size, "\"\n")
|
||||
|
||||
# 数据布局
|
||||
if self.DataLayout is not None:
|
||||
_append_cstr(buf, size, "target datalayout = \"")
|
||||
_append_cstr(buf, size, self.DataLayout)
|
||||
_append_cstr(buf, size, "\"\n")
|
||||
|
||||
# 空行
|
||||
_append_cstr(buf, size, "\n")
|
||||
|
||||
# 命名结构体类型定义(stub 和 full 模式输出,text 模式不输出)
|
||||
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
|
||||
# 扫描所有函数签名,为跨模块结构体引用添加 opaque 定义
|
||||
# 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义
|
||||
# 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册
|
||||
func_scan: Function | t.CPtr = self.FuncHead
|
||||
while func_scan is not None:
|
||||
if func_scan.RetTy is not None:
|
||||
self.ensure_opaque_for_type(pool, func_scan.RetTy)
|
||||
if func_scan.Params is not None:
|
||||
param_scan: Param | t.CPtr = func_scan.Params.Head
|
||||
while param_scan is not None:
|
||||
if param_scan.Ty is not None:
|
||||
self.ensure_opaque_for_type(pool, param_scan.Ty)
|
||||
param_scan = param_scan.Next
|
||||
func_scan = func_scan.Next
|
||||
nt: NamedTypeNode | t.CPtr = self.NamedTypeHead
|
||||
# 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够
|
||||
# 在循环外分配一次并复用,减少 pool 碎片
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(4096)
|
||||
while nt is not None:
|
||||
if nt.Ty is not None:
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
PrintStructDefinition(ty_buf, 4096, nt.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
_append_cstr(buf, size, "\n")
|
||||
nt = nt.Next
|
||||
|
||||
if self.NamedTypeHead is not None:
|
||||
_append_cstr(buf, size, "\n")
|
||||
|
||||
# 全局变量
|
||||
gv: GlobalVariable | t.CPtr = self.GlobalHead
|
||||
if mode == OUTPUT_STUB:
|
||||
# stub 模式:输出 external global(无初值)
|
||||
while gv is not None:
|
||||
_print_global_stub(buf, size, gv, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
gv = gv.Next
|
||||
else:
|
||||
# full 和 text 模式:输出完整全局变量
|
||||
# text 模式跳过无初值的全局变量(纯声明)
|
||||
gv_idx: t.CInt = 0
|
||||
while gv is not None:
|
||||
if mode == OUTPUT_TEXT and gv.Initializer is None:
|
||||
gv = gv.Next
|
||||
gv_idx += 1
|
||||
continue
|
||||
_print_global(buf, size, gv, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
gv = gv.Next
|
||||
gv_idx += 1
|
||||
|
||||
if self.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB):
|
||||
_append_cstr(buf, size, "\n")
|
||||
elif self.GlobalHead is not None and mode == OUTPUT_TEXT:
|
||||
# text 模式下如果输出了全局变量,也加空行
|
||||
had_global: t.CInt = 0
|
||||
gv2: GlobalVariable | t.CPtr = self.GlobalHead
|
||||
while gv2 is not None:
|
||||
if gv2.Initializer is not None:
|
||||
had_global = 1
|
||||
break
|
||||
gv2 = gv2.Next
|
||||
if had_global != 0:
|
||||
_append_cstr(buf, size, "\n")
|
||||
|
||||
# 遍历函数
|
||||
func: Function | t.CPtr = self.FuncHead
|
||||
func_idx: t.CInt = 0
|
||||
while func is not None:
|
||||
if mode == OUTPUT_STUB:
|
||||
# stub 模式:仅输出 declare(IsDeclared==1)
|
||||
if func.IsDeclared == 1:
|
||||
FunctionPrint(buf, size, func, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
elif mode == OUTPUT_TEXT:
|
||||
# text 模式:仅输出 define(IsDeclared==0)
|
||||
if func.IsDeclared == 0:
|
||||
FunctionPrint(buf, size, func, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
else:
|
||||
# full 模式:输出所有函数
|
||||
FunctionPrint(buf, size, func, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
func = func.Next
|
||||
func_idx += 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 工厂函数
|
||||
@@ -112,39 +344,19 @@ def new_global_variable(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 链表操作(嵌入式 Head/Tail/Count,O(1) 追加)
|
||||
# ============================================================
|
||||
def module_add_function(mod: LLVMModule | t.CPtr, func: Function | t.CPtr):
|
||||
"""将函数追加到模块函数链表(O(1))"""
|
||||
if mod is None or func is None: return
|
||||
func.Next = None
|
||||
if mod.FuncHead is None:
|
||||
mod.FuncHead = func
|
||||
else:
|
||||
mod.FuncTail.Next = func
|
||||
mod.FuncTail = func
|
||||
mod.FuncCount += 1
|
||||
return mod.add_function(func)
|
||||
|
||||
|
||||
def module_add_global(mod: LLVMModule | t.CPtr, gv: GlobalVariable | t.CPtr):
|
||||
"""将全局变量追加到模块全局变量链表(O(1))"""
|
||||
if mod is None or gv is None: return
|
||||
gv.Next = None
|
||||
if mod.GlobalHead is None:
|
||||
mod.GlobalHead = gv
|
||||
else:
|
||||
mod.GlobalTail.Next = gv
|
||||
mod.GlobalTail = gv
|
||||
mod.GlobalCount += 1
|
||||
return mod.add_global(gv)
|
||||
|
||||
|
||||
def module_set_target(mod: LLVMModule | t.CPtr, triple: t.CChar | t.CPtr):
|
||||
"""设置目标三元组"""
|
||||
if mod is None: return
|
||||
mod.TargetTriple = triple
|
||||
return mod.set_target(triple)
|
||||
|
||||
|
||||
def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr):
|
||||
"""设置数据布局"""
|
||||
if mod is None: return
|
||||
mod.DataLayout = layout
|
||||
return mod.set_datalayout(layout)
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -177,56 +389,7 @@ def _is_opaque_struct(ty: LLVMType | t.CPtr) -> int:
|
||||
|
||||
def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr):
|
||||
"""将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行)
|
||||
|
||||
非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。
|
||||
按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。
|
||||
"""
|
||||
if mod is None or pool is None or ty is None:
|
||||
return
|
||||
name: t.CChar | t.CPtr = get_struct_name(ty)
|
||||
if name is None:
|
||||
return
|
||||
# 去重检查(opaque 声明可被完整定义替换)
|
||||
cur: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
while cur is not None:
|
||||
if cur.Ty is not None:
|
||||
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
|
||||
if existing_name is not None:
|
||||
if string.strcmp(existing_name, name) == 0:
|
||||
# 已有完整定义则无需替换
|
||||
if _is_opaque_struct(cur.Ty) == 0:
|
||||
return
|
||||
# 已有 opaque,新类型也是 opaque 则不重复
|
||||
if _is_opaque_struct(ty) != 0:
|
||||
return
|
||||
# 用完整定义替换 opaque 声明(原地替换 Ty 指针)
|
||||
cur.Ty = ty
|
||||
return
|
||||
cur = cur.Next
|
||||
# 创建新节点
|
||||
node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE)
|
||||
if node is None:
|
||||
return
|
||||
string.memset(node, 0, NAMED_TYPE_NODE_SIZE)
|
||||
node.Ty = ty
|
||||
# opaque 类型插入链表头部,确保在引用它的完整定义之前声明。
|
||||
# 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明
|
||||
# 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。
|
||||
# 完整定义追加到链表尾部,保持原有顺序。
|
||||
if _is_opaque_struct(ty) != 0:
|
||||
node.Next = mod.NamedTypeHead
|
||||
if mod.NamedTypeHead is None:
|
||||
mod.NamedTypeTail = node
|
||||
mod.NamedTypeHead = node
|
||||
else:
|
||||
node.Next = None
|
||||
if mod.NamedTypeHead is None:
|
||||
mod.NamedTypeHead = node
|
||||
else:
|
||||
mod.NamedTypeTail.Next = node
|
||||
mod.NamedTypeTail = node
|
||||
mod.NamedTypeCount += 1
|
||||
return mod.add_named_type(pool, ty)
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -237,18 +400,7 @@ def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CP
|
||||
# 这解决了跨模块结构体引用导致的 llc "use of undefined type" 错误。
|
||||
# ============================================================
|
||||
def _is_type_defined_in_module(mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr) -> int:
|
||||
"""检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义"""
|
||||
if mod is None or name is None:
|
||||
return 0
|
||||
cur: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
while cur is not None:
|
||||
if cur.Ty is not None:
|
||||
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
|
||||
if existing_name is not None:
|
||||
if string.strcmp(existing_name, name) == 0:
|
||||
return 1
|
||||
cur = cur.Next
|
||||
return 0
|
||||
return mod._is_type_defined_in_module(name)
|
||||
|
||||
|
||||
def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
|
||||
@@ -299,12 +451,7 @@ def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
|
||||
def module_ensure_opaque_for_type(mod: LLVMModule | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr):
|
||||
"""为类型中的跨模块结构体引用添加 opaque 声明
|
||||
|
||||
当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时,
|
||||
如果该名称未在模块中定义,则添加 opaque 声明。
|
||||
"""
|
||||
_scan_type_for_cross_module_refs(pool, mod, ty)
|
||||
return mod.ensure_opaque_for_type(pool, ty)
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -350,119 +497,7 @@ OUTPUT_TEXT: t.CDefine = 2 # 仅代码(define + global 带初值)
|
||||
def LLVMModulePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
mode: t.CInt):
|
||||
"""将模块 mod 序列化为 .ll 文本写入 buf"""
|
||||
if mod is None or buf is None or size == 0: return
|
||||
|
||||
# 头部注释(stub 和 full 模式输出,text 模式不输出)
|
||||
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
|
||||
_append_cstr(buf, size, "; ModuleID = '")
|
||||
if mod.Name is not None:
|
||||
_append_cstr(buf, size, mod.Name)
|
||||
_append_cstr(buf, size, "'\n")
|
||||
|
||||
# 目标三元组
|
||||
if mod.TargetTriple is not None:
|
||||
_append_cstr(buf, size, "target triple = \"")
|
||||
_append_cstr(buf, size, mod.TargetTriple)
|
||||
_append_cstr(buf, size, "\"\n")
|
||||
|
||||
# 数据布局
|
||||
if mod.DataLayout is not None:
|
||||
_append_cstr(buf, size, "target datalayout = \"")
|
||||
_append_cstr(buf, size, mod.DataLayout)
|
||||
_append_cstr(buf, size, "\"\n")
|
||||
|
||||
# 空行
|
||||
_append_cstr(buf, size, "\n")
|
||||
|
||||
# 命名结构体类型定义(stub 和 full 模式输出,text 模式不输出)
|
||||
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
|
||||
# 扫描所有函数签名,为跨模块结构体引用添加 opaque 定义
|
||||
# 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义
|
||||
# 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册
|
||||
func_scan: Function | t.CPtr = mod.FuncHead
|
||||
while func_scan is not None:
|
||||
if func_scan.RetTy is not None:
|
||||
module_ensure_opaque_for_type(mod, pool, func_scan.RetTy)
|
||||
if func_scan.Params is not None:
|
||||
param_scan: Param | t.CPtr = func_scan.Params.Head
|
||||
while param_scan is not None:
|
||||
if param_scan.Ty is not None:
|
||||
module_ensure_opaque_for_type(mod, pool, param_scan.Ty)
|
||||
param_scan = param_scan.Next
|
||||
func_scan = func_scan.Next
|
||||
nt: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
# 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够
|
||||
# 在循环外分配一次并复用,减少 pool 碎片
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(4096)
|
||||
while nt is not None:
|
||||
if nt.Ty is not None:
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
PrintStructDefinition(ty_buf, 4096, nt.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
_append_cstr(buf, size, "\n")
|
||||
nt = nt.Next
|
||||
|
||||
if mod.NamedTypeHead is not None:
|
||||
_append_cstr(buf, size, "\n")
|
||||
|
||||
# 全局变量
|
||||
gv: GlobalVariable | t.CPtr = mod.GlobalHead
|
||||
if mode == OUTPUT_STUB:
|
||||
# stub 模式:输出 external global(无初值)
|
||||
while gv is not None:
|
||||
_print_global_stub(buf, size, gv, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
gv = gv.Next
|
||||
else:
|
||||
# full 和 text 模式:输出完整全局变量
|
||||
# text 模式跳过无初值的全局变量(纯声明)
|
||||
gv_idx: t.CInt = 0
|
||||
while gv is not None:
|
||||
if mode == OUTPUT_TEXT and gv.Initializer is None:
|
||||
gv = gv.Next
|
||||
gv_idx += 1
|
||||
continue
|
||||
_print_global(buf, size, gv, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
gv = gv.Next
|
||||
gv_idx += 1
|
||||
|
||||
if mod.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB):
|
||||
_append_cstr(buf, size, "\n")
|
||||
elif mod.GlobalHead is not None and mode == OUTPUT_TEXT:
|
||||
# text 模式下如果输出了全局变量,也加空行
|
||||
had_global: t.CInt = 0
|
||||
gv2: GlobalVariable | t.CPtr = mod.GlobalHead
|
||||
while gv2 is not None:
|
||||
if gv2.Initializer is not None:
|
||||
had_global = 1
|
||||
break
|
||||
gv2 = gv2.Next
|
||||
if had_global != 0:
|
||||
_append_cstr(buf, size, "\n")
|
||||
|
||||
# 遍历函数
|
||||
func: Function | t.CPtr = mod.FuncHead
|
||||
func_idx: t.CInt = 0
|
||||
while func is not None:
|
||||
if mode == OUTPUT_STUB:
|
||||
# stub 模式:仅输出 declare(IsDeclared==1)
|
||||
if func.IsDeclared == 1:
|
||||
FunctionPrint(buf, size, func, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
elif mode == OUTPUT_TEXT:
|
||||
# text 模式:仅输出 define(IsDeclared==0)
|
||||
if func.IsDeclared == 0:
|
||||
FunctionPrint(buf, size, func, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
else:
|
||||
# full 模式:输出所有函数
|
||||
FunctionPrint(buf, size, func, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
func = func.Next
|
||||
func_idx += 1
|
||||
return mod.PrintModule(buf, size, pool, mode)
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
# TPV 对象化重构方案
|
||||
|
||||
> 基线:TPV `f63dcd7` / TransPyC `e1cb560`(对象化前最后稳定版本,2026-08-09)
|
||||
> 状态:方案讨论稿,未开始实施
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 现状问题
|
||||
|
||||
TPV 编译器当前是"**数据对象 + 行为函数式**"架构:
|
||||
|
||||
- `includes/llvmlite/`:19 个数据结构类已对象化(`IRBuilder`/`LLVMModule`/`Value`/`LLVMType`…),但**所有操作是"首参传 self"的顶层函数**(`build_load(builder, ...)`、`module_add_function(mod, ...)`),与 C 风格 API 一致
|
||||
- `TransPyV/App/lib/core/Handles/`:**纯函数模块**(`translate_call(pool, builder, mod, node, funcs, count, trans)` 六参连传),且存在严重膨胀:
|
||||
|
||||
| 文件 | 大小 | 行数 |
|
||||
|---|---|---|
|
||||
| HandlesExprCall.vp | 362KB | 7043 |
|
||||
| HandlesExpr.vp | 181KB | 3715 |
|
||||
| HandlesClassDef.vp | 172KB | 4010 |
|
||||
| HandlesType.vp | 102KB | 2360 |
|
||||
|
||||
### 1.2 重构目标
|
||||
|
||||
1. **对象化**:引入 `Generator` 生成器对象(Mixin 组合),状态集中于 `self`,与 TPC 的 `Translator + LlvmCodeGenerator` 架构对齐
|
||||
2. **膨胀治理**:`translate_call` 7043 行 God Function 按职责拆散为 `CallGen` 的方法簇
|
||||
3. **不引入 TPC 代码**:基于 TPC 设计理念 + Viper 约束自研;TPC 的 LLVMCG 仅作参考
|
||||
4. **每阶段可验证**:bootstrap 编译 + 全 Test 回归,IR 输出零变化
|
||||
|
||||
## 2. 现状盘点(已实测)
|
||||
|
||||
### 2.1 llvmlite 模块(`includes/llvmlite/`,7 文件)
|
||||
|
||||
| 文件 | 内容 | 对象化程度 |
|
||||
|---|---|---|
|
||||
| `__init__.vp` (422行) | 10 工厂函数 + `LLVMModuleCore`(27 个薄封装方法) | **已有方法化先例** |
|
||||
| `__builder.vp` (1336行) | **60+ 个 `build_*` 顶层函数** + `IRBuilder`(4 字段:Pool/Func/CurBlock/Counter) | **IRBuilder 是天然状态对象,签名已按 self 优先** |
|
||||
| `__types.vp` (748行) | 34 类型工厂/打印/深拷贝 + `LLVMType`(**REnum tagged union**)+ `LLVMTypeCore`(19 方法) | REnum 应保留,Core 是方法化先例 |
|
||||
| `__module.vp` (565行) | 19 函数 + `LLVMModule`(12 字段容器,含 NamedType 链表) | 纯数据容器,可平移 |
|
||||
| `__function.vp` (798行) | 35 函数 + `Line/BasicBlock/Param/Function`(GSListNode 链) | 纯数据结构 |
|
||||
| `__values.vp` (230行) | 14 函数 + `Value`(5 字段) | 纯数据结构 |
|
||||
| `__verify.vp` (399行) | 15 验证函数 + `VerifyResult` | 独立,最后迁移 |
|
||||
|
||||
**关键结论**:
|
||||
- **IRBuilder 对象化零状态迁移成本**:4 字段已齐,60+ 顶层函数改方法只需 `self` 替代首参,签名一一对应
|
||||
- **LLVMModule 对象化有先例**:`LLVMModuleCore`/`LLVMTypeCore` 已证明"方法化封装"可行(但仍为薄壳,核心 `module_add_named_type`/打印仍是顶层函数)
|
||||
- **LLVMType 保持 REnum**:变体即"子类",不应转继承层次
|
||||
|
||||
### 2.2 演进阻力点
|
||||
|
||||
1. `@t.NoVTable` + 硬编码 SIZE(`BUILDER_SIZE=32`/`pool.alloc(96)`)强耦合——**方法化不改布局则无影响**;若转 `@t.CVTable` 需全量重写
|
||||
2. 16 个跨模块 stub 访问器(`value_get_ty`/`paramnode_get_ty`…)是规避 TransPyC stub 限制的产物——方法化后可逐步消除(**依赖编译器缺陷修复,非本方案范围**)
|
||||
3. `LLVMType` 的 `pool.alloc(__sizeof__)` + `c.DerefAs` 构造模式——保留为构造方法
|
||||
|
||||
## 3. 目标架构
|
||||
|
||||
```
|
||||
includes/llvmlite/ # ① 方法化平移(P0)
|
||||
├── __builder.vp # IRBuilder + 60 方法(build_load → self.load)
|
||||
├── __module.vp # LLVMModule + 方法 + 命名类型注册
|
||||
├── __types.vp # LLVMType(REnum) + 构造方法
|
||||
├── __values.vp / __function.vp / __verify.vp
|
||||
└── __init__.vp # 薄兼容层:旧顶层函数委托新方法(调用方零改动)
|
||||
|
||||
TransPyV/App/lib/core/
|
||||
├── Gen/ # ② 生成器对象(P1-P6)
|
||||
│ ├── Generator.vp # 入口:@t.CVTable,Mixin 组合,visit 分派
|
||||
│ ├── BaseGenMixin.vp # 状态/Pool/Module/Builder/SymTab + 错误/trace
|
||||
│ ├── TypeGenMixin.vp # 类型映射/注解解析(← HandlesType)
|
||||
│ ├── StructGenMixin.vp # struct 注册/字段/继承/vtable(← HandlesStruct+ClassDef 布局)
|
||||
│ ├── ExprGenMixin.vp # 表达式/二元/一元(← HandlesExpr+ExprOps)
|
||||
│ ├── CallGenMixin.vp # 调用分派/方法/类型转换/c.*/stdarg(← HandlesExprCall 拆解)
|
||||
│ ├── FuncGenMixin.vp # 函数/方法声明与翻译(← HandlesFunctions)
|
||||
│ ├── ClassGenMixin.vp # 类定义/泛型特化(← HandlesClassDef)
|
||||
│ ├── StmtGenMixin.vp # 语句(← Body/If/While/For/Assign/AnnAssign/Return/Match/Nonlocal)
|
||||
│ └── ImportsGenMixin.vp # 导入(← HandlesImports)
|
||||
└── Handles/ # ③ 迁移完成后:删除或保留为薄壳(P6 决定)
|
||||
```
|
||||
|
||||
## 4. P0:llvmlite 方法化(双轨过渡)
|
||||
|
||||
### 4.1 原则
|
||||
|
||||
**纯方法化平移,不改布局、不改语义**:顶层函数 → 类方法,`self` 替代首参;类保持 `@t.NoVTable` + 硬编码 SIZE(不引入 vtable 继承)。
|
||||
|
||||
### 4.2 方法映射示例
|
||||
|
||||
```python
|
||||
# 现状(__builder.vp)
|
||||
def build_load(builder, ty, ptr): ...
|
||||
def build_gep_struct(builder, struct_ty, field_ty, ptr, field_idx): ...
|
||||
|
||||
# 目标(同文件,类方法)
|
||||
@t.NoVTable
|
||||
class IRBuilder:
|
||||
Pool, Func, CurBlock, Counter
|
||||
def load(self, ty, ptr): ... # 原函数体,builder → self
|
||||
def gep_struct(self, struct_ty, field_ty, ptr, field_idx): ...
|
||||
|
||||
# 兼容层(__init__.vp):旧函数保留为薄包装
|
||||
def build_load(builder, ty, ptr):
|
||||
return builder.load(ty, ptr)
|
||||
```
|
||||
|
||||
### 4.3 覆盖清单(60+ 方法)
|
||||
|
||||
| 类别 | 方法 |
|
||||
|---|---|
|
||||
| 内存 | alloca / alloca_aligned / alloca_at_entry / load / store |
|
||||
| 整数二元 | add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr |
|
||||
| 浮点 | fadd/fsub/fmul/fdiv/frem/fneg |
|
||||
| 比较 | icmp / fcmp |
|
||||
| 控制流 | br / cond_br / ret / ret_void / unreachable / switch / select |
|
||||
| 调用 | call / call_indirect |
|
||||
| 转换 | bitcast/sext/trunc/zext/ptrtoint/inttoptr/fpext/fptrunc/fp2si/si2fp/fp2ui/ui2fp |
|
||||
| GEP | gep / gep_array / gep_struct |
|
||||
| Phi/原子/杂项 | phi / atomicrmw / cmpxchg / va_arg / inline_asm |
|
||||
|
||||
### 4.4 Module 方法化
|
||||
|
||||
```python
|
||||
def add_function(self, func): ...
|
||||
def add_global(self, gv): ...
|
||||
def add_named_type(self, ty): ...
|
||||
def ensure_opaque_for_type(self, ty): ...
|
||||
def set_target(self, triple): ...
|
||||
def print_ir(self, mode): ...
|
||||
```
|
||||
|
||||
### 4.5 验证
|
||||
|
||||
- bootstrap 编译 TPV(自举)通过
|
||||
- 全 Test 回归:编译产物 `.text.ll` 与基线**逐字节一致**(兼容层保证行为不变)
|
||||
- 兼容层在 P6 确认无调用方后删除
|
||||
|
||||
## 5. P1-P6:Generator 对象迁移
|
||||
|
||||
### 5.1 Generator 骨架(P1)
|
||||
|
||||
```python
|
||||
# 采用 @t.CVTable(多态 Mixin 继承,与现有 ReturnHandle(HandlesBase.Mixin) 模式一致,
|
||||
# 符合"多态类不用 NoVTable"约定;数据类 llvmlite 仍为 NoVTable)
|
||||
@t.CVTable
|
||||
class Generator(BaseGenMixin, TypeGenMixin, StructGenMixin,
|
||||
ExprGenMixin, CallGenMixin, FuncGenMixin,
|
||||
ClassGenMixin, StmtGenMixin, ImportsGenMixin):
|
||||
pass
|
||||
```
|
||||
|
||||
BaseGenMixin 状态字段(迁移自 HandlesTranslator):
|
||||
`Pool` / `Module` / `Builder` / `SymTab` / `FuncTable` / `FuncCount` / `StructTable` / `VTableCache` / `ImportedModules` / `FromImports` / `ModuleSha1` / `CurFunc` / `CurBuilder` / `CurClassName` / 错误 trace 栈
|
||||
|
||||
### 5.2 Mixin 方法映射表(P2-P5)
|
||||
|
||||
| Mixin | 来源(现状函数) | 迁移后方法 |
|
||||
|---|---|---|
|
||||
| TypeGenMixin | `HandlesType.map_t_type` / `resolve_annotation_type` / CDefine 表 | `self.map_type(name)` / `self.resolve_annotation(node)` |
|
||||
| StructGenMixin | `HandlesStruct.register_struct` / `find_struct` / `lookup_field`;`HandlesClassDef` 布局/vtable | `self.register_struct(...)` / `self.lookup_field(...)` / `self.gen_vtable(cls)` |
|
||||
| ExprGenMixin | `HandlesExpr.translate_value` / `translate_name_value` / 属性访问;`HandlesExprOps.translate_binop` / `try_unary_operator_overload` | `self.visit_value(node)` / `self.visit_binop(node)` / `self.visit_attr(node)` |
|
||||
| CallGenMixin | `HandlesExprCall.translate_call`(**拆解**)+ `_translate_method_call` / `_translate_t_type_cast` / `translate_c_addr` 等 | `self.visit_call(node)` → `self._call_method(...)` / `self._call_t_cast(...)` / `self._call_c_addr(...)` |
|
||||
| FuncGenMixin | `HandlesFunctions.translate_function_def` / `_mangle_name` | `self.translate_func(node)` / `self.mangle_name(name)` |
|
||||
| ClassGenMixin | `HandlesClassDef.translate_class_def` / `_specialize_generic_class` | `self.translate_class(node)` / `self.specialize_generic(...)` |
|
||||
| StmtGenMixin | `HandlesBody.translate_stmt` + If/While/For/Assign/AnnAssign/Return/Match/Nonlocal 各 Handle | `self.visit_stmt(node)` |
|
||||
| ImportsGenMixin | `HandlesImports` Import/ImportFrom | `self.import_module(...)` |
|
||||
|
||||
### 5.3 签名瘦身规则
|
||||
|
||||
```python
|
||||
# 现状:六参连传
|
||||
translate_call(pool, builder, mod, node, funcs_ptr, func_count, trans)
|
||||
|
||||
# 目标:self 持状态
|
||||
self.visit_call(node) # 内部用 self.Pool/self.Builder/self.Module/self.FuncTable
|
||||
```
|
||||
|
||||
- 中间态:`self.visit_call(node, funcs_ptr, func_count)`(表引用局部化后去参)
|
||||
- 迁移顺序**从叶子到根**(先无依赖者),每迁移一个 Mixin 立即 bootstrap
|
||||
|
||||
### 5.4 CallGen 拆解(P4,膨胀治理重点)
|
||||
|
||||
`translate_call` 7043 行按分支簇拆为方法(**纯移动,逻辑零改动**):
|
||||
|
||||
| 方法簇 | 对应分支 |
|
||||
|---|---|
|
||||
| `_call_generic_ctor(node)` | 泛型类构造 `list[int](pool, n)` |
|
||||
| `_call_binop_cast(node)` | `(A|t.CPtr)(val)` BinOp 强转 |
|
||||
| `_call_c_special(node)` | `c.Deref/Addr/Set/Load/Asm/LLVMIR/CIf/CIfdef` 系列 |
|
||||
| `_call_stdarg(node)` | `va_arg/arg/va_start/va_end` |
|
||||
| `_call_builtin_cast(node)` | `str/bytes/int/bool(x)` |
|
||||
| `_call_t_cast(node)` | `t.CInt(x)` / `t.CVoid(x, CPtr)` / 裸名 typedef |
|
||||
| `_call_class_sizeof(node)` | `ClassName.__sizeof__()` |
|
||||
| `_call_method(node)` | `self.field.method(...)` / `(expr).method(...)` |
|
||||
| `_call_plain(node)` | 普通函数/跨模块调用 |
|
||||
|
||||
## 6. 迁移计划总表
|
||||
|
||||
| 阶段 | 内容 | 产出 | 验证 |
|
||||
|---|---|---|---|
|
||||
| P0 | llvmlite 方法化 + 兼容层 | Builder/Module 方法化 | bootstrap + 全回归(IR 零差异) |
|
||||
| P1 | Generator 骨架 + trans 字段迁入 | `Gen/Generator.vp` 空状态对象 | bootstrap |
|
||||
| P2 | TypeGen / StructGen | 2 个 Mixin 文件 | bootstrap |
|
||||
| P3 | ExprGen(含 ExprOps) | 1-2 个 Mixin | bootstrap |
|
||||
| P4 | CallGen(拆 7043 行) | 9 个方法簇 | bootstrap |
|
||||
| P5 | FuncGen / ClassGen / StmtGen / ImportsGen | 4 个 Mixin | bootstrap |
|
||||
| P6 | 删除 Handles 壳 / 兼容层 / ast visitor(可选) | 收尾 | bootstrap + 全回归 |
|
||||
|
||||
**每阶段验收**:bootstrap 编译通过 → 全 Test 项目编译通过 → `.text.ll` 与基线 diff 为空(或仅行号差异)。
|
||||
|
||||
## 7. 风险与对策
|
||||
|
||||
| 风险 | 对策 |
|
||||
|---|---|
|
||||
| `@t.NoVTable` + 硬编码 SIZE 布局 | 方法化不改布局;Generator 用 `@t.CVTable`(数据类保持 NoVTable) |
|
||||
| 跨模块 stub 访问器 | 方法化后保留访问器(消除依赖编译器缺陷修复,延后) |
|
||||
| Viper 循环 import | 保持现有"延迟 import"模式 |
|
||||
| 迁移引入行为差异 | 每阶段 `.text.ll` 基线 diff 校验 |
|
||||
| REnum LLVMType 误转继承 | 明确保持 REnum 构造模式 |
|
||||
| 工作量/回归风险 | 纯移动优先(P0-P5),语义重构仅 P6(可选) |
|
||||
|
||||
## 8. 验收标准(最终)
|
||||
|
||||
1. TPV bootstrap 编译通过(三重编译流程)
|
||||
2. 全部 Test 项目编译 + 运行通过
|
||||
3. IR 输出与基线一致(无行为变化)
|
||||
4. `HandlesExprCall.vp` 7043 行 → `CallGen` 各方法簇 < 1500 行
|
||||
5. 所有 Handles 调用不再六参连传(`self` 持状态)
|
||||
Reference in new issue
Block a user