feat(backend): enable bf16 atomic-add on A2/A3, broaden atomic dtype tests - #1930
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds a new ChangesBF16 atomic-add support
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Codegen as pto_ops_common.cpp
participant PTOCodegen
participant Handler as BackendHandler
Codegen->>PTOCodegen: GetBackendHandler()
PTOCodegen->>Handler: backend_->GetHandler()
Codegen->>Handler: SupportsBf16AtomicAdd()
Handler-->>Codegen: true/false
alt bf16 unsupported
Codegen-->>Codegen: CHECK_SPAN failure with error message
else bf16 supported
Codegen-->>Codegen: emit atomic_add pto.tstore
end
Suggested labels: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3ace00478d
ℹ️ 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".
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/ir/op/tile_ops/memory.cpp (1)
240-250: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStale comment: A5 rejection no longer relies on the pto-isa static_assert.
The comment states bf16 atomic store on A5 "is rejected downstream by the pto-isa static_assert," but per this PR's codegen guard (
PTOCodegen::GetBackendHandler()->SupportsBf16AtomicAdd()inpto_ops_common.cpp), the rejection is now caught earlier by a clean, backend-awareCHECK_SPANerror — explicitly designed to avoid "deferring to a downstream pto-isa static_assert." Update the comment to reflect the actual mechanism.📝 Suggested comment fix
// Hardware atomic-add dtypes. bf16 is honoured on the A2/A3 (Ascend910B) and // kirinX90 profiles (pto-isa SetAtomicAdd<bfloat16_t> -> set_atomic_bf16); - // it is NOT supported on the A5/kirin9030 store path, where a bf16 atomic - // store is rejected downstream by the pto-isa static_assert. + // it is NOT supported on the A5/kirin9030 store path; codegen rejects this + // combination via BackendHandler::SupportsBf16AtomicAdd() with a clean + // backend-aware error, rather than falling through to a pto-isa static_assert.🤖 Prompt for 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. In `@src/ir/op/tile_ops/memory.cpp` around lines 240 - 250, The hardware atomic-add dtype comment in memory.cpp is stale because bf16 rejection on A5/kirin9030 no longer depends on a downstream pto-isa static_assert. Update the explanatory comment near the DataType check to describe the current backend-aware guard path, referencing SupportsBf16AtomicAdd and the CHECK_SPAN-based rejection in pto_ops_common.cpp, and remove the outdated mention of pto-isa static_assert.
🤖 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.
Nitpick comments:
In `@src/ir/op/tile_ops/memory.cpp`:
- Around line 240-250: The hardware atomic-add dtype comment in memory.cpp is
stale because bf16 rejection on A5/kirin9030 no longer depends on a downstream
pto-isa static_assert. Update the explanatory comment near the DataType check to
describe the current backend-aware guard path, referencing SupportsBf16AtomicAdd
and the CHECK_SPAN-based rejection in pto_ops_common.cpp, and remove the
outdated mention of pto-isa static_assert.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 89a98534-23b3-4667-bdbe-ee8880577f55
📒 Files selected for processing (15)
docs/en/user/02-operation_reference.mddocs/zh-cn/user/02-operation_reference.mdinclude/pypto/backend/910B/backend_910b_handler.hinclude/pypto/backend/950/backend_950_handler.hinclude/pypto/backend/common/backend_handler.hinclude/pypto/codegen/pto/pto_codegen.hpython/pypto/language/op/tensor_ops.pypython/pypto/language/op/tile_ops.pysrc/backend/common/pto_ops_common.cppsrc/codegen/pto/pto_codegen.cppsrc/ir/op/tensor_ops/memory.cppsrc/ir/op/tile_ops/memory.cpptests/st/runtime/ops/test_atomic_add.pytests/ut/codegen/test_pto_codegen_ops.pytests/ut/jit/test_split_k.py
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because no GitHub Actions runner was available. Make sure your repository has a runner available to run Copilot's review, or add a copilot-setup-steps.yml file specifying one with the runs-on attribute. See the docs for more details.
Enables bf16 atomic-add support for split-K accumulation on Ascend910B (A2/A3), adds backend-aware rejection on Ascend950 (A5), and expands atomic-add test coverage across hardware atomic dtypes.
Changes:
- Relax IR atomic-add dtype validation to include bf16 for
tile.storeandtensor.assemble. - Add backend handler API + codegen guard to reject bf16 atomic-add on Ascend950 with a clean error.
- Expand UT/ST coverage for atomic-add stores and split-K atomic accumulation across dtypes and core paths, and update user docs (EN/ZH).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/ut/jit/test_split_k.py | Adds split-K structural checks for direct bf16/fp16/int32 atomic-add lowering. |
| tests/ut/codegen/test_pto_codegen_ops.py | Refactors atomic-add codegen UTs to cover all vector atomic dtypes; adds Ascend950 bf16 rejection test. |
| tests/st/runtime/ops/test_atomic_add.py | Adds runtime numeric STs for atomic-add across bf16/fp16/int16/int8 and split-K bf16/fp16/int32. |
| src/ir/op/tile_ops/memory.cpp | Allows bf16 for atomic-add tile.store dtype validation. |
| src/ir/op/tensor_ops/memory.cpp | Allows bf16 for atomic-add tensor.assemble target dtype validation. |
| src/codegen/pto/pto_codegen.cpp | Exposes backend handler accessor for codegen-time backend decisions. |
| src/backend/common/pto_ops_common.cpp | Adds backend-aware guard rejecting bf16 atomic-add into GM on Ascend950 with clearer error. |
| python/pypto/language/op/tile_ops.py | Updates store docstring to include bf16 (Ascend910B-only). |
| python/pypto/language/op/tensor_ops.py | Updates assemble docstring to include bf16 (Ascend910B-only). |
| include/pypto/codegen/pto/pto_codegen.h | Declares GetBackendHandler() API on PTOCodegen. |
| include/pypto/backend/common/backend_handler.h | Adds SupportsBf16AtomicAdd() capability query. |
| include/pypto/backend/950/backend_950_handler.h | Implements SupportsBf16AtomicAdd() = false for Ascend950. |
| include/pypto/backend/910B/backend_910b_handler.h | Implements SupportsBf16AtomicAdd() = true for Ascend910B. |
| docs/zh-cn/user/02-operation_reference.md | Documents bf16 atomic-add availability constraint (Ascend910B-only). |
| docs/en/user/02-operation_reference.md | Documents bf16 atomic-add availability constraint (Ascend910B-only). |
- Restrict bf16 atomic-add system tests to a2a3 platforms (@pytest.mark.platforms) — bf16 atomic-add is A2/A3-only and is rejected in codegen on A5, so unmarked runs on a5/a5sim would go red. - Add an explicit forward declaration of backend::BackendHandler in pto_codegen.h instead of relying on a transitive include. - Capture and restore the prior backend in the Ascend950 rejection test (guarding the unset case) rather than hard-coding Ascend910B in finally. - Assert the cube atomic-add GM destination via a partition_tensor_view regex instead of the brittle "xbf16>" / "xf16>" substring.
- Restrict bf16 atomic-add system tests to a2a3 platforms (@pytest.mark.platforms) — bf16 atomic-add is A2/A3-only and is rejected in codegen on A5, so unmarked runs on a5/a5sim would go red. - Add an explicit forward declaration of backend::BackendHandler in pto_codegen.h instead of relying on a transitive include. - Capture and restore the prior backend in the Ascend950 rejection test (guarding the unset case) rather than hard-coding Ascend910B in finally. - Assert the cube atomic-add GM destination via a partition_tensor_view regex instead of the brittle "xbf16>" / "xf16>" substring.
0b75317 to
8dfd68e
Compare
Relax the tile.store / tensor.assemble atomic-add IR gates to accept bf16. On A2/A3 (Ascend910B) pto-isa lowers this through SetAtomicAdd<bfloat16_t> -> set_atomic_bf16 on the store pipe. bf16 atomic-add is not supported on Ascend950 (A5), so a new BackendHandler::SupportsBf16AtomicAdd() gate in codegen rejects it with a clean PyPTO error instead of deferring to a downstream pto-isa static_assert. The IR gate stays backend-agnostic; the backend-specific rejection lives in codegen (keyed on the GM destination dtype, so it also covers the cube fp32-Acc -> bf16-GM fix-pipe path). Add atomic-add test coverage across dtypes and both hardware core types: - Vector (AIV) load->store atomic: fp32/fp16/bf16/int32/int16/int8 - Cube (AIC) split-K matmul atomic: fp32/fp16/bf16/int32 (int16/int8 are vector-only: the Acc->GM whitelist is int32/float/half/bf16) - codegen tests assert loc=vec / loc=acc; system tests assert accumulation - new codegen test: bf16 atomic-add rejected on Ascend950 Update DSL docstrings and the user operation reference (en + zh-cn).
- Restrict bf16 atomic-add system tests to a2a3 platforms (@pytest.mark.platforms) — bf16 atomic-add is A2/A3-only and is rejected in codegen on A5, so unmarked runs on a5/a5sim would go red. - Add an explicit forward declaration of backend::BackendHandler in pto_codegen.h instead of relying on a transitive include. - Capture and restore the prior backend in the Ascend950 rejection test (guarding the unset case) rather than hard-coding Ascend910B in finally. - Assert the cube atomic-add GM destination via a partition_tensor_view regex instead of the brittle "xbf16>" / "xf16>" substring.
The int8 vector atomic-add store used a [16, 16] tile; ptoas rejects it because the tile row byte size (cols * sizeof(int8) = 16) must be 32-byte aligned. Widen the int8 store to [16, 32] (32 bytes) in both the codegen test (via a `cols` param on the shared helper) and the system test. The other dtypes at width 16 are already >= 32 bytes and are unaffected.
8dfd68e to
2e22006
Compare
…ved API ## What Bumps the `runtime` submodule `93adc386` → `799640e6` (69 commits) and adapts pypto to the three pypto-facing changes in that range. `runtime/pto_isa.pin` is unchanged at `cd4a3d3f`. **1. The PTO2 name retirement is complete** (simpler hw-native-sys#1963/hw-native-sys#1966/hw-native-sys#1969/hw-native-sys#1980). Every name pypto's orchestration codegen emitted is gone upstream: | before | after | | --- | --- | | `PTO2TaskId` | `TaskId` | | `PTO2_SCOPE` | `SIMPLER_SCOPE` | | `PTO2ScopeMode` | `ScopeMode` | | `PTO2OrchestrationConfig` | `OrchestrationConfig` | | `PTO2_ERROR_ASYNC_*` | `SIMPLER_ERROR_ASYNC_*` | | `#include "pto_orchestration_api.h"` | `#include "orchestration_api.h"` | | `#include "pto_async_kernel_api.h"` | `#include "async_kernel_api.h"` | Three of the five are prefix strips; `PTO2_SCOPE` and the error codes take `SIMPLER_` because a bare `SCOPE(` would expand too eagerly and the status codes share a band with the host-side C API. The header renames reach the eight `collectives/*/templates/entry.cpp.in` files as well as `orchestration_codegen.cpp`. **2. `TensorCreateInfo::set_initial_value` is gone** (simpler hw-native-sys#1975 for `tensormap_and_ringbuffer`; `host_build_graph` lost it in hw-native-sys#1930, so all four runtime variants now agree). pypto lowered `pl.create_tensor(..., init_value=)` to exactly that call, and no orchestration-side replacement exists — the host orchestrator cannot store to the GM-heap device address, which is why upstream dropped the fill. **Breaking change.** The kwarg is refused rather than ignored. It stays in both signatures so a caller gets the migration instead of a bare `TypeError`, and `ValueError` names the replacement: seed the buffer with a kernel, then order every reader after it with an explicit dependency. `.set_attr<double>` is dropped from the `tensor.create` schema so the parser, the `.pto` deserializer, and C++-built IR are gated too, not just the Python entry point. Silently dropping the request was the alternative and would have handed the consuming kernel uninitialized memory. `pl.full` is unaffected: it is a separate op that materializes its constant through a kernel, so it remains the supported way to get a filled tensor. **3. `ChipTensor` is no longer the type orchestration and kernels work in** (simpler hw-native-sys#1974). That commit split the fused type in two: the 72-byte `ChipTensor` is now only the argument as it arrives at the boundary, while the 128-byte descriptor — the old `ChipTensor` field-for-field — is each runtime's own `simpler::tmr::Tensor` / `simpler::hbg::Tensor`. `orch_args.tensor(i).ref()` and `TaskOutputTensors::get_ref()` return that type, and the payload a kernel reads holds it. Generated orchestration and kernels now name `TaskTensor`, the alias each runtime's `tensor.h` shim defines for its own type. pypto compiles against both runtime flavours, so naming `simpler::tmr::Tensor` outright would break `host_build_graph`. Orchestration gains `#include "tensor.h"`: the shim sits first on that include path, and `orchestration_api.h` does not reach it. The two halves of this failed differently. Orchestration failed loudly — a reference cannot bind across the two types. Kernels did not: `__gm__ ChipTensor*` over a payload element still compiles and reads `owner_task_id`'s bytes as `start_offset`, so the break there is silent corruption rather than a diagnostic. **4. The process-wide ring env vars are retired** (hw-native-sys#1980). `PTO2_RING_TASK_WINDOW` / `PTO2_RING_HEAP` / `PTO2_RING_DEP_POOL` are no longer read — the runtime warns once per bind if one is exported. `RunConfig` overrides now fall straight through to the compile-time default with no tier in between, so the docstrings and docs that described that tier are corrected rather than renamed. ## How the adaptation was bounded Name-level sweeps found the first two changes and could not have found the third. Grepping for `PTO2` finds the identifiers but not the renamed headers, which are plain `#include` string literals; extracting every `#include` and every `.member(` pypto emits and checking each against the new runtime tree finds those, and confirms `rt_orch_profile_now` / `rt_orch_profile_add_dynamic_dep_vector` are absent — though they were absent at the old pin too, so they are pre-existing and out of scope here. But `ChipTensor`, `add_input` and `add_output` all still *exist*; only the type relationship between them changed, which no name check can see. The check that does see it is compiling the output: a generated orchestration source now type-checks under `g++-15 -fsyntax-only` against all four runtime x arch include paths, and reverting `TaskTensor` to `ChipTensor` reproduces CI's exact `invalid initialization of reference` error. That is the evidence behind this adaptation being complete, not the greps. ## What did not change `ScopeMode`'s enumerators, the `TaskOutputTensors` / `ChipTaskArgs` / `TensorCreateInfo` shapes, and every emitted member (`add_output`, `get_ref`, `task_id`, `set_dependencies`, `set_predicate`, `set_require_sync_start`, `set_allow_early_resolve`, `add_no_dep`, `add_scalar`, `add_tensor`, `launch_spec.*`) survive the range unchanged. The `simpler` Python surface pypto imports — `Worker`, `CallConfig`, `ChipTensor`, `ChipStorageTaskArgs`, `TaskArgs`, `Tensor`, `scalar_to_uint64`, `AccessMode`, `BackendKind`, `mint_owner_instance_id`, `wrap_fork_inherited`, `KernelCompiler`, `torch_interop`, `pto_isa`, `swimlane_converter`, `strace_timing` — is intact; `task_interface.py` only gains `DeviceMemoryInfo` and `TaskHandle`. ## Validation - `pytest tests/ut/` — 10377 passed, 8 skipped, 2 xfailed. One local-only failure, `test_symlinked_import_path_still_names_the_caller`: it spawns a subprocess with a replaced `PYTHONPATH`, which drops the shim this worktree needs to bypass the editable install pointing at the main checkout. It resolves the main checkout's `pypto`, not this branch's, and does not reproduce in CI. - `ctest` — 1/1 passed - Generated orchestration type-checked with `g++-15 -fsyntax-only` against `{tensormap_and_ringbuffer,host_build_graph}` x `{a2a3,a5}` — all four clean - `ruff check` + `ruff format --check` + `pyright` on the changed files — clean. ruff 0.16.0 was substituted for the pinned 0.14.8, which is not installed here; two assertions were restructured so neither version needs to wrap them. - `tests/lint/check_*.py` (all twelve) — clean - No device run: the shared card pool is not available to this change, so the pure-output initialization behaviour that hw-native-sys#1975 touches is left for CI.
…ved API (#2530) ## Summary Bumps the `runtime` submodule `93adc386` → `799640e6` (69 commits) and adapts pypto to the four pypto-facing changes in that range: simpler finished retiring the `PTO2` naming, renamed two headers pypto `#include`s from generated code, split `ChipTensor` into a boundary type and a per-runtime working type, and removed `TensorCreateInfo::set_initial_value`. `runtime/pto_isa.pin` is unchanged at `cd4a3d3f`. The first three are mechanical but not optional: without them the generated orchestration C++ no longer compiles, and the kernels silently read the wrong struct. The fourth is a **breaking change** for users: `pl.create_tensor(..., init_value=...)` lowered to the removed call and now raises `ValueError` naming its replacement. ## Changes - `runtime`: submodule gitlink `93adc386` → `799640e6`. - `src/codegen/orchestration/`, `src/ir/`, `python/pypto/`: adopt the retired names — `PTO2TaskId`→`TaskId`, `PTO2_SCOPE`→`SIMPLER_SCOPE`, `PTO2ScopeMode`→`ScopeMode`, `PTO2OrchestrationConfig`→`OrchestrationConfig`, `PTO2_ERROR_ASYNC_*`→`SIMPLER_ERROR_ASYNC_*` (simpler #1963/#1966/#1969/#1980). Three are prefix strips; `PTO2_SCOPE` and the error codes take `SIMPLER_` because a bare `SCOPE(` would expand too eagerly and the status codes share a band with the host-side C API. - `src/codegen/orchestration/orchestration_codegen.cpp`, `python/pypto/runtime/builtins/collectives/*/templates/entry.cpp.in`: emit `orchestration_api.h` and `async_kernel_api.h`, which simpler #1963 renamed from their `pto_`-prefixed spellings. - `src/codegen/`, `python/pypto/backend/`, `python/pypto/runtime/builtins/collectives/*/templates/`: generated orchestration and kernels name `TaskTensor` instead of `ChipTensor`. simpler #1974 split the fused type: the 72-byte `ChipTensor` is now only the argument as it arrives at the boundary, while the 128-byte descriptor — the old `ChipTensor` field-for-field — is each runtime's own `simpler::tmr::Tensor` / `simpler::hbg::Tensor`. `orch_args.tensor(i).ref()` and `TaskOutputTensors::get_ref()` return that type, and the payload a kernel reads holds it. `TaskTensor` is the alias each runtime's `tensor.h` shim defines for its own type; pypto compiles against both runtime flavours, so naming `simpler::tmr::Tensor` outright would break `host_build_graph`. Orchestration gains `#include "tensor.h"` because the shim sits first on that include path and `orchestration_api.h` does not reach it. The host-side Python boundary (`task_interface.py`, `tensor_arg.py`, `device_tensor.py`) keeps `ChipTensor`, which is still exactly what it builds. - `python/pypto/ir/op/tensor_ops.py`, `python/pypto/language/op/tensor_ops.py`, `src/ir/op/tensor_ops/memory.cpp`, `src/codegen/tensor_op_codegen.cpp`: **breaking** — `init_value` on `tensor.create` is refused, not ignored. simpler #1975 removed the create-info fill from `tensormap_and_ringbuffer` (`host_build_graph` lost it in #1930, so all four variants now agree), and no orchestration-side replacement exists: the host orchestrator cannot store to the GM-heap device address. The kwarg stays in both signatures so a caller gets the migration rather than a bare `TypeError`, and `.set_attr<double>` is dropped from the op schema so the parser, the `.pto` deserializer, and C++-built IR are gated too. Silently dropping the request was the alternative and would have handed the consuming kernel uninitialized memory. - `python/pypto/runtime/{runner,worker,distributed_runner}.py`, `docs/**/05-runtime-ring-sizing.md`, `docs/**/user/{performance/05-memory, tutorials/05-scheduling-tuning}.md`: `PTO2_RING_TASK_WINDOW` / `_HEAP` / `_DEP_POOL` are retired by #1980 — the runtime warns once per bind if one is exported. The documented fallback chain loses that tier, so `RunConfig` overrides now fall straight through to the compile-time default. - `docs/**/02-error-handling.md`: the "user-supplied kwarg value" example moved from the removed `tensor.create` `init_value` to `tensor.assemble`'s `atomic`. ### Migration `pl.create_tensor(shape, dtype, init_value=v)` has no drop-in replacement. Seed the buffer with a kernel that writes it, then order every reader after that kernel with an explicit dependency (`pl.submit(..., deps=[seed_tid])` or `pl.at(..., deps=[seed_tid])`) — the pattern simpler #1922 established for the DeepSeek-V4 decode buffers. `pl.full` is unaffected and remains the supported way to get a filled tensor; it is a separate op that materializes its constant through a kernel. ### How the adaptation was bounded Name-level sweeps found the first two changes and could not have found the third. Grepping for `PTO2` finds the identifiers but not the renamed headers, which are plain `#include` string literals; extracting every `#include` and every `.member(` pypto emits and checking each against the new runtime tree finds those, and shows `rt_orch_profile_now` / `rt_orch_profile_add_dynamic_dep_vector` are absent from simpler — though they were absent at the old pin too, so they are pre-existing and out of scope here. But `ChipTensor`, `add_input` and `add_output` all still *exist*; only the type relationship between them changed, which no name check can see. Worse, the two halves failed differently: orchestration failed loudly, because a reference cannot bind across the two types, while `__gm__ ChipTensor*` over a payload element still compiles in a kernel and reads `owner_task_id`'s bytes as `start_offset` — silent corruption, no diagnostic. The check that sees both is compiling the output. A generated orchestration source now type-checks under `g++-15 -fsyntax-only` against all four runtime × arch include paths, and reverting `TaskTensor` to `ChipTensor` reproduces this PR's earlier CI error verbatim. That is the evidence behind the adaptation being complete, not the greps. `ScopeMode`'s enumerators, the `TaskOutputTensors` / `ChipTaskArgs` / `TensorCreateInfo` shapes, and every other emitted member (`add_output`, `get_ref`, `task_id`, `set_dependencies`, `set_predicate`, `set_require_sync_start`, `set_allow_early_resolve`, `add_no_dep`, `add_scalar`, `add_tensor`, `launch_spec.*`) survive the range unchanged. The `simpler` Python surface pypto imports is intact; `task_interface.py` only gains `DeviceMemoryInfo` and `TaskHandle`. ## Verification - `pytest tests/ut/` — 10377 passed, 8 skipped, 2 xfailed. Run inside the push transaction, bound to the pushed commit. - `pytest tests/ut/codegen tests/ut/runtime/test_run_config.py tests/ut/ir/transforms/test_classify_iter_arg_carry.py tests/ut/ir/operators/test_array_ops.py` — 1028 passed, 2 skipped - `ctest` — 1/1 passed - Generated orchestration type-checked with `g++-15 -fsyntax-only` against `{tensormap_and_ringbuffer,host_build_graph}` × `{a2a3,a5}` — all four clean - `tests/lint/check_*.py` (all twelve) — clean - `ruff check` + `ruff format --check` + `pyright` on the changed files — clean. ruff 0.16.0 was substituted for the pinned 0.14.8, which is not installed on this machine; two assertions were restructured so neither version needs to wrap them. - One local-only unit-test failure was deselected inside the transaction: `test_symlinked_import_path_still_names_the_caller` spawns a subprocess with a replaced `PYTHONPATH`, which drops the shim this linked worktree needs to bypass an editable install pointing at the main checkout. It resolves the main checkout's `pypto` rather than this branch's and does not reproduce in CI. - **No device run.** The shared card pool was not available to this change, so the pure-output initialization behaviour that simpler #1975 touches is left for CI to exercise. ## Known blocker: pypto-lib needs the same migration `pypto-lib-model` is red and stays red on re-run — deterministically, on two different devices, at the same task boundary (`completed=15/285`) and the same faulting `pc`. It is not a flake and not fixable from this repository. Qwen3-14B's hand-written attention kernels carry their own compat shim, `models/qwen3_14b/kernels/paged_attention_cce/kernel/runtime_tensor_compat.hpp`: ```cpp #if __has_include("task_interface/buffer.h") using PyPTORuntimeTensor = ChipTensor; #else using PyPTORuntimeTensor = Tensor; #endif ``` That header still exists after this bump, so the shim keeps selecting `ChipTensor` — which simpler #1974 redefined from the 128-byte payload descriptor to the 72-byte boundary argument. The kernel then reads `owner_task_id`'s bytes as `start_offset` and garbage as `shapes` / `strides`, which surfaces on device as `fftsplus aivector error` followed by `sub_class=S1:running-stalled`. This is the silent half of the `ChipTensor` split: the kernel path still compiles, so nothing catches it before the card. The fix belongs in pypto-lib — select `TaskTensor`, the alias each runtime's `tensor.h` shim defines for its own 128-byte type. **hw-native-sys/pypto-lib#1052** does that, and must land before this pin can go green. Every other check on this PR passes, including all four other device suites.
Summary
Enables bf16 atomic-add for
tile.store/tensor.assemble(split-K accumulation) on the Ascend910B (A2/A3) profile, and broadens atomic-add test coverage across all hardware atomic dtypes and both core types.tile_ops/memory.cpp,tensor_ops/memory.cpp) to acceptbf16. On A2/A3, pto-isa lowers this viaSetAtomicAdd<bfloat16_t>→set_atomic_bf16.BackendHandler::SupportsBf16AtomicAdd()(910B=true, 950=false) gates the codegenpto.tstoreemit — keyed on the GM destination dtype, so it also covers the cubefp32-Acc → bf16-GMfix-pipe path — raising a clean PyPTO error instead of deferring to a downstream pto-isastatic_assert. The IR gate stays backend-neutral; the backend-specific rejection lives in codegen (perpass-context-config.md).Test coverage (dtype × core × test-type)
loc=vec)loc=acc)int16/int8are vector-only — the pto-isa Acc→GM whitelist isint32/float/half/bf16, so an int32 accumulator cannot downcast-atomic into int16/int8 GM.Testing
clang-tidyclean; all pre-commit hooks passtests/st/) collect; they require a real device / CA-model to execute numerically (bf16 cases target A2/A3)