Repository navigation
Merge pull request #8 from liuzidi/feature-vmi-shengtao - #1
Merged
Merged
Conversation
VMI VF Fusion:add ColReduce/ColExpand/tcvt VMI tilelib candidates
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
VMI VF Fusion — fusion_region 技术方案
1. 整体思路
VMI tilelib 的 compute TileOp 展开后是单层
scf.for(内层 VL 循环)。把每个 compute TileOp 的 inline body 包进一个pto.fusion_region容器,然后在 unified VMI 层( lowering 之前)做两件事:scf.for融成一个。vstore→vload往返 forward 成纯 SSA 寄存器传递,消掉两端。做完再复用老路
PTOFlattenFusionRegion拆容器,继续 lower 到 VPTO。2. 容器:为什么用 fusion_region 而不是新建容器
复用老路
pto.fusion_region(SingleBlock +pto.yield)。它带 yield/outputs,语义和老路 a5 fusion lifecycle 一致;PTOFlattenFusionRegion收尾 pass 也直接复用(只 move ops + 删 region,对内部 op 零假设,vmi/vpto 通用)。fa 的 compute TileOp 是 DPS(in-place UB),几乎无值逃逸 region → region 是空 yield + 空 results,flatten 时 yield/result 那步空转。
3. Plan:圈定可融合范围(F1/F2/F3 + UB-disjoint)
PTOPlanVmiFusionRegion把相邻 region 合成一个 group region:mte_*/set_flag/wait_flag/mem_bar/pipe_barrier/vecscope/unknown-effectop 关闭当前 group。合并 = 把候选 region body(除 yield)splice 进 group region 的 yield 之前,删候选 region。fa 7 个 region → 1 个 group region。
关键坑:
FusionRegionOp有pto.yieldterminator(老FusionScopeOp是 NoTerminator)。plan 的 boundary walk 要把pto::YieldOp加进跳过列表,否则 region 自己的 yield 被误判成 sync boundary,每个 region 都自成一组。4. LoopFusion:能不能融 = 之间指令能不能 hoist/sink
判定准则(核心)
两个相邻
scf.for(同 header)能不能融成一个,取决于它们之间夹着的指令能不能合法地往上或往下提:between-ops 按依赖连通分量分组
两个 for 之间的指令不是一条条独立判,而是按数据依赖(SSA def-use,或同 UB 的 store→load)划分连通分量。每个分量必须整体 hoist 或整体 sink(拆散会断内部数据流)。一个分量既不能 hoist 又不能 sink → 断开。
fa 的实例
最终 fa 的 6 个 for → 2 个:
中间 ColSum 的
vstore(写 ColSum final)被 sink 到 for2 之后(tcvt 读别的 UB,不读 ColSum 的)。UB 身份追溯
判 hoist/sink 要查"两个 op 是不是操作同一 UB"。UB 身份 =
pto.castptr ← memref ← pto.pointer_cast(addr-const)追到 (地址常量, memref type) 对。两个 castptr 链追溯到同一 addr 常量 + 同 type = 同 UB。prelude / init-producer hoist
member for 之前的 loop-invariant op(pointer_cast/castptr/create_mask)和 init-arg 的定义 op(vbrc 等)不 clone 进 body,而是 moveBefore fused for——天然支配 body,且避免 body 内冗余物质化。后续 CSE 再合并跨 member 的同 UB 重复。
5. LoadStoreElision:消 UB 往返
扫描范围
elideInRegion在两层跑线性扫描:vstore→ tmulsvload。顶层段里遇到
scf.for自动 flush trackedStores(for body 可能读写 UB,之前的 store 可能 stale)。配对 forward
线性扫描:遇到
vstore记进TrackedStore{base, offset, mask, value};遇到vload查匹配(base + offset + mask 三元组相等)→ forward(load.result.replaceAllUsesWith(store.value))+ erase 两端;vstore覆盖同址则 erase 旧 store。pointer_cast→castptr追溯 UB,两个 castptr 链到同 addr+type 判等。vmi.vload无 mask operand,从 consumer op 推断(consumer 都带同 mask 才约束;mask-free consumer 如vcvt不约束 mask——std::optional<Value>,空 = 无约束,任意 mask 的 store 都匹配)。mte_*/sync/for等)→ flush trackedStores;纯计算(vmuls/vexp 等)透传。逃逸边界:哪些 store 不能消
一个
vstore写的 UB 若被 region 外读(如 region 后的mte_ub_gm把 UB 写回 GM),则它是 region 的输出边界,不能消。fa 里 scaled ColMax 的vstore写的 32768 UB 要被 region 外mte_ub_gm读输出给 host → 保留;但 ColExpand-sub 读它的vload可 forward 成 scaled ColMax 的 vreg。6. 关键技术点小结
pto.fusion_region(带 yield),PTOFlattenFusionRegion收尾castptr←memref←pointer_cast(addr-const),(addr, type) 对7. fa 实测结果
8. softmax 融合前后对比(伪代码)
fa softmax 链
ColMax → tmuls(scale) → ColExpand-sub → tmuls → texp → ColSum → tcvt,所有 for header 都是c0→c128 step1。融合前(Inline 后,6 个独立 for + 中间顶层 op)
融合后(LoopFusion + Elision 后,2 个 for)
要点
mte_ub_gm读输出给 host(scaled gmax 是 fa 的输出之一)→ region escape,不能消;但其 load 被 forward 成 SSA。9. 文件清单
lib/PTO/Transforms/PTOPlanVmiFusionRegion.cpp— F1/F2/F3 + UB-disjoint 合并lib/PTO/Transforms/PTOVmiLoopFusion.cpp— 单层融合,依赖连通分量判 hoist/sinklib/PTO/Transforms/PTOVmiLoadStoreElision.cpp— 顶层段 + for body UB 往返消除lib/PTO/Transforms/PTOInstantiateAndInlineOpLib.cpp— inline 时 wrap fusion_regiontools/ptoas/ptoas.cppappendVMISemanticPipeline— 挂载顺序ptodsl/ptodsl/vmi_tilelib.py+_tile_template_tracing.py— VMI candidate(emit_col_reduce/col_expand/tcvt)test/lit/vpto/vmi_fusion_region_softmax.pto— 回归测试test/samples/FlashAttention/fa_dn_softmax_128x64.pto— fa 样本