修正了一些错误

This commit is contained in:
2026-07-26 20:32:26 +08:00
parent ca7c2120b8
commit 1837339f69
203 changed files with 374300 additions and 2638 deletions

View File

@@ -227,6 +227,48 @@ def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr
block_append_line(block, line)
def block_insert_text_before_terminator(pool: memhub.MemBuddy | t.CPtr,
block: BasicBlock | t.CPtr,
text: t.CChar | t.CPtr):
"""创建指令行并插入到基本块终止指令之前
如果块未终止,追加到末尾。
如果块已终止(有 br/ret在终止指令之前插入确保 alloca 等指令
不出现在终止指令之后。
"""
if block is None or text is None: return
if block.Lines is None: return
line: Line | t.CPtr = new_line(pool, text)
if line is None: return
# 块未终止:直接追加
if block.IsTerminated == 0:
block_append_line(block, line)
return
# 块已终止:在 Tail终止指令之前插入
lines: GSList[Line] | t.CPtr = 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: Line | t.CPtr = 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
# ============================================================
# 属性设置
# ============================================================
@@ -276,6 +318,259 @@ def _ll_name_needs_quote(name: str) -> t.CInt:
return 0
# ============================================================
# RenumberSSA: 重编号函数内数字 SSA 名
#
# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致
# SSA 名在文本输出中非单调递增的问题llc 报错:
# "instruction expected to be numbered '%N' or greater")。
#
# 现象: entry 块原指令 %0-%6 + bralloca_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) -> t.CInt:
"""判断字符是否是 '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: t.CChar | t.CPtr, idx: t.CInt) -> t.CInt:
"""读取 i32 数组 map_arr[idx](显式字节偏移 idx*4
使用 (t.CInt | t.CPtr)(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: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off)
return c.Deref(elem_ptr)
def _map_set_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt, val: t.CInt):
"""写入 map_arr[idx] = vali32 数组,显式字节偏移 idx*4
使用 (t.CInt | t.CPtr)(uint64) 强转 + c.DerefAs 解引用赋值。
TPC 已修复类型联合强转,此写法可用。
"""
if map_arr is None:
return
byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4
elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off)
c.DerefAs(elem_ptr, val)
def _scan_max_ssa_in_text(text: t.CChar | t.CPtr, cur_max: t.CInt) -> t.CInt:
"""扫描文本,找出 %NN 为数字)中最大的 N与 cur_max 比较返回更大值
仅匹配 '%' 后紧跟数字的情况,跳过命名 SSA 名(%entry 等)。
"""
result: t.CInt = cur_max
p: t.CChar | t.CPtr = text
while p is not None and p[0] != '\0':
if p[0] == '%':
nxt: t.CChar | t.CPtr = p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: t.CInt = string.atoi(nxt)
if num > result:
result = num
p = p + 1
return result
def _find_max_ssa_number(func: Function | t.CPtr) -> t.CInt:
"""遍历所有 BB 指令行,找出最大的 %N 数字;无数字 SSA 名返回 -1"""
max_n: t.CInt = -1
if func is None or func.Blocks is None:
return max_n
blk: BasicBlock | t.CPtr = func.Blocks.Head
while blk is not None:
if blk.Lines is not None:
line: Line | t.CPtr = blk.Lines.Head
while line is not None:
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: t.CChar | t.CPtr,
map_arr: t.CChar | t.CPtr,
max_n: t.CInt, next_new: t.CInt) -> t.CInt:
"""扫描文本,对每个 %N数字若 map_arr[N]==-1 则分配 next_new
返回更新后的 next_new。按文本首次出现顺序建立映射。
"""
result: t.CInt = next_new
p: t.CChar | t.CPtr = text
while p is not None and p[0] != '\0':
if p[0] == '%':
nxt: t.CChar | t.CPtr = p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: t.CInt = 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: t.CChar | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
map_arr: t.CChar | t.CPtr,
max_n: t.CInt) -> t.CChar | t.CPtr:
"""构建新文本,将 %N 替换为映射后的新编号
逐字符扫描:遇到 %N数字查映射表替换其他字符原样复制。
返回新分配的缓冲区(调用方无需释放旧 Bufpool 统一管理)。
"""
src_len: t.CSizeT = string.strlen(text)
# 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64
new_size: t.CSizeT = src_len * 2 + 64
new_buf: t.CChar | t.CPtr = pool.alloc(new_size)
if new_buf is None:
return None
# 一次性分配数字缓冲区(循环中复用)
num_buf: t.CChar | t.CPtr = pool.alloc(16)
if num_buf is None:
new_buf[0] = '\0'
return new_buf
dst_idx: t.CSizeT = 0
src_p: t.CChar | t.CPtr = text
while src_p is not None and src_p[0] != '\0':
if dst_idx + 16 >= new_size:
# 缓冲区不足,截断
break
if src_p[0] == '%':
nxt: t.CChar | t.CPtr = src_p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: t.CInt = string.atoi(nxt)
new_num: t.CInt = _map_get_i32(map_arr, num)
if num >= 0 and num <= max_n and 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: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增
在 FunctionPrint 序列化函数体之前调用。
仅对 defineIsDeclared==0且 Blocks 非空 的函数生效。
"""
if func is None or pool is None:
return
if func.IsDeclared == 1:
return # declare 无函数体
if func.Blocks is None:
return
# 1. 第一遍扫描:找出最大 SSA 编号
max_n: t.CInt = _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 # t.CInt = 4 字节
map_arr: t.CChar | t.CPtr = pool.alloc(map_bytes)
if map_arr is None:
return
string.memset(map_arr, 0xFF, map_bytes) # 0xFF * 4 = 0xFFFFFFFF = -1
# 3. 第二遍扫描:按文本顺序分配新编号
next_new: t.CInt = 0
blk: BasicBlock | t.CPtr = func.Blocks.Head
while blk is not None:
if blk.Lines is not None:
line: Line | t.CPtr = blk.Lines.Head
while line is not None:
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: t.CInt = 0
i: t.CInt = 0
while i <= max_n:
v: t.CInt = _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
while blk is not None:
if blk.Lines is not None:
line: Line | t.CPtr = blk.Lines.Head
while line is not None:
if line.Buf is not None:
new_buf: t.CChar | t.CPtr = _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 文本
#
@@ -293,6 +588,12 @@ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
"""将函数 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: t.CChar | t.CPtr = pool.alloc(128)
if ty_buf is None: return
ty_buf[0] = '\0'
@@ -371,12 +672,22 @@ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
line: Line | t.CPtr = None
if blk.Lines is not None:
line = blk.Lines.Head
has_lines: t.CInt = 0
while line is not None:
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")