Files
Viper_VRTE/llvmlite/__function.vp
T
TermiNexus 62bceb6930 debug(chain): Renumber block 野值打印扩展为邻域快照(Params/Blocks/容器指针)
[DBGCHAIN] block 野值时一并输出 func.Params(Head/Tail/Count)、Blocks 容器/Tail/Count、func 指针,便于定位写入源。用后移除。
2026-09-05 15:04:46 +08:00

1015 lines
40 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 viperlib
import memhub
import stdio
import stdlib
from linkedlist import GSListNode, GSList
from .__types import LLVMType, ParamNode, TypePrint
# dump 哨兵:IR 链表遍历步数上限(成环检测,fail-fast,与 __module.vp 对齐)。
# 函数/基本块/指令行链的 Next 被越界写破坏成环时,遍历无限循环挂起;
# 超过上限即打印链表名并 exit(1),把"卡死"变成"确定性报错定位"。
IR_DUMP_CHAIN_LIMIT: t.CDefine = 100000
# ============================================================
# Line: 指令文本行
#
# 每条 LLVM IR 指令序列化为一行文本,通过链表组织。
# 继承 GSListNode[Line] 获取强类型 Next: Line|CPtr
#
# 注意: 必须加 @t.NoVTable。否则 TransPyC 为子类添加 vtable 指针(T*),
# 但完全丢失父类 GSListNode[T] 的 Next 字段,导致 struct 布局错位,
# 所有字段访问读取垃圾值(见续 XV 会话根因分析)。
# ============================================================
@t.NoVTable
class Line(GSListNode[Line]):
Buf: str # 行文本(NUL 结尾)
Len: t.CSizeT # 文本长度(不含 NUL)
# ============================================================
# BasicBlock: 基本块
#
# 持有名称 + 指令行链表 + 终止指令标志。
# 继承 GSListNode[BasicBlock] 获取强类型 Next: BasicBlock|CPtr
# Lines 为 GSList[Line] 指针,提供 O(1) 追加。
#
# 注意: 必须加 @t.NoVTable(理由同 Line)。
# ============================================================
@t.NoVTable
class BasicBlock(GSListNode[BasicBlock]):
Name: str # 块名(如 "entry"/"if.then")
Lines: rowptr[GSList[Line]] # 指令行链表容器(Head/Tail/Count)
IsTerminated: int # 1=已有终止指令(br/ret)
# ============================================================
# Param: 函数参数
#
# 继承 GSListNode[Param] 获取强类型 Next: Param|CPtr
# Attrs 存储参数属性文本(如 "noundef"/"nocapture"/"readonly"),None=无属性
#
# 注意: 必须加 @t.NoVTable(理由同 Line)。
# ============================================================
@t.NoVTable
class Param(GSListNode[Param]):
Ty: rowptr[LLVMType] # 参数类型
Name: str # 参数名(如 "%0"/"%a")
Attrs: str # 参数属性文本(None=无属性)
# ============================================================
# Function: 函数
#
# 持有名称 + 返回类型 + 参数链表 + 基本块链表。
# 继承 GSListNode[Function] 获取强类型 Next: Function|CPtr
# Params/Blocks 为 GSList 指针,提供 O(1) 追加。
# Attrs 存储函数级属性文本(如 "nounwind"/"noinline"),None=无属性
#
# 注意: 必须加 @t.NoVTable(理由同 Line)。
# ============================================================
@t.NoVTable
class Function(GSListNode[Function]):
Name: str # 函数名
RetTy: rowptr[LLVMType] # 返回类型
Params: rowptr[GSList[Param]] # 参数链表容器
Blocks: rowptr[GSList[BasicBlock]] # 基本块链表容器
IsDeclared: int # 1=仅声明(declare), 0=定义(define)
IsVarArg: int # 1=变参函数(...)
Attrs: str # 函数属性文本(None=无属性)
AttrGroup: str # 字符串属性组内容(如 '"section"=".text.startup"',None=无)
AttrGroupId: int # 属性组编号(>0 时函数行输出 #N,模块尾输出 attributes #N)
# ============================================================
# 工厂函数
# ============================================================
# Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节
LINE_SIZE: t.CDefine = 24
def new_line(pool: rowptr[memhub.MemBuddy], text: str) -> rowptr[Line]:
"""创建一个指令行,复制 text 到新分配的缓冲区"""
ptr: rowptr[Line] = pool.alloc(LINE_SIZE)
if ptr is None: return None
string.memset(ptr, 0, LINE_SIZE)
if text is not None:
slen: t.CSizeT = string.strlen(text)
buf: str = pool.alloc(slen + 1)
if buf is not None:
string.strcpy(buf, text)
ptr.Buf = buf
ptr.Len = slen
return ptr
def _new_gslist(pool: rowptr[memhub.MemBuddy], list_size: t.CSizeT) -> t.CPtr:
"""从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)"""
gsl: t.CPtr = pool.alloc(list_size)
if gsl is None: return None
string.memset(gsl, 0, list_size)
return gsl
# BasicBlock 硬编码大小: Next(8) + Name(8) + Lines(8) + IsTerminated(4) = 32 字节
BLOCK_SIZE: t.CDefine = 32
def new_basic_block(pool: rowptr[memhub.MemBuddy], name: str) -> rowptr[BasicBlock]:
"""创建一个基本块"""
ptr: rowptr[BasicBlock] = pool.alloc(BLOCK_SIZE)
if ptr is None: return None
string.memset(ptr, 0, BLOCK_SIZE)
ptr.Name = name
ptr.Lines = _new_gslist(pool, 24) # GSList: Head+Tail+Count
ptr.IsTerminated = 0
return ptr
# Param 硬编码大小: Next(8) + Ty(8) + Name(8) + Attrs(8) = 32 字节
PARAM_SIZE: t.CDefine = 32
def new_param(pool: rowptr[memhub.MemBuddy], ty: rowptr[LLVMType],
name: str) -> rowptr[Param]:
"""创建一个函数参数"""
ptr: rowptr[Param] = pool.alloc(PARAM_SIZE)
if ptr is None: return None
string.memset(ptr, 0, PARAM_SIZE)
ptr.Ty = ty
ptr.Name = name
ptr.Attrs = None
return ptr
# Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) + AttrGroup(8) + AttrGroupId(8) = 72 字节
FUNC_SIZE: t.CDefine = 72
def new_function(pool: rowptr[memhub.MemBuddy], name: str,
ret_ty: rowptr[LLVMType]) -> rowptr[Function]:
"""创建一个函数"""
ptr: rowptr[Function] = pool.alloc(FUNC_SIZE)
if ptr is None: return None
string.memset(ptr, 0, FUNC_SIZE)
ptr.Name = name
ptr.RetTy = ret_ty
ptr.Params = _new_gslist(pool, 24) # GSList: Head+Tail+Count
ptr.Blocks = _new_gslist(pool, 24)
ptr.IsDeclared = 0
ptr.Attrs = None
ptr.AttrGroup = None
ptr.AttrGroupId = 0
return ptr
# ============================================================
# 链表操作(委托 GSList.append)
# ============================================================
def function_add_param(func: rowptr[Function], param: rowptr[Param]):
"""将参数追加到函数参数链表"""
if func is None or param is None: return
# 注意:必须先用局部变量 + 类型参数(对齐 function_move_block_to_end 注释),
# 链式 func.Params.append() 会被编译器解析成 LinkedNode.append 且 this 前移
# sizeof(LinkedNode)(兄弟 Mixin 兜底误匹配),写穿容器前 48 字节破坏数据结构。
params: rowptr[GSList[Param]] = func.Params
if params is None: return
params.append(param)
def function_add_block(func: rowptr[Function], block: rowptr[BasicBlock]):
"""将基本块追加到函数块链表"""
if func is None or block is None: return
blocks: rowptr[GSList[BasicBlock]] = func.Blocks
if blocks is None: return
blocks.append(block)
def function_move_block_to_end(func: rowptr[Function], block: rowptr[BasicBlock]):
"""将 block 移动到函数块链表末尾(保证 BB 文本顺序与控制流顺序一致)。
用于解决 SSA 名非单调问题:BB 按创建顺序排列,但指令按控制流顺序生成,
导致 SSA 编号在文本输出时非单调递增,llc 报错。
在 position_at_end 时调用此函数,使 BB 顺序与 position 顺序一致。
注意:必须使用 GSList[BasicBlock] 带类型参数,否则 TransPyC 创建不完整
struct 类型,导致 blocks.Head/Tail/Count 字段访问读取垃圾值。
"""
if func is None or block is None: return
blocks: rowptr[GSList[BasicBlock]] = func.Blocks
if blocks is None: return
# 已经是 Tail,无需移动
if blocks.Tail is block:
return
# 从链表中移除 block
if blocks.Head is block:
# block 是 Head,直接后移 Head
blocks.Head = block.Next
else:
# 遍历找前驱
prev: rowptr[BasicBlock] = blocks.Head
while prev is not None and prev.Next is not block:
prev = prev.Next
if prev is None:
# block 不在链表中,直接 append
blocks.append(block)
return
prev.Next = block.Next
# block.Next 由移除逻辑处理,重置为 None
block.Next = None
# append 到末尾(不调用 blocks.append 以避免 Count 重复递增)
if blocks.Tail is not None:
blocks.Tail.Next = block
blocks.Tail = block
def block_append_line(block: rowptr[BasicBlock], line: rowptr[Line]):
"""将指令行追加到基本块"""
if block is None or line is None: return
lines: rowptr[GSList[Line]] = block.Lines
if lines is None: return
lines.append(line)
def block_set_terminated(block: rowptr[BasicBlock], val: int):
"""设置块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)"""
if block is None: return
block.IsTerminated = val
def block_get_terminated(block: rowptr[BasicBlock]) -> int:
"""获取块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)"""
if block is None:
return 1
return block.IsTerminated
def block_append_text(pool: rowptr[memhub.MemBuddy], block: rowptr[BasicBlock],
text: str):
"""创建指令行并追加到基本块"""
if block is None or text is None: return
line: rowptr[Line] = new_line(pool, text)
if line is not None:
block_append_line(block, line)
def block_insert_text_before_terminator(pool: rowptr[memhub.MemBuddy],
block: rowptr[BasicBlock],
text: str):
"""创建指令行并插入到基本块终止指令之前
如果块未终止,追加到末尾。
如果块已终止(有 br/ret),在终止指令之前插入,确保 alloca 等指令
不出现在终止指令之后。
"""
if block is None or text is None: return
if block.Lines is None: return
line: rowptr[Line] = new_line(pool, text)
if line is None: return
# 块未终止:直接追加
if block.IsTerminated == 0:
block_append_line(block, line)
return
# 块已终止:在 Tail(终止指令)之前插入
lines: rowptr[GSList[Line]] = block.Lines
if lines.Head is None:
block_append_line(block, line)
return
# 只有一个节点:在 Head 之前插入
if lines.Head is lines.Tail:
line.Next = lines.Head
lines.Head = line
lines.Count += 1
return
# 找到 Tail 的前驱节点
prev: rowptr[Line] = lines.Head
while prev is not None and prev.Next is not lines.Tail:
prev = prev.Next
if prev is None:
# 找不到前驱,回退到追加
block_append_line(block, line)
return
# 在 prev 和 Tail 之间插入 line
line.Next = lines.Tail
prev.Next = line
lines.Count += 1
# ============================================================
# 属性设置
# ============================================================
def function_set_attrs(func: rowptr[Function], attrs: str):
"""设置函数级属性文本(如 "nounwind"/"noinline")"""
if func is None: return
func.Attrs = attrs
_g_attr_group_counter: int = 0
def function_set_attr_group(func: rowptr[Function], group: str):
"""设置函数字符串属性组(如 '"section"=".text.startup"')并分配组编号 #N。
LLVM 字符串属性(带值的,如 section)不能内联在函数签名行,
必须用属性组:函数行输出 #N,组定义输出在函数尾。
"""
global _g_attr_group_counter
if func is None or group is None:
return
func.AttrGroup = group
_g_attr_group_counter += 1
func.AttrGroupId = _g_attr_group_counter
def param_set_attrs(param: rowptr[Param], attrs: str):
"""设置参数属性文本(如 "noundef"/"nocapture"/"readonly")"""
if param is None: return
param.Attrs = attrs
# ============================================================
# _ll_name_needs_quote - 检查 LLVM 标识符是否需要加引号
#
# LLVM IR 规范:标识符合法字符集为 [-a-zA-Z$._][-a-zA-Z$._0-9]*
# 以数字开头或含非合法字符(如 '['、']'、' '、'@' 等)时必须用双引号包围。
# '.' 是合法字符,不需要加引号(如 @.str、@llvm.memcpy 都不加引号)。
# SHA1 命名空间的函数名(如 "4dad2ba72ed7ba09.GSListNode[Param]")含 '['、']',
# 需要加引号;但纯 hex+点 的名字(如 "abc.def")不需要。
# ============================================================
def _ll_name_needs_quote(name: str) -> int:
"""检查 LLVM 标识符是否需要加引号(以数字开头或含非合法字符)
LLVM IR 合法字符:a-z, A-Z, 0-9, -, $, ., _
首字符是数字时需要加引号(LLVM 要求局部/全局标识符首字符非数字,除非加引号)。
含其他字符(如 '['、']'、空格)时需要加引号。
"""
if name is None:
return 0
c0: t.CChar = name[0]
if c0 >= '0' and c0 <= '9':
return 1
name_len: t.CSizeT = string.strlen(name)
i: t.CSizeT = 0
while i < name_len:
ch: t.CChar = name[i]
# 合法字符:a-z, A-Z, 0-9, -, $, ., _
if not ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or
(ch >= '0' and ch <= '9') or ch == '-' or ch == '$' or
ch == '.' or ch == '_'):
return 1
i += 1
return 0
# ============================================================
# RenumberSSA: 重编号函数内数字 SSA 名
#
# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致
# SSA 名在文本输出中非单调递增的问题(llc 报错:
# "instruction expected to be numbered '%N' or greater")。
#
# 现象: entry 块原指令 %0-%6 + br,alloca_at_entry 插入 %28/%41 到 br 之前,
# 文本输出顺序为 entry(%0..%6, %28, %41) → if.then(%7..%27),
# 导致 %28 出现在 %7 之前,llc 拒绝编译。
#
# 算法:
# 1. 扫描所有 BB 指令行,按文本输出顺序收集数字 SSA 名 %N
# 2. 按首次出现顺序建立 old→new 映射(从 0 递增)
# 3. 替换所有指令行文本中的 %N 为新编号
#
# 注意:
# - 仅重编号纯数字 SSA 名(%0, %1, ...)
# - 命名 SSA 名(%entry, %.tmp, %self)、块标签、全局符号 @N 不重编号
# - 仅对 define(有函数体)调用,declare 无函数体无需处理
# - 当前 TransPyV 参数多为命名(%self/%env/%n),非数字,无需重编号参数
# ============================================================
# 判定字符是否为十进制数字
def _is_digit_ch(ch: t.CChar) -> int:
"""判断字符是否是 '0'-'9'
ch 是值类型 (t.CChar = i8),TPC 已修复值类型 is None 处理:
值类型 is None 恒为 false(生成 i1 0 常量),不会解引用空指针。
"""
if ch is None:
return 0
if ch >= '0' and ch <= '9':
return 1
return 0
# ============================================================
# i32 数组的安全访问(显式字节偏移)
#
# TransPyC 的 ptr[i] 指针索引可能被当作字节索引(i8*)而非 i32* 索引,
# 导致内存损坏。必须显式计算字节偏移:addr = base + idx * 4,再转型为 i32*。
# 参见 HandlesTranslator.py:358 的 t.CUInt64T(ptr) + offset * sizeof 用法。
# ============================================================
def _map_get_i32(map_arr: str, idx: int) -> int:
"""读取 i32 数组 map_arr[idx](显式字节偏移 idx*4)
使用 (rowptr[int])(uint64) 强转将字节偏移转为 i32*,再用 c.Deref 解引用。
TPC 已修复类型联合强转(_HandleTypeUnionCastLlvm 添加 fallback),此写法可用。
"""
if map_arr is None:
return -1
byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4
elem_ptr: rowptr[int] = (rowptr[int])(byte_off)
return c.Deref(elem_ptr)
def _map_set_i32(map_arr: str, idx: int, val: int):
"""写入 map_arr[idx] = val(i32 数组,显式字节偏移 idx*4)
使用 (rowptr[int])(uint64) 强转 + c.DerefAs 解引用赋值。
TPC 已修复类型联合强转,此写法可用。
"""
if map_arr is None:
return
byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4
elem_ptr: rowptr[int] = (rowptr[int])(byte_off)
c.DerefAs(elem_ptr, val)
def _scan_max_ssa_in_text(text: str, cur_max: int) -> int:
"""扫描文本,找出 %N(N 为数字)中最大的 N,与 cur_max 比较返回更大值
仅匹配 '%' 后紧跟数字的情况,跳过命名 SSA 名(%entry 等)。
"""
result: int = cur_max
p: str = text
while p is not None and p[0] != '\0':
if p[0] == '%':
nxt: str = p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: int = string.atoi(nxt)
if num > result:
result = num
p = p + 1
return result
def _find_max_ssa_number(func: rowptr[Function]) -> int:
"""遍历所有 BB 指令行,找出最大的 %N 数字;无数字 SSA 名返回 -1"""
max_n: int = -1
if func is None or func.Blocks is None:
return max_n
blk: rowptr[BasicBlock] = func.Blocks.Head
blk_steps: t.CSizeT = 0
while blk is not None:
blk_steps += 1
if blk_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 扫描终止)\n", func.Name)
stdlib.exit(1)
if blk.Lines is not None:
line: rowptr[Line] = blk.Lines.Head
line_steps: t.CSizeT = 0
while line is not None:
line_steps += 1
if line_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 扫描终止)\n",
func.Name, blk.Name)
stdlib.exit(1)
if line.Buf is not None:
max_n = _scan_max_ssa_in_text(line.Buf, max_n)
line = line.Next
blk = blk.Next
return max_n
def _assign_new_numbers(text: str,
map_arr: str,
max_n: int, next_new: int) -> int:
"""扫描文本,对每个 %N(数字),若 map_arr[N]==-1 则分配 next_new
返回更新后的 next_new。按文本首次出现顺序建立映射。
"""
result: int = next_new
p: str = text
while p is not None and p[0] != '\0':
if p[0] == '%':
nxt: str = p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: int = string.atoi(nxt)
if num >= 0 and num <= max_n:
if _map_get_i32(map_arr, num) == -1:
_map_set_i32(map_arr, num, result)
result += 1
p = p + 1
return result
def _replace_ssa_numbers(text: str,
pool: rowptr[memhub.MemBuddy],
map_arr: str,
max_n: int) -> str:
"""构建新文本,将 %N 替换为映射后的新编号
逐字符扫描:遇到 %N(数字)查映射表替换,其他字符原样复制。
返回新分配的缓冲区(调用方无需释放旧 Buf,pool 统一管理)。
"""
src_len: t.CSizeT = string.strlen(text)
# 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64
new_size: t.CSizeT = src_len * 2 + 64
new_buf: str = pool.alloc(new_size)
if new_buf is None:
return None
# 一次性分配数字缓冲区(循环中复用)
num_buf: str = pool.alloc(16)
if num_buf is None:
new_buf[0] = '\0'
return new_buf
dst_idx: t.CSizeT = 0
src_p: str = text
while src_p is not None and src_p[0] != '\0':
if dst_idx + 16 >= new_size:
# 缓冲区不足,截断
break
if src_p[0] == '%':
nxt: str = src_p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: int = string.atoi(nxt)
# 先做范围检查再读 map_arr:num 超 max_n 时 map_arr 只有
# (max_n+1)*4 字节,先读后查会越界读远端内存
if num >= 0 and num <= max_n:
new_num: int = _map_get_i32(map_arr, num)
if new_num != -1:
# 写入 '%'
new_buf[dst_idx] = '%'
dst_idx += 1
# 写入新编号
num_buf[0] = '\0'
viperlib.snprintf(num_buf, 16, "%d", new_num)
k: t.CSizeT = 0
while num_buf[k] != '\0' and dst_idx + 1 < new_size:
new_buf[dst_idx] = num_buf[k]
dst_idx += 1
k += 1
# 跳过旧数字字符
src_p = src_p + 1
while src_p is not None and _is_digit_ch(src_p[0]) != 0:
src_p = src_p + 1
continue
# 普通字符:直接复制
new_buf[dst_idx] = src_p[0]
dst_idx += 1
src_p = src_p + 1
new_buf[dst_idx] = '\0'
return new_buf
def RenumberSSA(func: rowptr[Function], pool: rowptr[memhub.MemBuddy]):
"""重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增
在 FunctionPrint 序列化函数体之前调用。
仅对 define(IsDeclared==0)且 Blocks 非空 的函数生效。
"""
if func is None or pool is None:
return
if func.IsDeclared == 1:
return # declare 无函数体
if func.Blocks is None:
return
# [DBGCHAIN] RenumberSSA 前全链验证(临时诊断,用后移除):定位
# Blocks/Lines/line.Buf 被写坏的归属函数
blk_v: rowptr[BasicBlock] = func.Blocks.Head
blk_vs: t.CSizeT = 0
while blk_v is not None:
blk_vs += 1
if blk_vs > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[DBGCHAIN] RenumberSSA blocks 成环: func=%s blocks=%llu\n",
func.Name if func.Name is not None else "(nil)", t.CUInt64T(blk_vs))
stdio.fflush(None)
stdlib.exit(1)
bv: t.CUInt64T = t.CUInt64T(blk_v)
if bv < 0x10000 or bv == t.CUInt64T(0xFFFFFFFFFFFFFFFF) or ((bv >> 56) & 0xFF) == 0xFF:
fp_v: t.CUInt64T = 0
if func.Params is not None:
fp_v = t.CUInt64T(func.Params)
fh_v: t.CUInt64T = 0
if func.Params is not None and func.Params.Head is not None:
fh_v = t.CUInt64T(func.Params.Head)
ft_v: t.CUInt64T = 0
if func.Params is not None and func.Params.Tail is not None:
ft_v = t.CUInt64T(func.Params.Tail)
fc_v: t.CUInt64T = 0
if func.Params is not None:
fc_v = t.CUInt64T(func.Params.Count)
bb_v: t.CUInt64T = 0
if func.Blocks is not None:
bb_v = t.CUInt64T(func.Blocks)
bt_v: t.CUInt64T = 0
if func.Blocks is not None and func.Blocks.Tail is not None:
bt_v = t.CUInt64T(func.Blocks.Tail)
bc_v: t.CUInt64T = 0
if func.Blocks is not None:
bc_v = t.CUInt64T(func.Blocks.Count)
stdio.printf("[DBGCHAIN] RenumberSSA block 野值: func=%s func=%llx blocks=%llx Params=%llx(PH=%llx PT=%llx PC=%llu) block=%llx BTail=%llx BCount=%llu steps=%llu\n",
func.Name if func.Name is not None else "(nil)",
t.CUInt64T(func), bb_v,
fp_v, fh_v, ft_v, fc_v,
bv, bt_v, bc_v, t.CUInt64T(blk_vs))
stdio.fflush(None)
stdlib.exit(1)
if blk_v.Lines is not None:
ln_v: rowptr[Line] = blk_v.Lines.Head
ln_vs: t.CSizeT = 0
while ln_v is not None:
ln_vs += 1
if ln_vs > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[DBGCHAIN] RenumberSSA lines 成环: func=%s block=%s lines=%llu\n",
func.Name if func.Name is not None else "(nil)",
blk_v.Name if blk_v.Name is not None else "(nil)", t.CUInt64T(ln_vs))
stdio.fflush(None)
stdlib.exit(1)
lv: t.CUInt64T = t.CUInt64T(ln_v)
if lv < 0x10000 or lv == t.CUInt64T(0xFFFFFFFFFFFFFFFF) or ((lv >> 56) & 0xFF) == 0xFF:
stdio.printf("[DBGCHAIN] RenumberSSA line 野值: func=%s block=%s steps=%llu line=%llx\n",
func.Name if func.Name is not None else "(nil)",
blk_v.Name if blk_v.Name is not None else "(nil)", t.CUInt64T(ln_vs), lv)
stdio.fflush(None)
stdlib.exit(1)
if ln_v.Buf is not None:
lbv: t.CUInt64T = t.CUInt64T(ln_v.Buf)
if lbv < 0x10000 or lbv == t.CUInt64T(0xFFFFFFFFFFFFFFFF) or ((lbv >> 56) & 0xFF) == 0xFF:
stdio.printf("[DBGCHAIN] RenumberSSA line.Buf 野值: func=%s block=%s steps=%llu line=%llx buf=%llx len=%llu\n",
func.Name if func.Name is not None else "(nil)",
blk_v.Name if blk_v.Name is not None else "(nil)", t.CUInt64T(ln_vs), lv, lbv,
t.CUInt64T(ln_v.Len))
stdio.fflush(None)
stdlib.exit(1)
if ln_v.Len > 0x100000:
stdio.printf("[DBGCHAIN] RenumberSSA line.Len 异常: func=%s len=%llu buf=%llx\n",
func.Name if func.Name is not None else "(nil)",
t.CUInt64T(ln_v.Len), lbv)
stdio.fflush(None)
stdlib.exit(1)
ln_v = ln_v.Next
blk_v = blk_v.Next
# 1. 第一遍扫描:找出最大 SSA 编号
max_n: int = _find_max_ssa_number(func)
if max_n < 0:
return # 无数字 SSA 名
# 2. 分配并初始化映射数组 map_arr[0..max_n] = -1
# 用 i8* 存储(pool.alloc 返回 i8*),通过 _map_get_i32/_map_set_i32 访问。
# 初始化为 -1:每个 i32 元素 4 字节,0xFFFFFFFF = -1(有符号 i32)。
# 用 memset 一次性填充,避免循环内 ptr[i] 指针索引问题。
map_bytes: t.CSizeT = (max_n + 1) * 4 # int = 4 字节
map_arr: str = pool.alloc(map_bytes)
if map_arr is None:
return
string.memset(map_arr, 0xFF, map_bytes) # 0xFF * 4 = 0xFFFFFFFF = -1
# 3. 第二遍扫描:按文本顺序分配新编号
next_new: int = 0
blk: rowptr[BasicBlock] = func.Blocks.Head
blk_steps: t.CSizeT = 0
while blk is not None:
blk_steps += 1
if blk_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 重编号终止)\n", func.Name)
stdlib.exit(1)
if blk.Lines is not None:
line: rowptr[Line] = blk.Lines.Head
line_steps: t.CSizeT = 0
while line is not None:
line_steps += 1
if line_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 重编号终止)\n",
func.Name, blk.Name)
stdlib.exit(1)
if line.Buf is not None:
next_new = _assign_new_numbers(line.Buf, map_arr, max_n, next_new)
line = line.Next
blk = blk.Next
# 4. 检查是否有需要重编号的(old != new)
need_renumber: int = 0
i: int = 0
while i <= max_n:
v: int = _map_get_i32(map_arr, i)
if v != -1 and v != i:
need_renumber = 1
break
i += 1
if need_renumber == 0:
return # 编号已单调,无需替换
# 5. 第三遍扫描:替换所有指令行文本
blk = func.Blocks.Head
blk_steps = 0
while blk is not None:
blk_steps += 1
if blk_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 替换终止)\n", func.Name)
stdlib.exit(1)
if blk.Lines is not None:
line: rowptr[Line] = blk.Lines.Head
line_steps = 0
while line is not None:
line_steps += 1
if line_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 替换终止)\n",
func.Name, blk.Name)
stdlib.exit(1)
if line.Buf is not None:
new_buf: str = _replace_ssa_numbers(
line.Buf, pool, map_arr, max_n)
if new_buf is not None:
line.Buf = new_buf
line.Len = string.strlen(new_buf)
line = line.Next
blk = blk.Next
# ============================================================
# FunctionPrint: 将函数序列化为 IR 文本
#
# 格式:
# define <ret_ty> @<name>(<params>) {
# <block_name>:
# <instruction>
# <instruction>
# <block_name>:
# <instruction>
# }
# ============================================================
def FunctionPrint(buf: str, size: t.CSizeT,
func: rowptr[Function], pool: rowptr[memhub.MemBuddy]):
"""将函数 func 序列化为 IR 文本写入 buf"""
if func is None or buf is None or size == 0: return
# 在序列化前重编号数字 SSA 名,确保按文本输出顺序单调递增。
# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致
# SSA 名非单调(llc 报错 "instruction expected to be numbered '%N' or greater")。
# RenumberSSA 内部会跳过 declare 函数(IsDeclared==1),无需在此判断。
RenumberSSA(func, pool)
ty_buf: str = pool.alloc(128)
if ty_buf is None: return
ty_buf[0] = '\0'
# define <ret_ty> @<name>(<params>)
if func.IsDeclared == 1:
_append_cstr(buf, size, "declare ")
else:
# 泛型特化类方法(如 GSList[NameEntry].__before_init__):多个模块各自
# 特化生成同名定义 → ld.lld duplicate symbol warning。特化方法代码由
# 相同模板+类型参数生成,定义相同,输出 linkonce_odr 让链接器合并。
if func.Name is not None and string.strchr(func.Name, 91) is not None:
_append_cstr(buf, size, "define linkonce_odr ")
else:
_append_cstr(buf, size, "define ")
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, func.RetTy, pool)
_append_cstr(buf, size, ty_buf)
_append_cstr(buf, size, " @")
if func.Name is not None:
if _ll_name_needs_quote(func.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, func.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, func.Name)
_append_cstr(buf, size, "(")
# 参数列表(从 GSList[Param].Head 遍历)
cur: rowptr[Param] = None
if func.Params is not None:
cur = func.Params.Head
first: int = 1
cur_steps: t.CSizeT = 0
while cur is not None:
cur_steps += 1
if cur_steps > IR_DUMP_CHAIN_LIMIT:
if func.Params is not None:
stdio.printf("[IR-DUMP] 链表异常: func params(函数名=%s,Params.Count=%zu,遍历超 %d 步,print 终止)\n",
func.Name, func.Params.Count, IR_DUMP_CHAIN_LIMIT)
else:
stdio.printf("[IR-DUMP] 链表异常: func params(函数名=%s,Params=None,遍历超 %d 步,print 终止)\n",
func.Name, IR_DUMP_CHAIN_LIMIT)
stdlib.exit(1)
if first == 0:
_append_cstr(buf, size, ", ")
# 参数属性(如 "noundef"/"nocapture")在类型之前
if cur.Attrs is not None:
_append_cstr(buf, size, cur.Attrs)
_append_cstr(buf, size, " ")
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, cur.Ty, pool)
_append_cstr(buf, size, ty_buf)
# declare 和 define 都打印参数名(如果有)
if cur.Name is not None:
_append_cstr(buf, size, " ")
# LLVM IR 要求参数名以 % 开头
if cur.Name[0] != '%':
_append_cstr(buf, size, "%")
_append_cstr(buf, size, cur.Name)
cur = cur.Next
first = 0
# 变参函数追加 ...
if func.IsVarArg == 1:
if func.Params is not None and func.Params.Head is not None:
_append_cstr(buf, size, ", ...")
else:
_append_cstr(buf, size, "...")
_append_cstr(buf, size, ")")
# 函数级属性(如 "nounwind"/"noinline")在 ) 之后
if func.Attrs is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, func.Attrs)
# B5:字符串属性(section 等)必须用属性组 #N 引用(LLVM 不接受内联
# section="..."),函数行输出 #N,组定义在函数尾/模块中输出。
if func.AttrGroup is not None and func.AttrGroupId > 0:
ag_ref: str = pool.alloc(32)
if ag_ref is not None:
viperlib.snprintf(ag_ref, 32, " #%d", func.AttrGroupId)
_append_cstr(buf, size, ag_ref)
if func.IsDeclared == 1:
_append_cstr(buf, size, "\n")
_append_attr_group_def(buf, size, pool, func)
return
# 函数体
_append_cstr(buf, size, " {\n")
blk: rowptr[BasicBlock] = None
if func.Blocks is not None:
blk = func.Blocks.Head
blk_steps: t.CSizeT = 0
while blk is not None:
blk_steps += 1
if blk_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,print 终止)\n", func.Name)
stdlib.exit(1)
# 块标签
if blk.Name is not None:
_append_cstr(buf, size, blk.Name)
_append_cstr(buf, size, ":\n")
# 指令行(从 GSList[Line].Head 遍历)
line: rowptr[Line] = None
if blk.Lines is not None:
line = blk.Lines.Head
has_lines: int = 0
line_steps: t.CSizeT = 0
while line is not None:
line_steps += 1
if line_steps > IR_DUMP_CHAIN_LIMIT:
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,print 终止)\n",
func.Name, blk.Name)
stdlib.exit(1)
if line.Buf is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, line.Buf)
_append_cstr(buf, size, "\n")
has_lines = 1
line = line.Next
# 块未终止兜底:LLVM IR 要求每个基本块以终止指令(br/ret/unreachable)结尾。
# 两种情况需要补 unreachable:
# 1. 空块(has_lines==0):标签后无任何指令
# 2. 有指令但未终止(IsTerminated==0):如 break/continue 后的 dead.N 块
# 被后续语句填入指令但缺少终止符,导致下一个标签处报
# "expected instruction opcode"
if has_lines == 0 or blk.IsTerminated == 0:
_append_cstr(buf, size, " unreachable\n")
blk = blk.Next
_append_cstr(buf, size, "}\n")
_append_attr_group_def(buf, size, pool, func)
def _append_attr_group_def(buf: str, size: t.CSizeT,
pool: rowptr[memhub.MemBuddy],
func: rowptr[Function]):
"""输出字符串属性组定义: attributes #N = { "section"="..." }"""
if func is None or func.AttrGroup is None or func.AttrGroupId <= 0:
return
ag_buf: str = pool.alloc(192)
if ag_buf is None:
return
viperlib.snprintf(ag_buf, 192, "attributes #%d = { %s }\n",
func.AttrGroupId, func.AttrGroup)
_append_cstr(buf, size, ag_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
# ============================================================
# 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型
# (字段不足且字段类型可能错误),导致 TransPyC 静默跳过
# 字段访问(不生成 GEP,不报错),字段值永远为 null。
#
# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问
# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。
# ============================================================
def function_get_name(func: rowptr[Function]) -> str:
"""获取函数名"""
if func is None:
return None
return func.Name
def function_get_ret_ty(func: rowptr[Function]) -> rowptr[LLVMType]:
"""获取函数返回类型"""
if func is None:
return None
return func.RetTy
def function_get_params(func: rowptr[Function]) -> rowptr[GSList[Param]]:
"""获取函数参数链表容器"""
if func is None:
return None
return func.Params
def function_get_param_head(func: rowptr[Function]) -> rowptr[Param]:
"""获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head)"""
if func is None:
return None
if func.Params is None:
return None
return func.Params.Head
def function_get_next(func: rowptr[Function]) -> rowptr[Function]:
"""获取链表下一个函数"""
if func is None:
return None
return func.Next
def function_is_declared(func: rowptr[Function]) -> int:
"""获取函数是否为声明(1=declare 仅声明, 0=define 定义)"""
if func is None:
return 0
return func.IsDeclared
def param_get_name(param: rowptr[Param]) -> str:
"""获取参数名"""
if param is None:
return None
return param.Name
def param_get_ty(param: rowptr[Param]) -> rowptr[LLVMType]:
"""获取参数类型"""
if param is None:
return None
return param.Ty
def param_get_next(param: rowptr[Param]) -> rowptr[Param]:
"""获取链表下一个参数"""
if param is None:
return None
return param.Next