From 03450a71ffd25cd9bbfe225115315e36d4365d04 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 5 Oct 2026 19:58:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(mlirlite):=20=E5=B1=80=E9=83=A8=E7=AA=A5?= =?UTF-8?q?=E5=AD=94=E4=BC=98=E5=8C=96=E6=AF=8F=E4=B8=AA=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E4=BD=93=E5=8F=AA=E6=89=A7=E8=A1=8C=E4=B8=80=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PrintModule 会按 STUB/TEXT/FULL 三次 dump 同一模块,而 FunctionPrint 每次都跑 _peephole_opt;T2(entry-slot store→load 转发)不是幂等变换,第二遍会误删仍有 load 指向的 entry alloca,留下悬空 SSA 名(mlir-opt: op using value defined outside the region)。给 Function 加 PeepDone 守卫,优化只作用于 builder 产出的原始文本。 --- mlirlite/__function.vp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/mlirlite/__function.vp b/mlirlite/__function.vp index 67903ec..9ff1fa3 100644 --- a/mlirlite/__function.vp +++ b/mlirlite/__function.vp @@ -90,6 +90,7 @@ novirtual class Function(GSListNode[Function]): AttrGroupId: int # attribute group id (>0 emits #N on the function line and attributes #N at module end) NameLen: sizet # function name length (computed once at creation, always == strlen(Name); appended last so existing field offsets stay) DbgRef: str # DISubprogram ref (kept as-is; ignored by MLIR printing, e.g. "!3") + PeepDone: int # 1=local peephole already applied to this body (runs once; see FunctionPrint) # ============================================================ @@ -150,8 +151,8 @@ def new_param(pool: memhub.MemBuddy*, ty: LLVMType*, return ptr -# Function hardcoded size: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) + AttrGroup(8) + AttrGroupId(8) + NameLen(8) + DbgRef(8) = 88 bytes (same layout as llvmlite) -define FUNC_SIZE = 88 +# Function hardcoded size: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) + AttrGroup(8) + AttrGroupId(8) + NameLen(8) + DbgRef(8) + PeepDone(8) = 96 bytes (same layout as llvmlite) +define FUNC_SIZE = 96 def new_function(pool: memhub.MemBuddy*, name: str, ret_ty: LLVMType*) -> Function*: @@ -167,6 +168,7 @@ def new_function(pool: memhub.MemBuddy*, name: str, ptr.Attrs = None ptr.AttrGroup = None ptr.AttrGroupId = 0 + ptr.PeepDone = 0 # NameLen computed once: Name never changes, so NameLen == strlen(Name) (avoids repeated strlen). # name=None sets 0, matching new_line's null convention (explicit for fixed semantics, not allocator behavior). if name is not None: @@ -3209,8 +3211,13 @@ def FunctionPrint(buf: str, size: sizet, # no-op bitcast removal): peepholes match by name and delete lines by setting Buf=None. # They act on the builders' intermediate instruction text and are orthogonal to MLIR rendering; # RenumberSSA internally skips declare functions (IsDeclared==1). - if func.IsDeclared == 0 and G_PeepEnable != 0: + # Run at most ONCE per body: the module is printed several times (STUB/TEXT/FULL, see PrintModule) + # and the T2 forwarding is NOT idempotent — a second pass over the already-optimized text can + # drop an entry alloca whose use was only reachable through a line the first pass had removed, + # leaving dangling SSA names (mlir-opt: "op using value defined outside the region"). + if func.IsDeclared == 0 and G_PeepEnable != 0 and func.PeepDone == 0: _peephole_opt(func, pool) + func.PeepDone = 1 RenumberSSA(func, pool) _MlirTablesInit(pool)