fix(mlir): 全局初始化器区域缓冲溢出不再误报为模块缓冲溢出

- GV_REGION_BUF_SIZE 由 32KB 提升到 4MB,并改用 malloc 分配(原走模块子池,容量受限)
- 新增 _MlirGvOutTrunc 与 _append_gv:区域缓冲溢出独立上报,不再置位模块截断标志
- MlirGvResetScratch 负责释放这两块 malloc 缓冲

复现:font 这类嵌套聚合全局初始化器超过 23 行(368 元素)即误报
module text exceeds output buffer,实际模块缓冲 8MB 远未写满。
This commit is contained in:
TermiNexus committed 2026-10-07 14:24:06 +08:00
1 parent 825919b202
commit 825cd2b027
1 file changed
+64 -36
+64 -36
View File
@@ -923,7 +923,10 @@ def _MlirArrayDenseAt(buf: str, size: sizet, src: str,
# top-level aggregate and whose index path comes from a parallel initializer/type walk. Element MLIR
# types come from the global type tree via TypePrint; constexpr bitcast/GEP are treated as symbol
# references; unsupported leaves fail loud.
define GV_REGION_BUF_SIZE = 32768
# Sized for large aggregate tables (e.g. a [256][16] uint8 font: 4096 leaves plus 4096 insertvalue
# lines of ~110 B each ≈ 450 KiB). These two buffers are malloc'd instead of taken from the module
# sub-pool, so their size is independent of the pool capacity.
define GV_REGION_BUF_SIZE = 4194304
# Index-path reuse stack: one slot per recursion depth (top-level path="" → depth d in slot d).
# Depth cap matches _MlirGvWalk's 64-level guard with margin (72); 512 bytes per slot suffices.
@@ -939,6 +942,9 @@ _MlirGvPrev: str = None # SSA name of the previous insertvalue result
_MlirGvPool: memhub.MemBuddy* = None
_MlirGvLeafSeq: int = 0
_MlirGvInsSeq: int = 0
# Set when a region scratch buffer (leaf/insertvalue) overflows, so its failure is reported as a
# region-buffer overflow instead of being conflated with the module output buffer.
_MlirGvOutTrunc: int = 0
# ---- Region-render REUSED scratch buffers (lazily allocated once, shared across globals/nodes) ----
# Allocating new buffers per global/node exhausted the ~2 MiB sub-pool for struct/vtable-heavy
@@ -957,9 +963,13 @@ def MlirGvResetScratch():
The scratch is reused only within a single PrintModule (shared across globals/nodes); clearing
it at print end prevents reusing a previous print's pointers (freed or reused pool → dangling).
The two large region buffers are malloc'd, so they are freed here.
"""
global _MlirGvLeafBuf
global _MlirGvLeafBuf, _MlirGvInsBuf
if _MlirGvLeafBuf is not None: stdlib.free(_MlirGvLeafBuf)
if _MlirGvInsBuf is not None: stdlib.free(_MlirGvInsBuf)
_MlirGvLeafBuf = None
_MlirGvInsBuf = None
def _MlirGvEnsureScratch(pool: memhub.MemBuddy*) -> int:
@@ -969,8 +979,8 @@ def _MlirGvEnsureScratch(pool: memhub.MemBuddy*) -> int:
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)
lb: str = stdlib.malloc(GV_REGION_BUF_SIZE)
ib: str = stdlib.malloc(GV_REGION_BUF_SIZE)
tb: str = pool.alloc(4096)
la: str = pool.alloc(32)
pr: str = pool.alloc(32)
@@ -1067,7 +1077,7 @@ def _MlirGlobalInitRegion(buf: str, size: sizet,
Each line ends with '\\n'; the caller appends '}' and the module layer re-indents by 2.
"""
global _MlirGvPool, _MlirGvLeafSeq, _MlirGvInsSeq
global _MlirGvPool, _MlirGvLeafSeq, _MlirGvInsSeq, _MlirGvOutTrunc
x: str = gv.Initializer
if x is None:
return
@@ -1089,6 +1099,7 @@ def _MlirGlobalInitRegion(buf: str, size: sizet,
_MlirGvPool = pool
_MlirGvLeafSeq = 0
_MlirGvInsSeq = 0
_MlirGvOutTrunc = 0
is_agg: int = 0
match gv.Ty:
@@ -1102,7 +1113,9 @@ def _MlirGlobalInitRegion(buf: str, size: sizet,
# Start of the insertvalue chain: top-level undef
string.strcpy(prevbuf, "%undef")
_MlirGvWalk(x, gv.Ty, "", 0)
_MlirGvWalk(x, gv.Ty, "", 0)
if _MlirGvOutTrunc != 0:
MlirFail("MLIR render: global initializer region text exceeds GV_REGION_BUF_SIZE (increase it)")
# Emit leaf ops first, then the undef + insertvalue chain
_append_cstr(buf, size, leafbuf)
@@ -1462,11 +1475,11 @@ def _MlirGvNextLeafName() -> str:
def _MlirGvEmitAddressOf(name: str):
"""Emit a leaf op: %vN = llvm.mlir.addressof @"name" : !llvm.ptr."""
ln: str = _MlirGvNextLeafName()
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " ")
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ln)
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " = llvm.mlir.addressof ")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " ")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ln)
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " = llvm.mlir.addressof ")
_MlirSymRefAppend(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, name)
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " : !llvm.ptr\n")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " : !llvm.ptr\n")
string.strcpy(_MlirGvLast, ln)
@@ -1476,11 +1489,11 @@ def _MlirGvEmitZero(ty: LLVMType*):
mt[0] = '\0'
TypePrint(mt, 4096, ty, _MlirGvPool)
ln: str = _MlirGvNextLeafName()
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " ")
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ln)
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " = llvm.mlir.zero : ")
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, mt)
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, "\n")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " ")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ln)
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " = llvm.mlir.zero : ")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, mt)
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, "\n")
string.strcpy(_MlirGvLast, ln)
@@ -1492,19 +1505,19 @@ def _MlirGvEmitConst(val: str, ty: LLVMType*):
if mt[0] != 'i' and mt[0] != 'f':
MlirFail("MLIR render: global initializer scalar element type is neither integer nor float")
ln: str = _MlirGvNextLeafName()
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " ")
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ln)
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " = llvm.mlir.constant(")
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, val)
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " ")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ln)
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " = llvm.mlir.constant(")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, val)
# i1's `true`/`false` are MLIR bare boolean keywords and take no type suffix
# (`llvm.mlir.constant(false : i1)` errors "expected ')'"); other scalars must use
# `value : type` (otherwise they are untyped attrs and mismatch the result type).
if string.strcmp(val, "true") != 0 and string.strcmp(val, "false") != 0:
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " : ")
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, mt)
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ") : ")
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, mt)
_append_cstr(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, "\n")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, " : ")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, mt)
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, ") : ")
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, mt)
_append_gv(_MlirGvLeafBuf, GV_REGION_BUF_SIZE, "\n")
string.strcpy(_MlirGvLast, ln)
@@ -1514,17 +1527,17 @@ def _MlirGvInsertLeaf(path: str):
_MlirGvInsSeq += 1
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)
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, " = llvm.insertvalue ")
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, _MlirGvLast)
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, ", ")
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, _MlirGvPrev)
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, "[")
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, path)
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, "] : ")
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, _MlirGvTopType)
_append_cstr(_MlirGvInsBuf, GV_REGION_BUF_SIZE, "\n")
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, " ")
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, sn)
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, " = llvm.insertvalue ")
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, _MlirGvLast)
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, ", ")
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, _MlirGvPrev)
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, "[")
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, path)
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, "] : ")
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, _MlirGvTopType)
_append_gv(_MlirGvInsBuf, GV_REGION_BUF_SIZE, "\n")
string.strcpy(_MlirGvPrev, sn)
string.strcpy(_MlirGvLast, sn)
@@ -1597,4 +1610,19 @@ def _append_cstr(dst: str, dst_size: sizet, src: str):
if i < slen:
_MlirModOutTrunc = 1
dst[dlen + i] = '\0'
_g_last_pos = dlen + i
_g_last_pos = dlen + i
def _append_gv(dst: str, dst_size: sizet, src: str):
"""Append to a global-initializer region scratch buffer; overflow sets _MlirGvOutTrunc.
_append_cstr carries a single truncation flag shared with the module output buffer, so that flag
is masked out here and a region-buffer overflow is recorded separately (otherwise a region
overflow is misreported as "module text exceeds output buffer").
"""
global _MlirGvOutTrunc, _MlirModOutTrunc
saved: int = _MlirModOutTrunc
_MlirModOutTrunc = 0
_append_cstr(dst, dst_size, src)
if _MlirModOutTrunc != 0: _MlirGvOutTrunc = 1
_MlirModOutTrunc = saved