fix(mlirlite): 常量表与自动常量名空间(%c<seq>)按需扩容

原实现三处都钉死在 MLIR_CONST_CAP(512):常量表满 → MlirFail("constant table overflow")、%c0..%c511 用尽 → MlirFail、_MlirMarkUsedCName 里"更大的后缀不可能冲突"的假设。这些只是资源限制,不该中断编译。

- 新增 _MLIR_ConstCap 活容量与 _MlirConstGrow(池内翻倍扩容常量表 + 已用名表并拷贝旧内容)
- 常量表满、名字空间用尽改为扩容后重试;_MlirMarkUsedCName 记录任意 c<digits> 并先扩容再置位
- _MlirTablesInit 按活容量分配/清零,复用分支保留已扩容容量
This commit is contained in:
TermiNexus committed 2026-10-12 12:40:20 +08:00
1 parent cc7cfdb4af
commit 4914311014
1 file changed
+61 -23
+61 -23
View File
@@ -1210,9 +1210,11 @@ _MlirTablesValid: int = 0
_MlirTablesPool: memhub.MemBuddy* = None
# Live capacities of the constant/alias tables: start at the define defaults and grow on demand
# (_MlirAliasGrow / const table), instead of hard-failing the whole compile when a big function
# needs more entries than the fixed caps allow.
# (_MlirAliasGrow / _MlirConstGrow), instead of hard-failing the whole compile when a big function
# needs more entries than the fixed caps allow. _MLIR_ConstCap also bounds the auto constant name
# space (%c<seq>) and the used-name table, which used to be nailed to MLIR_CONST_CAP.
_MLIR_AliasCap: int = MLIR_ALIAS_CAP
_MLIR_ConstCap: int = MLIR_CONST_CAP
def MlirTablesReset():
@@ -1254,7 +1256,7 @@ def _MlirTablesInit(pool: memhub.MemBuddy*):
function-heavy modules; the equivalent global-region scratch (MlirGvEnsureScratch) already reuses
this way. Callers that may reset the pool between prints must call MlirTablesReset first.
"""
global _MLIR_Pool, _MLIR_Pass, _MLIR_ConstTy, _MLIR_ConstVal, _MLIR_ConstName, _MLIR_ConstCount, _MLIR_ConstNameSeq, _MLIR_UsedC, _MLIR_AliasFrom, _MLIR_AliasTo, _MLIR_AliasCount, _MLIR_AliasCap, _SC_Op, _SC_Tb, _SC_Ty, _SC_Ty2, _SC_V1, _SC_V2, _SC_V3, _SC_Callee, _SC_Args, _SC_ArgTs, _SC_IdxV, _SC_IdxT, _SC_Mt, _SC_Tmp, _SC_Tmp2, _SC_P1, _SC_P2, _SC_B1, _SC_B2, _SC_Buf, _MlirTablesValid, _MlirTablesPool
global _MLIR_Pool, _MLIR_Pass, _MLIR_ConstTy, _MLIR_ConstVal, _MLIR_ConstName, _MLIR_ConstCount, _MLIR_ConstNameSeq, _MLIR_UsedC, _MLIR_ConstCap, _MLIR_AliasFrom, _MLIR_AliasTo, _MLIR_AliasCount, _MLIR_AliasCap, _SC_Op, _SC_Tb, _SC_Ty, _SC_Ty2, _SC_V1, _SC_V2, _SC_V3, _SC_Callee, _SC_Args, _SC_ArgTs, _SC_IdxV, _SC_IdxT, _SC_Mt, _SC_Tmp, _SC_Tmp2, _SC_P1, _SC_P2, _SC_B1, _SC_B2, _SC_Buf, _MlirTablesValid, _MlirTablesPool
if pool is None:
MlirFail("MLIR render: memory pool is null")
if _MlirTablesValid != 0 and _MlirTablesPool == pool:
@@ -1266,27 +1268,28 @@ def _MlirTablesInit(pool: memhub.MemBuddy*):
_MLIR_ConstCount = 0
_MLIR_ConstNameSeq = 0
_MLIR_AliasCount = 0
string.memset(_MLIR_UsedC, 0, MLIR_CONST_CAP * 4)
string.memset(_MLIR_UsedC, 0, _MLIR_ConstCap * 4)
return
_MLIR_Pool = pool
_MLIR_Pass = 0
_MLIR_ConstCount = 0
_MLIR_ConstNameSeq = 0
_MLIR_AliasCount = 0
_MLIR_ConstTy = pool.alloc(MLIR_CONST_CAP * 8)
_MLIR_ConstVal = pool.alloc(MLIR_CONST_CAP * 8)
_MLIR_ConstName = pool.alloc(MLIR_CONST_CAP * 8)
_MLIR_UsedC = pool.alloc(MLIR_CONST_CAP * 4)
_MLIR_ConstCap = MLIR_CONST_CAP
_MLIR_ConstTy = pool.alloc(_MLIR_ConstCap * 8)
_MLIR_ConstVal = pool.alloc(_MLIR_ConstCap * 8)
_MLIR_ConstName = pool.alloc(_MLIR_ConstCap * 8)
_MLIR_UsedC = pool.alloc(_MLIR_ConstCap * 4)
_MLIR_AliasCap = MLIR_ALIAS_CAP
_MLIR_AliasFrom = pool.alloc(_MLIR_AliasCap * 8)
_MLIR_AliasTo = pool.alloc(_MLIR_AliasCap * 8)
if _MLIR_ConstTy is None or _MLIR_ConstVal is None or _MLIR_ConstName is None \
or _MLIR_UsedC is None or _MLIR_AliasFrom is None or _MLIR_AliasTo is None:
MlirFail("MLIR render: constant/alias table allocation failed")
string.memset(_MLIR_ConstTy, 0, MLIR_CONST_CAP * 8)
string.memset(_MLIR_ConstVal, 0, MLIR_CONST_CAP * 8)
string.memset(_MLIR_ConstName, 0, MLIR_CONST_CAP * 8)
string.memset(_MLIR_UsedC, 0, MLIR_CONST_CAP * 4)
string.memset(_MLIR_ConstTy, 0, _MLIR_ConstCap * 8)
string.memset(_MLIR_ConstVal, 0, _MLIR_ConstCap * 8)
string.memset(_MLIR_ConstName, 0, _MLIR_ConstCap * 8)
string.memset(_MLIR_UsedC, 0, _MLIR_ConstCap * 4)
string.memset(_MLIR_AliasFrom, 0, _MLIR_AliasCap * 8)
string.memset(_MLIR_AliasTo, 0, _MLIR_AliasCap * 8)
_SC_Op = pool.alloc(64)
@@ -1355,6 +1358,36 @@ def _MlirAliasGrow():
_MLIR_AliasCap = old_cap * 2
def _MlirConstGrow():
"""扩容常量表 + 自动常量名空间(%c<seq>)+ 已用名表:池内分配翻倍新块并拷贝旧内容。
原实现三处都钉死在 MLIR_CONST_CAP(512):常量表满 → MlirFail("constant table overflow")、
%c0..%c511 用尽 → MlirFail、以及 _MlirMarkUsedCName 里"更大的后缀不可能冲突"的假设。
这些只是资源限制,不该中断编译,故统一按需扩容。
"""
global _MLIR_ConstTy, _MLIR_ConstVal, _MLIR_ConstName, _MLIR_UsedC, _MLIR_ConstCap
old_cap: int = _MLIR_ConstCap
nb_ty: bytes = _MLIR_Pool.alloc(old_cap * 16)
nb_val: bytes = _MLIR_Pool.alloc(old_cap * 16)
nb_nm: bytes = _MLIR_Pool.alloc(old_cap * 16)
nb_used: bytes = _MLIR_Pool.alloc(old_cap * 8)
if nb_ty is None or nb_val is None or nb_nm is None or nb_used is None:
MlirFail("MLIR render: constant table growth allocation failed")
string.memcpy(nb_ty, _MLIR_ConstTy, old_cap * 8)
string.memcpy(nb_val, _MLIR_ConstVal, old_cap * 8)
string.memcpy(nb_nm, _MLIR_ConstName, old_cap * 8)
string.memcpy(nb_used, _MLIR_UsedC, old_cap * 4)
string.memset(nb_ty + old_cap * 8, 0, old_cap * 8)
string.memset(nb_val + old_cap * 8, 0, old_cap * 8)
string.memset(nb_nm + old_cap * 8, 0, old_cap * 8)
string.memset(nb_used + old_cap * 4, 0, old_cap * 4)
_MLIR_ConstTy = nb_ty
_MLIR_ConstVal = nb_val
_MLIR_ConstName = nb_nm
_MLIR_UsedC = nb_used
_MLIR_ConstCap = old_cap * 2
def _MlirAliasAdd(from_name: str, to_name: str):
"""Register a no-op bitcast alias (from is replaced by to)"""
global _MLIR_AliasCount
@@ -1410,9 +1443,8 @@ def _usedc_get(idx: int) -> int:
def _MlirMarkUsedCName(name: str):
"""Mark name (an SSA name, with or without a leading '%') as used iff it is exactly c<digits>.
Only numbers in [0, MLIR_CONST_CAP) can ever be produced by the constant namer (it fails before
reaching MLIR_CONST_CAP), so larger suffixes cannot collide and are ignored. A longer name like
`c1x` is not c<digits> and is ignored too (its token would not match `%c1`).
自动常量名 %c<seq> 的编号空间会按需扩容(见 _MlirConstGrow),所以这里记录**任意** c<digits>
后缀:越界的编号先扩容已用名表再置位,否则扩出来的编号可能与该函数自带的 c<N> 撞名。
"""
if name is None:
return
@@ -1450,13 +1482,16 @@ def _MlirScanUsedCText(text: str):
d: int = 0
nd: int = 0
while _is_digit_ch(e[0]) != 0:
if d < MLIR_CONST_CAP:
# 上限只用于防溢出:记录任何 c<digits>(名字空间会按需扩容,
# 不能再假设"更大的后缀不会与自动名冲突")
if d < 100000000:
d = d * 10 + (int(e[0]) - 48)
nd += 1
e = e + 1
if nd > 0 and _MlirIsSsaNameChar(e[0]) == 0:
if d < MLIR_CONST_CAP:
_usedc_set(d, 1)
if d >= _MLIR_ConstCap:
_MlirConstGrow()
_usedc_set(d, 1)
p = e
continue
p = p + 1
@@ -1517,8 +1552,8 @@ def _MlirConstGet(tytext: str, valtext: str) -> str:
if _MLIR_Pass == 2:
# pass1 already scanned all instruction lines; no new constant should appear here
MlirFail("MLIR render: unmaterialized constant in emit pass (scan missed it)")
if _MLIR_ConstCount >= MLIR_CONST_CAP:
MlirFail("MLIR render: constant table overflow")
if _MLIR_ConstCount >= _MLIR_ConstCap:
_MlirConstGrow()
nm: str = _MLIR_Pool.alloc(32)
if nm is None:
MlirFail("MLIR render: constant name allocation failed")
@@ -1526,10 +1561,13 @@ def _MlirConstGet(tytext: str, valtext: str) -> str:
# seq is strictly increasing, so names stay unique; it is decoupled from the table index, and the
# (type,value) cache above still makes identical constants reuse the same name.
seq: int = _MLIR_ConstNameSeq
while seq < MLIR_CONST_CAP and _usedc_get(seq) != 0:
while seq < _MLIR_ConstCap and _usedc_get(seq) != 0:
seq += 1
if seq >= MLIR_CONST_CAP:
MlirFail("MLIR render: no free constant SSA name (%c0..%c511 all used by the function)")
if seq >= _MLIR_ConstCap:
# 名字空间同样按需扩容:原来钉死在 %c0..%c511,用尽就 MlirFail
_MlirConstGrow()
while seq < _MLIR_ConstCap and _usedc_get(seq) != 0:
seq += 1
_MLIR_ConstNameSeq = seq + 1
viperlib.snprintf(nm, 32, "%%c%d", seq)
sp2: str* = _mlir_slotp(_MLIR_ConstTy, _MLIR_ConstCount)