Skip to content

feat(vpto): add sequential soft post-update analysis - #1018

Open
yexiaosu wants to merge 3 commits into
hw-native-sys:mainfrom
yexiaosu:vmi-post-update-3
Open

feat(vpto): add sequential soft post-update analysis#1018
yexiaosu wants to merge 3 commits into
hw-native-sys:mainfrom
yexiaosu:vmi-post-update-3

Conversation

@yexiaosu

@yexiaosu yexiaosu commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Implement Step 3 of VPTOSoftPostUpdate for issue #941 : convert fixed-stride memory accesses within a single block into chained post-update operations.

Key changes

  • Add a second analysis phase after loop-path rewriting.

    • Recollect blocks after all scf.for rewrites.
    • Scan normal blocks, scf.for bodies, and nested regions such as scf.if.
    • Skip operations already converted by the loop path.
  • Normalize addresses as (rootBase, baseOffset) through pto.addptr chains.

  • Reuse the loop-path infrastructure for:

    • element/block unit conversion;
    • effective stride calculation;
    • initial pointer construction;
    • type and range validation;
    • pure definition-chain cloning;
    • generic post-update op creation.
  • Support constant and symbolic affine strides, including:

    • varying base and offset whose combined address step is fixed;
    • non-constant affine expressions;
    • exactly divisible block strides such as 8 * k for f32 vsstb.
  • Group candidates by (op type, rootBase) and detect deterministic,
    non-overlapping maximal arithmetic runs.

    • Different buckets may be physically interleaved.
    • A stride break ends the current run and starts analysis from the breaking candidate.
    • A run must contain at least three operations before it is rewritten.
  • Analyze all accepted runs before materialization, then rewrite operations in
    original program order while maintaining an independent pointer chain per run.

  • Update the pass description and Step 3 design documentation.

Test coverage

Added 8 sequential-path lit test files containing 22 focused scenarios, including:

  • fixed-base constant sequences;
  • minimum run length and zero-stride rejection;
  • run restart after invalid or too-short prefixes;
  • multiple maximal runs;
  • varying base/offset cancellation;
  • multilevel pto.addptr normalization;
  • constant and symbolic affine strides;
  • pure symbolic leaf cloning and conservative rejection;
  • scf.for body fallback and nested scf.if blocks;
  • partial loop-path conversion followed by sequential fallback;
  • interleaved buckets and same-op/different-root isolation;
  • already-post-update operations interleaved with a run;
  • vlds, vsts, and vsstb pointer chaining;
  • exact and inexact block-unit conversion;
  • nonzero initial vsstb repeat stride;
  • narrow stride type overflow rejection;
  • operation attribute preservation.

Validation

  • Sequential-path tests: 8/8 passed
  • All soft-post-update tests: 39/39 passed

Commands:

llvm-lit -sv -j 8 build/test/lit \
  --filter 'soft_postupdate_sequential'

llvm-lit -sv -j 8 build/test/lit \
  --filter 'soft_postupdate'

@yexiaosu
yexiaosu force-pushed the vmi-post-update-3 branch from 875a554 to 5baca6d Compare July 28, 2026 01:47
@yexiaosu
yexiaosu force-pushed the vmi-post-update-3 branch from 1d24871 to 3e10509 Compare July 28, 2026 11:53

@mouliangyu mouliangyu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体方向上,在 VPTO/MLIR 层识别 post-update 是合理的;但当前 sequential path 还需要补齐收益判定,并分开地址数学语义与硬件窄 stride 编码。具体见两条 inline comment。


static bool validateSequentialRun(SequentialRun &run,
DominanceInfo &dominance) {
if (run.candidates.size() < 3)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里似乎把‘能够改写为 post-update’直接当成了‘值得改写’,但目前没有看到 sequential path 的 profitability 判断。

例如本 PR 的 sequential_constant

vlds %base[0]
vlds %base[64]
vlds %base[128]

未开启该优化时,LLVM IR 已经是三条彼此独立的访存:

vlds(base, 0)
vlds(base, 256)
vlds(base, 512)

这里没有额外地址计算需要消除。改写后则变成:

v0, p1 = vlds.post(base, 256)
v1, p2 = vlds.post(p1, 256)
v2, p3 = vlds.post(p2, 256)

不仅没有减少地址计算,还在原本独立的访存之间增加了 pointer dependency;最后一条产生的 p3 也没有被使用。

因此仅用 run length >= 3 作为改写条件似乎不够。是否应该只处理能够实际消除动态 addptr/offset 计算的序列,或者先基于汇编与性能数据建立 cost model?另外,对于长度为 N 的链,通常只需要前 N-1 条使用 post-update,最后一条可以使用当前 pointer 加零 offset 的普通形式。

return e->leaf;
case StrideExpr::Kind::Cast: {
Type inputType = e->castOp->getOperand(0).getType();
if (wantType == inputType)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里直接把规范化后的地址差表达式按目标 operand 类型物化,会把‘宽类型地址语义’和‘硬件窄 stride 编码’混在一起,可能改变原程序语义。

例如 %k: i16,三个 vsstb 的 base 分别为:

%k_idx = arith.index_castui %k : i16 to index
%off1 = arith.muli %k_idx, %c16 : index
%off2 = arith.muli %k_idx, %c32 : index

base, addptr(base, 16 * zext(k)), addptr(base, 32 * zext(k))

对 f32 而言,相邻地址差是 2 * zext(k) 个 32B block。当前实现会消除 index_castui,生成:

%step = arith.muli %k, %c2_i16 : i16

%k = 40000 时,原始地址差是 80000 blocks,但新表达式在 i16 中先回绕成 14464,地址序列已经不同。

我觉得这里不只是缺少一个常量范围检查。地址差分析应该始终在 index/宽整数的数学域中完成;确认完整表达式能够精确编码到该 op 的硬件 stride 类型后,才能在最后一步生成 i16 operand。无法证明运行时范围时应保守放弃,而不是通过去掉 cast 将运算下沉到 i16。

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