Repository navigation
Conversation
…T wiring
Direct (non-GEMM) weight-gradient kernels for wave32 gfx1250, mirrored in
the Python and C++ engines and served from the direct-conv AOT cache:
- Image-per-block direct wgrad (direct_wgrad on wave32): one workgroup per
image and k x c tile on WMMA 16x16x32, register blocking
(wave_tiles_k/c), rows_per_sync, a row split over grid y (row_blocks),
TDM staging (tdm_stages), a coalesced LDS epilogue (lds_epilogue).
- Small-C stems (direct_wgrad_small_c): a GEMM over the flattened (r, s, c)
filter row for 3 input channels, with vectorised X loads (vec_x),
sub_steps staging and an optional uniform wave index.
- Depthwise VALU wgrad (direct_depthwise_wgrad, DirectDepthwiseWgradSpec):
lanes own channels and accumulate the taps in fp32 registers, with an LDS
reduction over waves; the channel count comes from the p_groups kernarg.
- Two-stage reduction: every kernel adds into one of ws_replicas fp32
scratch slabs; the cached direct_wgrad_reduce helper folds them into dW.
The run-from-cache plan zeroes the scratch (DirectPlan.zeroed) and
launches both steps; the helper identity goes through _helper_identity.
Platform: the tile.buffer_atomic_fadd_f32 IR op (raw_ptr_buffer_atomic_fadd
with a cache-policy immediate) in both engines, with a C++ host test.
AOT: direct_wgrad_small_c and direct_depthwise_wgrad join the direct grid
next to direct_wgrad, the wave32 image grid gains the two-stage knobs, and
the reduce helper is cached per replica count. gfx950 grids are unchanged.
No dispatcher wiring: gfx1250 conv is served from the AOT cache.
Tests: parity configs 201..238 in conv_direct_grouped_emit.{py,c} (wave32
wgrad 201..231, depthwise wgrad 232..238), harness cases
conv_direct_wgrad/gfx1250/* with their golden, CPU checks of the AOT grid
and launch plans, and GPU correctness tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…channels - C=3: the stride-1 3x3 input layers (K 32 / 64) and the unpadded 3x3/s2 stem join the small-C rows; without a small-C binary they fell back to an implicit GEMM with an odd GEMM-N (27) that cannot split. - C=4: 3x3 s1 p1 stems with K 320 / 512 (the latent-space input convolution of the latent diffusion UNets). - The 16-wave vec_x=4 / sub_steps=4 small-C tile is cached with uniform_wave off: with it on, the binary spills SGPRs into VGPR lanes at the 128-VGPR cap and returns an all-zero dW. Grid and caps only; the kernels are unchanged. Parity configs 239..241 pin both engines on the cached stem tiles (C=4 with uniform_wave off, and the two new C=3 stems). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A byte extent past 2^31 on an i32 kernarg raised struct.error while the run-from-cache sweep bound the plan's launches, and ended the whole direct sweep of the shard. Skip that plan instead, as an unloadable one already is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wgrad reduces over the batch, so a problem whose activations pass the kernels' i32 byte addressing was refused. It can still run as consecutive batch slices if every slice adds into the one dW, zeroed once: - implicit GEMM from the cache: _batch_chunks now slices wgrad; a sliced wgrad problem is offered only the packed-atomic split-K kernels (_wgrad_accumulates), dY / X are offset per slice, dW is shared, and only the first slice's launch clears dW (_cached_bind zero_dw). - direct conv from the cache: _batch_chunks slices wgrad too, the slices bind dY and X windows and the whole dW (_chunk_buffers), and only the one-step plans without scratch are kept (_accumulates_dw): their kernel adds into the zeroed fp32 dW, where a fold, a reduce or a scratch slab would overwrite it. Problems that fit keep the single-launch path unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ All Checks Passed — Ready for Review
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🎉 All checks passed! This PR is ready for review. |
There was a problem hiding this comment.
🟡 Changes recommended
The public wgrad spec changes size without updating both ABI constants, allowing old callers to pass compatibility checks despite possible out-of-bounds reads or incompatible return layouts.
4 open issues
What changed in this PR
This PR extends rocKE’s direct-convolution AOT cache with gfx1250 weight-gradient support for dense/grouped layers, small-channel stems, and depthwise convolutions, without adding dispatcher wiring.
Changes:
- Adds wave32 wgrad support, replicated scratch buffers, and cached second-stage reduction plans.
- Introduces a buffer fp32 atomic-add IR operation with matching Python and C++ lowering.
- Extends batch-sliced execution, validation tests, parity goldens, and support documentation.
Paths below are relative to dnn-providers/hip-kernel-provider/.
| File | Description |
|---|---|
rocke/platform/tests/instances/rocke_ir_parity_harness.py |
Adds representative gfx1250 wgrad cases. |
rocke/platform/tests/instances/differential/golden/llvm_gfx_all.json |
Adds differential hashes for new configurations. |
rocke/platform/tests/golden/rocke_representative_ir_sha256/conv_direct_wgrad.json |
Records new IR hashes and expected flavor failures. |
rocke/platform/tests/core/test_opcode_values.cpp |
Pins the appended atomic opcode. |
rocke/platform/tests/core/test_buffer_atomic_fadd.py |
Tests Python atomic lowering and policy validation. |
rocke/platform/tests/core/test_buffer_atomic_fadd.cpp |
Adds corresponding C++ host tests. |
rocke/platform/tests/cmake/CoreTests.cmake |
Registers and installs the atomic host test. |
rocke/platform/python/rocke/instances/SUPPORT_MATRIX.md |
Documents gfx1250 AOT wgrad availability. |
rocke/platform/python/rocke/core/lower_llvm.py |
Lowers buffer atomic adds in Python. |
rocke/platform/python/rocke/core/ir.py |
Adds the atomic builder API and cache-policy constant. |
rocke/platform/python/rocke/core/arch/data/intrinsic_arch_domain.llvm23.json |
Records atomic intrinsic architecture support. |
rocke/platform/dsl_docs/instances/index.md |
Indexes new wgrad specs and helpers. |
rocke/platform/dsl_docs/instances/convolution.md |
Describes kernels, scratch layout, and AOT serving. |
rocke/platform/cpp/instances/common/conv_direct_grouped_public_entry_glue.cpp |
Routes image and small-C specs to their builders. |
rocke/platform/cpp/instances/common/conv_direct_grouped_build_wgrad.cpp |
Extends wgrad staging and atomics for wave32. |
rocke/platform/cpp/include/rocke/ir.h |
Declares the atomic opcode and builder API. |
rocke/platform/cpp/include/rocke/instance_conv_direct_grouped.h |
Extends public wgrad specs and declarations. |
rocke/platform/cpp/include/rocke/instance_conv_direct_grouped_internal.h |
Adds wave32 builder state and entry points. |
rocke/platform/cpp/core/lower_llvm/mem.cpp |
Implements C++ atomic lowering. |
rocke/platform/cpp/core/lower_llvm/data.cpp |
Declares the LLVM atomic intrinsic. |
rocke/platform/cpp/core/ir/ir_flow.cpp |
Builds atomic operations with policy validation. |
rocke/platform/cpp/core/ir/core_types.cpp |
Registers the atomic name and effectful classification. |
rocke/library/tests/test_kernel_label.py |
Extends label checks to wave32-only variants. |
rocke/library/tests/test_direct_kernel_cache.py |
Tests AOT coverage, reduction plans, and batch slicing. |
rocke/library/tests/test_direct_conv_correctness.py |
Adds gfx1250 numerical wgrad coverage. |
rocke/library/tests/test_conv_batch_and_miopen_parse.py |
Tests wgrad slicing and accumulating-kernel eligibility. |
rocke/library/tests/test_builder_signature_contract.py |
Registers the depthwise wgrad spec contract. |
rocke/library/tests/parity/conv_direct_grouped_emit.py |
Adds Python parity and rejection configurations. |
rocke/library/tests/parity/conv_direct_grouped_emit.c |
Mirrors parity configurations in C++. |
rocke/library/kernels/conv/direct_variants.py |
Adds variants, scratch sizing, and reduction specs. |
rocke/library/kernels/conv/direct_aot_jobs.py |
Adds tuning grids, stem rows, and reduction jobs. |
rocke/library/benchmarks/common/kernel_cache.py |
Adds a cache namespace for wgrad helpers. |
rocke/library/benchmarks/common/direct_kernel_sweep.py |
Constructs and binds two-stage wgrad plans. |
rocke/library/benchmarks/common/benchmark_implicit_gemm_conv.py |
Accumulates oversized wgrad batches across slices. |
rocke/library/benchmarks/common/benchmark_direct_conv.py |
Handles scratch initialization, slicing, and kernarg skips. |
ROCKE_ENGINE_test_categories_external.yaml |
Categorizes the new atomic host test. |
Review effort: Balanced
rocke_direct_conv_wgrad_spec_t gained image_per_block through uniform_wave at its end, which changes its size. A caller built against the old header would pass the ABI check while allocating a smaller spec. Bump ROCKE_ABI_VERSION and the Python BINARY_ABI together, and pin the struct size next to the ABI level in conv_direct_dw_dgrad_host so the next change to the struct has to move both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A NaN rel_err compared false against `>= tol`, so non-finite depthwise wgrad output passed. Reject anything not below the tolerance, as the other wgrad helpers do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The buffer_atomic_fadd_f32 docs said an out-of-range voffset is dropped. On gfx1250 a buffer atomic at the out-of-range sentinel faults, while a load there reads 0. Say that callers must guard invalid offsets (as the wgrad kernels do with scf_if), in both engines' docs and the convolution doc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Link test_buffer_atomic_fadd.cpp into the already categorized rocke_buffer_rsrc_hip binary, whose self-check now calls it, instead of registering a separate rocke_buffer_atomic_fadd CTest. The coverage keeps running in every tier without a new test name, so the provider's test category list goes back to the develop version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fer atomics For raw or imported IR the two LLVM lowerers disagreed on the tile.buffer_atomic_fadd_f32 cachepolicy attr: Python truncated 20.9 to 20 while C++ read it as 0, a missing attr became 0, and values above 31 reached the intrinsic. Both lowerers now refuse a missing, non-integer (including bool) or out-of-range attr with a ValueError. Builder-made kernels always carry a valid policy, so emitted IR does not change. Tests: the Python test and the C++ checks (run by rocke_buffer_rsrc_hip) rewrite the attr to missing, 20.9, true, -1 and 32 and expect the refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max PR #14833 — gfx1250 direct wgrad kernels with two-stage reduction (jakpiase) — 🟠 First-round: arch-domain rows missing
Utility: 🟢 Positive — gfx1250 direct wgrad for dense, stem, depthwise layers; numerics author-run only. Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted First-round review: first pass by a local qwen3.6 model, verified by the orchestrator (Claude Opus 5.5). Checks: merge with develop, native build + ctest, byte identity ×4, goldens, PR tests, arch-domain test per flavor, shipped gfx1250 grid compile, CI at head. Flags whether a closer look is needed; not an approval or rejection. |
… and llvm24 columns The raw.ptr.buffer.atomic.fadd.f32 declaration had arch-domain rows on the llvm23 column only, so test_every_decl_key_is_covered_on_every_wired_arch failed on an llvm20, llvm22 or llvm24 host. Add its canonical name and per-arch rows to the other three columns, measured with tools/gen_arch_domain.py --only raw.ptr.buffer.atomic.fadd.f32 on each flavor's toolchain (the llvm20 and llvm22 builds the columns were blessed with). llvm22 and llvm24: ok on every wired arch. llvm20: ok everywhere except gfx1250, which that compiler cannot target (target_unsupported), as for every other key in that column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mage tiles Where a block's dW tile does not fit the LDS epilogue, the wave32 wgrad grid falls back to the direct epilogue for the same tiling. For a 16-wave block with two tiles per wave and register-staged rows (tdm_stages=0) that binary spills: a block of more than 8 waves caps a wave at 256 VGPRs, and the register-staged multi-tile body needs more than that. The spec's register estimate counts only the accumulators and fragments, so it let them through, and the grid comment claimed the estimate drops every spilling combination. Add _wgrad_image_spills, a grid filter like the other *_spills predicates, that skips those tilings (32 binaries per dtype). Their TDM-staged fallbacks stay under the cap and are still cached. The spec's validity rules and both engines are unchanged. Every remaining 8- and 16-wave image job compiles without scratch. Test: test_w32_wgrad_grid_skips_the_spilling_16_wave_register_staged_tiles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the review. The prior items were fixed at 1aa95f0: ABI bumped to 7 (develop is still 6), NaN-safe tolerance check, cachepolicy validated in both lowerers, and the docs now say callers must guard offsets.
|
|
Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max PR #14833 — gfx1250 direct wgrad kernels with two-stage reduction (jakpiase, AICK-2878) — 🟡 Follow-up: all items fixed; body stale
Utility: 🟢 Positive — gfx1250 direct wgrad for dense, stem, depthwise layers; numerics author-run only. Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted Follow-up review: first pass by a local qwen3.6 model, verified by the orchestrator (Claude Opus 5.5). Checks: merge with develop, native build + ctest, byte identity ×4, goldens, PR tests, arch-domain tests per flavor, ABI counters, cachepolicy in both lowerers, NaN check on GPU, shipped gfx1250 grid compile, CI at head. Flags whether a closer look is needed; not an approval or rejection. |
The ABI 8 layout canary for rocke_direct_conv_wgrad_spec_t sat in conv_direct_dw_dgrad_host.cpp, a dgrad test. Move it unchanged into conv_direct_wgrad_refusals_host.cpp, the host test of the wgrad validators, and restore the dgrad test to develop's text. List rocke_conv_direct_wgrad_refusals_host in the quick and FFM tiers of ROCKE_ENGINE_test_categories_external.yaml, next to the dgrad host test, so the provider tiers run it and the canary with it. test_cmake_test_registration.py failed on it being untiered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…check
The check that every direct wgrad refusal except the three boolean-flag ones
names its value only looked for a digit, which 14 of the 17 texts from before
the "(got ...)" rewording already had (">= 1", "wave32", "gfx1250").
Both tables now require the reason to end with "(got ...)". The 11 refusals
that state a measured value inside the sentence instead (VGPR and LDS budgets,
the threads cap, the depthwise dtype, channel and wave-size checks, the tdm
wave count and the wave32 mfma_k gate) are listed with the value text each
must carry. All 17 old texts fail the new check in both engines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the follow-up. All three items are done, in new commits on top of 0e5ec03 (develop at 98e132f, no new develop merge needed):
Gates: the C++ build and |
|
Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max PR #14833 — gfx1250 direct wgrad kernels with two-stage reduction (jakpiase, AICK-2878) — 🟡 Follow-up: fixes hold; minor nits left
Utility: 🟢 Positive — gfx1250 direct wgrad kernels; all three of last round's items fixed. Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted Follow-up review: first pass by a local qwen3.6 model, verified by the orchestrator (Claude Opus 5.5). Checks: merge with develop and 14835 (trial compile); native build + ctest, byte identity ×4, goldens, differential, PR tests (installed tree), compile, the refusal value checks in both engines (three mutations each), develop's tier registration test at both heads, CI logs, code quality. Flags whether a closer look is needed; not an approval or rejection. |
…ke/gfx1250-wgrad-direct Develop now carries #14835, which replaces ROCKE_DCONV_WGRAD_REJECT with the shared ROCKE_SPEC_FAIL / rocke_spec_set_reasonf and takes ABI 8. - The seven ROCKE_DCONV_WGRAD_REJECT calls and the five ROCKE_DW_WGRAD_REJECT calls this branch adds now use ROCKE_SPEC_FAIL(reason, reason_cap, ...); ROCKE_DW_WGRAD_REJECT is removed. ROCKE_WGRAD_IMG_WHY, ROCKE_WGRAD_SC_WHY and ROCKE_DW_WGRAD_WHY keep their names and their return true, with a rocke_spec_set_reasonf body. The refusal texts are unchanged. - The wgrad spec growth is now ABI 9 (abi.h, BINARY_ABI in abi.py, the layout canary in conv_direct_wgrad_refusals_host.cpp). - direct_variants.__all__, benchmark_direct_conv.py (the wgrad chunk filter, then the kernel_map filter) and test_direct_kernel_cache.py keep both sides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the follow-up. N10 (body names the old canary location): fixed. The ABI: paragraph now names #14835 landed first, so this PR made the port from the overlap notice in its develop merge (10e926d):
Gates at 10e926d:
The PR's CPU tests show no new failures: 457 passed. There are 7 failures:
|
|
Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max PR #14833 — gfx1250 direct wgrad kernels with two-stage reduction (jakpiase, AICK-2878) — 🟡 Follow-up: port holds; minor nits left
Utility: 🟢 Positive — the port landed as asked, texts intact; Linux rocKE shards green. Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted Follow-up review: first pass by a local qwen3.6 model, verified by the orchestrator (Claude Opus 5.5). Checks: the develop merges' conflict resolutions; a scratch merge with develop: native build + ctest, byte identity ×4, goldens, differential; both validators' refusal texts against the last head; PR tests (native engine, torch, installed tree); CI logs; code quality. Flags whether a closer look is needed; not an approval or rejection. |
…ke/gfx1250-wgrad-direct # Conflicts: # dnn-providers/hip-kernel-provider/rocke/platform/cpp/include/rocke/abi.h
There was a problem hiding this comment.
🟡 Changes recommended
Public builders still accept a known-wrong kernel configuration, and depthwise atomics use an architecture-inappropriate cache policy, leaving critical correctness issues unresolved.
4 open issues
4 resolved since last review
Review effort: Max
- Both small_c validators refuse uniform_wave with more than 8 waves, vec_x=4, sub_steps >= 4 and >= 4 wave tiles: that body spills its SGPR column tables into VGPR lanes and returns an all-zero dW. The cache grid already skipped it; direct builder callers could still reach it. Refusal case added to both tables. - The depthwise wgrad atomics carry CPOL_ATOMIC_CASCADE_DEV on gfx12 targets only and the default policy elsewhere, in both engines: the immediate is the gfx12 th/scope encoding, and gfx11 reads the same bits as glc/slc/dlc. The cache builds this kernel for every wave32 target. Tested per arch in both engines. - IRBuilder.buffer_atomic_fadd_f32 refuses a non-integer (or bool) cachepolicy instead of rounding it to a valid policy. - The image-per-block and small_c wgrad builders copy the validator's reason into the builder error, so rocke_direct_conv_wgrad_lower_to_llvm reports it; the C++ refusal test now checks it through that entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: max PR #14833 — gfx1250 direct wgrad kernels with two-stage reduction (jakpiase, AICK-2878) — 🔴 Follow-up: golden not re-recorded; CI red
Utility: 🟡 Mixed — review fixes hold in both engines; golden re-record missed, CI red. Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted Follow-up review: first pass by a local qwen3.6 model, verified by the orchestrator (Claude Opus 5.5). Checks: scratch merges with develop, 14811's IR change included: native build + ctest, byte identity ×4, goldens, differential (its cause traced with a policy shim, the re-record tried on a copy); the review fixes probed in both engines; PR tests (native engine, torch, installed tree, unforced LLVM); CI logs; code quality. Flags whether a closer look is needed; not an approval or rejection. |
…ke/gfx1250-wgrad-direct
- Re-record the differential golden (ll for llvm20/22/23/24 and canonical IR): config 235 moved when the depthwise atomics took a per-arch cache policy; develop's unrecorded configs 171-176 are added with it. - Run test_direct_depthwise_wgrad_cachepolicy.py in the installed conv pytest lane. - Raise the wgrad spec layout canary to ROCKE_ABI_VERSION >= 10. - One ROCKE_CPOL_ATOMIC_CASCADE_DEV in rocke/ir.h replaces the four TU-local copies. - The depthwise wgrad validator writes its reason with rocke_spec_set_reasonf. - test_conv_tr_lane_map.py uses the shared IntLaneBuilder. - The refusal texts of the wgrad cases move to one table, library/tests/direct_wgrad_refusal_reasons.inc, that the C++ host test includes and the Python test parses, so a reword in one engine fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the follow-up. Everything from this round and the earlier open rows is fixed in 03ddb35, on top of a develop merge (e9cb4c1, clean):
Checks: byte identity GREEN at llvm20, llvm22, llvm23 and llvm24. IR parity golden OK. Build-tree ctest 53/53. The conv pytest lane's file list passes 1066, with 66 skipped. pre-commit is clean. |
…ke/gfx1250-wgrad-direct # Conflicts: # dnn-providers/hip-kernel-provider/rocke/platform/cpp/core/ir/core_types.cpp # dnn-providers/hip-kernel-provider/rocke/platform/cpp/include/rocke/abi.h # dnn-providers/hip-kernel-provider/rocke/platform/tests/core/test_opcode_values.cpp
|
Develop moved again: #14448 took ABI 10 and opcode 230. The develop merge 6a9aab8 resolves both conflicts by keeping develop's entries and putting this PR's after them:
Checks after the merge: byte identity GREEN at llvm20, llvm22, llvm23 and llvm24. IR parity and differential goldens (ll and canonical) OK. Build-tree ctest 58/58. The conv pytest lane plus |
|
Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: high PR #14833 — gfx1250 direct wgrad kernels with two-stage reduction (jakpiase, AICK-2878) — 🟠 Follow-up: conflicts with develop's 14822
Utility: 🟢 Positive — every open row fixed and verified; one develop conflict to resolve Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted Follow-up review: first pass by qwen3.6 (local), verified by the orchestrator (Claude Opus 5.5). Checks: the develop conflict traced to its commit and resolved on a scratch merge (both one-sided resolutions as controls), the conv lane and changed tests on it (native engine, unforced LLVM), saved ABI and golden probes, the merge's ABI and opcode lines, a trial merge with 14707, CI logs, code quality. Flags whether a closer look is needed; not an approval or rejection. |
…ke/gfx1250-wgrad-direct # Conflicts: # dnn-providers/hip-kernel-provider/rocke/library/benchmarks/common/direct_kernel_sweep.py
Key the CMake guard of rocke_conv_direct_wgrad_refusals_host on the sibling library tree, as the platform's library installs are, rather than on direct_wgrad_refusal_reasons.inc: a moved table now fails the build instead of dropping the test without a word. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the follow-up.
Checks at 4921f11:
|
|
Automated review: Model - qwen3.6:35b-a3b-coding-mtp-q4_K_M, effort: high PR #14833 — gfx1250 direct wgrad kernels with two-stage reduction (jakpiase, AICK-2878) — 🟠 Follow-up: conflicts with develop's 14907
Utility: 🟢 Positive — prior items fixed; one develop merge and a land order left Legend: 🔴 blocking · 🟠 should-fix · 🟡 minor nit · 🟢 info/good · ⚪ retracted Follow-up review: first pass by qwen3.6 (local), verified by the orchestrator (Claude Opus 5.5). Checks: the develop merge with 14907 resolved and checked (goldens, changed tests, ABI and port probes, syntax of the splice), the 11-06 develop merge's resolution, a moved-table mutant of the CMake guard, byte identity and ctest at the last clean merge, Windows CI logs for the refusals test, a trial merge with 14707, code quality. Flags whether a closer look is needed; not an approval or rejection. |



Motivation
On gfx1250 (wave32), the direct-conv AOT cache has no weight-gradient kernel for dense / grouped 3x3 layers, for small-channel stem convolutions or for depthwise layers (the depthwise one is also missing on the other wave32 targets, gfx1151 and gfx1201). Those problems fall back to the implicit-GEMM wgrad. For the stems this means an odd GEMM-N (
KH * KW * C, e.g. 27) that the split-K kernels cannot take.This PR adds three direct wgrad kernels (two gfx1250 WMMA kernels and a VALU depthwise kernel) and their Stage 2 reduce helper. Both engines build them, and they are served from the direct-conv AOT cache. It also makes the run-from-cache path robust for problems whose activations exceed the kernels' 2^31-byte addressing, and for kernargs that do not fit.
Technical Details
Kernels (
library/kernels/common/conv_direct_grouped.py, C++ twins inplatform/cpp/instances/common/conv_direct_grouped_build_{wgrad_image,wgrad_small_c,depthwise_wgrad}.cpp):DirectConvWgradSpec(image_per_block=True), variantdirect_wgradon wave32):k x ctile on WMMA 16x16x32;wave_tiles_k/wave_tiles_c) androws_per_syncrows per LDS sync;row_blocks);tdm_stages, llvm23 or llvm24);lds_epilogue).DirectConvWgradSpec(small_c=True), variantdirect_wgrad_small_c):(r, s, c)filter row for ungrouped stems (kpga multiple of 8, any filter, stride and padding); the cache carries stems with 3 or 4 input channels;vec_x),sub_stepsstaging, an optional uniform wave index.DirectDepthwiseWgradSpec, variantdirect_depthwise_wgrad):r_splitsplits the filter rows over wave groups);p_groupskernarg.ws_replicasfp32 scratch slabs;direct_wgrad_reducehelper (WgradReduceSpec, one binary per replica count) folds the slabs into dW;direct_kernel_sweep.plan_forbuilds the two-step plan;DirectPlan.zeroednames the scratch the caller zeroes.Shared lane map: the three builders take the wave32
ds_load_tr16_b128transpose-read lane map fromConvKOuterFragmentReader.wave32_lane_offsets(C++:rocke_conv_tr_lane_offsets32), which the implicit-GEMM fragment reader now calls too. The gfx1250 dgrad WMMA builders already on develop still compute the same map inline; this PR does not touch them.Platform: a new IR op
tile.buffer_atomic_fadd_f32(raw_ptr_buffer_atomic_faddwith a cache-policy immediate) in both engines. It is appended to the opcode enum (value 231, after develop'stile.gpu_check_failed), and the intrinsic declaration is added to both lowerers and to the llvm20, llvm22, llvm23 and llvm24 arch-domain data, with a cell for every wired arch.ABI:
rocke_direct_conv_wgrad_spec_tgains fields at its end (image_per_blockthroughuniform_wave), which changes its size, soROCKE_ABI_VERSION(abi.h) andBINARY_ABI(portable_ir/src/abi.py) move to 11 (develop is at 10). A layout canary inplatform/tests/instances/conv_direct_wgrad_refusals_host.cpppins the struct size to the ABI version.AOT (
library/kernels/conv/direct_aot_jobs.py,direct_variants.py):direct_wgrad_small_canddirect_depthwise_wgradjoin the direct grid.vec_x=4/sub_steps=4small-C tile is cached withuniform_waveoff.tdm_stages=0) image tiles with more than one tile per wave are not cached at 16 waves, where the 256-VGPR cap of a block with more than 8 waves makes them spill; their TDM-staged twins are cached.Run side (
benchmark_direct_conv.py,benchmark_implicit_gemm_conv.py):struct.errorwhile binding) is skipped instead of ending the sweep.AOT-cache-served; no dispatcher wiring. gfx1250 conv is served from the AOT cache, as it is for gfx950.
Test Plan
platform/tools/check_byte_identity.py, fresh--build-rootper flavor) at llvm20, llvm22, llvm23 (full), and llvm24 (--only conv_direct_grouped).library/tests/parity/conv_direct_grouped_emit.{py,c}:conv_direct_wgrad/gfx1250/*;platform/tests/instances/differential/golden/llvm_gfx_all.json;rocke_ir_parity_harness.py --checkandrun_diff.py --check-golden.rocke_buffer_rsrc_hip,rocke_opcode_valuespins the new opcode, and the newrocke_conv_direct_wgrad_refusals_hostruns every refusal case below through the C++ validators.test_direct_wgrad_refusals.py: one reason-match case per refusal check of the image-per-block, small-C and depthwise validators and their arch gates, and a check that every refusal of a numeric knob or an arch names the value it got;library/tests/direct_wgrad_refusal_reasons.inc, that the C++ host test includes and the Python test parses, so both engines are held to the same text;test_direct_depthwise_wgrad_cachepolicy.py(per-arch cache policy of the depthwise atomics) runs in the installed conv pytest lane;test_conv_tr_lane_map.py: the shared wave32 lane map, lane by lane, and that each wave32 direct wgrad builder uses it;test_direct_kernel_cache.py: AOT rows and reduce helpers, the skipped 16-wave register-staged tiles, two-step plans, stem serving, kernarg skip, wgrad batch chunks, andgrid_caches_variantagainst the enumerated jobs;test_direct_conv_correctness.py::TestDirectDepthwiseWgradGate: the depthwise numeric test's arch gate;platform/tests/tools/test_arch_domain_artifact.pyandplatform/tests/core/test_arch_domain_lane.pyatROCKE_LLVM_FLAVORllvm20, llvm22, llvm23 and llvm24;test_kernel_label.py;test_builder_signature_contract.py;test_conv_batch_and_miopen_parse.py;platform/tests/core/test_buffer_atomic_fadd.py.test_direct_conv_correctness.py:TestDirectConvWgradCorrectness(gfx1250: image-per-block, image row split with TDM, small-C) andTestDirectDepthwiseWgradCorrectness, which runs wherever the AOT grid caches the depthwise kernel (asked of the grid throughgrid_caches_variant: the wave32 targets, gfx1151 and gfx1201 included), and on gfx950. The wgrad test gate now admits gfx1250;TestDirectWgradAotKernelsCorrectness, whose cases are the gfx950 AOT wgrad kernels, stays gfx950-only.--compile-all --directions wgrad --arch gfx1250, then--run-from-cache --verifyper family and dtype.Test Result
test_direct_conv_correctness.py,test_direct_kernel_cache.py,test_direct_wgrad_specs.py,test_buffer_atomic_fadd.py): all pass.--run-from-cache --verifysmoke, fp16 and bf16: the C=3 stems (3x3 s1 p1 and unpadded 3x3 s2), the C=4 stem, 3x3 and 7x7 depthwise, and a dense 3x3 layer each run a new direct kernel, and every verified kernel passes. A bf16 3x3 layer with activations past 2^31 bytes runs as two batch slices accumulating into dW and verifies.Submission Checklist
JIRA ID : AICK-2878