Skip to content

fix(vpto): insert mem_bar for V tile hazards#906

Open
TaoTao-real wants to merge 1 commit into
hw-native-sys:mainfrom
TaoTao-real:codex/fix-vpto-v-membar-issue866
Open

fix(vpto): insert mem_bar for V tile hazards#906
TaoTao-real wants to merge 1 commit into
hw-native-sys:mainfrom
TaoTao-real:codex/fix-vpto-v-membar-issue866

Conversation

@TaoTao-real

Copy link
Copy Markdown
Contributor

Summary

Fixes #866.

This PR adds an A5 VPTO pto-insert-v-membar pass to insert pto.mem_bar for V-pipeline UB hazards before TileLang expansion. It handles RAW, WAR, and WAW dependencies between structured PIPE_V tile ops using DPS read/write roles and alloc_tile addr byte ranges.

The pass runs before VPTO fusion planning, so inserted pto.mem_bar operations act as tile-native scheduling boundaries instead of breaking already-created fusion regions.

Key behavior

  • RAW: previous write -> current read inserts VST_VLD.
  • WAR: previous read -> current write inserts VLD_VST.
  • WAW: previous write -> current write inserts VST_VST.
  • Multiple hazard kinds on the same edge insert VV_ALL.
  • Existing pto.mem_bar only suppresses insertion when its kind covers the hazard.
  • Unknown tile ranges are conservatively treated as may-alias.

Validation

  • ninja -C build-llvm21 PTOTransforms ptoas
  • llvm-lit -v build-llvm21/test/lit/vpto/vmembar_tile_hazards.pto build-llvm21/test/lit/vpto/membar_barrier_types_vpto_llvm.pto
  • git diff --check

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces the PTOInsertVMemBar pass to automatically insert VPTO V-pipeline memory barriers (pto.mem_bar) for overlapping UB tile hazards (RAW, WAR, WAW) before TileLang expansion. Feedback on the implementation suggests optimizing the barrier insertion by performing it on-the-fly to prevent redundant or overly conservative barriers, using operand indices instead of raw OpOperand * pointers to improve robustness, and adding overflow checks in the address range overlap calculation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +262 to +296
SmallVector<std::pair<Operation *, MemBarKind>, 16> insertions;
bool sawUnknownRange = false;

for (Block &block : func.getBody()) {
SmallVector<VTileOpInfo, 16> vOps;
for (Operation &op : block) {
if (!isStructuredVTileOp(&op))
continue;
auto accesses = collectTileAccesses(&op);
if (accesses.empty())
continue;
sawUnknownRange |= hasUnknownRange(accesses);

HazardSet uncovered;
for (const VTileOpInfo &previous : vOps) {
HazardSet hazards = classifyHazards(previous.accesses, accesses);
if (hazards.empty())
continue;
if (!hasCoveringMemBarBetween(previous.op, &op, hazards))
uncovered.merge(hazards);
}

if (!uncovered.empty())
insertions.push_back({&op, getMemBarKindFor(uncovered)});
vOps.push_back(VTileOpInfo{&op, std::move(accesses)});
}
}

OpBuilder builder(func.getContext());
for (auto [op, kind] : insertions) {
builder.setInsertionPoint(op);
builder.create<pto::MemBarOp>(op->getLoc(),
pto::MemBarAttr::get(func.getContext(),
kind));
}

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.

high

We can optimize the memory barrier insertion by performing it on-the-fly instead of deferring it to the end of the block traversal.

Currently, because insertions are deferred, hasCoveringMemBarBetween cannot see the barriers that will be inserted for earlier hazards in the same block. This leads to redundant barriers (e.g., multiple VST_VLD barriers for the same RAW hazard on subsequent reads) and overly conservative barriers (e.g., merging multiple hazards into a heavy VV_ALL barrier when a lighter barrier inserted earlier would have already covered some of them).

By inserting the barriers on-the-fly, subsequent hazard checks will correctly detect the already-inserted barriers, resulting in minimal and optimal barrier insertion.

    OpBuilder builder(func.getContext());
    bool sawUnknownRange = false;

    for (Block &block : func.getBody()) {
      SmallVector<VTileOpInfo, 16> vOps;
      for (Operation &op : block) {
        if (!isStructuredVTileOp(&op))
          continue;
        auto accesses = collectTileAccesses(&op);
        if (accesses.empty())
          continue;
        sawUnknownRange |= hasUnknownRange(accesses);

        HazardSet uncovered;
        for (const VTileOpInfo &previous : vOps) {
          HazardSet hazards = classifyHazards(previous.accesses, accesses);
          if (hazards.empty())
            continue;
          if (!hasCoveringMemBarBetween(previous.op, &op, hazards))
            uncovered.merge(hazards);
        }

        if (!uncovered.empty()) {
          builder.setInsertionPoint(&op);
          builder.create<pto::MemBarOp>(
              op.getLoc(),
              pto::MemBarAttr::get(func.getContext(),
                                   getMemBarKindFor(uncovered)));
        }
        vOps.push_back(VTileOpInfo{&op, std::move(accesses)});
      }
    }

Comment on lines +167 to +179
SmallPtrSet<OpOperand *, 4> writeOperands;
for (OpOperand &init : dps.getDpsInitsMutable()) {
if (isa<TileBufType>(init.get().getType()))
writeOperands.insert(&init);
}

for (OpOperand &operand : op->getOpOperands()) {
if (!isa<TileBufType>(operand.get().getType()))
continue;
accesses.push_back(
TileAccess{resolveTileAddrRange(operand.get()),
writeOperands.contains(&operand)});
}

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.

medium

In collectTileAccesses, storing and comparing OpOperand * pointers from dps.getDpsInitsMutable() and op->getOpOperands() can be fragile and relies on the iterator implementation details of MutableOperandRange.

A more robust and standard approach in MLIR is to store the operand indices (using OpOperand::getOperandNumber()) and check if the operand index is in the set of write operand indices.

Suggested change
SmallPtrSet<OpOperand *, 4> writeOperands;
for (OpOperand &init : dps.getDpsInitsMutable()) {
if (isa<TileBufType>(init.get().getType()))
writeOperands.insert(&init);
}
for (OpOperand &operand : op->getOpOperands()) {
if (!isa<TileBufType>(operand.get().getType()))
continue;
accesses.push_back(
TileAccess{resolveTileAddrRange(operand.get()),
writeOperands.contains(&operand)});
}
llvm::SmallDenseSet<unsigned, 4> writeOperandIndices;
for (OpOperand &init : dps.getDpsInitsMutable()) {
if (isa<TileBufType>(init.get().getType()))
writeOperandIndices.insert(init.getOperandNumber());
}
for (OpOperand &operand : op->getOpOperands()) {
if (!isa<TileBufType>(operand.get().getType()))
continue;
accesses.push_back(
TileAccess{resolveTileAddrRange(operand.get()),
writeOperandIndices.contains(operand.getOperandNumber())});
}

Comment on lines +77 to +81
static bool overlaps(const AddrRange &lhs, const AddrRange &rhs) {
if (!lhs.valid || !rhs.valid)
return true;
return lhs.base < rhs.base + rhs.size && rhs.base < lhs.base + lhs.size;
}

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.

medium

The overlaps function performs addition on uint64_t values (rhs.base + rhs.size and lhs.base + lhs.size) without checking for potential integer overflow. While tile sizes and bases are typically small, it is safer and more robust to check for overflow to prevent undefined behavior or incorrect overlap detection.

static bool overlaps(const AddrRange &lhs, const AddrRange &rhs) {
  if (!lhs.valid || !rhs.valid)
    return true;
  uint64_t lhs_end = lhs.base + lhs.size;
  uint64_t rhs_end = rhs.base + rhs.size;
  if (lhs_end < lhs.base || rhs_end < rhs.base)
    return true;
  return lhs.base < rhs_end && rhs.base < lhs_end;
}

@reedhecre

reedhecre commented Jul 7, 2026

Copy link
Copy Markdown

Codex Review

该评论由 review 机器人自动更新。

  • PR: fix(vpto): insert mem_bar for V tile hazards #906 fix(vpto): insert mem_bar for V tile hazards
  • Author: TaoTao-real
  • Base/Head: main / codex/fix-vpto-v-membar-issue866
  • Head SHA: 5351c34f7389
  • Trigger: 检测到新的 open PR
  • Generated At: 2026-07-07T07:30:43Z
  • Status: failed at codex-review (exit=1)

Summary

Review failed at stage codex-review: exit=1

Findings

未生成结构化 findings,因为 review 过程提前失败。

Log Tail

git clone --branch 'main' --depth 50 'https://github.com/hw-native-sys/PTOAS.git' '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/repo'
cd '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/repo'
git fetch origin 'refs/pull/906/head:pr-906' --depth 50
git fetch origin 'main' --depth 50 || true
git checkout -f 'pr-906'
git rev-parse HEAD
git diff --stat 'origin/main...HEAD' || true
Cloning into '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/repo'...
From https://github.com/hw-native-sys/PTOAS
 * [new ref]           refs/pull/906/head -> pr-906
From https://github.com/hw-native-sys/PTOAS
 * branch              main       -> FETCH_HEAD
Switched to branch 'pr-906'
5351c34f73897fa02005bebfbd0d84583480afcb
 include/PTO/Transforms/Passes.h         |   1 +
 include/PTO/Transforms/Passes.td        |  16 ++
 lib/PTO/Transforms/CMakeLists.txt       |   1 +
 lib/PTO/Transforms/PTOInsertVMemBar.cpp | 310 ++++++++++++++++++++++++++++++++
 test/lit/vpto/vmembar_tile_hazards.pto  | 126 +++++++++++++
 tools/ptoas/ptoas.cpp                   |  12 ++
 6 files changed, 466 insertions(+)
===== END STAGE clone rc=0 @ 2026-07-07 15:30:34 =====

===== STAGE codex-review @ 2026-07-07 15:30:34 =====
set -euo pipefail
cd '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/repo'
'codex' exec -C '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/repo' -s read-only -c 'model_provider="codereview"' -c 'model="gpt-5.4"' -c 'model_reasoning_effort="xhigh"' --output-schema '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/review_schema.json' -o '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/codex_last_message.json' --color never - < '/tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/review_prompt.txt'
[monitor] stage timeout: 1800s
OpenAI Codex v0.115.0 (research preview)
--------
workdir: /tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/repo
model: gpt-5.4
provider: codereview
approval: never
sandbox: read-only
reasoning effort: xhigh
reasoning summaries: none
session id: 019f3b7c-6218-7fc3-9829-6db455bd3021
--------
user
你现在在审查 GitHub PR。

仓库:hw-native-sys/PTOAS
PR:#906 fix(vpto): insert mem_bar for V tile hazards
作者:TaoTao-real
base branch:origin/main
head branch:HEAD(当前已 checkout 到 PR head)

要求:
1. 只审查这个 PR 相对 origin/main 的改动,必要时可以看上下文文件。
2. 重点找真实的 correctness / regression / contract mismatch / CI / runtime / compatibility 问题。
3. 不要提纯风格建议,不要提低价值猜测。
4. 严格按优先级输出:
   - P1:高概率会导致错误结果、编译/运行失败、严重回归、发布阻断
   - P2:重要缺陷、行为回归、遗漏校验/测试、较大兼容性问题
   - P3:次要但明确可改的问题
5. 如果没有问题,summary 直接写:未检查到 PR #906 存在问题,并返回 findings=[]。
6. 如果有问题,summary 简洁概括,findings 里每条都要给出:
   - severity
   - title
   - body(说明为什么是问题,尽量具体)
   - file(尽量给相对路径)
   - line(能确定就填整数,否则 null)

建议先查看:
- git status --short
- git diff --stat origin/main...HEAD
- git diff --unified=80 origin/main...HEAD

最终输出必须严格匹配 JSON schema。

mcp startup: no servers
Reconnecting... 1/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a175250b9a822719-LAX, request id: 6288c215-d243-4832-ae56-09659c661312)
Reconnecting... 2/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a175250fcca76e2c-LAX, request id: 09e0bd88-4365-49e0-a6e9-609a814c21fb)
Reconnecting... 3/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a17525137d222eaf-LAX, request id: defb2226-910f-4872-9f04-0e840a4b4d81)
Reconnecting... 4/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a1752519bddea982-LAS, request id: 2f057eaf-9696-4f13-a867-fbb4ff0b663e)
Reconnecting... 5/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a1752524dcd70ad7-LAS, request id: 0c933649-bc53-4df6-903e-ed0bd433cf02)
ERROR: unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a1752539cce8b256-LAX, request id: 1a5d8af0-7956-4b03-8ab0-4d8b23d855b3
Warning: no last agent message; wrote empty content to /tmp/ptoas-pr-review-monitor/runs/20260707_153027_pr906/codex_last_message.json
===== END STAGE codex-review rc=1 @ 2026-07-07 15:30:43 =====

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.

[Bug] rope_kv_cache精度问题

2 participants