fix(mlir): 类型文本缓冲按长度给足 + 截断响亮报错(系统性)

根因:MLIR 把具名结构体内联为完整字段体(`!llvm.struct<"名", (i32, !llvm.ptr, …)>`),
单个类型文本可达数百字节,远长于 LLVM 形态的 `%"名"` 引用(十几字节);而 builders
仍按旧的短类型尺寸分配(128/256),指令行里的类型被截断 → 畸形 MLIR。
实测:alloca 行类型被 128 字节缓冲截断,mlir-opt 报
"unbalanced '(' character in pretty dialect name"。

- __types.vp:新增截断溢出标志 _MlirTypeTrunc(_strappend/_MlirAppendN 写入
  被截断时置位),TypePrint / MlirTypeText 渲染后检查并 MlirFail —— 任何截断
  都不再静默产出畸形 MLIR
- __builder.vp:新增 _TY_TEXT_CAP(512)/_LINE_CAP(2560),全部指令行缓冲(alloca
  /ret/load/store/各类 cast/gep/icmp/fcmp/select/atomicrmw/cmpxchg/va_arg/switch
  /case/inline_asm…)改为 _LINE_CAP;build_call / build_call_indirect 的实参表
  与行缓冲按实参个数与实际长度动态分配(原固定 1024/2048 会在两个以上结构体
  实参时静默截断)
- __values.vp:ValuePrint 的类型缓冲 256 → 512
This commit is contained in:
TermiNexus committed 2026-10-03 21:07:55 +08:00
1 parent 33d5737f0c
commit a502c7242f
3 files changed
+163 -110

No files matched your search

+124 -103
View File
@@ -28,6 +28,19 @@ from .__function import Function, BasicBlock, block_append_text, block_set_termi
# 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=40 保持一致
# (方法以实例方法实现,无虚表;文件末尾的同名顶层函数为一行委托)。
# ============================================================
# 指令文本缓冲尺寸
#
# MLIR 形态的类型文本会**内联具名结构体的完整字段体**
# (如 `!llvm.struct<"sha1.Cls", (i32, !llvm.ptr, …)>`),单个类型可达数百字节,
# 远长于 LLVM 形态的 `%"sha1.Cls"` 引用(十几字节)。故指令行缓冲必须按
# "一行最多内嵌几个类型文本"给足:_LINE_CAP 覆盖 5 个类型文本 + 固定部分。
# 渲染侧 TypePrint/MlirTypeText 已加溢出护栏:一旦截断即响亮报错,不再静默
# 产出畸形 MLIR(历史故障:alloca 行类型被 128 字节缓冲截断 → mlir-opt 报
# "unbalanced '(' character in pretty dialect name")。
# ============================================================
_TY_TEXT_CAP: sizet = 512
_LINE_CAP: sizet = 2560
novirtual class IRBuilder:
Pool: memhub.MemBuddy* # 内存池
Func: rawptr[Function] # 所属函数
@@ -49,16 +62,16 @@ novirtual class IRBuilder:
def _type_str(self, ty: rawptr[LLVMType]) -> str:
"""获取类型的 MLIR 文本(从 pool 分配 512 字节缓冲区)
"""获取类型的 MLIR 文本(从 pool 分配 _TY_TEXT_CAP 字节缓冲区)
注意:复杂结构体类型(如 13 方法的虚表 !llvm.struct<(...)>)可能超过
64 字节,必须使用足够大的缓冲区,否则 '>' 会被截断导致语法错误。
MLIR 类型文本内联具名结构体的完整字段体,可达数百字节;超出
_TY_TEXT_CAP 时 TypePrint 会**响亮报错**(不再静默截断)。
"""
pool: memhub.MemBuddy* = self.Pool
buf: str = pool.alloc(512)
buf: str = pool.alloc(_TY_TEXT_CAP)
if buf is None: return None
buf[0] = '\0'
TypePrint(buf, 512, ty, pool)
TypePrint(buf, _TY_TEXT_CAP, ty, pool)
# [IR-FAIL] 校验护栏:LLVMType 类型对象可能被 MemBuddy 覆盖/悬空
# (跨遍 reset 回收后 pool 内存复用),此时 TypePrint 输出首字符
# 变为垃圾(如 't')或为空。立即 fail-fast 终止,防止生成
@@ -112,9 +125,9 @@ novirtual class IRBuilder:
pool: memhub.MemBuddy* = self.Pool
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(lhs.Ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = %s %s %s, %s", name, op, ty_s, lhs.Name, rhs.Name)
viperlib.snprintf(line, _LINE_CAP, "%s = %s %s %s, %s", name, op, ty_s, lhs.Name, rhs.Name)
self._emit(line)
return SSAValue(pool, lhs.Ty, name)
@@ -160,9 +173,9 @@ novirtual class IRBuilder:
pool: memhub.MemBuddy* = self.Pool
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(ty)
line: str = pool.alloc(128)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 128, "%s = alloca %s", name, ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = alloca %s", name, ty_s)
self._emit(line)
# 结果类型是 ty*
@@ -185,9 +198,9 @@ novirtual class IRBuilder:
pool: memhub.MemBuddy* = self.Pool
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(ty)
line: str = pool.alloc(128)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 128, "%s = alloca %s, align %d", name, ty_s, align)
viperlib.snprintf(line, _LINE_CAP, "%s = alloca %s, align %d", name, ty_s, align)
self._emit(line)
# 结果类型是 ty*
@@ -216,9 +229,9 @@ novirtual class IRBuilder:
return self.build_alloca(ty)
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(ty)
line_text: str = pool.alloc(128)
line_text: str = pool.alloc(_LINE_CAP)
if line_text is None: return None
viperlib.snprintf(line_text, 128, "%s = alloca %s", name, ty_s)
viperlib.snprintf(line_text, _LINE_CAP, "%s = alloca %s", name, ty_s)
# 在入口块终止指令之前插入:若入口块已以 br/ret 终止(如嵌套循环内
# 再分配循环变量),block_append_text 会把 alloca 追加到终止指令之后,
# 生成 "br 之后不可达指令" 的非法 IR(llc: "instruction expected to be
@@ -248,12 +261,12 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(ty)
ptr_ty_s: str = self._type_str(ptr.Ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
if is_volatile != 0:
viperlib.snprintf(line, 256, "%s = load volatile %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name)
viperlib.snprintf(line, _LINE_CAP, "%s = load volatile %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name)
else:
viperlib.snprintf(line, 256, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name)
viperlib.snprintf(line, _LINE_CAP, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name)
self._emit(line)
return SSAValue(pool, ty, name)
@@ -269,12 +282,12 @@ novirtual class IRBuilder:
pool: memhub.MemBuddy* = self.Pool
val_ty_s: str = self._type_str(val.Ty)
ptr_ty_s: str = self._type_str(ptr.Ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return
if is_volatile != 0:
viperlib.snprintf(line, 256, "store volatile %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name)
viperlib.snprintf(line, _LINE_CAP, "store volatile %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name)
else:
viperlib.snprintf(line, 256, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name)
viperlib.snprintf(line, _LINE_CAP, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name)
self._emit(line)
@@ -398,9 +411,9 @@ novirtual class IRBuilder:
pool: memhub.MemBuddy* = self.Pool
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(val.Ty)
line: str = pool.alloc(128)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 128, "%s = fneg %s %s", name, ty_s, val.Name)
viperlib.snprintf(line, _LINE_CAP, "%s = fneg %s %s", name, ty_s, val.Name)
self._emit(line)
return SSAValue(pool, val.Ty, name)
@@ -419,9 +432,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(lhs.Ty)
pred_s: str = _icmp_pred_str(pred)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = icmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name)
viperlib.snprintf(line, _LINE_CAP, "%s = icmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name)
self._emit(line)
# 结果类型是 i1
@@ -443,9 +456,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(lhs.Ty)
pred_s: str = _fcmp_pred_str(pred)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = fcmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name)
viperlib.snprintf(line, _LINE_CAP, "%s = fcmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name)
self._emit(line)
# 结果类型是 i1
@@ -475,9 +488,9 @@ novirtual class IRBuilder:
"""br i1 <cond>, label %<then>, label %<else_>"""
if self is None or cond is None or then_blk is None or else_blk is None: return
pool: memhub.MemBuddy* = self.Pool
line: str = pool.alloc(128)
line: str = pool.alloc(_LINE_CAP)
if line is None: return
viperlib.snprintf(line, 128, "br i1 %s, label %%%s, label %%%s",
viperlib.snprintf(line, _LINE_CAP, "br i1 %s, label %%%s, label %%%s",
cond.Name, then_blk.Name, else_blk.Name)
self._emit(line)
self._mark_terminated()
@@ -488,9 +501,9 @@ novirtual class IRBuilder:
if self is None or val is None: return
pool: memhub.MemBuddy* = self.Pool
ty_s: str = self._type_str(val.Ty)
line: str = pool.alloc(128)
line: str = pool.alloc(_LINE_CAP)
if line is None: return
viperlib.snprintf(line, 128, "ret %s %s", ty_s, val.Name)
viperlib.snprintf(line, _LINE_CAP, "ret %s %s", ty_s, val.Name)
self._emit(line)
self._mark_terminated()
@@ -537,33 +550,36 @@ novirtual class IRBuilder:
ret_ty_s: str = self._type_str(ret_ty)
# 构建参数列表文本 + 变参函数类型签名
args_buf: str = pool.alloc(1024)
# 实参类型文本内联具名结构体体(单个可达 _TY_TEXT_CAP 字节),故按
# 实参个数给足容量;固定 1024 字节会在两个以上结构体实参时静默截断。
arg_cap: sizet = sizet(arg_count + 1) * (_TY_TEXT_CAP + 32) + 32
args_buf: str = pool.alloc(arg_cap)
if args_buf is None: return None
args_buf[0] = '\0'
func_ty_buf: str = pool.alloc(1024)
func_ty_buf: str = pool.alloc(arg_cap)
if func_ty_buf is None: return None
func_ty_buf[0] = '\0'
cur: rawptr[Value] = args
first: int = 1
while cur is not None:
if first == 0:
_append_cstr(args_buf, 1024, ", ")
_append_cstr(func_ty_buf, 1024, ", ")
_append_cstr(args_buf, arg_cap, ", ")
_append_cstr(func_ty_buf, arg_cap, ", ")
arg_ty_s: str = self._type_str(cur.Ty)
_append_cstr(args_buf, 1024, arg_ty_s)
_append_cstr(args_buf, 1024, " ")
_append_cstr(args_buf, arg_cap, arg_ty_s)
_append_cstr(args_buf, arg_cap, " ")
if cur.Name is not None:
_append_cstr(args_buf, 1024, cur.Name)
_append_cstr(func_ty_buf, 1024, arg_ty_s)
_append_cstr(args_buf, arg_cap, cur.Name)
_append_cstr(func_ty_buf, arg_cap, arg_ty_s)
cur = cur.Next
first = 0
if is_variadic == 1:
if first == 0:
_append_cstr(func_ty_buf, 1024, ", ")
_append_cstr(func_ty_buf, 1024, "...")
_append_cstr(func_ty_buf, arg_cap, ", ")
_append_cstr(func_ty_buf, arg_cap, "...")
# 构造带引号的 callee 名字(SHA1 前缀名含 '.' 或以数字开头需要加引号)
callee_buf: str = pool.alloc(128)
callee_buf: str = pool.alloc(_LINE_CAP)
if callee_buf is None: return None
callee_buf[0] = '\0'
if _ll_name_needs_quote(callee) != 0:
@@ -573,18 +589,20 @@ novirtual class IRBuilder:
else:
_append_cstr(callee_buf, 128, callee)
line: str = pool.alloc(2048)
line_cap: sizet = string.strlen(ret_ty_s) + string.strlen(args_buf) \
+ string.strlen(func_ty_buf) + string.strlen(callee_buf) + 64
line: str = pool.alloc(line_cap)
if line is None: return None
if is_variadic == 1:
if is_void == 1:
viperlib.snprintf(line, 2048, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf)
viperlib.snprintf(line, line_cap, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf)
else:
viperlib.snprintf(line, 2048, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf)
viperlib.snprintf(line, line_cap, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf)
else:
if is_void == 1:
viperlib.snprintf(line, 2048, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf)
viperlib.snprintf(line, line_cap, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf)
else:
viperlib.snprintf(line, 2048, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf)
viperlib.snprintf(line, line_cap, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf)
self._emit(line)
if is_void == 1:
@@ -620,29 +638,32 @@ novirtual class IRBuilder:
ret_ty_s: str = self._type_str(ret_ty)
# 构建参数列表文本
args_buf: str = pool.alloc(1024)
# 构建参数列表文本(容量按实参个数给足,理由同 build_call)
arg_cap2: sizet = sizet(arg_count + 1) * (_TY_TEXT_CAP + 32) + 32
args_buf: str = pool.alloc(arg_cap2)
if args_buf is None: return None
args_buf[0] = '\0'
cur: rawptr[Value] = args
first: int = 1
while cur is not None:
if first == 0:
_append_cstr(args_buf, 1024, ", ")
_append_cstr(args_buf, arg_cap2, ", ")
arg_ty_s: str = self._type_str(cur.Ty)
_append_cstr(args_buf, 1024, arg_ty_s)
_append_cstr(args_buf, 1024, " ")
_append_cstr(args_buf, arg_cap2, arg_ty_s)
_append_cstr(args_buf, arg_cap2, " ")
if cur.Name is not None:
_append_cstr(args_buf, 1024, cur.Name)
_append_cstr(args_buf, arg_cap2, cur.Name)
cur = cur.Next
first = 0
line: str = pool.alloc(2048)
line_cap2: sizet = string.strlen(ret_ty_s) + string.strlen(args_buf) \
+ string.strlen(callee_val.Name) + 64
line: str = pool.alloc(line_cap2)
if line is None: return None
if is_void == 1:
viperlib.snprintf(line, 2048, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf)
viperlib.snprintf(line, line_cap2, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf)
else:
viperlib.snprintf(line, 2048, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf)
viperlib.snprintf(line, line_cap2, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf)
self._emit(line)
if is_void == 1:
@@ -662,11 +683,11 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
if val.Name is None:
return None
viperlib.snprintf(line, 256, "%s = bitcast %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = bitcast %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
ret: rawptr[Value] = SSAValue(pool, to_ty, name)
return ret
@@ -680,9 +701,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = sext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = sext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -695,9 +716,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = trunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = trunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -710,9 +731,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = zext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = zext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -725,9 +746,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = ptrtoint %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = ptrtoint %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -740,9 +761,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = inttoptr %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = inttoptr %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -758,9 +779,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = fpext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = fpext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -773,9 +794,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = fptrunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = fptrunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -788,9 +809,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = fptosi %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = fptosi %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -803,9 +824,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = sitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = sitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -818,9 +839,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = fptoui %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = fptoui %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -833,9 +854,9 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
from_ty_s: str = self._type_str(val.Ty)
to_ty_s: str = self._type_str(to_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = uitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
viperlib.snprintf(line, _LINE_CAP, "%s = uitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
self._emit(line)
return SSAValue(pool, to_ty, name)
@@ -891,9 +912,9 @@ novirtual class IRBuilder:
elem_ty_s: str = self._type_str(elem_ty)
ptr_ty_s: str = self._type_str(ptr.Ty)
idx_ty_s: str = self._type_str(idx.Ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, %s %s",
viperlib.snprintf(line, _LINE_CAP, "%s = getelementptr %s, %s %s, %s %s",
name, elem_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name)
self._emit(line)
@@ -922,9 +943,9 @@ novirtual class IRBuilder:
array_ty_s: str = self._type_str(array_ty)
ptr_ty_s: str = self._type_str(ptr.Ty)
idx_ty_s: str = self._type_str(idx.Ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, i32 0, %s %s",
viperlib.snprintf(line, _LINE_CAP, "%s = getelementptr %s, %s %s, i32 0, %s %s",
name, array_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name)
self._emit(line)
@@ -1032,18 +1053,18 @@ novirtual class IRBuilder:
ty_s: str = self._type_str(val.Ty)
# 构建主体: switch <ty> <val>, label %default
line: str = pool.alloc(512)
line: str = pool.alloc(_LINE_CAP)
if line is None: return
viperlib.snprintf(line, 512, "switch %s %s, label %%%s",
viperlib.snprintf(line, _LINE_CAP, "switch %s %s, label %%%s",
ty_s, val.Name, default_blk.Name)
_append_cstr(line, 512, " [")
_append_cstr(line, 512, "\n")
_append_cstr(line, _LINE_CAP, " [")
_append_cstr(line, _LINE_CAP, "\n")
# 遍历 case 列表
cur: rawptr[SwitchCase] = cases_head
case_ty_s: str = self._type_str(val.Ty)
while cur is not None:
case_line: str = pool.alloc(128)
case_line: str = pool.alloc(_LINE_CAP)
if case_line is not None:
# 使用中间变量避免链式结构体成员访问被编译器丢弃
cv: rawptr[Value] = cur.CaseVal
@@ -1052,12 +1073,12 @@ novirtual class IRBuilder:
cv_name: str = cv.Name
cb_name: str = cb.Name
if cv_name is not None and cb_name is not None:
viperlib.snprintf(case_line, 128, " %s %s, label %%%s\n",
viperlib.snprintf(case_line, _LINE_CAP, " %s %s, label %%%s\n",
case_ty_s, cv_name, cb_name)
_append_cstr(line, 512, case_line)
_append_cstr(line, _LINE_CAP, case_line)
cur = cur.Next
_append_cstr(line, 512, "]")
_append_cstr(line, _LINE_CAP, "]")
self._emit(line)
self._mark_terminated()
@@ -1072,9 +1093,9 @@ novirtual class IRBuilder:
pool: memhub.MemBuddy* = self.Pool
name: str = self._alloc_ssa_name()
ty_s: str = self._type_str(true_val.Ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = select i1 %s, %s %s, %s %s",
viperlib.snprintf(line, _LINE_CAP, "%s = select i1 %s, %s %s, %s %s",
name, cond.Name, ty_s, true_val.Name, ty_s, false_val.Name)
self._emit(line)
return SSAValue(pool, true_val.Ty, name)
@@ -1108,9 +1129,9 @@ novirtual class IRBuilder:
val_ty_s: str = self._type_str(val.Ty)
op_s: str = _atomic_op_str(op)
ord_s: str = _atomic_order_str(order)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 256, "%s = atomicrmw %s %s %s, %s %s %s",
viperlib.snprintf(line, _LINE_CAP, "%s = atomicrmw %s %s %s, %s %s %s",
name, op_s, ptr_ty_s, ptr.Name, val_ty_s, val.Name, ord_s)
self._emit(line)
return SSAValue(pool, val.Ty, name)
@@ -1131,9 +1152,9 @@ novirtual class IRBuilder:
new_ty_s: str = self._type_str(new_val.Ty)
succ_s: str = _atomic_order_str(succ_order)
fail_s: str = _atomic_order_str(fail_order)
line: str = pool.alloc(384)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
viperlib.snprintf(line, 384, "%s = cmpxchg %s %s, %s %s, %s %s %s %s",
viperlib.snprintf(line, _LINE_CAP, "%s = cmpxchg %s %s, %s %s, %s %s %s %s",
name, ptr_ty_s, ptr.Name, cmp_ty_s, cmp_val.Name,
new_ty_s, new_val.Name, succ_s, fail_s)
self._emit(line)
@@ -1154,11 +1175,11 @@ novirtual class IRBuilder:
name: str = self._alloc_ssa_name()
va_list_ty_s: str = self._type_str(va_list_ptr.Ty)
arg_ty_s: str = self._type_str(arg_ty)
line: str = pool.alloc(256)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
if va_list_ptr.Name is None:
return None
viperlib.snprintf(line, 256, "%s = va_arg %s %s, %s",
viperlib.snprintf(line, _LINE_CAP, "%s = va_arg %s %s, %s",
name, va_list_ty_s, va_list_ptr.Name, arg_ty_s)
self._emit(line)
return SSAValue(pool, arg_ty, name)
@@ -1190,22 +1211,22 @@ novirtual class IRBuilder:
name = self._alloc_ssa_name()
ret_ty_s: str = self._type_str(ret_ty)
line: str = pool.alloc(512)
line: str = pool.alloc(_LINE_CAP)
if line is None: return None
if has_side_effects != 0:
if is_void == 1:
viperlib.snprintf(line, 512, "call %s asm sideeffect \"%s\", \"%s\"()",
viperlib.snprintf(line, _LINE_CAP, "call %s asm sideeffect \"%s\", \"%s\"()",
ret_ty_s, asm_text, constraints)
else:
viperlib.snprintf(line, 512, "%s = call %s asm sideeffect \"%s\", \"%s\"()",
viperlib.snprintf(line, _LINE_CAP, "%s = call %s asm sideeffect \"%s\", \"%s\"()",
name, ret_ty_s, asm_text, constraints)
else:
if is_void == 1:
viperlib.snprintf(line, 512, "call %s asm \"%s\", \"%s\"()",
viperlib.snprintf(line, _LINE_CAP, "call %s asm \"%s\", \"%s\"()",
ret_ty_s, asm_text, constraints)
else:
viperlib.snprintf(line, 512, "%s = call %s asm \"%s\", \"%s\"()",
viperlib.snprintf(line, _LINE_CAP, "%s = call %s asm \"%s\", \"%s\"()",
name, ret_ty_s, asm_text, constraints)
self._emit(line)
+37 -5
View File
@@ -402,7 +402,15 @@ def MlirFail(msg: str):
# 类型转换失败报文再把它追加出来,一次定位到出错的那一行中间文本。
# 依赖方向保持单向:本模块只存/读,不反向 import __function.vp。
# ============================================================
_MlirCtxLine: str = None
_MlirCtxLine: str = None
# 类型文本渲染溢出标志:_strappend/_MlirAppendN 因缓冲上限截断时置 1,
# 由 TypePrint / MlirTypeText 在渲染后检查并响亮报错。
# 为什么必须响亮:MLIR 把具名结构体内联为**完整字段体**
# (`!llvm.struct<"name", (13 个字段…)>`),类型文本远长于 LLVM 形态的
# `%"name"` 引用,固定小缓冲(128/256)会被截断并产出畸形 MLIR
# (实测:alloca 行类型截断 → mlir-opt 报 "unbalanced '(' character")。
_MlirTypeTrunc: int = 0
def MlirSetContextLine(line: str = None):
@@ -673,11 +681,17 @@ def TypePrint(buf: str, size: sizet,
"""将类型 ty 序列化为 MLIR 类型文本写入 buf(容量 size)
pool 用于递归打印子类型时分配临时缓冲区。
溢出(类型文本超出 size)**响亮报错**:截断的类型文本会产出畸形 MLIR。
"""
global _MlirTypeTrunc
if buf is None or size == 0:
return
buf[0] = '\0'
_MlirTypeTrunc = 0
_MlirTypePrintDepth(buf, size, ty, pool, 0)
if _MlirTypeTrunc != 0:
_MlirTypeTrunc = 0
MlirFail("MLIR 渲染: 类型文本超出输出缓冲被截断(该处缓冲过小,需按类型长度增大)")
# ============================================================
@@ -691,10 +705,18 @@ def TypePrint(buf: str, size: sizet,
# / `double` / `%"name"`,由下方各分支转写为对应 MLIR 语法。
# ============================================================
def MlirTypeText(dst: str, dstsz: sizet, src: str, pool: memhub.MemBuddy*):
"""把中间文本类型(MLIR 或 LLVM 形态)规范化为 MLIR 类型文本(追加到 dst)"""
"""把中间文本类型(MLIR 或 LLVM 形态)规范化为 MLIR 类型文本(追加到 dst)
溢出(转换结果超出 dstsz)同样响亮报错。
"""
global _MlirTypeTrunc
if dst is None or dstsz == 0 or src is None:
return
_MlirTypeTrunc = 0
_MlirTypeAppend(dst, dstsz, src, pool, 0)
if _MlirTypeTrunc != 0:
_MlirTypeTrunc = 0
MlirFail("MLIR 渲染: 类型文本转换结果超出输出缓冲被截断(该处缓冲过小,需按类型长度增大)")
def MlirTypeTextIsPointer(src: str) -> int:
@@ -740,17 +762,21 @@ def _MlirTextLen(p: str) -> sizet:
def _MlirAppendN(dst: str, dstsz: sizet, src: str, n: sizet):
"""把 src 的前 n 字节追加到 dst"""
"""把 src 的前 n 字节追加到 dst;被截断时置溢出标志"""
global _MlirTypeTrunc
if dst is None or src is None or n == 0:
return
dl: sizet = string.strlen(dst)
if dl >= dstsz:
_MlirTypeTrunc = 1
return
rem: sizet = dstsz - dl
i: sizet = 0
while i < n and i + 1 < rem:
dst[dl + i] = src[i]
i += 1
if i < n:
_MlirTypeTrunc = 1
dst[dl + i] = '\0'
@@ -1182,20 +1208,26 @@ def _MlirStructFields(buf: str, size: sizet,
# 内部辅助
# ============================================================
def _strappend(dst: str, dst_size: sizet, src: str):
"""将 src 追加到 dst 末尾(不超过 dst_size)"""
"""将 src 追加到 dst 末尾(不超过 dst_size);被截断时置溢出标志"""
global _MlirTypeTrunc
if dst is None or src is None: return
dlen: sizet = string.strlen(dst)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到 GB 外
if dlen >= dst_size:
_MlirTypeTrunc = 1
return
slen: sizet = string.strlen(src)
remain: sizet = dst_size - dlen
if remain <= 0: return
if remain <= 0:
_MlirTypeTrunc = 1
return
i: sizet = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
if i < slen:
_MlirTypeTrunc = 1
dst[dlen + i] = '\0'
+2 -2
View File
@@ -188,9 +188,9 @@ def ValuePrint(buf: str, size: sizet,
# 常量: "<常量文本> : <MLIR 类型>"
_append_str(buf, size, val.Name)
_append_str(buf, size, " : ")
tp: str = pool.alloc(256)
tp: str = pool.alloc(512)
if tp is not None:
TypePrint(tp, 256, val.Ty, pool)
TypePrint(tp, 512, val.Ty, pool)
_append_str(buf, size, tp)