Skip to content

feat(vpto): 支持 stateful stream 融合 - #1260

Draft
mouliangyu wants to merge 11 commits into
mainfrom
codex/vmi-unaligned-load-store
Draft

feat(vpto): 支持 stateful stream 融合#1260
mouliangyu wants to merge 11 commits into
mainfrom
codex/vmi-unaligned-load-store

Conversation

@mouliangyu

@mouliangyu mouliangyu commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

背景

VMI 连续 vload/vstore 及部分 group_store lowering 会产生多条独立的 stateful unaligned stream,重复初始化和 flush,增加访存指令与 align 状态管理开销。

修改内容

  • 保留 VMI 连续 load/store 的对齐快路径;非对齐或对齐未知时生成 vldas/vldusinit_align/vstus/vstas SSA align 链。
  • 优化 compact group_store 的连续场景,避免多轮 1PT_B32 抽取和地址操作,直接生成 stateful store stream。
  • 新增独立 VPTOStatefulStreamFusion pass(CLI:-vpto-stateful-stream-fusion):
    • 融合同一 block 内地址连续的 vldas -> vldus* load streams;
    • 融合同一 block 内地址连续的 init_align -> vstus* -> vstas store streams,覆盖 ordinary store 与 group store;
    • 支持跨 scf.for 迭代传递 base/align:loop 外初始化,loop 内每轮继续 vldus/vstus,loop 后一次 vstas 收尾;
    • 仅在静态 trip count、IV 仿射地址步幅等于 stream advance,且无潜在别名访存时融合;未知指针根、调用和同 buffer memory effect 保持原有逐轮 stream;
    • 通过 !pto.align SSA 管理 align 状态,不向 VMI 接口暴露物理寄存器编号。
  • 更新回归测试,覆盖 load/store loop fusion、动态/单迭代 loop、非连续地址、不同 root、side effect 和 alias 阻断等场景。

范围说明

  • 过期 masked load、runtime expand_load、通用 group_loadgroup_slot_load 不新增非对齐路径。
  • 显式稀疏 mask store 仍使用 predicated vsts

验证

  • ninja -C build pto-test-opt PTOASCompiler
  • llvm-lit -sv build/test/lit/vmi_new:524/524 通过
  • stateful stream fusion 与 fused_quant_dequant_vmi_opt focused lit:2/2 通过
  • check_changed_code.py --repo . --base origin/main:0 error,0 warning
  • git diff --check

已有 A5 CA model 基准显示:单块 vlds 约 50 cycles,vldas+vldus 约 51 cycles;双块 load 2xvlds 约 61 cycles,vldas+2xvldus 约 60 cycles。此次 loop-carried store 的指令形态从 4 组 init_align/vstus/vstas 降为 1 次初始化、4 次 vstus、1 次 vstas;该形态已由 opt case 的 VPTO FileCheck 覆盖,CA case 后续可直接复用同一 kernel 做 cycle 对比。

@mouliangyu mouliangyu changed the title feat(vmi): 支持连续 vload/vstore 非对齐访存 feat(vmi): 支持连续非对齐访存并优化 group_store Aug 17, 2026
@mouliangyu mouliangyu changed the title feat(vmi): 支持连续非对齐访存并优化 group_store feat(vpto): 支持 stateful stream 融合 Aug 17, 2026
@mouliangyu

Copy link
Copy Markdown
Collaborator Author

CA Model 性能验证:16B group store

使用 dav_3510 CA model,按真实的 16B payload 场景对比三种 store 实现。

测试约束

  • 4 次 loop iteration,每轮写入 16B,总计 64B。
  • 三组 load 完全一致:每轮执行 1 条普通 vlds,总计 4 条 RV_VLDI
  • 均使用普通 256B carrier:!pto.vreg<64xf32>;每轮仅 16B payload 有效。
  • 仅改变 store 序列:
    • 1PT baseline:每轮 4 x 1PT_B32,共 16 条 one-point store。
    • 独立 stream:每轮 init_align -> vstus(16B) -> vstas(16B)
    • 跨迭代融合 stream:init_align -> loop(4 x vstus(16B)) -> vstas(16B)
  • 三组输出均通过 golden compare。

CA 结果

方案 实际 vector memory 指令 kernel ticks system ticks RVEC busy cycles
1PT baseline 4 RV_VLDI + 16 RV_VST 2037 2250 108
独立 stream 4 RV_VLDI + 4 RV_VSTUI + 4 RV_VSTAI 2021 2235 92
跨迭代融合 stream 4 RV_VLDI + 4 RV_VSTUI + 1 RV_VSTAI 2014 2224 85

相对 1PT baseline:

  • 独立 stream:kernel 减少 16 cycles,RVEC busy 减少 16 cycles(约 14.8%)。
  • 跨迭代融合 stream:kernel 减少 23 cycles,RVEC busy 减少 23 cycles(约 21.3%)。
  • 跨迭代融合相对独立 stream 再减少 7 cycles,来源与少执行 3 条 vstas 一致。

关于 1PT 的 unmapped SRC_PREGS warning

CA model 会为 1PT RV_VST 打印 unmapped SRC_PREGS:[v_idx=1]。这是因为 1PT 指令 ABI 仍保留 mask operand,但硬件语义忽略该 mask;PTOAS 会将其 lower 为 undef,不实际分配 predicate register。数据 vector register 正常分配,16 条 store 均正常 issue/retire,UB write log 和 golden compare 均正确,因此该 warning 不影响本次结果。

验证产物位于本地忽略目录 .work/stateful-stream-bench/runs/16b_{1pt_v2,independent_v2,fused_v2}

@mouliangyu

Copy link
Copy Markdown
Collaborator Author

CA 性能验证:vmi_new/opt/fused_quant_dequant_vmi_opt.pto

用 host VPTO validation + A5 CA simulator 构造了可执行 GM wrapper,输入/输出均为 32768B uint16 buffer,参数 arg1=16, arg2=1024,保持 load 路径和计算完全一致,仅对比主线 1PT store 与 PR 的 stateful stream store。两组 output compare 均通过。

方案 kernel ticks system ticks RVEC busy store 指令
origin/main 9434 9648 5082 384 × RV_VST(其中 inner loop 为 1PT_B32)
PR (VPTOStatefulStreamFusion) 9394 9605 5048 256 × RV_VST + 64 × RV_VSTUI + 16 × RV_VSTAI

变化:kernel -40-0.42%),system -43-0.45%),RVEC busy -34-0.67%)。两组 load 均为 RV_VLD=320;主要计算指令数一致。该 case 的 VSTUI/VSTAI 分别对应循环内连续 stream store 与循环收尾的 vstas

另外两个近期更新的 opt case(blockquant_bf16_group4_scale_expand_vmi_opt.ptocompute_y1_to_fp8_fp16_vmi_opt.pto)入口参数是 UB pointer,不具备当前 host validation 所需的 GM kernel ABI;已确认 lowering 结果,但没有伪造端到端性能数字。临时 benchmark 位于 .work/stateful-opt-bench/,未加入提交。

@mouliangyu

Copy link
Copy Markdown
Collaborator Author

补充:为另外两个 vmi_new/opt case 增加 GM wrapper 后的 CA 结果

wrapper 均放在 .work/stateful-opt-bench/,通过 GM→UB、原 VMI 计算、UB→GM 构造成可执行 kernel;主线和 PR 使用相同输入和 wrapper,所有可执行组 output compare 均通过。

blockquant_bf16_group4_scale_expand

为避免把尚未支持的非对齐 load 混入 store 对比,wrapper 将两次 load 固定在对齐地址,只让 store 使用运行时 off

  • off=1:主线 lowering 为 RV_VSTS,CA 明确报告 Address 0x1002 is not aligned to 32 bytes;PR lowering 为 RV_VSTUI + RV_VSTAI,无 misalign,正确完成。主线是 faulting baseline,因此这组不能给出有效的性能加速比。
  • off=0(合法成本对照):
方案 kernel ticks system ticks RVEC busy store
main 2203 2415 96 1 × RV_VSTS
PR 2204 2417 97 1 × RV_VSTUI + 1 × RV_VSTAI

即单次独立 stream 在运行时实际对齐时成本约 +1 kernel tick;非对齐 off=1 的 PR 为 2207 kernel ticks。

另一个发现:原 opt case 的 load 和 store 共用动态 %off。如果实际传 off=1,当前两次 load 仍 lower 为 RV_VLDS 并触发 misalign;当前 PR 修复的是 store 路径,原 case 本身不能证明非对齐 load 已支持。

compute_y1_to_fp8_fp16

参数使用 blockCount=16, vlHalf=128,实际运行地址连续且对齐,但 vlHalf 保留为运行时参数,以忠实保留原 case 的“编译期可能非对齐”语义。

方案 kernel ticks system ticks RVEC busy store
main 2399 2612 197 16 × RV_VSTS
PR 2413 2626 211 16 × RV_VSTUI + 16 × RV_VSTAI

PR 为 +14 kernel ticks / +14 RVEC busy。这里当前 lowering 是每轮独立 init_align → vstus → vstas,没有跨 16 轮融合成一条 stream。

这不是 pass 漏掉一个可直接证明的连续流:循环步长为运行时 2 * vlHalf,IR 中无法证明它恒等于 256B payload。若要跨迭代融合,需要前端/IR 提供该等式,或者生成 stride == payload_bytes 的运行时 guard 后走 fused fast path。

@mouliangyu

Copy link
Copy Markdown
Collaborator Author

更正性能 benchmark 范围

前一条评论对 blockquant_bf16_group4_scale_expandcompute_y1_to_fp8_fp16 的解读不准确:这两个 case 本身不是“多轮 1PT store”场景。

  • blockquant 主线期望的是普通 vsts,payload 为 128×bf16 = 256B。
  • compute_y1 主线期望的是每轮普通 vsts,payload 为 256×fp8 = 256B。
  • 两个 case 的 opt 变更是 continuous access lowering/能力 guard,不应通过构造非对齐输入来制造 benchmark 条件。
  • 我之前传 off=1 的 wrapper 同时让 blockquant 的 load 也非对齐,超出了该 case 的有效输入约束;相关 faulting baseline 和性能数字应全部作废。

真正对应“多条 1PT 合并成 stateful unaligned stream”的测试应使用明确 lower 成 1PT_B32 的 case,例如 vmi_to_vpto_group_store_slots1_1pt.ptomhc_pre_apply_mix_bwd_vmi_opt.pto。这类 benchmark 输入地址保持正常对齐即可;非对齐是后端用来承载连续 1PT 拼接的内部机制,不需要由 host 输入人为制造。

@mouliangyu

Copy link
Copy Markdown
Collaborator Author

根据端到端地址形态调整了两个 opt case(commit 72092a7f):

  • UB pointer 改为 kernel 内静态 pto.castptr
  • blockquant%off 改为 %tile * 128 个 bf16,即 256B 对齐步长;
  • ComputeY1 循环 load/store offset 改为 %i * 256 elements,保持每轮 256B 对齐;
  • FileCheck 恢复验证普通 vsts,不再因为 standalone UB pointer/动态 stride 信息不足而期望 vstus/vstas

三条原始 RUN/FileCheck 均通过;changed-code compliance: 0 errors, 0 warnings。

@mouliangyu
mouliangyu force-pushed the codex/vmi-unaligned-load-store branch from 137422c to 73bf9d9 Compare August 25, 2026 08:49
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.

1 participant