diff --git a/mlirlite/__builder.vp b/mlirlite/__builder.vp index 516ccfa..41fad01 100644 --- a/mlirlite/__builder.vp +++ b/mlirlite/__builder.vp @@ -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 , label %, label %""" 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 , 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) diff --git a/mlirlite/__types.vp b/mlirlite/__types.vp index 7da9762..ec7d802 100644 --- a/mlirlite/__types.vp +++ b/mlirlite/__types.vp @@ -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' diff --git a/mlirlite/__values.vp b/mlirlite/__values.vp index 1371113..217c2db 100644 --- a/mlirlite/__values.vp +++ b/mlirlite/__values.vp @@ -188,9 +188,9 @@ def ValuePrint(buf: str, size: sizet, # 常量: "<常量文本> : " _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)