Skip to content

fix(ir): Gather the operand's split axis at the V->C boundary - #2129

Merged
lyfne123 merged 2 commits into
hw-native-sys:mainfrom
Hzfengsy:fix/lower-auto-vector-split-vc-boundary
Jul 27, 2026
Merged

fix(ir): Gather the operand's split axis at the V->C boundary#2129
lyfne123 merged 2 commits into
hw-native-sys:mainfrom
Hzfengsy:fix/lower-auto-vector-split-vc-boundary

Conversation

@Hzfengsy

Copy link
Copy Markdown
Member

Summary

LowerAutoVectorSplit rewrites a vector→cube tile.move into tile.aic_gather plus the original cube-placement move, but kept that move's original result type without ever checking the gather actually reassembled back to it. Two ways that broke:

  • Un-halved operand. A Vec parameter moved straight to cube (or a tile whose split dim is a singleton the affinity gate deliberately preserves) has no half to gather. Doubling it produced a [256, 128] operand under a move still typed [128, 128]. tile.move is shape-preserving, so the result was IR that contradicts its own op contract and does not survive print→parse. Now rejected with an actionable ValueError.
  • Migrated split axis. The gather doubled the function split axis, but a tile.reshape can migrate it — the rms_norm [N,1]↔[1,N] column reshape — and TileInfo::split_dim tracks where it landed. A [1, 8] lane-local operand under UP_DOWN gathered to [2, 8] where the move expected [1, 16]. The gather now follows the operand's tracked split dim (dim 0 → split=1, dim 1 → split=2), so this case lowers correctly instead of emitting a contradiction.

An internal postcondition now asserts the gather result matches the kept move type, so any residual mismatch fails loudly instead of silently.

The parser was right to reject the old output; the pass was wrong. Per first-principles, the fix is in the pass.

Test authoring

The pass's transform-output tests move to the mandated @pl.program Before/Expected style. The tile-level IR this pass consumes and produces is expressible in the DSL: memory spaces are ordinary pl.Mem.* annotations, the lowered boundary has a dedicated outlined form (pl.tile.aiv_shard(x, split=N)) the printer emits for exactly this shape, and no memref exists this early (init_mem_ref runs ten passes later).

The explicit SplitAivScopeStmt region tests stay hand-built, for a verified reason: the parser always wraps a pl.split_aiv region in a scope when the enclosing function is pl.FunctionType.InCore, and this pass rejects a scope-nested region by design — so no DSL spelling delivers a bare region. Verified for both top-level and loop-nested regions.

_lower now keeps the print→parse roundtrip instrument on. That check is what surfaced the defect, and the file previously suppressed it via a blanket PassContext([]). One test opts out, documented against its upstream cause (OutlineIncoreScopes emits an InCore function that reads/rebinds a captured pl.Out tensor without declaring it a parameter — pre-existing, filed separately).

Test count 52 → 54: the 6 parametrized generator cases map 1:1 to named tests (a DSL Before can't be parametrized over shape — annotations are read from the AST), test_store_offset_* was strengthened from a duplicate of the C→V program to a non-zero base that actually distinguishes additive from replaced offsets, plus two new regression tests for the fixes above.

Testing

  • tests/ut — 7595 passed, 2 skipped
  • tests/ut/ir/transforms — 2391 passed (post-rebase)
  • tests/st/codegen/torch/test_torch_codegen_cross_core.py — 27 passed (numeric golden vs torch, both V→C modes)
  • clang-tidy, clang-format, cpplint, ruff, pyright, markdownlint — clean
  • docs EN/ZH parity, English-only, headers — clean

Documentation

docs/en/dev/passes/18-lower_auto_vector_split.md and the zh-CN mirror document the half-operand precondition, the tracked-split-axis rule, and quote the diagnostic verbatim.

Copilot AI review requested due to automatic review settings July 24, 2026 03:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b63b48a3-efce-4a91-8de3-34bbd4ab5877

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

LowerAutoVectorSplit now validates tracked HALF operands and split dimensions before emitting tile.aic_gather, checks gathered shapes against cube placement types, and expands DSL-based tests and English/Chinese documentation for these rules.

Changes

AUTO vector-to-cube boundary

Layer / File(s) Summary
Validate and emit VECTOR_TO_CUBE gather
src/ir/transforms/lower_auto_vector_split_pass.cpp
The pass resolves tracked half-width operands, derives and validates the operand split dimension, emits tile.aic_gather, and checks rank and structural shape equality before the cube-side tile.move.
Exercise AUTO split lowering paths
tests/ut/ir/transforms/test_lower_auto_vector_split.py
Tests migrate to Before/Expected DSL programs, retain roundtrip validation, cover rejection cases, and verify AUTO and outlined-region behavior.
Document gather operand and split-axis rules
docs/en/dev/passes/18-lower_auto_vector_split.md, docs/zh-cn/dev/passes/18-lower_auto_vector_split.md
Documentation explains the required per-lane HALF operand, tracked split-axis encoding, and V→C rejection conditions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Poem

A bunny checks each HALF in line,
Then gathers tiles in shapes divine.
Split axes hop from one to two,
Bad full-width values get told “no.”
Tests and docs now neatly cheer—
The cube-boundary path is clear!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly captures the main change: gathering along the operand’s split axis at the V->C boundary.
Description check ✅ Passed The description matches the changeset and accurately summarizes the pass fix, validation, tests, and docs updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4272b02a1d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ir/transforms/lower_auto_vector_split_pass.cpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/ir/transforms/lower_auto_vector_split_pass.cpp`:
- Around line 339-349: Update the C→V shard-result construction that initializes
TileInfo to also store the computed split_dim, rather than leaving split_dim at
its default value. Preserve the existing HalfDimExtent(tt->shape_[split_dim])
initialization while ensuring LEFT_RIGHT shards retain split_dim == 1 through
the subsequent V→C gather path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 85f4d9ae-da9c-473d-888c-ac55291ba8d9

📥 Commits

Reviewing files that changed from the base of the PR and between efb7837 and 4272b02.

📒 Files selected for processing (4)
  • docs/en/dev/passes/18-lower_auto_vector_split.md
  • docs/zh-cn/dev/passes/18-lower_auto_vector_split.md
  • src/ir/transforms/lower_auto_vector_split_pass.cpp
  • tests/ut/ir/transforms/test_lower_auto_vector_split.py

Comment thread src/ir/transforms/lower_auto_vector_split_pass.cpp
Hzfengsy added a commit to Hzfengsy/pypto that referenced this pull request Jul 24, 2026
- Carry split_dim into the C->V shard result's TileInfo. The V->C arm now
  gathers along the operand's tracked split_dim, so a shard result fed
  straight into a V->C boundary under LEFT_RIGHT was gathering dim 0
  (split_dim defaulted to 0) instead of dim 1 — doubling rows [128,64] ->
  [256,64] and tripping the shape invariant. Flagged by both review bots.
- Add a regression test for the LEFT_RIGHT direct-shard->gather flow (the
  per-op halving path the cross-core ST already covers seeds split_dim
  correctly; this exercises the shard arm's own seeding).
Copilot AI review requested due to automatic review settings July 24, 2026 04:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Hzfengsy added 2 commits July 25, 2026 12:52
LowerAutoVectorSplit rewrites a vector->cube tile.move into tile.aic_gather
plus the original cube-placement move, but kept that move's original result
type without checking the gather actually reassembled back to it. Two ways
that broke:

- An un-halved operand (a Vec parameter moved straight to cube, or a tile
  whose split dim is a singleton the affinity gate preserves) has no half to
  gather. Doubling it produced a [256, 128] operand under a move still typed
  [128, 128]; tile.move is shape-preserving, so that IR did not survive
  print->parse. Now rejected with an actionable ValueError.
- The gather doubled the *function* split axis, but a tile.reshape can
  migrate the split axis (the rms_norm [N,1]<->[1,N] column reshape) and
  TileInfo::split_dim tracks where it landed. A [1, 8] lane-local operand
  under UP_DOWN gathered to [2, 8] where the move expected [1, 16]. The
  gather now follows the operand's tracked split dim (dim 0 -> split=1,
  dim 1 -> split=2), so the migrated case lowers correctly instead of
  emitting a contradiction.

An internal postcondition asserts the gather result matches the kept move
type, so any residual mismatch fails loudly rather than silently.

Convert the pass's transform-output tests to the mandated @pl.program
Before/Expected style. The tile-level IR this pass consumes and produces is
expressible in the DSL, including the outlined pl.tile.aiv_shard(x, split=N)
boundary form; memory spaces are ordinary pl.Mem.* annotations and no memref
exists this early. The explicit SplitAivScopeStmt region tests stay
hand-built: the parser always wraps a pl.split_aiv region in a scope that
this pass rejects by design, so no DSL spelling delivers a bare region.

_lower now keeps the print->parse roundtrip instrument on. That check is what
surfaced the boundary defect, and the file previously suppressed it.
- Carry split_dim into the C->V shard result's TileInfo. The V->C arm now
  gathers along the operand's tracked split_dim, so a shard result fed
  straight into a V->C boundary under LEFT_RIGHT was gathering dim 0
  (split_dim defaulted to 0) instead of dim 1 — doubling rows [128,64] ->
  [256,64] and tripping the shape invariant. Flagged by both review bots.
- Add a regression test for the LEFT_RIGHT direct-shard->gather flow (the
  per-op halving path the cross-core ST already covers seeds split_dim
  correctly; this exercises the shard arm's own seeding).
@Hzfengsy
Hzfengsy force-pushed the fix/lower-auto-vector-split-vc-boundary branch from caa4d8a to ee2ed27 Compare July 25, 2026 04:54
Copilot AI review requested due to automatic review settings July 25, 2026 04:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@lyfne123
lyfne123 merged commit ad0ac97 into hw-native-sys:main Jul 27, 2026
22 of 23 checks passed
@Hzfengsy
Hzfengsy deleted the fix/lower-auto-vector-split-vc-boundary branch July 27, 2026 06:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants