fix(mlirlite): 全局数组 dense 渲染缓冲提到循环外复用(消每元素~5KB泄漏) + 聚合值读取必前进(修 too many global array elements)

This commit is contained in:
TermiNexus committed 2026-10-16 12:04:24 +08:00
1 parent 1eb46faa41
commit e9e1933a62
1 file changed
+56 -13
+56 -13
View File
@@ -878,18 +878,57 @@ def _MlirCStringToMlir(buf: str, size: sizet, src: str, pool: memhub.MemBuddy*):
_append_cstr(buf, size, p)
def _mlir_read_aggregate_token(p: str, out: str, outsz: sizet) -> str:
"""读取一个聚合/复合值 token(括号配平),到**顶层**分隔符(`,` 或 `]`)为止,不消费分隔符。
用于 `_mlir_read_value` 覆盖不到的形态,例如 `[16 x i8] zeroinitializer`、`{ i32 1, i32 2 }`:
这类值以 `[`/`{` 开头,`_mlir_read_value` 不会前进,会让外层数组解析原地打转。
如果连一个字符都没读到(调用方随后会做"至少前进 1 字符"的兜底)。
"""
p = _mlir_ws(p)
n: sizet = 0
d: int = 0
while p[0] != '\0':
ch: int = p[0]
if d == 0 and (ch == ',' or ch == ']'):
break
if ch == '[' or ch == '{' or ch == '(' or ch == '<':
d += 1
elif ch == ']' or ch == '}' or ch == ')' or ch == '>':
if d == 0:
break
d -= 1
if n + 1 < outsz:
out[n] = char(ch)
n += 1
p = p + 1
out[n] = '\0'
return p
def _MlirArrayDenseAt(buf: str, size: sizet, src: str,
pool: memhub.MemBuddy*) -> str:
"""LLVM array literal → MLIR dense content (nested recursive); returns the new cursor."""
if src is None or src[0] != '[':
MlirFail("MLIR render: global array initializer form unsupported in v1")
# [修复] 三个临时缓冲**在进入时分配一次**并全程复用:原实现是"每个元素分配
# 512(类型文本) + 512(值文本) + 4096(元素 MLIR 类型) ≈ 5KB 且从不释放",于是
# `[256][16]uint8` 这类大表(4096 元素)单次就吃掉 ~20MB 编译池,多个全局数组叠加
# 直接耗尽(现场:[MEM] alloc failed … order=5/8 占 943MB、attribution site=?)。
tb: str = pool.alloc(512)
vb: str = pool.alloc(512)
mtb: str = pool.alloc(4096)
if tb is None or vb is None or mtb is None:
MlirFail("MLIR render: array element buffer allocation failed")
p: str = src + 1
_append_cstr(buf, size, "[")
n: int = 0
g: int = 0
while p[0] != '\0':
g += 1
if g > 4096:
# 上限只用于防"解析不收敛"的死循环,不是数组容量限制:位图字体表
# `[256] x [16]uint8` 本身就 4352 个元素(外层 256 + 内层 4096),旧值 4096 会误报。
if g > 1048576:
MlirFail("MLIR render: too many global array elements")
p = _mlir_ws(p)
if p[0] == ']':
@@ -902,23 +941,25 @@ def _MlirArrayDenseAt(buf: str, size: sizet, src: str,
if p[0] == '[':
p = _MlirArrayDenseAt(buf, size, p, pool)
else:
tb: str = pool.alloc(512)
if tb is None:
MlirFail("MLIR render: array element type buffer allocation failed")
p = _mlir_read_type(p, tb, 512)
p = _mlir_ws(p)
vb: str = pool.alloc(512)
if vb is None:
MlirFail("MLIR render: array element value buffer allocation failed")
p = _mlir_read_value(p, vb, 512)
p2: str = _mlir_read_value(p, vb, 512)
# [修复] 值不是 %name / @"name" / 字面量时(聚合值:`[16 x i8] zeroinitializer`、
# `{ i32 1, i32 2 }`),`_mlir_read_value` 原地不前进 ⇒ 外层 while 不收敛 ⇒
# g 冲到上限并误报 "too many global array elements"。这里回退为括号配平读取,
# 并保证**至少前进 1 个字符**,绝不原地打转。
if p2 == p:
p2 = _mlir_read_aggregate_token(p, vb, 512)
if p2 == p:
vb[0] = char(p[0])
vb[1] = '\0'
p2 = p + 1
p = p2
_append_cstr(buf, size, vb)
# Elements must carry a type annotation: MLIR array attributes default to i64, so
# i8/i32/pointer elements would mismatch the global type (working form:
# `[1 : i8, 2 : i8] : !llvm.array<2 x i8>`).
_append_cstr(buf, size, " : ")
mtb: str = pool.alloc(4096)
if mtb is None:
MlirFail("MLIR render: array element MLIR type buffer allocation failed")
mtb[0] = '\0'
MlirTypeText(mtb, 4096, tb, pool)
_append_cstr(buf, size, mtb)
@@ -1275,7 +1316,8 @@ def _MlirGvWalkStruct(p: str, ty: LLVMType*, path: str, depth: int) -> str:
guard: int = 0
while done == 0:
guard += 1
if guard > 4096:
# 防解析不收敛的死循环,不是字段数上限(大结构体的初始化器可能很长)。
if guard > 1048576:
MlirFail("MLIR render: too many struct initializer elements")
p = _mlir_ws(p)
if p[0] == '\0':
@@ -1312,7 +1354,8 @@ def _MlirGvWalkArray(p: str, ty: LLVMType*, path: str, depth: int) -> str:
guard: int = 0
while done == 0:
guard += 1
if guard > 65536:
# 防解析不收敛的死循环,不是数组元素上限(大数组的初始化器可能很长)。
if guard > 1048576:
MlirFail("MLIR render: too many array initializer elements")
p = _mlir_ws(p)
if p[0] == '\0':