Files
Viper_VRTE/llvmlite/__module.vp
T

787 lines
35 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import string
import stdio
import stdlib
import viperlib
import memhub
from linkedlist import GSList, GSListNode
from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct, ParamNode
from .__function import Function, FunctionPrint, _ll_name_needs_quote, Param, param_get_next, param_get_ty
# ============================================================
# GlobalVariable: LLVM IR 全局变量
#
# 持有名称 + 类型 + 初始化值 + 常量标志 + 链接类型。
# 继承 GSListNode[GlobalVariable] 获取强类型 Next。
# ============================================================
@t.NoVTable
class GlobalVariable(GSListNode[GlobalVariable]):
Name: str # 全局变量名(如 ".str" / "my_global")
Ty: rowptr[LLVMType] # 变量类型
Initializer: rowptr[t.CVoid] # 初始化值 Value*(None = 无初始化)
IsConstant: int # 1=constant, 0=variable
Linkage: str # 链接类型("private"/"internal"/"external"/...)
Section: str # 段名(None = 默认)
UnnamedAddr: int # 1=unnamed_addr, 2=local_unnamed_addr, 0=none
Align: int # 对齐字节数(0=默认对齐,如 @c.Attribute(t.attr.aligned(16)))
# ============================================================
# NamedTypeNode: 命名结构体类型链表节点
#
# 持有 LLVMType* 指针(必须是命名 Struct 类型)。
# 继承 GSListNode[NamedTypeNode] 获取强类型 Next。
# ============================================================
@t.NoVTable
class NamedTypeNode(GSListNode[NamedTypeNode]):
Ty: rowptr[LLVMType] # 命名结构体类型指针
IsPacked: int # 1=packed 结构体(输出 <{...}>,无字段填充)
# ============================================================
# LLVMModule: LLVM IR 模块容器
#
# 使用嵌入式 Head/Tail/Count 字段代替 GSList 指针,
# 避免泛型 GSList 的 __sizeof__ 返回 0 和 vtable 偏移不一致问题。
# LLVMModulePrint 输出完整 .ll 文件内容。
# 注意: 类名必须为 LLVMModule 而非 Module,避免与 ast.Module 命名冲突
# ============================================================
@t.NoVTable
class LLVMModule:
Name: str # 模块名
FuncHead: rowptr[Function] # 函数链表头
FuncTail: rowptr[Function] # 函数链表尾
FuncCount: t.CSizeT # 函数计数
GlobalHead: rowptr[GlobalVariable] # 全局变量链表头
GlobalTail: rowptr[GlobalVariable] # 全局变量链表尾
GlobalCount: t.CSizeT # 全局变量计数
TargetTriple: str # 目标三元组(如 "x86_64-pc-linux-gnu")
DataLayout: str # 数据布局(如 "e-m:e-p270:32:32-...")
NamedTypeHead: rowptr[NamedTypeNode] # 命名结构体类型链表头
NamedTypeTail: rowptr[NamedTypeNode] # 命名结构体类型链表尾
NamedTypeCount: t.CSizeT # 命名结构体类型计数
# 总计: 12 字段 * 8 = 96 字节(无 vtable)
# ============================================================
# 实例方法(对象化重构:原 module_* 顶层函数改写为方法,
# 原顶层函数保留为一行委托)
# ============================================================
# ---- 链表操作 ----
def add_function(self, func: rowptr[Function]):
"""将函数追加到模块函数链表(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: rowptr[GlobalVariable]):
"""将全局变量追加到模块全局变量链表(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: str):
"""设置目标三元组"""
if self is None: return
self.TargetTriple = triple
def set_datalayout(self, layout: str):
"""设置数据布局"""
if self is None: return
self.DataLayout = layout
# ---- 命名结构体类型管理 ----
def add_named_type(self, pool: rowptr[memhub.MemBuddy], ty: rowptr[LLVMType]):
"""将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行)
非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。
按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。
"""
if self is None or pool is None or ty is None:
return
name: str = get_struct_name(ty)
if name is None:
return
# 去重检查(opaque 声明可被完整定义替换)
cur: rowptr[NamedTypeNode] = self.NamedTypeHead
cnt_dedup: int = 0
while cur is not None:
# 步数守卫:NamedTypeHead 链表成环(内存损坏/插入 bug)会导致
# 无限遍历挂起(G3 编译 LinkedNode.prepend 挂起根因)。
# 正常链表节点数远小于此上限,超限即链表损坏 → 立即报错终止。
cnt_dedup += 1
if cnt_dedup > 100000:
stdio.printf("[ANT-LOOP] NamedTypeHead 链表疑似成环, name=%s, 遍历节点=%d, 强制终止\n",
name if name is not None else "(null)", cnt_dedup)
stdlib.exit(1)
if cur.Ty is not None:
existing_name: str = 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: rowptr[NamedTypeNode] = pool.alloc(NAMED_TYPE_NODE_SIZE)
if node is None:
return
string.memset(node, 0, NAMED_TYPE_NODE_SIZE)
node.Ty = ty
node.IsPacked = 0
# 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: str) -> int:
"""检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义"""
if self is None or name is None:
return 0
cur: rowptr[NamedTypeNode] = self.NamedTypeHead
cnt_tdm: int = 0
while cur is not None:
# 步数守卫:同上,防 NamedTypeHead 链表成环无限遍历
cnt_tdm += 1
if cnt_tdm > 100000:
stdio.printf("[TDM-LOOP] NamedTypeHead 链表疑似成环, name=%s, 强制终止\n",
name if name is not None else "(null)")
stdlib.exit(1)
if cur.Ty is not None:
existing_name: str = 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: rowptr[memhub.MemBuddy],
ty: rowptr[LLVMType]):
"""为类型中的跨模块结构体引用添加 opaque 声明
当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时,
如果该名称未在模块中定义,则添加 opaque 声明。
"""
_scan_type_for_cross_module_refs(pool, self, ty)
# ---- 打印 ----
def PrintModule(self, buf: str, size: t.CSizeT,
pool: rowptr[memhub.MemBuddy], mode: int):
"""将模块序列化为 .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: rowptr[Function] = self.FuncHead
func_scan_steps: t.CSizeT = 0
while func_scan is not None:
func_scan_steps += 1
if func_scan_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: module funcs(FuncCount=%zu,dump 终止)\n",
self.FuncCount)
stdlib.exit(1)
if func_scan.RetTy is not None:
self.ensure_opaque_for_type(pool, func_scan.RetTy)
if func_scan.Params is not None:
# [DBGCHAIN] Function.Params 指针合理性护栏(临时诊断,用后移除)
fp_v: t.CUInt64T = t.CUInt64T(func_scan.Params)
if fp_v < 0x10000 or fp_v == t.CUInt64T(0xFFFFFFFFFFFFFFFF) or ((fp_v >> 56) & 0xFF) == 0xFF:
fnp: str = "(nil)"
if func_scan.Name is not None:
fnp = func_scan.Name
stdio.printf("[DBGCHAIN] Function.Params 野值: func=%s func=%llx steps=%zu Params=%llx FuncCount=%zu\n",
fnp, t.CUInt64T(func_scan), func_scan_steps, fp_v, t.CUInt64T(self.FuncCount))
stdio.fflush(None)
stdlib.exit(1)
params_scan: rowptr[GSList[Param]] = func_scan.Params
param_scan: rowptr[Param] = params_scan.Head
param_scan_steps: t.CSizeT = 0
while param_scan is not None:
param_scan_steps += 1
if param_scan_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表异常: func params(函数名=%s,Params.Count=%zu,param=%llu next=%llu,遍历超 %d 步,终止)\n",
func_scan.Name, params_scan.Count,
t.CUInt64T(param_scan), t.CUInt64T(param_scan.Next), IR_DUMP_CHAIN_LIMIT)
stdlib.exit(1)
# [DBGCHAIN] param 指针合理性护栏(临时诊断,用后移除):
# 指针被写坏成小值/全 F 时先打印归属函数与链表状态,再退出
pv_scan: t.CUInt64T = t.CUInt64T(param_scan)
pv_next: t.CUInt64T = 0
if param_scan.Next is not None:
pv_next = t.CUInt64T(param_scan.Next)
if pv_scan < 0x10000 or pv_scan == t.CUInt64T(0xFFFFFFFFFFFFFFFF) or ((pv_scan >> 56) & 0xFF) == 0xFF:
stdio.printf("[DBGCHAIN] param 指针野值: func=%s steps=%zu param=%llx next=%llx Params.Head=%llx Params.Tail=%llx Params.Count=%zu\n",
func_scan.Name, param_scan_steps, pv_scan, pv_next,
t.CUInt64T(params_scan.Head), t.CUInt64T(params_scan.Tail),
t.CUInt64T(params_scan.Count))
stdio.fflush(None)
stdlib.exit(1)
# 用访问器(__function.vp 完整类型内)绕开 stub 字段访问
# 陷阱:跨模块 struct 字段访问可能生成错误 GEP/静默跳过,
# 导致 param_scan 永不更新死循环。
if param_get_ty(param_scan) is not None:
self.ensure_opaque_for_type(pool, param_get_ty(param_scan))
param_scan = param_get_next(param_scan)
func_scan = func_scan.Next
nt: rowptr[NamedTypeNode] = self.NamedTypeHead
# 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够
# 在循环外分配一次并复用,减少 pool 碎片
ty_buf: str = pool.alloc(4096)
nt_steps: t.CSizeT = 0
while nt is not None:
nt_steps += 1
if nt_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: module named types(NamedTypeCount=%zu,dump 终止)\n",
self.NamedTypeCount)
stdlib.exit(1)
if nt.Ty is not None:
if ty_buf is not None:
ty_buf[0] = '\0'
PrintStructDefinition(ty_buf, 4096, nt.Ty, pool, nt.IsPacked)
_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: rowptr[GlobalVariable] = self.GlobalHead
gv_steps: t.CSizeT = 0
if mode == OUTPUT_STUB:
# stub 模式:输出 external global(无初值)
while gv is not None:
gv_steps += 1
if gv_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: module globals stub(GlobalCount=%zu,dump 终止)\n",
self.GlobalCount)
stdlib.exit(1)
_print_global_stub(buf, size, gv, pool)
_append_cstr(buf, size, "\n")
gv = gv.Next
else:
# full 和 text 模式:输出完整全局变量
# text 模式跳过无初值的全局变量(纯声明)
gv_idx: int = 0
while gv is not None:
gv_steps += 1
if gv_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: module globals(GlobalCount=%zu,dump 终止)\n",
self.GlobalCount)
stdlib.exit(1)
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: int = 0
gv2: rowptr[GlobalVariable] = self.GlobalHead
gv2_steps: t.CSizeT = 0
while gv2 is not None:
gv2_steps += 1
if gv2_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: module globals text(GlobalCount=%zu,dump 终止)\n",
self.GlobalCount)
stdlib.exit(1)
if gv2.Initializer is not None:
had_global = 1
break
gv2 = gv2.Next
if had_global != 0:
_append_cstr(buf, size, "\n")
# 遍历函数
func: rowptr[Function] = self.FuncHead
func_idx: int = 0
func_steps: t.CSizeT = 0
while func is not None:
func_steps += 1
if func_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: module funcs print(FuncCount=%zu,dump 终止)\n",
self.FuncCount)
stdlib.exit(1)
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
# ============================================================
# 工厂函数
# ============================================================
def new_module(pool: rowptr[memhub.MemBuddy], name: str) -> rowptr[LLVMModule]:
"""创建一个模块"""
# 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable)
ptr: rowptr[LLVMModule] = pool.alloc(96)
if ptr is None: return None
string.memset(ptr, 0, 96)
ptr.Name = name
ptr.FuncHead = None
ptr.FuncTail = None
ptr.FuncCount = 0
ptr.GlobalHead = None
ptr.GlobalTail = None
ptr.GlobalCount = 0
ptr.TargetTriple = None
ptr.DataLayout = None
ptr.NamedTypeHead = None
ptr.NamedTypeTail = None
ptr.NamedTypeCount = 0
return ptr
# GlobalVariable 硬编码大小: Next(8) + Name(8) + Ty(8) + Initializer(8) + IsConstant(4) + Linkage(8) + Section(8) + UnnamedAddr(4) + Align(4) = 72 字节
GV_SIZE: t.CDefine = 72
# NamedTypeNode 硬编码大小: Next(8) + Ty(8) + IsPacked(8) = 24 字节
NAMED_TYPE_NODE_SIZE: t.CDefine = 24
def new_global_variable(pool: rowptr[memhub.MemBuddy],
name: str, ty: rowptr[LLVMType]) -> rowptr[GlobalVariable]:
"""创建一个全局变量"""
ptr: rowptr[GlobalVariable] = pool.alloc(GV_SIZE)
if ptr is None: return None
string.memset(ptr, 0, GV_SIZE)
ptr.Name = name
ptr.Ty = ty
ptr.Initializer = None
ptr.IsConstant = 0
ptr.Linkage = "external"
ptr.Section = None
ptr.UnnamedAddr = 0
ptr.Align = 0
return ptr
# ============================================================
# 链表操作(嵌入式 Head/Tail/Count,O(1) 追加)
# ============================================================
def module_add_function(mod: rowptr[LLVMModule], func: rowptr[Function]):
mod.add_function(func)
def module_get_func_head(mod: rowptr[LLVMModule]) -> rowptr[Function]:
"""获取模块函数链表头(跨模块访问器,绕 stub 字段访问陷阱)"""
if mod is None:
return None
return mod.FuncHead
def module_add_global(mod: rowptr[LLVMModule], gv: rowptr[GlobalVariable]):
mod.add_global(gv)
def module_set_target(mod: rowptr[LLVMModule], triple: str):
mod.set_target(triple)
def module_set_datalayout(mod: rowptr[LLVMModule], layout: str):
mod.set_datalayout(layout)
# ============================================================
# 命名结构体类型管理
# ============================================================
# ============================================================
# _is_opaque_struct - 检查类型是否是 opaque 结构体
#
# opaque 结构体特征: Struct 类型,fcount == -1(哨兵标记,跨模块前向
# 声明,仅名称无字段定义)。通过 Struct(pool, None, -1, name) 创建,
# IR 输出为 %"name" = type opaque。注意区分空结构体(fcount==0,
# fields==None,无字段类)——它是合法完整定义(= type {},可 alloca)。
# 用于在 module_add_named_type 中区分 opaque 声明和完整定义,
# 确保 opaque 声明插入链表头部(在使用之前声明)。
#
# Returns: 1=是 opaque / 0=否
# ============================================================
def _is_opaque_struct(ty: rowptr[LLVMType]) -> int:
"""检查类型是否是 opaque 结构体
opaque 是跨模块前向声明(仅名称无字段定义),由
_scan_type_for_cross_module_refs 创建,fcount=-1 哨兵标记。
空结构体(fcount==0, fields==None,无字段类)是合法完整定义
(LLVM {} 类型,可 alloca),必须与 opaque 区分——此前混淆导致
空类结构体被输出为 "= type opaque",alloca 报 Cannot allocate
unsized type。
"""
if ty is None:
return 0
match ty:
case LLVMType.Struct(fields, fcount, name):
# opaque: fcount == -1(哨兵)
if fcount < 0:
return 1
return 0
case _:
return 0
def module_add_named_type(mod: rowptr[LLVMModule], pool: rowptr[memhub.MemBuddy],
ty: rowptr[LLVMType]):
mod.add_named_type(pool, ty)
def module_set_named_type_packed(mod: rowptr[LLVMModule], pool: rowptr[memhub.MemBuddy],
ty: rowptr[LLVMType], is_packed: int):
"""按名称设置命名结构体的 packed 标记(输出 %"name" = type <{...}>)。
编译器解析 @c.Attribute(t.attr.packed) 后调用,使 llc 按 packed 布局
(无字段填充)计算字段偏移/GEP。ty 为命名 Struct 类型(按 get_struct_name
定位已注册节点);未找到则静默跳过(opaque/跨模块 stub 场景无布局需求)。
"""
if mod is None or ty is None:
return
name: str = get_struct_name(ty)
if name is None:
return
cur: rowptr[NamedTypeNode] = mod.NamedTypeHead
cnt_p: int = 0
while cur is not None:
cnt_p += 1
if cnt_p > 100000:
return
if cur.Ty is not None:
existing_name: str = get_struct_name(cur.Ty)
if existing_name is not None and string.strcmp(existing_name, name) == 0:
cur.IsPacked = is_packed
return
cur = cur.Next
# ============================================================
# module_ensure_opaque_for_type - 为类型中的跨模块结构体引用添加 opaque 声明
#
# 递归扫描 LLVMType 树,当遇到 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时,
# 如果该名称未在模块中定义,则添加 opaque 声明(%"name" = type opaque)。
# 这解决了跨模块结构体引用导致的 llc "use of undefined type" 错误。
# ============================================================
def _is_type_defined_in_module(mod: rowptr[LLVMModule], name: str) -> int:
return mod._is_type_defined_in_module(name)
def _scan_type_for_cross_module_refs(pool: rowptr[memhub.MemBuddy],
mod: rowptr[LLVMModule],
ty: rowptr[LLVMType],
depth: int = 0):
"""递归扫描类型树,为跨模块结构体引用添加 opaque 声明"""
if ty is None or mod is None or pool is None:
return
# 深度守卫:自引用结构体(链表/树节点,如 Node{...; Ptr(Node) next})
# 会无限递归栈溢出,与其他递归(TypePrint/DeepCopyType)一致设上限
if depth >= 100:
return
match ty:
case LLVMType.Ptr(pointee):
if pointee is not None:
match pointee:
case LLVMType.Struct(sfields, sfcount, sname):
if sname is not None:
# 检查是否为跨模块引用(名称包含 '.')
if string.strchr(sname, 46) is not None:
# 检查是否已在模块中定义
if _is_type_defined_in_module(mod, sname) == 0:
# 创建 opaque 类型并添加到模块
# fcount=-1 哨兵标记 opaque(区别于空结构体 {},
# 后者 fcount==0 是合法完整定义,可 alloca)
opaque_ty: rowptr[LLVMType] = Struct(pool, None, -1, sname)
if opaque_ty is not None:
module_add_named_type(mod, pool, opaque_ty)
# 递归扫描结构体字段中的跨模块引用
# 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用
if sfields is not None:
fld: rowptr[ParamNode] = sfields
fld_steps: t.CSizeT = 0
while fld is not None:
fld_steps += 1
if fld_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: struct fields(sname=%s,dump 终止)\n",
sname)
stdlib.exit(1)
if fld.Ty is not None:
_scan_type_for_cross_module_refs(pool, mod, fld.Ty, depth + 1)
fld = fld.Next
case _:
_scan_type_for_cross_module_refs(pool, mod, pointee, depth + 1)
case LLVMType.Struct(sfields2, sfcount2, sname2):
# 顶层结构体(非指针):递归扫描字段
if sfields2 is not None:
fld2: rowptr[ParamNode] = sfields2
fld2_steps: t.CSizeT = 0
while fld2 is not None:
fld2_steps += 1
if fld2_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: struct fields2(sname=%s,dump 终止)\n",
sname2)
stdlib.exit(1)
if fld2.Ty is not None:
_scan_type_for_cross_module_refs(pool, mod, fld2.Ty, depth + 1)
fld2 = fld2.Next
case LLVMType.Array(elem_ty, acount):
if elem_ty is not None:
_scan_type_for_cross_module_refs(pool, mod, elem_ty, depth + 1)
case _:
pass
def module_ensure_opaque_for_type(mod: rowptr[LLVMModule],
pool: rowptr[memhub.MemBuddy],
ty: rowptr[LLVMType]):
mod.ensure_opaque_for_type(pool, ty)
# ============================================================
# 全局变量属性设置
# ============================================================
def global_set_constant(gv: rowptr[GlobalVariable], is_const: int):
"""设置全局变量是否为常量"""
if gv is None: return
gv.IsConstant = is_const
def global_set_linkage(gv: rowptr[GlobalVariable], linkage: str):
"""设置链接类型 (private/internal/external/... )"""
if gv is None: return
gv.Linkage = linkage
def global_set_unnamed_addr(gv: rowptr[GlobalVariable], level: int):
"""设置 unnamed_addr 属性 (0=none, 1=unnamed_addr, 2=local_unnamed_addr)"""
if gv is None: return
gv.UnnamedAddr = level
def global_set_section(gv: rowptr[GlobalVariable], section: str):
"""设置段名"""
if gv is None: return
gv.Section = section
# ============================================================
# 输出模式常量
# ============================================================
OUTPUT_FULL: t.CDefine = 0 # 完整 IR(stub + text)
OUTPUT_STUB: t.CDefine = 1 # 仅声明(header + 类型定义 + declare + external global)
OUTPUT_TEXT: t.CDefine = 2 # 仅代码(define + global 带初值)
# dump 哨兵:IR 链表遍历步数上限(成环检测,fail-fast)。
# 任何一条链(函数/全局/命名类型/结构体字段)的 Next 被越界写破坏成环时,
# 遍历会无限循环导致 tpv.exe 挂起(builtins.vp dump 卡死根因排查)。
# 超过上限即打印链表名并 exit(1),把"卡死"变成"确定性报错定位"
# (对齐 memhub.self_check 的 max_steps 哲学)。
IR_DUMP_CHAIN_LIMIT: t.CDefine = 100000
# ============================================================
# LLVMModulePrint: 将模块序列化为 .ll 文本
#
# mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码
# ============================================================
def LLVMModulePrint(buf: str, size: t.CSizeT,
mod: rowptr[LLVMModule], pool: rowptr[memhub.MemBuddy],
mode: int):
mod.PrintModule(buf, size, pool, mode)
# ============================================================
# 全局变量打印
# ============================================================
def _print_global(buf: str, size: t.CSizeT,
gv: rowptr[GlobalVariable], pool: rowptr[memhub.MemBuddy]):
"""打印单个全局变量: @<name> = [linkage] [unnamed_addr] [constant] <ty> <init>"""
if gv is None: return
_append_cstr(buf, size, "@")
if gv.Name is not None:
if _ll_name_needs_quote(gv.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, " = ")
# 链接类型(有初始值时不输出 external,因为 external + 初始值是非法 IR)
if gv.Linkage is not None:
if gv.Initializer is not None and string.strcmp(gv.Linkage, "external") == 0:
pass
else:
_append_cstr(buf, size, gv.Linkage)
_append_cstr(buf, size, " ")
# unnamed_addr
if gv.UnnamedAddr == 1:
_append_cstr(buf, size, "unnamed_addr ")
elif gv.UnnamedAddr == 2:
_append_cstr(buf, size, "local_unnamed_addr ")
# constant / global
if gv.IsConstant == 1:
_append_cstr(buf, size, "constant ")
else:
_append_cstr(buf, size, "global ")
# 类型
ty_buf: str = pool.alloc(512)
if ty_buf is not None:
ty_buf[0] = '\0'
TypePrint(ty_buf, 512, gv.Ty, pool)
_append_cstr(buf, size, ty_buf)
# 初始化值
if gv.Initializer is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, gv.Initializer)
# 段名
if gv.Section is not None:
_append_cstr(buf, size, ", section \"")
_append_cstr(buf, size, gv.Section)
_append_cstr(buf, size, "\"")
# 对齐(@c.Attribute(t.attr.aligned(N)) 类的全局实例,如 fpu_context 16 对齐)
if gv.Align > 0:
align_buf: str = pool.alloc(32)
if align_buf is not None:
viperlib.snprintf(align_buf, 32, ", align %d", gv.Align)
_append_cstr(buf, size, align_buf)
# ============================================================
# _print_global_stub - 打印全局变量的声明形式(external global,无初值)
# ============================================================
def _print_global_stub(buf: str, size: t.CSizeT,
gv: rowptr[GlobalVariable], pool: rowptr[memhub.MemBuddy]):
"""打印全局变量声明: @<name> = external global <ty>"""
if gv is None: return
_append_cstr(buf, size, "@")
if gv.Name is not None:
if _ll_name_needs_quote(gv.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, " = external global ")
# 类型
ty_buf: str = pool.alloc(512)
if ty_buf is not None:
ty_buf[0] = '\0'
TypePrint(ty_buf, 512, gv.Ty, pool)
_append_cstr(buf, size, ty_buf)
# ============================================================
# 内部辅助
# ============================================================
# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位,
# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。
# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。
_g_last_dst: t.CUInt64T = 0
_g_last_pos: t.CSizeT = 0
def _append_cstr(dst: str, dst_size: t.CSizeT, src: str):
"""将 C 字符串 src 追加到 dst 末尾"""
global _g_last_dst, _g_last_pos
if dst is None or src is None: return
dlen: t.CSizeT = 0
if _g_last_dst == t.CUInt64T(dst):
dlen = _g_last_pos
# 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部
if dlen > 0 and dst[0] == '\0':
dlen = 0
else:
dlen = string.strlen(dst)
_g_last_dst = t.CUInt64T(dst)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外
if dlen >= dst_size:
return
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
_g_last_pos = dlen + i