Skip to content

Feature/a2a3 llvm#908

Open
castigli wants to merge 24 commits into
hw-native-sys:mainfrom
castigli:feature/a2a3-llvm
Open

Feature/a2a3 llvm#908
castigli wants to merge 24 commits into
hw-native-sys:mainfrom
castigli:feature/a2a3-llvm

Conversation

@castigli

@castigli castigli commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

A2/A3 VPTO Elementwise PR Summary

Summary

This branch adds the A2/A3 VPTO UB lowering path for tile elementwise operations and validates it end-to-end on A3 hardware. The implementation routes A2/A3 through the planned-memory UB pipeline (from A5 pipeline), lowers supported PTO tile ops to VPTO UB ops, and emits LLVM intrinsics.

What Changed

  • Added the A2/A3 VPTO UB lowering pipeline:
    PTOViewToMemref -> PTOPlanMemory -> PTOResolveReservedBuffers -> PTOMaterializeTileHandles -> LowerPTOToUBufOps.
  • Implemented A2/A3 UB lowering for binary elementwise ops:
    tadd, tsub, tmul, tdiv, tmax, tmin, tand, tor, txor, tshls, and tshrs.
  • Implemented unary elementwise ops:
    tabs, trelu, tneg, texp, tlog, tsqrt, trsqrt, and trecip.
  • Implemented scalar-tile elementwise ops:
    tadds, tmuls, tmaxs, and tmins.
  • Added fused elementwise support for taddrelu, including PTO IR, UB IR, lowering, LLVM intrinsic emission, PTODSL wrappers, and tests.
  • Added UB/LLVM support for new VPTO UB ops and intrinsics, including vaddrelu, vdup, and vln.
  • Integrated planned UB address allocation so UB lowering consumes planner-assigned alloc_tile addr values and models scratch usage for ops such as txor.
  • Extended dispatch coverage for small, normal, count, row-repeat, tail, chunked, and multi-row shapes.
  • Extended the PTODSL elementwise surface through helpers and pto.tile.* APIs.
  • Added lit and hardware e2e coverage for binary, unary, scalar, bitwise, shift, fused, log, and reciprocal cases.

Validation

Verified after merging current main with the LLVM 21 docker image:

  • Build: passed
  • VPTO UB lit: 60/60
  • Runtime toolchain pytest: 4/4
  • A3 unary hardware e2e: 80/80
  • A3 binary hardware e2e: 192/192
  • A3 scalar hardware e2e: 120/120

Total A2/A3 shared VPTO elementwise hardware coverage validated on A3: 392 tests.

@reedhecre

reedhecre commented Jul 7, 2026

Copy link
Copy Markdown

Codex Review

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

  • PR: Feature/a2a3 llvm #908 Feature/a2a3 llvm
  • Author: castigli
  • Base/Head: main / feature/a2a3-llvm
  • Head SHA: 616d7fb3ef5e
  • Trigger: PR 有新提交
  • Generated At: 2026-07-08T11:10:47Z
  • Previous Head SHA: 44bc1c6ec9a4
  • Status: failed at codex-review (exit=1)

Summary

Review failed at stage codex-review: exit=1

Findings

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

Log Tail

 .../vpto/ub/ub_to_llvm/elementwise/vadd_dtypes.pto |   87 +
 .../vpto/ub/ub_to_llvm/elementwise/vadd_packed.pto |   49 +
 .../vpto/ub/ub_to_llvm/elementwise/vaddrelu.pto    |   57 +
 test/lit/vpto/ub/ub_to_llvm/elementwise/vdiv.pto   |   30 +
 test/lit/vpto/ub/ub_to_llvm/elementwise/vdup.pto   |   27 +
 test/lit/vpto/ub/ub_to_llvm/elementwise/vln.pto    |   26 +
 .../vpto/ub/ub_to_llvm/elementwise/vmax_vmin.pto   |   64 +
 test/lit/vpto/ub/ub_to_llvm/elementwise/vmul.pto   |   30 +
 test/lit/vpto/ub/ub_to_llvm/elementwise/vsub.pto   |   30 +
 .../lit/vpto/ub/ub_to_llvm/mask/set_mask_count.pto |   47 +
 test/lit/vpto/ub/ub_to_llvm/mask/set_mask_full.pto |   26 +
 test/lit/vpto/ub/ub_to_llvm/mask/set_mask_tail.pto |   25 +
 .../lit/vpto/ub/ub_to_llvm/transfer/copy_gm_ub.pto |   26 +
 .../vpto/ub/ub_to_llvm/transfer/copy_gm_ub_pad.pto |   25 +
 .../lit/vpto/ub/ub_to_llvm/transfer/copy_ub_gm.pto |   25 +
 test/lit/vpto/ub/ub_to_llvm/transfer/mte_gm_ub.pto |   25 +
 .../vpto/ub/ub_to_llvm/transfer/mte_gm_ub_pad.pto  |   29 +
 tools/ptoas/ObjectEmission.cpp                     |   30 +-
 tools/ptoas/driver.cpp                             |    6 +-
 tools/ptoas/ptoas.cpp                              |  155 +-
 104 files changed, 15363 insertions(+), 159 deletions(-)
===== END STAGE clone rc=0 @ 2026-07-08 19:10:38 =====

===== STAGE codex-review @ 2026-07-08 19:10:38 =====
set -euo pipefail
cd '/tmp/ptoas-pr-review-monitor/runs/20260708_191028_pr908/repo'
'codex' exec -C '/tmp/ptoas-pr-review-monitor/runs/20260708_191028_pr908/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/20260708_191028_pr908/review_schema.json' -o '/tmp/ptoas-pr-review-monitor/runs/20260708_191028_pr908/codex_last_message.json' --color never - < '/tmp/ptoas-pr-review-monitor/runs/20260708_191028_pr908/review_prompt.txt'
[monitor] stage timeout: 1800s
OpenAI Codex v0.115.0 (research preview)
--------
workdir: /tmp/ptoas-pr-review-monitor/runs/20260708_191028_pr908/repo
model: gpt-5.4
provider: codereview
approval: never
sandbox: read-only
reasoning effort: xhigh
reasoning summaries: none
session id: 019f416c-37a4-70e2-af5f-672f5327a0f2
--------
user
你现在在审查 GitHub PR。

仓库:hw-native-sys/PTOAS
PR:#908 Feature/a2a3 llvm
作者:castigli
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 #908 存在问题,并返回 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: a17ea4c75c8fd938-LAX, request id: cb113f4e-6ccc-4395-a83b-b0aa42d7dd55)
Reconnecting... 2/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a17ea4ca38265121-LAX, request id: 1d247a34-c8f6-4396-9589-8a176a794c39)
Reconnecting... 3/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a17ea4ce4d20e9e4-LAX, request id: 7beb13d6-79ac-4608-a0d7-45695a5c8341)
Reconnecting... 4/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a17ea4d4ade19810-LAX, request id: 098dd69d-fce4-4a6a-9feb-a142296d307f)
Reconnecting... 5/5 (unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a17ea4e06ccd4113-LAX, request id: a2a942f2-df9f-40e8-8d7f-02dcc5a8b078)
ERROR: unexpected status 403 Forbidden: {"code":"INSUFFICIENT_BALANCE","message":"Insufficient account balance"}, url: https://codex.0u0o.com/responses, cf-ray: a17ea4f7aeb77eb9-LAX, request id: 8abd7e47-9f66-475a-a97d-9e36b6238eec
Warning: no last agent message; wrote empty content to /tmp/ptoas-pr-review-monitor/runs/20260708_191028_pr908/codex_last_message.json
===== END STAGE codex-review rc=1 @ 2026-07-08 19:10:47 =====

@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 implements a direct pointer-based lowering pipeline for A3 (dav-c220-vec) targets, introducing the LowerPTOToUBufOps pass and corresponding LLVM lowering patterns. The code review identified several critical and high-severity issues that must be addressed: a syntax/compilation error in VPTOLLVMEmitter.cpp due to a leftover lambda block; multiple checks in ptoas.cpp and LowerPTOToUBufOps.cpp that restrict the pipeline to "a3" and break "a2" support; an overly restrictive check in VPTOLLVMEmitter.cpp that excludes "dav-c220-cube" and triggers invalid A5 DMA lowering; redundant dead loop generation when headRepeats is zero; and a typo in a macro name in VPTO.cpp.

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 11066 to 11070
target.addLegalOp<ModuleOp>();
target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
target.addLegalOp<pto::AddPtrOp>();([&](func::FuncOp op) {
return typeConverter.isSignatureLegal(op.getFunctionType()) &&
typeConverter.isLegal(&op.getBody());
});

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.

critical

There is a critical syntax/compilation error on line 11067. The statement target.addLegalOp<pto::AddPtrOp>(); ends with a semicolon, but is immediately followed by a lambda block ([&](func::FuncOp op) { ... }); which was left over from the previous addDynamicallyLegalOp call. This will cause a compilation failure.\n\nPlease restore the addDynamicallyLegalOp<func::FuncOp> call properly alongside the new addLegalOp<pto::AddPtrOp>() call.

  target.addLegalOp<ModuleOp>();\n  target.addLegalOp<pto::AddPtrOp>();\n  target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {\n    return typeConverter.isSignatureLegal(op.getFunctionType()) &&\n           typeConverter.isLegal(&op.getBody());\n  });

Comment thread tools/ptoas/ptoas.cpp Outdated
auto &kernelModulePM = pm.nest<ModuleOp>();
auto moduleArchAttr =
module->getAttrOfType<mlir::StringAttr>("pto.target_arch");
const bool isA3 = moduleArchAttr && moduleArchAttr.getValue() == "a3";

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

The check isA3 only matches "a3". Since A2 and A3 share the same VPTO lowering pipeline (as documented in the design specs), this check should also include "a2". Otherwise, targeting "a2" will incorrectly fall back to the A5 ExpandTileOp path.

Suggested change
const bool isA3 = moduleArchAttr && moduleArchAttr.getValue() == "a3";
const bool isA3 = moduleArchAttr && (moduleArchAttr.getValue() == "a2" || moduleArchAttr.getValue() == "a3");

Comment thread tools/ptoas/ptoas.cpp Outdated
std::string arch = ptoTargetArch;
for (char &c : arch)
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
options.march = (arch == "a3") ? "dav-c220-vec" : "dav-c310-vec";

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

The target architecture selection on line 2591 defaults to "dav-c310-vec" (the A5 target) if the architecture is not exactly "a3". If the user targets "a2", this will incorrectly select the A5 target instead of "dav-c220-vec".\n\nUpdate the ternary operator to map both "a2" and "a3" to "dav-c220-vec".

Suggested change
options.march = (arch == "a3") ? "dav-c220-vec" : "dav-c310-vec";
options.march = (arch == "a2" || arch == "a3") ? "dav-c220-vec" : "dav-c310-vec";

Comment thread tools/ptoas/ptoas.cpp Outdated
Comment on lines +2914 to +2915
const bool enableLocalTilePlanning =
ptoTargetArch != "a3" || effectiveBackend == PTOBackend::VPTO;

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

The check ptoTargetArch != "a3" will evaluate to true when targeting "a2", which incorrectly enables local tile planning unconditionally for "a2" even if the backend is not VPTO.\n\nSince A2 and A3 share the same pipeline, they should use the same condition.

  const bool isA2A3 = (ptoTargetArch == "a2" || ptoTargetArch == "a3");\n  const bool enableLocalTilePlanning =\n      !isA2A3 || effectiveBackend == PTOBackend::VPTO;

Comment on lines +221 to +223
auto archAttr = mod->getAttrOfType<StringAttr>("pto.target_arch");
if (!archAttr || archAttr.getValue() != "a3")
return;

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

The LowerPTOToUBufOpsPass currently returns early if the target architecture is not exactly "a3". This prevents the pass from running when targeting "a2", which shares the same lowering pipeline.\n\nUpdate the check to allow both "a2" and "a3".

    auto archAttr = mod->getAttrOfType<StringAttr>("pto.target_arch");\n    if (!archAttr || (archAttr.getValue() != "a2" && archAttr.getValue() != "a3"))\n      return;

Comment thread lib/PTO/Transforms/VPTOLLVMEmitter.cpp Outdated
Comment on lines +4605 to +4607
bool useA3NonPadded = (march == "dav-c220-vec") && isGmUb && !hasPadding;
bool useA3UbGm = (march == "dav-c220-vec") && !isGmUb;
bool useSingleConfig = useA3NonPadded || useA3UbGm;

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

The check march == "dav-c220-vec" is too restrictive because it excludes the A2/A3 cube target "dav-c220-cube". Both vector and cube targets on A2/A3 use the same single-config V220 DMA engine. If "dav-c220-cube" is targeted, this will incorrectly fall back to the A5 dual-config DMA lowering, which is invalid for A2/A3.\n\nUpdate the check to cover any C220 target (e.g., by checking if march starts with "dav-c220" or explicitly checking both vector and cube variants).

    bool isC220 = (march == "dav-c220-vec" || march == "dav-c220-cube");\n    bool useA3NonPadded = isC220 && isGmUb && !hasPadding;\n    bool useA3UbGm = isC220 && !isGmUb;\n    bool useSingleConfig = useA3NonPadded || useA3UbGm;

Comment on lines +1083 to +1095
auto forOp = b.create<scf::ForOp>(loc, idxc0(loc, b),
idxc(headRepeats, loc, b), idxc1(loc, b));
b.setInsertionPointToStart(forOp.getBody());
Value iv = forOp.getInductionVar();
Value off = b.create<arith::MulIOp>(loc, iv, idxc(epr, loc, b)).getResult();
Value rd = addPtr(loc, b, dst, ptrTy, off);
Value r0 = addPtr(loc, b, s0, ptrTy, off);
Value r1 = addPtr(loc, b, s1, ptrTy, off);
b.create<pto::UBSetMaskCountOp>(loc);
b.create<pto::UBSetMaskOp>(loc, i64c(epr, loc, b), i64c0(loc, b));
emitUBBinOp<UBop>(loc, b, rd, r0, r1, i64c1(loc, b), i64c8(loc, b));
b.create<pto::UBSetMaskNormOp>(loc);
b.setInsertionPointAfter(forOp);

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

When headRepeats is 0 (which happens when totalV < epr), b.create<scf::ForOp> is still called to generate a loop from 0 to 0. While functionally a no-op, generating dead loops complicates downstream optimization passes and produces redundant IR.\n\nSince headRepeats is a compile-time constant, wrap the loop generation in a C++ conditional check if (headRepeats > 0).

    if (headRepeats > 0) {\n      auto forOp = b.create<scf::ForOp>(loc, idxc0(loc, b),\n                                          idxc(headRepeats, loc, b), idxc1(loc, b));\n      b.setInsertionPointToStart(forOp.getBody());\n      Value iv = forOp.getInductionVar();\n      Value off = b.create<arith::MulIOp>(loc, iv, idxc(epr, loc, b)).getResult();\n      Value rd = addPtr(loc, b, dst, ptrTy, off);\n      Value r0 = addPtr(loc, b, s0, ptrTy, off);\n      Value r1 = addPtr(loc, b, s1, ptrTy, off);\n      b.create<pto::UBSetMaskCountOp>(loc);\n      b.create<pto::UBSetMaskOp>(loc, i64c(epr, loc, b), i64c0(loc, b));\n      emitUBBinOp<UBop>(loc, b, rd, r0, r1, i64c1(loc, b), i64c8(loc, b));\n      b.create<pto::UBSetMaskNormOp>(loc);\n      b.setInsertionPointAfter(forOp);\n    }

Comment thread lib/PTO/IR/VPTO.cpp Outdated
return success();
}

#define PTO_DEFINE_UB_UNARY_VERITY_AND_EFFECTS(OpName) \

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

There is a typo in the macro name: VERITY instead of VERIFY. Please rename it to PTO_DEFINE_UB_UNARY_VERIFY_AND_EFFECTS for consistency and readability.

Suggested change
#define PTO_DEFINE_UB_UNARY_VERITY_AND_EFFECTS(OpName) \
#define PTO_DEFINE_UB_UNARY_VERIFY_AND_EFFECTS(OpName) \\

Comment thread ptodsl/examples/bop_launch_a3.py Outdated
if __package__ in {None, ""}:
here = Path(__file__).resolve()
for candidate in here.parents:
if (candidate / "ptodsl" / "__init__.py").exists():

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.

In latest main branch, you can install ptodsl package to the python env with pip install . --no-build-isolation. No need to manually search ptodsl path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed. I removed the manual parent-directory sys.path probing from the example; it now assumes PTODSL is installed in the Python environment.

Comment thread ptodsl/examples/bop_launch_a3.py Outdated
if (candidate / "ptodsl" / "__init__.py").exists():
sys.path.insert(0, str(candidate))
break
else:

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.

We already have some ST cases in test/tilelib-st. Maybe you can reuse them by just changing the target from a5 to a3.

Comment thread ptodsl/ptodsl/_ops.py
)


def taddrelu(src0, src1, dst):

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.

Is this a A2A3-only op? Should restrict its usage inside A2A3 kernels.

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.

Please also add documents for this new interface in the ptodsl/docs/user_guide directory.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed. I documented pto.tile.addrelu in ptodsl/docs/user_guide/08-compute-operations.md, including formula, supported dtypes, and the A2/A3-only restriction.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, this is A2/A3-only. I added a PTODSL tracing-time target guard, an IR verifier rejection for A5, and regression coverage for both PTODSL diagnostics and hand-authored PTO IR.

@@ -0,0 +1,486 @@
# Copyright (c) 2026 Huawei Technologies Co., Ltd.

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.

The naming of this test suite is not clear. I suggest reuse the TileOp ST cases we already have in tilelib-st, which will be completed soon.

For vpto level test, you should place them under the test/vpto directory.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I can move these tests under test/tilelib-st if that is the preferred repository layout, but I’m worried we would lose clarity and potentially coverage.

The current pytest suite is a comprehensive PTODSL e2e sweep for the new A2/A3 VPTO elementwise path. It covers binary, unary, scalar, bitwise, shift, fused, log, and reciprocal ops across multiple dtypes and dispatch shapes.

My concern with test/tilelib-st is that the folder name is not very descriptive for this purpose: these are specifically PTODSL end-to-end tests for the A2/A3 VPTO lowering pipeline. Moving them there may make that less obvious.

If you still prefer the ST layout, I can migrate them, but I’d like to preserve the current breadth of coverage.

Comment thread docker/Dockerfile.dev
# =========================================================================
# 5. Torch + torch-npu (for on-device kernel launch)
# =========================================================================
RUN pip install --no-cache-dir torch==2.9.0 --index-url https://download.pytorch.org/whl/cpu \

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.

Better use torch==2.9.0.post2 or 2.10.0 here for CANN-9.0.0, see compatibility matrix here: https://gitcode.com/Ascend/pytorch/blob/master/README.zh.md#ascend-extension-for-pytorch%E7%89%88%E6%9C%AC%E9%85%8D%E5%A5%97%E8%A1%A8

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. The CANN 9.0.0 matrix pairs Ascend Extension for PyTorch 2.9.0.post2 with upstream PyTorch 2.9.0, so I kept torch==2.9.0 and updated torch-npu to 2.9.0.post2. I also updated the non-dev Dockerfile for consistency.

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.

4 participants