diff --git a/mlirlite/__module.vp b/mlirlite/__module.vp index db6f17a..88751fd 100644 --- a/mlirlite/__module.vp +++ b/mlirlite/__module.vp @@ -340,6 +340,10 @@ class LLVMModule: # 打印期间有效,清空后不再解引用(避免 pool reset 后悬空)。 _MlirPublishNamedTypes(self, pool) + # 使 region 渲染草稿失效:本次打印首次用到时按当前 pool 惰性重建(见 + # _MlirGvEnsureScratch)。跨打印绝不复用(上一次的池可能已释放/被复用)。 + MlirGvResetScratch() + _append_cstr(buf, size, "module {\n") # 模式说明注释(MLIR 无 stub/text 二分) @@ -1028,7 +1032,13 @@ def _MlirArrayDenseAt(buf: str, size: sizet, src: str, # * 符号名一律经 _MlirSymRefAppend(先剥 LLVM 口径引号,再按 MLIR 口径重加); # * 不支持的叶子形态一律 MlirFail(带原始文本),绝不静默输出错误 MLIR。 # ============================================================ -GV_REGION_BUF_SIZE: t.CDefine = 32768 +GV_REGION_BUF_SIZE: t.CDefine = 32768 + +# 下标路径复用栈:每个递归深度一个槽(顶层 path="" → 深度 d 的路径写在槽 d)。 +# 深度上限与 _MlirGvWalk 的 64 层守卫一致,留余量取 72;每槽 512 字节足够 +# (64 层 × " , NN" ≈ 400 字节)。 +GV_PATH_SLOT: t.CDefine = 512 +GV_PATH_MAX: t.CDefine = 72 # region 渲染期状态(单线程递归渲染,逐全局重置) _MlirGvLeafBuf: str = None # 叶子 op 缓冲 @@ -1040,6 +1050,72 @@ _MlirGvPool: memhub.MemBuddy* = None _MlirGvLeafSeq: int = 0 _MlirGvInsSeq: int = 0 +# ---- region 渲染的**复用**草稿缓冲(惰性分配一次,跨全局/跨节点共享)---- +# +# 此前每个全局、每个初值节点都从模块子分配器 alloc 新缓冲且从不释放: +# 每全局 leaf/ins 各 32 KiB、每节点 4 KiB ⇒ 结构体/vtable 全局多的模块 +# (MLIRLiteTest #12)把 ~2 MiB 子池耗尽,报 "零初值类型缓冲分配失败"。 +# region 渲染是单线程顺序的,草稿内容用完即弃 ⇒ 分配一次复用即可。 +_MlirGvSbRead1: str = None # 512B:类型前缀记号读取草稿 +_MlirGvSbRead2: str = None # 512B:叶子类型记号读取草稿 +_MlirGvSbName: str = None # 512B:符号名 / 常量表达式符号名草稿 +_MlirGvSbVal: str = None # 512B:标量初值字面量草稿 +_MlirGvTyBuf: str = None # 4096B:元素 MLIR 类型文本(zero/const) +_MlirGvNameBuf: str = None # 32B:SSA 名生成草稿 +_MlirGvPathStack: str = None # GV_PATH_MAX × GV_PATH_SLOT:下标路径复用栈 + + +def MlirGvResetScratch(): + """使 region 渲染的复用草稿失效(下次 EnsureScratch 按当前池重新分配) + + 草稿只在**单次 PrintModule** 内经惰性分配复用(跨全局/跨节点共享); + 打印结束由 PrintModule 调用本函数置空 ⇒ 绝不复用上一次打印的指针 + (上一次的池可能已释放,或同一地址被新池复用 → 悬空写穿)。 + """ + global _MlirGvLeafBuf + _MlirGvLeafBuf = None + + +def _MlirGvEnsureScratch(pool: memhub.MemBuddy*) -> int: + """惰性分配本次 PrintModule 的复用草稿缓冲(跨全局/跨节点共享),返回 1=就绪""" + global _MlirGvLeafBuf, _MlirGvInsBuf, _MlirGvTopType, _MlirGvLast, _MlirGvPrev + global _MlirGvSbRead1, _MlirGvSbRead2, _MlirGvSbName, _MlirGvSbVal + global _MlirGvTyBuf, _MlirGvNameBuf, _MlirGvPathStack + if _MlirGvLeafBuf is not None: + return 1 + lb: str = pool.alloc(GV_REGION_BUF_SIZE) + ib: str = pool.alloc(GV_REGION_BUF_SIZE) + tb: str = pool.alloc(4096) + la: str = pool.alloc(32) + pr: str = pool.alloc(32) + r1: str = pool.alloc(512) + r2: str = pool.alloc(512) + nm: str = pool.alloc(512) + vl: str = pool.alloc(512) + tyb: str = pool.alloc(4096) + nb: str = pool.alloc(32) + ps: str = pool.alloc(GV_PATH_SLOT * GV_PATH_MAX) + if lb is None or ib is None or tb is None or la is None or pr is None \ + or r1 is None or r2 is None or nm is None or vl is None \ + or tyb is None or nb is None or ps is None: + MlirFail("MLIR 渲染: 全局 region 缓冲分配失败") + lb[0] = '\0'; ib[0] = '\0'; tb[0] = '\0'; la[0] = '\0'; pr[0] = '\0' + r1[0] = '\0'; r2[0] = '\0'; nm[0] = '\0'; vl[0] = '\0' + tyb[0] = '\0'; nb[0] = '\0'; ps[0] = '\0' + _MlirGvLeafBuf = lb + _MlirGvInsBuf = ib + _MlirGvTopType = tb + _MlirGvLast = la + _MlirGvPrev = pr + _MlirGvSbRead1 = r1 + _MlirGvSbRead2 = r2 + _MlirGvSbName = nm + _MlirGvSbVal = vl + _MlirGvTyBuf = tyb + _MlirGvNameBuf = nb + _MlirGvPathStack = ps + return 1 + def _MlirGlobalInitNeedsRegion(x: str) -> int: """判定全局初值是否改走 initializer region(1=region / 0=属性路径) @@ -1110,19 +1186,18 @@ def _MlirGlobalInitRegion(buf: str, size: sizet, 每行都带 '\\n';调用方在末尾补 '}',模块层再统一缩进 2 空格。 """ - global _MlirGvLeafBuf, _MlirGvInsBuf, _MlirGvTopType, _MlirGvLast - global _MlirGvPrev, _MlirGvPool, _MlirGvLeafSeq, _MlirGvInsSeq + global _MlirGvPool, _MlirGvLeafSeq, _MlirGvInsSeq x: str = gv.Initializer if x is None: return - topbuf: str = pool.alloc(4096) - leafbuf: str = pool.alloc(GV_REGION_BUF_SIZE) - insbuf: str = pool.alloc(GV_REGION_BUF_SIZE) - lastbuf: str = pool.alloc(32) - prevbuf: str = pool.alloc(32) - if topbuf is None or leafbuf is None or insbuf is None \ - or lastbuf is None or prevbuf is None: - MlirFail("MLIR 渲染: 全局 region 缓冲分配失败") + # 复用缓冲(惰性分配一次,跨全局共享)——此前逐全局 alloc 且不释放, + # 结构体/vtable 全局多时耗尽模块子分配器。 + _MlirGvEnsureScratch(pool) + topbuf: str = _MlirGvTopType + leafbuf: str = _MlirGvLeafBuf + insbuf: str = _MlirGvInsBuf + lastbuf: str = _MlirGvLast + prevbuf: str = _MlirGvPrev topbuf[0] = '\0' leafbuf[0] = '\0' insbuf[0] = '\0' @@ -1130,11 +1205,6 @@ def _MlirGlobalInitRegion(buf: str, size: sizet, prevbuf[0] = '\0' TypePrint(topbuf, 4096, gv.Ty, pool) - _MlirGvLeafBuf = leafbuf - _MlirGvInsBuf = insbuf - _MlirGvTopType = topbuf - _MlirGvLast = lastbuf - _MlirGvPrev = prevbuf _MlirGvPool = pool _MlirGvLeafSeq = 0 _MlirGvInsSeq = 0 @@ -1185,18 +1255,14 @@ def _MlirGvWalk(p: str, ty: rawptr[LLVMType], path: str, depth: int) -> str: MlirFail("MLIR 渲染: 全局初值文本意外结束") # 显式数组类型前缀(如字段写成 "[3 x i8] [i8 1, i8 2]")先整体读掉 if p[0] == '[' and _MlirGvIsArrayType(p) != 0: - tb: str = _MlirGvPool.alloc(4096) - if tb is None: - MlirFail("MLIR 渲染: 数组类型前缀缓冲分配失败") + tb: str = _MlirGvSbRead1 p = _mlir_read_type(p, tb, 512) p = _mlir_ws(p) # 显式结构体类型前缀(如 llvm.global_ctors 元素的 # "{ i32, void ()*, i8* } { i32 65535, … }")先整体读掉;`{…}` 既可能是 # 类型也可能是字面量,靠"其后是否紧跟另一个 `{`"区分(见 _MlirGvIsStructType) if p[0] == '{' and _MlirGvIsStructType(p) != 0: - stb: str = _MlirGvPool.alloc(4096) - if stb is None: - MlirFail("MLIR 渲染: 结构体类型前缀缓冲分配失败") + stb: str = _MlirGvSbRead1 p = _mlir_read_type(p, stb, 512) p = _mlir_ws(p) # MLIR 形态聚合类型前缀(`!llvm.array<…>` / `!llvm.struct<…>`)后紧跟聚合 @@ -1205,9 +1271,7 @@ def _MlirGvWalk(p: str, ty: rawptr[LLVMType], path: str, depth: int) -> str: # TranslatorGenMixin._build_array_initializer_text),上方 LLVM 形态前缀 # 判据(_MlirGvIsArrayType/_MlirGvIsStructType)认不出 '!' 开头 if p[0] == '!': - mtb: str = _MlirGvPool.alloc(4096) - if mtb is None: - MlirFail("MLIR 渲染: MLIR 类型前缀缓冲分配失败") + mtb: str = _MlirGvSbRead1 qm: str = _mlir_read_type(p, mtb, 512) qm = _mlir_ws(qm) if qm[0] == '[' or qm[0] == '{': @@ -1276,15 +1340,19 @@ def _MlirGvIsStructType(p: str) -> int: return 0 -def _MlirGvPathChild(path: str, idx: int) -> str: - """由父下标路径与子序号拼出子下标路径(顶层 path="" → "0")""" - nb: str = _MlirGvPool.alloc(string.strlen(path) + 16) - if nb is None: - MlirFail("MLIR 渲染: 下标路径缓冲分配失败") +def _MlirGvPathChild(path: str, idx: int, depth: int) -> str: + """由父下标路径与子序号拼出子下标路径(顶层 path="" → "0") + + 写入按递归深度分槽的复用栈(槽 = depth):祖先路径占 0..depth-1, + 本层写槽 depth、子层写槽 depth+1,互不覆盖;避免逐节点 alloc 泄漏。 + """ + if depth < 0 or depth >= GV_PATH_MAX: + MlirFail("MLIR 渲染: 下标路径深度越界") + nb: str = _MlirGvPathStack + depth * GV_PATH_SLOT if path[0] == '\0': - viperlib.snprintf(nb, string.strlen(path) + 16, "%d", idx) + viperlib.snprintf(nb, GV_PATH_SLOT, "%d", idx) else: - viperlib.snprintf(nb, string.strlen(path) + 16, "%s, %d", path, idx) + viperlib.snprintf(nb, GV_PATH_SLOT, "%s, %d", path, idx) return nb @@ -1317,7 +1385,7 @@ def _MlirGvWalkStruct(p: str, ty: rawptr[LLVMType], path: str, depth: int) -> st fty: rawptr[LLVMType] = None if cur is not None: fty = paramnode_get_ty(cur) - p = _MlirGvWalk(p, fty, _MlirGvPathChild(path, idx), depth + 1) + p = _MlirGvWalk(p, fty, _MlirGvPathChild(path, idx, depth), depth + 1) if cur is not None: cur = paramnode_get_next(cur) idx += 1 @@ -1351,7 +1419,7 @@ def _MlirGvWalkArray(p: str, ty: rawptr[LLVMType], path: str, depth: int) -> str elif p[0] == ',': p = p + 1 else: - p = _MlirGvWalk(p, elem_ty, _MlirGvPathChild(path, idx), depth + 1) + p = _MlirGvWalk(p, elem_ty, _MlirGvPathChild(path, idx, depth), depth + 1) idx += 1 if idx == 0: string.strcpy(_MlirGvLast, "%undef") @@ -1395,26 +1463,20 @@ def _MlirGvWalkLeaf(p: str, ty: rawptr[LLVMType], path: str, depth: int) -> str: p = _mlir_ws(p) if _MlirGvIsBareValue(p) == 0: # 元素自带类型记号(`i8* null` / `!llvm.ptr null` 等):只用于推进游标 - tb: str = _MlirGvPool.alloc(4096) - if tb is None: - MlirFail("MLIR 渲染: 叶子类型记号缓冲分配失败") + tb: str = _MlirGvSbRead2 p = _mlir_read_type(p, tb, 512) p = _mlir_ws(p) if p[0] == '\0': MlirFail("MLIR 渲染: 叶子初值只有类型、缺少值") if p[0] == '@': # 裸符号引用(剥 LLVM 引号 → 经 _MlirSymRefAppend 按 MLIR 口径重加) - nb: str = _MlirGvPool.alloc(4096) - if nb is None: - MlirFail("MLIR 渲染: 符号名缓冲分配失败") + nb: str = _MlirGvSbName p = _MlirGvReadSymName(p, nb, 512) _MlirGvEmitAddressOf(nb) elif string.strncmp(p, "bitcast", 7) == 0 \ or string.strncmp(p, "getelementptr", 13) == 0: # 常量表达式整体视为符号引用(bitcast 不透明指针下恒等;GEP 取首元素地址) - nb2: str = _MlirGvPool.alloc(4096) - if nb2 is None: - MlirFail("MLIR 渲染: 常量表达式符号名缓冲分配失败") + nb2: str = _MlirGvSbName p = _MlirGvScanConstExprSym(p, nb2, 512) _MlirGvEmitAddressOf(nb2) elif string.strncmp(p, "null", 4) == 0: @@ -1426,9 +1488,7 @@ def _MlirGvWalkLeaf(p: str, ty: rawptr[LLVMType], path: str, depth: int) -> str: else: c0: int = p[0] if c0 == '-' or (c0 >= '0' and c0 <= '9') or c0 == '.': - vb: str = _MlirGvPool.alloc(4096) - if vb is None: - MlirFail("MLIR 渲染: 标量初值缓冲分配失败") + vb: str = _MlirGvSbVal p = _mlir_read_value(p, vb, 512) _MlirGvEmitConst(vb, ty) else: @@ -1513,11 +1573,9 @@ def _MlirGvSymNameEnd(ch: int) -> int: def _MlirGvNextLeafName() -> str: - """分配下一个叶子 SSA 名(%v0, %v1, …)""" + """分配下一个叶子 SSA 名(%v0, %v1, …;复用共享名缓冲,调用后立即取用)""" global _MlirGvLeafSeq - ln: str = _MlirGvPool.alloc(32) - if ln is None: - MlirFail("MLIR 渲染: 叶子 SSA 名缓冲分配失败") + ln: str = _MlirGvNameBuf viperlib.snprintf(ln, 32, "%%v%d", _MlirGvLeafSeq) _MlirGvLeafSeq += 1 return ln @@ -1536,9 +1594,7 @@ def _MlirGvEmitAddressOf(name: str): def _MlirGvEmitZero(ty: rawptr[LLVMType]): """发射叶子 op: %vN = llvm.mlir.zero : <元素 MLIR 类型>""" - mt: str = _MlirGvPool.alloc(4096) - if mt is None: - MlirFail("MLIR 渲染: 零初值类型缓冲分配失败") + mt: str = _MlirGvTyBuf mt[0] = '\0' TypePrint(mt, 4096, ty, _MlirGvPool) ln: str = _MlirGvNextLeafName() @@ -1552,9 +1608,7 @@ def _MlirGvEmitZero(ty: rawptr[LLVMType]): def _MlirGvEmitConst(val: str, ty: rawptr[LLVMType]): """发射叶子 op: %vN = llvm.mlir.constant( : <元素 MLIR 类型>) : <同类型>""" - mt: str = _MlirGvPool.alloc(4096) - if mt is None: - MlirFail("MLIR 渲染: 标量元素类型缓冲分配失败") + mt: str = _MlirGvTyBuf mt[0] = '\0' TypePrint(mt, 4096, ty, _MlirGvPool) if mt[0] != 'i' and mt[0] != 'f': @@ -1580,9 +1634,7 @@ def _MlirGvInsertLeaf(path: str): """发射 insertvalue(多下标路径;类型后缀始终是顶层聚合类型)""" global _MlirGvInsSeq _MlirGvInsSeq += 1 - sn: str = _MlirGvPool.alloc(32) - if sn is None: - MlirFail("MLIR 渲染: insertvalue SSA 名缓冲分配失败") + sn: str = _MlirGvNameBuf viperlib.snprintf(sn, 32, "%%s%d", _MlirGvInsSeq) _append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, " ") _append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, sn)