Skip to content

fix(vmi): dynamic vci index + group-periodic share (raw vci) - #1112

Open
peanutchan wants to merge 9 commits into
hw-native-sys:mainfrom
peanutchan:feat/vmi-vci-dynamic-index-base
Open

fix(vmi): dynamic vci index + group-periodic share (raw vci)#1112
peanutchan wants to merge 9 commits into
hw-native-sys:mainfrom
peanutchan:feat/vmi-vci-dynamic-index-base

Conversation

@peanutchan

@peanutchan peanutchan commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Dynamic loop IVs (TileLang T.serial / scf.for) arrive as MLIR index; coerce to signless i32 in PTODSL so pto.vmi.vci ODS/verify accept the base.
  • Restore optional {group} on vci/iota (ODS + PTODSL group=), preserve through unified→legacy and rematerialize.
  • Semantics: without {group} → continuous ramp base..base+L-1 (VL128: 0..63 then 64..127). With {group=C} → group-periodic restart per group of size S = L/C.
  • Contiguous packing lowers as raw pto.vci(%chunkBase). Identical group runs share one physical index VL (return %idx, %idx for VL128/g=2).
  • Sub-VL contiguous groups (S < physVL and physVL % S == 0, e.g. i32 64/g=2, i16 128/g=2): vci(base) then per-group ∓ g·S + lane-range vsel. Early reject when S neither divides nor is a multiple of phys VL (ODS verify + PTODSL).
  • Deinterleaved / interleaved group results: no dedicated grouped-deint iota path. Require contiguous materialization; unified→legacy rewrites non-contiguous grouped vci/iota to contiguous iota + ensure_layout so layout infer / rematerialize can produce vdintlv etc.

Test plan

  • lit: vmi_to_vpto_iota_group2.pto → shared %idx = pto.vci %base
  • lit: vmi_to_vpto_iota_group_subvl.pto → i32 64/g2, i16 128/g2, i32 128/g4 share
  • lit: vmi_to_vpto_iota_group_deint.pto → shared contiguous vci then vdintlv
  • python3 ptodsl/tests/test_vmi_vci_dynamic_index.py (const / dynamic / group=2 / sub-VL / untileable reject)
  • Simple camodel share case:
    scripts/sim_dsl.sh --output /tmp/vci_vadds_g2_out ptodsl/examples/vci_vadds_share_launch.py -- --groups 2
    vci(0)+vadds(1000)+vsts expects 1000..1063|1000..1063 (g=1: 1000..1063)
  • CI ptodsl / lit as applicable

After rebuild: ninja ptoas_runtime_staging (ptoas loads runtime-staging/lib/ptoas.so).

peanutchan and others added 2 commits August 3, 2026 22:31
Dynamic loop IVs (TileLang T.serial / scf.for) arrive as MLIR index.
VCI ODS/verify require an integer/float sreg element type; default
index→i32 so dynamic bases lower to VCI Vd, Sn like Ascend S.vci.

Co-authored-by: Cursor <cursoragent@cursor.com>
Dynamic group=2 (VL128) failed on camodel when contiguous iota used
raw VCI with a register Sn base. Restore {group} on vci/iota, keep
group-periodic lane offsets, and materialize contiguous chunks as
vci(0)+vadds like deinterleaved/ASC so dynamic bases rematerialize.

Co-authored-by: Cursor <cursoragent@cursor.com>
@peanutchan peanutchan changed the title fix(ptodsl): coerce MLIR index bases to i32 for pto.vmi.vci fix(vmi): dynamic vci index coerce + grouped contiguous iota for camodel Aug 3, 2026
group=2 is group-periodic [base..base+S | …], not a continuous 0..L-1
ramp. Physical parts with the same laneOffset reuse one iota chunk so
VL128 group=2 does not re-emit duplicate vci/vadds.

Co-authored-by: Cursor <cursoragent@cursor.com>
@peanutchan peanutchan changed the title fix(vmi): dynamic vci index coerce + grouped contiguous iota for camodel fix(vmi): dynamic vci index + group-periodic iota (shared index vreg) Aug 3, 2026
Drop the vci(0)+vadds contiguous materialize path; contiguous iota is
pto.vci(chunkBase) again, with group=2 reusing one SSA. Replace the
topk-heavy share proof with lit expectations plus a simple
vci(0)+vadds(1000)+vsts camodel example.

Co-authored-by: Cursor <cursoragent@cursor.com>
@peanutchan peanutchan changed the title fix(vmi): dynamic vci index + group-periodic iota (shared index vreg) fix(vmi): dynamic vci index + group-periodic share (raw vci) Aug 4, 2026
@mouliangyu

mouliangyu commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

当前 group 的合法性约束在 PTODSL / op verifier 与 VMIToVPTO lowering 之间不一致,建议合入前统一。

例如 pto.vmi.vci(pto.i32(0), size=64, group=2)

  • PTODSL 只检查 group > 0size % group == 0,因此接受该调用;
  • VMIVciOp::verify() / VMIIotaOp::verify() 同样只检查整除,因此 IR 验证通过;
  • VMIToVPTO 额外要求 group_size % physical_lanes_per_part == 0。这里 group_size=32、i32 物理 VL 为 64,最终在 lowering 报 failed to legalize operation pto.vmi.iota

请明确并统一接口约束:

  1. 如果 ODS 中声明的任意可整除 group 都应支持,请补齐 sub-VL group-periodic ramp 的 materialization;
  2. 如果当前只支持 group size 为物理 VL 整数倍,请在 PTODSL 和 op verifier 提前拒绝,并给出可执行的诊断,不要让合法性问题延迟到 conversion failure;
  3. 补充 i32 size=64/group=2、i16 size=128/group=2 等边界/negative tests,并确保 PTODSL 与直接 MLIR 两条入口约束一致。

另外,grouped deinterleaved layout 也需要纳入约束或测试;当前 factor=1, part=0 的 materialization 会把两路相同 ramp 交错成 [base, base, base+1, base+1, ...],与声明的 group-periodic 语义不一致。

Support group-periodic vci/iota when S < physVL (mask+vsel), and rewrite
non-contiguous grouped results to contiguous iota + ensure_layout so
layout infer handles interleave/deinterleave without a dedicated path.

Co-authored-by: Cursor <cursoragent@cursor.com>
@peanutchan

Copy link
Copy Markdown
Contributor Author

已按方案 1 补齐,并统一了 PTODSL / ODS verify / VMIToVPTO 的约束(最新 commit d407583ee):

  1. Sub-VL group-periodic:当 S < physVLphysVL % S == 0(如 i32 64/g=2、i16 128/g=2)时,用 vci(base) + 按组 ∓ g·S + lane-range vsel 拼出 group-periodic ramp;S 既不能整除也不能被整除 phys VL 时,PTODSL 与 VMIVciOp/VMIIotaOp::verify 提前拒绝(不再拖到 conversion failure)。
  2. Grouped deinterleaved:不单独做 grouped-deint materialization。grouped vci/iota 只生成 contiguous;若结果 layout 非 contiguous,unified→legacy 改写为 contiguous iota + ensure_layout,由 layout infer 产出 vdintlv 等。这样避免 factor=1, part=0 把两路相同 ramp 交错成 [base,base,base+1,base+1,...]
  3. 测试
    • lit vmi_to_vpto_iota_group_subvl.pto(i32 64/g2、i16 128/g2、i32 128/g4 share)
    • lit vmi_to_vpto_iota_group_deint.pto(shared vcivdintlv
    • PTODSL test_vmi_vci_dynamic_index.py 增加 sub-VL 与 untileable reject

请再看一眼 PR description 与上述 lit。

peanutchan and others added 3 commits August 4, 2026 21:17
Replace unpack-only checks with real consumers: shared group2 + vadds/vsts,
more sub-VL group sizes (i32 g2/g4/g8, i16 g2/g4), and deint + sitofp vcvt.

Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid mixing top-level mlir.ir bindings with ptoas MLIR types in the
untileable group reject check.

Co-authored-by: Cursor <cursoragent@cursor.com>
Exercise full-VL sharing and sub-VL group restart semantics through vadds, vsts, and GM output so native regressions catch lowering gaps.

Co-authored-by: Cursor <cursoragent@cursor.com>
@peanutchan

Copy link
Copy Markdown
Contributor Author

E2E verification update:

  • Native PTOAS -> Bisheng builds passed for g1, full-VL g2, sub-VL i32_g2, i32_g4, and i16_g2 (each produced an AArch64 kernel.o and launch .so).
  • Ascend950PR_9599 camodel passed all five cases. Each kernel computes vci(0, group=...) + vadds(1000), stores through vsts, DMA-copies to GM, and checks exact host output. Group boundaries restart at 1000 as expected.
  • Grouped VMI lit regressions: 3/3 passed.
  • PTODSL dynamic/group/sub-VL regression: passed.

The launch probes are now committed on this PR branch in 3ae313def.

@mouliangyu

mouliangyu commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

复检 3ae313def 后,sub-VL group 的物化已经补上,但仍有两个 correctness 问题需要合入前处理。

1. [P1] deinterleaved 修复在真实编译流程中可能不会触发

PR 的处理思路是:当 grouped vci/iota 的结果需要 non-contiguous layout 时,先生成 contiguous grouped iota,再用 ensure_layout 转成目标 layout。这个思路本身没有问题。

问题是该 rewrite 与 layout assignment 的执行顺序相反:

VMILowerUnifiedToLegacy   ← 这里执行新增 rewrite
...
VMILayoutAssignment      ← 到这里才决定结果采用什么 layout
VMILayoutRematerialize
...
VMIToVPTO

对应 pipeline 在 tools/ptoas/ptoas.cpp:3024-3051。新增 rewrite 位于 VMILowerUnifiedToLegacy.cpp:1222-1242, 1625-1655,它只有在执行时已经看到 concrete non-contiguous layout 才会插入 contiguous iota + ensure_layout

正常 PTODSL/PTO surface IR 在这个阶段还没有 layout。因此真实流程可能是:

1. lower-unified 看到 grouped iota,但类型尚未分配 layout
   → rewrite 不触发
2. layout assignment 根据 widening/elementwise consumer,
   将这个 grouped iota 分配为 deinterleaved=2
3. 不会再次执行 lower-unified rewrite
4. VMIToVPTO 在 5403-5406 行拒绝 grouped non-contiguous iota
   → legalization/编译失败

这里不是假设 layout assignment 会自动保护 iota:VMILayoutPropagation.cpp:784-786 当前把 VMIIotaOp 当作 free-result-layout producer,允许它直接获得 consumer 请求的 layout。

新增测试 test/lit/vmi_new/vmi_to_vpto_iota_group_deint.pto:19-20 没覆盖这条真实路径。测试提前把结果类型写成了 deinterleaved=2,并且只运行:

-vmi-lower-unified-to-legacy -vmi-to-vpto

这等于提前向 rewrite 提供了 production pipeline 在该阶段尚不知道的信息,所以测试能通过,不能证明从无 layout 的 surface IR 出发也能通过。

建议考虑定义一条独立的内部 legacy op,例如 pto.vmi.group_iota,用于承载 grouped iota 的特殊行为:

public unified API:
  vci(..., group=None)  → legacy iota
  vci(..., group=C)     → legacy group_iota

layout capability:
  iota        → 保持现有普通 iota 的 layout/tail 行为
  group_iota  → 只能直接产生 contiguous layout

这里不需要增加新的 PTODSL 用户 API;对外仍是 pto.vmi.vci(..., group=...)。关键是让 group_iota 在 layout support/propagation 中明确成为 contiguous-only producer,而不是继续复用当前允许任意结果 layout 的 VMIFreeResultLayoutTransfer

这样当 widening/elementwise consumer 请求 deinterleaved=2 时,现有 propagator 会自然把 group_iota 的 primary layout 选为 contiguous,将 consumer 的请求记录为 use conflict,并由 materializeUseConflict() 自动插入 ensure_layout。PR 当前在 VMILayoutRematerialize.cpp:243-250 增加的保护会保留该 ensure,随后 VMIToVPTO 分别 lowering contiguous group_iota 与 layout conversion。

独立 op 也可以把 group 整除约束、full-VL/sub-VL materialization 和 grouped lowering 从普通 iota 的 verifier/lowering 中隔离出来,避免继续在多个阶段用 getGroupAttr() 分支表达两套不同的 producer capability。

同时请增加一个从无 layout 的 !pto.vmi.vreg<...> 输入开始、运行完整 semantic pipeline,并由 widening consumer 自然推导出 deinterleaved layout 的回归测试,确认 group_iota(contiguous) → ensure_layout(deinterleaved) 是由 assignment 自动生成的。

2. [P2] group=1 错误拒绝合法 tail ramp

按本 PR 的语义,group=1 只有一个组,因此应与不写 group 完全等价。例如:

vci(size=100)           → 0..99
vci(size=100, group=1)  → 也应为 0..99

现有 ungrouped lowering 已支持 i32 size=100 的 tail,测试在 test/lit/vmi_new/vmi_to_vpto_iota_tail.pto:12-19

但新约束要求 group_size 与物理 VL 互相整除(VMI.cpp:965-971, 2629-2635ptodsl/ptodsl/_vmi_namespace.py:285-295)。对 i32 size=100, group=1

group_size = 100
physical VL = 64

二者互不整除,因此 PTODSL/verifier 会拒绝这个本应等价于普通 iota 的输入;即使绕过 verifier,grouped lowering 的 physical-result-count 检查也不支持该 tail。

若采用上述内部 op 划分,建议在 unified→legacy lowering 时直接把 group == 1 规范化为普通 iota,只有 group > 1 才生成 group_iota;并增加 size=100, group=1 的 PTODSL 与直接 MLIR 回归。

其他合入条件

  • 用户文档尚未同步 group 参数与 group-periodic 语义:ptodsl/docs/user_guide/14-vmi-virtual-instruction-set.md:420-432docs/isa/vmi-isa/02-index-gen.md:12-39
  • 当前 GitHub 状态仍为 CONFLICTING / DIRTY,最终 head 没有 checks;与当前 main 的内容冲突在 ptodsl/ptodsl/_vmi_namespace.py。请 rebase/resolve 后让完整 CI 在最终 head 上重新运行。

Lower grouped VCI through a contiguous-only internal producer so layout assignment materializes deinterleaved consumers, while normalizing group=1 to ordinary tail-capable iota.

Co-authored-by: Cursor <cursoragent@cursor.com>
@peanutchan

Copy link
Copy Markdown
Contributor Author

Addressed the two correctness blockers in c38c487d9:

  • P1: added internal contiguous-only pto.vmi.group_iota; layout assignment now produces group_iota(contiguous) -> ensure_layout(deinterleaved) for widening-consumer inference before VPTO lowering.
  • P2: normalized group=1 to ordinary iota, preserving legal tails such as i32 size=100.
  • Added no-layout full-pipeline deinterleaved regression, realistic group=1 tail coverage with vadds/vstore, PTODSL coverage, and updated semantics docs.

Verified:

  • rebuilt pto-test-opt, PTOASCompiler, and PTOASPythonPackage
  • new P1/P2 lit regressions
  • existing grouped iota group=2, sub-VL, and pre-annotated deinterleaved regressions
  • ordinary iota tail/rematerialization/verifier regressions
  • ptodsl/tests/test_vmi_vci_dynamic_index.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants