Skip to content

test(integration-tests): add the SDPA backward test plan and its generated bundles - #14622

Merged
brockhargreaves-amd merged 21 commits into
developfrom
users/brockhargreaves-amd/sdpa-bwd-test-plan
Nov 5, 2026
Merged

brockhargreaves-amd merged 21 commits into
developfrom
users/brockhargreaves-amd/sdpa-bwd-test-plan

Conversation

@brockhargreaves-amd

@brockhargreaves-amd brockhargreaves-amd commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR adds the SDPA backward test plan required by RFC 0022 (Per-Op Test Plans, merged in #13937). It also adds a generator that writes the SdpaBackward bundles from the plan, and the bundles it writes. The 16 inherited SdpaBackward cases (all B = H = 1, packed BHSD, fixed scale) are replaced by 503 generated cases in four levels. Each case carries a purpose and traces to the plan items it covers.

Written with AI assistance (Claude Code). The plan follows the merged RFC 0022; it records one remaining deviation (DV-4) for reviewers to approve.

JIRA ID : ALMIOPEN-2894

Risk Assessment

Risk 2 of 5. The PR changes test data, test tooling, test configuration and documentation only; no library or provider code changes. The changes that reach beyond the SdpaBackward bundles:

  • support_matrix_units.collect_sweep_units() leaves out cases whose metadata.purpose is probe, as RFC 0022 §9 requires. Today only SdpaBackward cases carry a purpose, so other ops' matrices are unchanged. The committed SUPPORT_MATRIX_OVERVIEW.md is re-rendered.
  • ASM_SDPA_ENGINE.toml: two dtype-only SdpaBackward tolerance rows are replaced by 12 generated rows (seven tolerance classes), plus temporary skips for the open engine defects, each naming its ticket.
  • ASM_SDPA_ENGINE_test_categories_integration.yaml: six rejection probes that ASM_SDPA_ENGINE wrongly accepts are quarantined with their tickets (RFC 0022 §6). Both files affect the ASM lane only.
  • feat(hipdnn): SDPA CPU and GPU references cover the full SDPA graph API #14358's eight PyTorch golden cases move, unchanged, from quick/SdpaBackward/{Default,AdditiveMask}/ to quick/SdpaBackward/Golden/{Default,AdditiveMask}/, so the generator owns the Default sweeps. They keep their fp16 tolerance row. bhsd/ and the *_fwd_pair bundles are untouched.

The main risk is CI noise from new cases. Every level has been run on gfx942 and gfx950 with no failure (see Testing Checklist).

ASIC Coverage

The bundles run in every provider lane whose tier YAML matches *Sdpa*. Only ASM_SDPA_ENGINE accepts SdpaBackward graphs today, and only on gfx942: its backward plan builder declines every other device ("Device string does not match gfx942"). Claims are harvested for gfx942 only. PR CI tests gfx942. On gfx950 every generated backward case is declined, so a gfx950 run only shows that nothing fails; one is recorded below. PR CI on gfx942 is sufficient.

Testing Summary

  • Generator tests (hipdnn_sdpa_bwd_bundle_generator_python_tests, label quick, 19 tests). They fail when the checked-in sweeps or the TOML block drift from the generator. They also check legality, all-pairs coverage up to nightly, the per-case ceilings and cumulative budgets of each level, two-way traceability between plan items and cases, that every TOML skip still matches a written case, and that the tier-YAML quarantine holds only rejection probes.
  • generate_sdpa_bwd_bundles.py --dry-run --report. Reports counts, budgets, the all-pairs proof, legality, and each declared-but-gated case with its gate.
  • Claims run (2026-10-26, MI300X, gfx942). All generated bundles ran on ASM_SDPA_ENGINE, configured like CI. harvest_support_claims.py turned the passing cases into the 272 claims. Every claimed case passes its tolerance class with a margin of at least 2.4 (median 4.2).
  • Measured run, every level on GPU (2026-11-04, plan §4.5). hipdnn_integration_tests ran on ASM_SDPA_ENGINE configured like the CI lane: --test-engine (claims enforced), the PR's ASM_SDPA_ENGINE.toml, the tier YAML's quarantine as a GTest filter, device input fill and the GPU reference as oracle. It ran all four levels, on a fresh MI300X (gfx942) and an MI355X (gfx950) node, built from this branch. The bundles, TOML and YAML are identical to 6e014ad50e0.
  • PR CI runs the quick and standard levels on gfx942.

Testing Checklist

  • Generator tests - CTest hipdnn_sdpa_bwd_bundle_generator_python_tests - 19 of 19 - Status: Passed
  • Plan report - python3 reference-data-scripts/generate_sdpa_bwd_bundles.py --dry-run --report - 503 written, 77 gated, 0 legality violations, all-pairs 669 of 669 - Status: Passed
  • Bundle and support-matrix checks - verify_support_claims.py, render_support_matrix.py --output -, feature_matrix.py --check; the bundle, claim, render and support-feature pytest suites - Status: Passed (verify_golden_bundles.py reports no SdpaBackward error; its 322 errors in other ops' bundles are on develop too)
  • pre-commit on the changed files - Status: Passed
  • Claims run - hipdnn_integration_tests, ASM_SDPA_ENGINE, MI300X (gfx942), 2026-10-26 - Status: Passed
  • Measured run, gfx942 - hipdnn_integration_tests --test-engine ASM_SDPA_ENGINE --test-config ASM_SDPA_ENGINE.toml '--gtest_filter=*SdpaBackward*-<the tier YAML quarantine>' - MI300X, Slurm job 68275259 - Status: Passed. 553 tests in 43.3 s, 0 failed, no claim broken:
    • 289 executed and passed against the GPU reference, and 15 expected rejections rejected;
    • 226 declined by ASM, and 23 hit the DEF skips;
    • per level: quick 2.4 s, PR 2.8 s, nightly 16.5 s, full 21.4 s.
  • Quarantine check, gfx942 - the six quarantined cases run alone - Status: all six fail as expected ("Engine ASM_SDPA_ENGINE accepted expected-rejection bundle"), which shows the quarantine is needed.
  • Every level, gfx950 - same command - MI355X, Slurm job 68275260 - Status: Passed. 0 failed: ASM declines every backward graph on gfx950, and the rejection probes, quarantined ones included, are correctly rejected.
  • The other SDPA bundles, same lane - --gtest_filter=*Sdpa*:-*SdpaBackward* - Status: Passed. gfx942: 47 passed, 84 skipped. gfx950: 16 passed, 115 skipped. 0 failed on either.
  • PR CI on gfx942 - TheRock multi-arch CI - Status: Pending on 6e014ad50e0. The 2026-11-02 run failed one case, prbr01, which is now gated. Later runs failed only on the hipCCL configure break from feat(rocthrust,hipcub): add compatibility with libhipcxx 3.4 via legacy headers #14976, which develop reverted in Revert "feat(rocthrust,hipcub): add compatibility with libhipcxx 3.4 via legacy headers" #15089 (merged into this branch).

Technical Changes

What this adds

  • The plan: dnn-providers/integration-tests/docs/test-plans/sdpa-bwd.md. It follows the RFC 0022 template: the operation, the feature inventory, the shape catalog, building the sweep (levels, budgets, probes, regressions, trade-off register), the golden reference, pass criteria, and exhaustive mode.

  • The generator: reference-data-scripts/sdpa_bwd_plan.py holds the declarations: axes, legality, the shape catalog, level rules and the cost model, one record per case. generate_sdpa_bwd_bundles.py writes the sweeps, the support-claim files and the engine-TOML tolerance block from them. Nobody edits the bundles by hand. RFC 0022 open question 1 cites this module as the per-op Python option.

  • The bundles: 503 written cases, spread across the levels:

    Level Directory Cases
    quick quick/ 56
    PR standard/ 152
    nightly comprehensive/ 220
    full full/ 75
    • Each case carries purpose (claim, probe or regression) and its plan items.
    • 77 more cases are declared but not written yet, each waiting on a named gate: an oracle extension, a harness feature or golden data.
    • One of the 77 is PRB-R01 (dropout_probability = 0). Since feat(hipdnn): SDPA CPU and GPU references cover the full SDPA graph API #14358 the references decline any graph that sets dropout_probability, so it waits on ALMIOPEN-3149 or ALMIOPEN-3150.
  • Levels: the cost model assigns each case to the lowest level whose per-case limits it fits:

    Level Per-case time Per-case bytes Cumulative budget
    quick 1.5 s 4 MiB 20 s
    PR 5 s 16 MiB 120 s
    nightly 75 s 64 MiB 480 s
    full 300 s no limit 1,800 s

    Each cumulative budget covers that level and every level below it, and keeps 5 % in reserve. The budgets come from a CPU-reference cost model; with the GPU reference, the measured run above is far below them. The ASM lane YAML picks the cases up by GTest prefix (quick_*Sdpa*, standard_*Sdpa* and so on), and each level also runs every level below it.

  • Rejection probes (21) carry metadata.expected_rejection (feat(hipdnn-integration-tests): no-reference and expected-rejection bundle metadata flags #14346): the harness never executes them, and an engine that accepts one fails the lane. PRB-M02 and PRB-M02f (right_bound = -2) are not written, because the frontend rejects them since feat(hipdnn): SDPA CPU and GPU references cover the full SDPA graph API #14358; TestSdpaBwdNode.PreValidateChecksDiagonalBandBounds covers that rule.

  • dBias: the five dBias probes and the live GL-14 case are written, now that feat(hipdnn): SDPA CPU and GPU references cover the full SDPA graph API #14358's references model dBias. To keep PR and nightly inside their reserve, the plan's trim rule moved M07.pr to nightly and M26.n to full.

  • Tolerance classes: seven classes, written as 12 [[tolerance_overrides]] rows between generated BEGIN and END markers in ASM_SDPA_ENGINE.toml.

  • Support claims: 272 claims for ASM_SDPA_ENGINE on gfx942.

  • Probes left out of the support matrices (RFC 0022 §9). This is the support_matrix_units change above.

  • Generator file I/O is UTF-8, so its tests pass on Windows.

Temporary ASM_SDPA_ENGINE exclusions

These stay until each fix lands; the PR with the fix deletes its entries.

Open engine defects ([[test_skips]] in ASM_SDPA_ENGINE.toml). These are valid graphs that ASM accepts and computes wrong. Other engines still run them.

Cases What goes wrong Ticket Fix
DEF-01 head-dim stride other than 1 ALMIOPEN-3036 #14684
DEF-02 non-packed Stats ALMIOPEN-3037 #14684
DEF-04 Hk = Hq > Hv ALMIOPEN-3039 #14684
DEF-05 and H61 odd element strides ALMIOPEN-3038 #14684
DEF-06 scale of 0 or below ALMIOPEN-3043 #14688
DEF-03 fp16 dV precision in the AITER kernel ALMIOPEN-3046 none in hipDNN (kernel)

Quarantined rejection probes (_common_excludes in ASM_SDPA_ENGINE_test_categories_integration.yaml, as RFC 0022 §6 asks). These are undefined graphs ASM should decline but accepts.

Cases What ASM accepts Ticket Fix
prbu01, prbu03 O or dQ dims that differ from Q's ALMIOPEN-3039 #14684
prbu13 a dQ sequence stride below D (overlapping rows) ALMIOPEN-3038 #14684
prbt04, prbt04n an O dtype that differs from Q's ALMIOPEN-3050 none yet
prbr05 dropout_scale_inv without a dropout mask ALMIOPEN-3051 none yet

Dependencies (all merged)

Interaction with other open PRs

Before review

  • prbr01 (dropout_probability = 0) gated; ALMIOPEN-3149 and ALMIOPEN-3150 track the decision.
  • Rejection probes carry expected_rejection; the six ASM accepts are quarantined in the ASM tier YAML with their tickets.
  • prbm02 and prbm02f removed; the frontend unit test of R14 covers them.
  • The five dBias probes and GL-14 written; REG-08 (rank-3 Stats) still waits for the derivation extension.
  • The plan refreshed against the merged RFC: DV-1 and DV-2 now agree with it, DV-3 is an RFC §11 gap, and only DV-4 remains a deviation.
  • The measured run (plan §4.5) recorded above.

🤖 Generated with Claude Code

@therock-pr-bot

therock-pr-bot Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —
🤖 therock-pr-bot ✅ Pass —

🎉 All checks passed! This PR is ready for review.

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot

therock-pr-bot Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

@brockhargreaves-amd
brockhargreaves-amd force-pushed the users/brockhargreaves-amd/sdpa-bwd-test-plan branch from a0de08f to 2e14bfd Compare October 29, 2026 02:55
@therock-pr-bot

Copy link
Copy Markdown

Pre-commit check failed

⛔ pre-commit failed

Please run locally:

  • python -m pip install pre-commit
  • pre-commit install
  • pre-commit run --all-files --show-diff-on-failure

This repo uses .pre-commit-config.yaml.

brockhargreaves-amd added a commit that referenced this pull request Oct 29, 2026
…youts

SdpaBwdPlanBuilder::isApplicable accepted tensor layouts that the gfx942
backward kernels address wrongly. On gfx942 (MI300X) each one gave
silent wrong gradients instead of a decline. The evidence comes from two
sources. One is GPU runs of the plugin from a CI build of #14312,
which accepts all of these layouts. The other is disassembly of the dispatched .co files.

Q/K/V/O/dO/dQ/dK/dV strides. The ODO, DQDKDV and DQ_CONVERT argument
blocks carry only batch, head and sequence byte strides. isApplicable
now declines:
- A head-dim (innermost) stride other than 1. The kernels read it as 1:
  a stride-2 Q gave Inf dK/dV, and a stride-2 dQ left elements
  unwritten.
- A sequence stride below D, also on a length-1 sequence axis. Each
  buffer ends S * seq stride bytes into its (batch, head) slice, so the
  end of the last row reads as 0, and writes there are dropped. A seq
  stride of 1 on a length-1 axis gave wrong gradients for each of the
  eight tensors. Seq strides of D/2 and 2 did the same for Q, K, V and
  dO.
- An odd stride on an axis whose offset DQDKDV puts in its 4-byte record
  index (byte offset >> 2). That is the sequence axis of Q, K, V, dO, dK
  and dV, and the head axis of dK and dV. Rows that start 2 bytes into a
  dword are read or written one element early. A seq stride of D+1
  failed on each of the six. A dO row pitch of D+1 gave 47-97 %
  wrong dQ, dK and dV.
Odd strides on the other axes are addressed correctly and stay accepted:
- batch strides, which are added to the 64-bit buffer base;
- head strides of Q, K, V, O, dO and dQ;
- seq strides of O and dQ, which ODO and DQ_CONVERT address by byte
  offset.
The causal kernels also add the dK/dV head offset to the base, but the
check does not depend on the mask.

Stats (LSE). All 28 dispatched batch-mode DQDKDV kernels compute the LSE
and D offset as ((b * H_q + h) * S_q + s) * 4 and never load Hs_lsed. A
stats head stride padded to S_q + 64 gave wrong gradients that changed
between runs with identical inputs. A padded batch stride, a seq stride
of 2 and [B, S_q, H] storage also gave wrong gradients. isApplicable now
requires stats dims [B, H_q, S_q] or [B, H_q, S_q, 1] matching Q, with
packed strides on every axis longer than 1. buildPlan sets the LSE/D
strides from Q's dims, so the stride of a size-1 stats axis no longer
reaches a kernel argument or the 32-bit stride check.

These layouts stay accepted, all GPU-verified on gfx942: BSHD on all
tensors, dO strides that differ from O, seq strides D+2 and D+8, B and
H above 1, hd192, fp16, causal and sliding-window masks, BR causal with
Sq above Skv, Sq in {1, 16, 17}, and tails.

New tests in TestSdpaBwdPlanBuilder.cpp (gfx942 only, like the other
isApplicable tests). Each decline arm has a case that only it declines,
and each exemption has an accept case:
- IsApplicableAcceptsAddressableLayouts
- IsApplicableRejectsNonUnitHeadDimStride
- IsApplicableRejectsMisalignedOrShortRows
- IsApplicableRejectsNonPackedStats

Checked on gfx942 (MI300X). This commit's plugin replaced the one in a CI
build of #14312, and results were compared with the CPU reference:
- Each declined layout above failed with the old plugin, which accepts
  it, and now declines. Each layout named above as addressed correctly
  passed with the old plugin and still passes. The probes cover hd128
  and hd192, bf16 and fp16, and the no-mask, causal and sliding-window
  kernels.
- The shipped bf16 tolerance hides some short-row errors, so those were
  also compared at atol=1e-9 with packed controls. Their error was 7-34x
  the controls'; for Q, the dQ error sits in the cut-off last row.
- The develop quick/standard SdpaBackward bundles and the CI Sdpa
  bundles give the same results as before.
- The unit tests pass. Each of 29 mutants that removes or widens one arm
  of these checks makes one of the new tests fail.

Rebased onto develop 98b504d, after #14075, whose range gate now
runs first in isApplicable. The GPU results above are from develop
61c2675. On the new base, the four ALMIOPEN-3035 ASM SDPA fix
branches (backward layouts, attention scale, a16 accumulator, forward
layouts) were built and run together:
- hip_kernel_provider_tests: 912 pass and 7 skip on gfx942 (MI325X),
  886 pass and 33 skip on gfx950 (MI355X); none fail.
- hip_kernel_provider_integration_tests: none fail on either.
- develop's SDPA bundles on ASM_SDPA_ENGINE, run like the CI lane
  (claims enforced): 62 pass and 56 skip on gfx942, 15 pass and 103
  skip on gfx950, and no support claim fails. A host-side run of the
  real isApplicable over these bundles finds no outcome change from
  develop.
- #14622's SdpaBackward bundles (138218c) with its temporary
  [[test_skips]] removed: 275 pass and 225 skip on gfx942, none fail,
  and no support claim fails.
  This branch's checks decline the 20 cases behind the DEF-01, DEF-02,
  DEF-04, DEF-05/H61, prbu01, prbu03 and prbu13 skips, and no other
  case (host-checked for this branch alone).
- clang-tidy 20 and clang-format 18 are clean on the changed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brockhargreaves-amd added a commit that referenced this pull request Oct 29, 2026
…ales

SdpaFwdPlanBuilder::isApplicable and SdpaBwdPlanBuilder::isApplicable
accepted any attention scale, and execute passed it to the kernels
unchecked. cuDNN and hipDNN accept any scale value. On gfx942 (MI300X)
a scale of 0, -0.0, a negative value or a subnormal gave NaN or Inf
outputs and gradients instead of a decline.

The mechanism comes from the .co disassembly. The forward and backward
kernels write -inf into every masked score (causal and sliding-window
masks, and the padding past S_kv in the last K tile), and only then
multiply the scores by scale * log2(e). A scale of 0 turns those scores
into NaN, and a negative scale turns them into +inf. The bf16 forward
kernels also start the running row max at -FLT_MAX / (scale * log2(e)),
which is positive for a negative scale or -0.0, so every exp2 overflows
even with no mask. 32-bit denormals are flushed, so a subnormal scale
acts as 0. An infinite scale gives NaN everywhere.

The gfx942 runs used the plugin from a CI build of #14312, which
accepts all of these scales, and compared results with the CPU reference:
- Backward: 0, -0.0, 1e-40 and -1.2 gave NaN or Inf dQ, dK and dV with
  top-left or bottom-right causal masks and sliding windows, in bf16
  and fp16, hd128 and hd192. With no mask and S_kv = 128 (the hd128 K
  tile is 192), all of dQ was NaN.
- Forward: -1.2, -0.088 and -0.0 gave NaN O and Inf LSE even with no
  mask. 0 gave NaN O with a bottom-right causal mask or S_kv = 200.
- A runtime pass-by-value scale tensor gave the same results as
  attn_scale_value.

Both isApplicable functions now decline a scale that is not a finite,
positive, normal float (FLT_MIN <= scale <= FLT_MAX; NaN fails). The
check covers attn_scale_value, and the value of a compile-time constant
or runtime-with-default pass-by-value scale tensor, narrowed to the f32
kernarg as execute narrows it. They also decline a scale tensor whose
value the plugin SDK cannot read, on which buildPlan would throw. The
value of a pure runtime pass-by-value scale tensor arrives only at
execute, so both execute functions now throw BAD_PARAM for such a scale
before the first launch, as the gfx1151 WMMA attention pack does for its
runtime scale. The check is shared in SdpaPlanUtils.hpp.

An unset scale (1.0) and every finite, positive, normal scale stay
accepted; 1e-37 and 1/sqrt(128) were correct on gfx942. The rule also
declines some cases that happened to compute correctly: no mask with
S_kv a multiple of the K tile, for any of these scales in the backward
and for +0.0 or a subnormal scale in the forward. A rule keyed on the
mask and the tile would break once group mode makes the K tail
per-sequence, so the decline does not depend on them. Scales near
FLT_MAX (1e37, 1e38) still give NaN in the forward; that is a separate
issue.

New tests:
- TestSdpaPlanUtils (host only):
  IsSupportedAttnScaleRequiresFinitePositiveNormalFloat and
  AttnScaleBeforeExecute.
- TestSdpaFwdPlanBuilder and TestSdpaBwdPlanBuilder (gfx942, and gfx950
  for the forward, like the other isApplicable tests):
  IsApplicableRejectsUnsupportedAttnScale declines 0, -0.0, -1.2,
  -1/sqrt(128), -FLT_MIN, three subnormals, NaN and +-inf, each from
  attn_scale_value, a constant scale tensor and a runtime scale tensor
  default, plus an FP8_E4M3 scale tensor.
  IsApplicableAcceptsSupportedAttnScale accepts 1e-37, 1/sqrt(128) and
  1 from each source, the unset default and a pure runtime scale tensor.
- TestSdpaFwdPlanExecute and TestSdpaBwdPlanExecute: execute returns
  BAD_PARAM for each unsupported runtime scale (host only, on a plan
  with no loaded kernels), and passes supported ones on to the launch.

Checked on gfx942 (MI300X). This commit's plugin replaced the one in a CI
build of #14312, and results were compared with the CPU reference on
the 82 scale cases behind the results above:
- The 61 cases whose unsupported scale comes from attn_scale_value or a
  constant scale tensor are now declined. With the old plugin 48 of
  them failed, 12 passed (the no-mask cases named above) and one was
  already declined (fp16 forward).
- The 4 cases with an unsupported runtime scale tensor (0 and -1.2,
  forward and backward) now fail at execute with BAD_PARAM, and the
  message gives the scale. The old plugin gave NaN or Inf in 3 of them.
- The 15 cases with a supported scale pass with both plugins:
  1/sqrt(128) with each mask, dtype and scale source, and 1e-37. The
  forward with 1e37 or 1e38 fails with both, as noted above.
- On the develop CI build, develop's quick and standard SdpaFwd,
  SdpaFwdRuntimeScale and SdpaBackward bundles give the same result for
  each case as with develop's plugin: 42 pass and 39 are declined, for
  the same reasons, none of them the scale.
- The unit tests pass. Each of 14 mutants that removes, widens or
  narrows one arm of these checks makes one of the new tests fail.

Rebased onto develop 98b504d, after #14075, whose range gate now
runs first in isApplicable. The GPU results above are from develop
61c2675. On the new base, the four ALMIOPEN-3035 ASM SDPA fix
branches (backward layouts, attention scale, a16 accumulator, forward
layouts) were built and run together:
- hip_kernel_provider_tests: 912 pass and 7 skip on gfx942 (MI325X),
  886 pass and 33 skip on gfx950 (MI355X); none fail.
- hip_kernel_provider_integration_tests: none fail on either.
- develop's SDPA bundles on ASM_SDPA_ENGINE, run like the CI lane
  (claims enforced): 62 pass and 56 skip on gfx942, 15 pass and 103
  skip on gfx950, and no support claim fails. A host-side run of the
  real isApplicable over these bundles finds no outcome change from
  develop.
- #14622's SdpaBackward bundles (138218c) with its temporary
  [[test_skips]] removed: 275 pass and 225 skip on gfx942, none fail,
  and no support claim fails.
  This change declines def06a, def06b and def06c (scale 0 and -1.2),
  the cases behind the DEF-06 skip, and no other case (host-checked
  for this branch alone). The execute-path scale tests
  (PassesSupportedRuntimeAttnScaleToLaunch) pass on both GPUs.
- clang-tidy 20 and clang-format 18 are clean on the changed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brockhargreaves-amd added a commit that referenced this pull request Oct 29, 2026
SdpaBwdPlanBuilder advertised the sdpa.bwd.accumulator_type knob with
valid values a32 and a16, and initializeExecutionSettings accepted a16.
isApplicable checks only the A32 kernels. With an A16 setting, buildPlan
asks for a DQDKDV row with atomic32=0, pssk=1, pddv=1, and the gfx942
registry has none: its 24 a16 rows all have pssk=0, hd64 or hd128, and
mask none or top-left causal. So buildPlan threw INTERNAL_ERROR "failed
to resolve dqdkdv kernel ... (isApplicable should have rejected)" for
every graph isApplicable accepts. On gfx942 (MI300X), develop's builder
built all 42 accepted graphs of a sweep with a32 and failed all 42 with
a16: bf16 and fp16; hd128 with no mask, top-left and bottom-right causal
and sliding window; hd192 with no mask and both causal masks.

hipDNN users cannot reach this today. AsmSdpaEngine publishes no builder
knobs and never calls initializeExecutionSettings, so it always builds
A32 plans, and the frontend refuses or drops knobs that an engine does
not advertise. This change leaves the engine alone: with only a32 valid
there is nothing to forward, and forwarding the knobs before this fix
would have exposed the failure.

Selecting the a16 rows that do exist would not fix it either. The gfx942
a16 kernels add dQ atomically, in the 16-bit output type, into the
output dQ, address dQ and dO with Q's strides, and never load seqlen_k,
the window bounds, or any V, dO, dK or dV stride other than dK's seq
stride. In a bf16 diagnostic run with those rows patched in, cases
inside that envelope matched a32 to 1 bf16 ulp. A dQ holding stale
values, a dQ or dO layout that differs from Q's, Sq != Skv, and S not a
multiple of 64 each gave wrong gradients, and a padded Q/dO row pitch
and S=300 also wrote past the end of dQ.

Now:
- getCustomKnobs lists only a32.
- initializeExecutionSettings rejects a16 with INVALID_VALUE and a
  message of its own. Other unknown strings still get INVALID_VALUE and
  non-string values BAD_PARAM.
- buildPlan refuses an A16 setting with an INTERNAL_ERROR that says so,
  before it queries the device or resolves a kernel. It is the only
  gate: getMaxWorkspaceSize still sizes an A16 setting without dq_acc,
  but no A16 plan is ever built to use that size, and the A16 code in
  buildPlan and SdpaBwdPlan is kept for a future enablement.
- Comments in the builder, the plan, and the params, kernel-args and
  workspace-size headers that said A16 can be selected, or that its
  kernels write dQ directly in BF16 and need no dQ zeroing, now say
  that the a16 kernels add dQ atomically into the output dQ, which must
  be zeroed first, and that A16 is refused. The comment on the rejection
  lists the graphs that getCustomKnobs and initializeExecutionSettings
  would have to limit A16 to before it could be enabled. isApplicable
  cannot do that: it sees no knob, and it also validates A32, which
  runs graphs A16 cannot.
An unset knob and a32 behave as before, and isApplicable and the A32
plans are unchanged.

Tests in TestSdpaBwdPlanBuilder.cpp:
- GetCustomKnobsReturnsAccumulatorKnob now expects only a32 (gfx942
  only, like the other isApplicable tests).
- InitializeExecutionSettingsAcceptsA32 covers a32, and an unset knob
  from an invalid config, a valid config with no knobs, and a valid
  config with only another knob.
- InitializeExecutionSettingsRejectsA16
- InitializeExecutionSettingsRejectsUnknownAccumulator
- BuildPlanRejectsA16Setting, which needs no GPU.
- Gfx942HasNoA16DqdkdvForDispatchedLayout pins the registry fact that
  the rejection comment cites, with the pssk=0 a16 rows as positive
  controls.

Checked on gfx942 (MI300X). All 228 asm_sdpa unit tests pass except
IsApplicableRejectsGfx950, which skips on gfx942 as it does on develop
(223 tests there). The host-only tests also pass on a machine without
a gfx942 device. Each of 9 mutants makes one of the tests above fail:
mapping a16 back to A16, dropping the a16 arm, letting a32 fall
through, listing a16 again, dropping the buildPlan check (buildPlan
then fails to resolve a DQDKDV kernel, as on develop), accepting
unknown strings, dropping the has-knob check (a valid config without
the knob then throws std::out_of_range), pointing the registry check
at gfx950, which has such rows, and making every lookup in it miss.
develop's quick and standard SdpaBackward bundles (8 cases) pass
against the CPU reference with this plugin, as with develop's, and
still build A32 plans. clang-format 18 and clang-tidy 20 are clean on
the changed files.

Rebased onto develop 98b504d, after #14075, whose range gate now
runs first in isApplicable. The GPU results above are from develop
61c2675. On the new base, the four ALMIOPEN-3035 ASM SDPA fix
branches (backward layouts, attention scale, a16 accumulator, forward
layouts) were built and run together:
- hip_kernel_provider_tests: 912 pass and 7 skip on gfx942 (MI325X),
  886 pass and 33 skip on gfx950 (MI355X); none fail.
- hip_kernel_provider_integration_tests: none fail on either.
- develop's SDPA bundles on ASM_SDPA_ENGINE, run like the CI lane
  (claims enforced): 62 pass and 56 skip on gfx942, 15 pass and 103
  skip on gfx950, and no support claim fails. A host-side run of the
  real isApplicable over these bundles finds no outcome change from
  develop.
- No #14622 SdpaBackward case changes outcome: no bundle sets a knob
  (host-checked for this branch alone).
- clang-tidy 20 and clang-format 18 are clean on the changed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brockhargreaves-amd added a commit that referenced this pull request Oct 29, 2026
…outs

SdpaFwdPlanBuilder::isApplicable accepted Q/K/V/O and stats (LSE)
layouts that the forward kernels address wrongly. Its only stride check
was that byte strides fit in 32 bits. On gfx942 (MI300X) each kind of
layout below gave a silently wrong O or wrong stats instead of a
decline, in the cases that were run (the exceptions are noted). The
evidence comes from two sources. One is GPU runs of the develop CI
plugin, which accepts all of these layouts, compared with the CPU
reference. The other is disassembly of the 14 forward .co files.

Q/K/V/O strides. The forward argument block carries only batch, head
and sequence byte strides, and the kernels read or write each row as D
contiguous elements. isApplicable now declines:
- A head-dim (innermost) stride other than 1. The kernels read it as 1.
  Stride-2 Q, K or V gave a wrong O that changed between runs, because
  the kernels read the gaps between elements. A stride-2 O left half of
  O unwritten. Q stored as [B, H, D, S] and hd192 Q with stride 2 also
  failed.
- A sequence stride below the tensor's own head dim, also 0 and also on
  a length-1 sequence axis. Each buffer ends S * seq stride bytes into
  its (batch, head) slice, so the end of the last row reads as 0 and
  writes there are dropped. A seq stride of D/2 gave a wrong O for Q
  and V, and for K at S_kv = 2. At S_kv = 256 the K case stayed within
  the bf16 tolerance, but its error was about 6x the packed run's. With
  S_q = 1 and an O seq stride of 1, O was left NaN. With S_kv = 1 and a
  V seq stride of 1, O was 0. K and V with seq stride 0 gave O and
  stats off by up to 1.0 and 1.3, Q with seq stride 0 gave a wrong O
  and stats, and O with seq stride 0 was left unwritten. With S_kv = 1
  a K seq stride of 1 still gave the right O, since the one key takes
  all the softmax weight; by the address formula its score, and so the
  stats, are wrong.
  Each tensor is compared with its own head dim. That relies on K
  having Q's head dim and O being [B, H_q, S_q, D_v], because the
  kernels size K rows by Q's head dim and O's buffer by S_q. The
  forward isApplicable does not check those dims yet; a forward
  counterpart of the backward's mismatched-dims decline is a separate
  change.
- A zero O batch or head stride on an axis longer than 1. Each (batch,
  head) slice of O is written by its own workgroups, so such slices
  overwrite each other: with an O batch or head stride of 0, half or
  two thirds of O differed from the packed run, and O changed between
  some runs with identical inputs.
Nonzero strides that make O overlap itself are not checked. On gfx942,
O with equal batch and head strides (B = H = 2), or with a head stride
of half a slice, differed from the packed run in a quarter of its
elements, with both plugins. As in the backward, only a zero stride is
checked: a zero stride is how a broadcast is written, so O gets one
when it is given a broadcast input's strides, while overlapping nonzero
strides have to be built by hand. PyTorch's check for tensors that an
operation writes to also rejects only a zero stride on an axis longer
than 1. Stats do get an overlap check (below), because their address
formula leaves a single comparison to make; for O it would take a
footprint check over three axes in any order, which would fit better in
hipDNN's graph validation, where every engine gets it.
The zero O batch stride check assumes batch mode, the only mode with
forward kernels. In group (ragged) mode the kernels locate each batch
by its sequence offsets and get no O batch stride, so when group-mode
forward kernels are added, a ragged O must be exempt from the
batch-axis part of this check.

Stats. Every forward kernel writes the LSE of (b, h, s) at
((b * H_q + h) * lse_Hs + s) * 4 bytes, with lse_Hs the stats head
stride, and takes no stats batch or sequence stride. isApplicable now
declines stats whose seq stride is not 1 when S_q > 1, or whose batch
stride is not H_q times the head stride when B > 1. It also declines a
head stride below S_q when B * H_q > 1, with which (batch, head) slices
overlap. On gfx942 each of these gave wrong or NaN stats while O was
correct:
- a batch stride padded to H_q * S_q + 128, with hd128, hd192 and GQA;
- a seq stride of 2;
- [B, S_q, H] storage, and H_q = 1 with strides [S_q, 1, 1, 1];
- [H, B, S_q] storage, which by the kernels' address formula also
  writes 2 KiB past the end of the stats buffer.
This is looser than the backward's packed-only stats rule on purpose.
The backward kernels ignore the stats strides, but the forward kernels
use lse_Hs: a head stride padded to S_q + 64, with a batch stride of
H_q times that, gave correct stats on gfx942 and stays accepted. The
stride of a size-1 stats batch or sequence axis is not checked. A
size-1 head axis is, on purpose: buildPlan passes the head stride as
lse_Hs, so with H_q = 1 the kernel steps between batches by the head
stride. Passing the batch stride instead when H_q = 1 would also accept
packed [B, 1, S_q] stats with any head stride, such as the H_q = 1 case
above; they are rare and decline. The stats decline reasons name the
stats dims and strides and Q's dims.

These stay accepted, all GPU-verified with bf16 on gfx942:
- BSHD on all tensors, and O BSHD with BHSD inputs;
- seq strides D+2 and D+8;
- odd strides: a seq stride of D+1 and odd head and batch strides on
  each of Q, K, V and O, with hd128 and hd192, gave O bitwise equal to
  the packed runs (the backward declines some of these);
- hd192, GQA, bottom-right causal, tails, and S_q = 1 or S_kv = 1
  packed;
- a zero batch or head stride on Q, K or V (a broadcast): K and V with
  a zero batch or head stride, and Q with a zero batch stride, gave O
  bitwise equal to the packed runs and stats that matched the CPU
  reference.
A zero stride on a length-1 O axis is accepted too, since it only ever
multiplies index 0.

The gfx950 kernels have the same argument block and the same LSE
address formula (from their disassembly), but load rows with 16-byte
LDS-DMA where the gfx942 kernels use 4-byte. On gfx950 (MI355X), this
commit's plugin gave the BSHD, D+2, D+8 and odd-stride layouts above,
with hd128 and hd192, the same mismatch counts and max and mean error
against the CPU reference at atol=1e-9 as the packed layouts. The fp8
kernels also have the same argument block and LSE formula, so the same
rules apply to them. They were not run; in particular odd strides,
which put fp8 rows 1 or 3 bytes past a 4-byte boundary, are unverified
with fp8.

New tests in TestSdpaFwdPlanBuilder.cpp (gfx942 and gfx950, like the
other forward isApplicable tests). Each decline arm has a case that only
it declines, and each exemption has an accept case:
- IsApplicableAcceptsAddressableLayouts
- IsApplicableRejectsNonUnitHeadDimStride
- IsApplicableRejectsShortRows, including hd192 Q and K rows long
  enough for V's and O's head dim but not their own
- IsApplicableRejectsZeroStrideOutput
- IsApplicableRejectsUnaddressableStats

The zero-stride and overlapping layouts were run with a standalone
hipDNN probe that drives ASM_SDPA_ENGINE on its own buffers, because
the bundle harness's test tensors reject zero strides.

Checked on gfx942 (MI300X). This commit's plugin replaced the one in a
develop CI build whose ASM SDPA engine source matches this commit's
parent, and results were compared with the CPU reference:
- 84 forward layout probes. The 25 that this commit declines now skip,
  each with a reason that names the tensor, its dims and its strides.
  With the develop plugin, 21 of them gave a wrong O or wrong stats.
  Two could not be checked there: the harness rejects a zero stride
  (the standalone probe covers it), and the CPU reference rejects
  rank-3 stats. The last two passed but are wrong in ways the check
  missed: the K seq stride D/2 case stays within the bf16 tolerance,
  and with S_kv = 1 a K seq stride of 1 only gives the right O because
  one key takes all the softmax weight.
- The other 59 give the same results as with the develop plugin, down
  to the mismatch counts and the max and mean error at atol=1e-9. 47
  pass; they cover every layout named above as staying accepted except
  the broadcasts, which the next item covers. 3 were already declined.
  9 still fail: non-positive or denormal scales, which are left to a
  separate change, and rank-3 stats, which the CPU reference cannot
  check.
- On the standalone probe, K/V and Q broadcasts still match the CPU
  reference and are bitwise equal to their packed twins in each of 3
  runs. An O batch or head stride of 0 and a Q, K/V or O seq stride of
  0 now decline; with the develop plugin each gave a wrong O. The two
  overlapping O layouts are accepted by both plugins, with the same
  mismatch counts.
- 19 probes with tensors of up to 4 GiB, which exercise the kernels'
  32-bit address math, give the same results as before (10 of them
  still fail with both plugins; the 32-bit address math is a separate
  change).
- The develop SdpaFwd and SdpaFwdRuntimeScale bundles (102 tests, quick
  to full) give the same results as before: 46 pass and 56 skip, with
  the same decline reasons.
- The provider's own forward GPU integration tests
  (hip_kernel_provider_integration_tests, *IntegrationGpuSdpaFwd*:
  Smoke, SmokeFp8, SmokeStats, ShapeSweep, Gqa and AsymmetricSeq) pass
  against this commit's plugin: 29 pass, and 21 skip as gfx950-only or
  causal with stats.
- The unit tests pass. Each of 33 mutants that removes, narrows or
  widens one arm of these checks, or compares a row stride with another
  tensor's head dim or a fixed 128, makes one of the new tests fail.
On gfx950 the 84 forward layout probes ran with this commit's plugin
only, since the develop CI build has no gfx950 kernels. The same 28
skip, and every probe that passes on gfx942 and has a gfx950 kernel
passes. The forward unit tests pass there too.

Rebased onto develop 98b504d, after #14075, whose range gate now
runs first in isApplicable. The GPU results above are from develop
61c2675. On the new base, the four ALMIOPEN-3035 ASM SDPA fix
branches (backward layouts, attention scale, a16 accumulator, forward
layouts) were built and run together:
- hip_kernel_provider_tests: 912 pass and 7 skip on gfx942 (MI325X),
  886 pass and 33 skip on gfx950 (MI355X); none fail.
- hip_kernel_provider_integration_tests: none fail on either.
- develop's SDPA bundles on ASM_SDPA_ENGINE, run like the CI lane
  (claims enforced): 62 pass and 56 skip on gfx942, 15 pass and 103
  skip on gfx950, and no support claim fails. A host-side run of the
  real isApplicable over these bundles finds no outcome change from
  develop.
- No develop or #14622 bundle case changes outcome (host-checked for
  this branch alone). The new forward tests pass on gfx942 and gfx950.
- clang-tidy 20 and clang-format 18 are clean on the changed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brockhargreaves-amd added a commit that referenced this pull request Oct 30, 2026
…ales

SdpaFwdPlanBuilder::isApplicable and SdpaBwdPlanBuilder::isApplicable
accepted any attention scale, and execute passed it to the kernels
unchecked. cuDNN and hipDNN accept any scale value. On gfx942 (MI300X)
a scale of 0, -0.0, a negative value or a subnormal gave NaN or Inf
outputs and gradients instead of a decline.

The mechanism comes from the .co disassembly. The forward and backward
kernels write -inf into every masked score (causal and sliding-window
masks, and the padding past S_kv in the last K tile), and only then
multiply the scores by scale * log2(e). A scale of 0 turns those scores
into NaN, and a negative scale turns them into +inf. The bf16 forward
kernels also start the running row max at -FLT_MAX / (scale * log2(e)),
which is positive for a negative scale or -0.0, so every exp2 overflows
even with no mask. 32-bit denormals are flushed, so a subnormal scale
acts as 0. An infinite scale gives NaN everywhere.

The gfx942 runs used the plugin from a CI build of #14312, which
accepts all of these scales, and compared results with the CPU reference:
- Backward: 0, -0.0, 1e-40 and -1.2 gave NaN or Inf dQ, dK and dV with
  top-left or bottom-right causal masks and sliding windows, in bf16
  and fp16, hd128 and hd192. With no mask and S_kv = 128 (the hd128 K
  tile is 192), all of dQ was NaN.
- Forward: -1.2, -0.088 and -0.0 gave NaN O and Inf LSE even with no
  mask. 0 gave NaN O with a bottom-right causal mask or S_kv = 200.
- A runtime pass-by-value scale tensor gave the same results as
  attn_scale_value.

Both isApplicable functions now decline a scale that is not a finite,
positive, normal float (FLT_MIN <= scale <= FLT_MAX; NaN fails). The
check covers attn_scale_value, and the value of a compile-time constant
or runtime-with-default pass-by-value scale tensor, narrowed to the f32
kernarg as execute narrows it. They also decline a scale tensor whose
value the plugin SDK cannot read, on which buildPlan would throw. The
value of a pure runtime pass-by-value scale tensor arrives only at
execute, so both execute functions now throw BAD_PARAM for such a scale
before the first launch, as the gfx1151 WMMA attention pack does for its
runtime scale. The check is shared in SdpaPlanUtils.hpp.

An unset scale (1.0) and every finite, positive, normal scale stay
accepted; 1e-37 and 1/sqrt(128) were correct on gfx942. The rule also
declines some cases that happened to compute correctly: no mask with
S_kv a multiple of the K tile, for any of these scales in the backward
and for +0.0 or a subnormal scale in the forward. A rule keyed on the
mask and the tile would break once group mode makes the K tail
per-sequence, so the decline does not depend on them. Scales near
FLT_MAX (1e37, 1e38) still give NaN in the forward; that is a separate
issue.

New tests:
- TestSdpaPlanUtils (host only):
  IsSupportedAttnScaleRequiresFinitePositiveNormalFloat and
  AttnScaleBeforeExecute.
- TestSdpaFwdPlanBuilder and TestSdpaBwdPlanBuilder (gfx942, and gfx950
  for the forward, like the other isApplicable tests):
  IsApplicableRejectsUnsupportedAttnScale declines 0, -0.0, -1.2,
  -1/sqrt(128), -FLT_MIN, three subnormals, NaN and +-inf, each from
  attn_scale_value, a constant scale tensor and a runtime scale tensor
  default, plus an FP8_E4M3 scale tensor.
  IsApplicableAcceptsSupportedAttnScale accepts 1e-37, 1/sqrt(128) and
  1 from each source, the unset default and a pure runtime scale tensor.
- TestSdpaFwdPlanExecute and TestSdpaBwdPlanExecute: execute returns
  BAD_PARAM for each unsupported runtime scale (host only, on a plan
  with no loaded kernels), and passes supported ones on to the launch.

Checked on gfx942 (MI300X). This commit's plugin replaced the one in a CI
build of #14312, and results were compared with the CPU reference on
the 82 scale cases behind the results above:
- The 61 cases whose unsupported scale comes from attn_scale_value or a
  constant scale tensor are now declined. With the old plugin 48 of
  them failed, 12 passed (the no-mask cases named above) and one was
  already declined (fp16 forward).
- The 4 cases with an unsupported runtime scale tensor (0 and -1.2,
  forward and backward) now fail at execute with BAD_PARAM, and the
  message gives the scale. The old plugin gave NaN or Inf in 3 of them.
- The 15 cases with a supported scale pass with both plugins:
  1/sqrt(128) with each mask, dtype and scale source, and 1e-37. The
  forward with 1e37 or 1e38 fails with both, as noted above.
- On the develop CI build, develop's quick and standard SdpaFwd,
  SdpaFwdRuntimeScale and SdpaBackward bundles give the same result for
  each case as with develop's plugin: 42 pass and 39 are declined, for
  the same reasons, none of them the scale.
- The unit tests pass. Each of 14 mutants that removes, widens or
  narrows one arm of these checks makes one of the new tests fail.

Rebased onto develop 98b504d, after #14075, whose range gate now
runs first in isApplicable. The GPU results above are from develop
61c2675. On the new base, the four ALMIOPEN-3035 ASM SDPA fix
branches (backward layouts, attention scale, a16 accumulator, forward
layouts) were built and run together:
- hip_kernel_provider_tests: 912 pass and 7 skip on gfx942 (MI325X),
  886 pass and 33 skip on gfx950 (MI355X); none fail.
- hip_kernel_provider_integration_tests: none fail on either.
- develop's SDPA bundles on ASM_SDPA_ENGINE, run like the CI lane
  (claims enforced): 62 pass and 56 skip on gfx942, 15 pass and 103
  skip on gfx950, and no support claim fails. A host-side run of the
  real isApplicable over these bundles finds no outcome change from
  develop.
- #14622's SdpaBackward bundles (138218c) with its temporary
  [[test_skips]] removed: 275 pass and 225 skip on gfx942, none fail,
  and no support claim fails.
  This change declines def06a, def06b and def06c (scale 0 and -1.2),
  the cases behind the DEF-06 skip, and no other case (host-checked
  for this branch alone). The execute-path scale tests
  (PassesSupportedRuntimeAttnScaleToLaunch) pass on both GPUs.
- clang-tidy 20 and clang-format 18 are clean on the changed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brockhargreaves-amd and others added 13 commits November 2, 2026 13:41
The SdpaBackward bundles come from the SDPA backward test plan
(docs/test-plans/sdpa-bwd.md, RFC 0022), in the shape of the
convolution-forward generator:

- sdpa_bwd_plan.py declares the plan: levels and the baseline switches,
  the window semantics (left_bound = W - 1 on develop, W after SEM-001),
  the stride kinds of every layout, the cost model, ceilings and
  budgets, the legality layers (F, WF, EXT, U), the oracle gates with
  their tracking items, the purpose rule, the value domains, the
  tolerance classes and their rule, the magnitude estimator, the
  all-pairs axes and check, and the S, H, X, M and L catalog with the
  model-layer reduction rule.
- generate_sdpa_bwd_bundles.py holds the level rules, the graph
  templates of all twelve topologies, the sweep writer (metadata with
  purpose, plan_items, size class, seed, per-uid inputs, notes and
  tolerance class), the TOML tolerance-row writer and the report. It
  writes only cases whose oracle is ready; the others stay declared with
  level notrun and their gate. --dry-run --report prints counts,
  budgets, the all-pairs proof, legality and gates.
- sdpa_bwd_calibration.json records the NumPy magnitude estimates behind
  the tolerance classes, keyed by plan item and dtype with a fingerprint
  of the estimate's inputs. A run fails on a missing or stale estimate;
  --calibrate recomputes it.

The generator reproduces the reviewed case list (sdpa_bwd_cases.json,
580 cases) case for case: ids, levels, topologies, dims, strides,
attributes, inputs, purposes, plan items and tolerance classes. The
differences are deliberate: S46 keeps its odd row pitch, H62 its zero
K/V batch stride and H87 its Q = K = V = 133120 fill (all three not
run), and the DEF entry gates name the companion engine pull requests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…est plan

Replaces the 16 captured SdpaBackward cases with the 500 cases of the
test plan, written by generate_sdpa_bwd_bundles.py:

| Level | Cases | Sweeps |
|---|---|---|
| quick | 57 | Default, AdditiveMask, ScaleTensor |
| standard | 151 | Default, AdditiveMask, DBiasOnly, ScaleTensor, DropoutScaleInv, SeqLenQOnly |
| comprehensive | 222 | Default, AdditiveMask, DBiasOnly, ScaleTensor, FwdBwdChained |
| full | 70 | Default |

80 more cases wait for a gate (#14358, the #14312 derivation extension,
harness items) and are not written. Each sweep gets an empty
support.json; claims are harvested.

The templates make the band, attn_scale_value (null = unset), the
deprecated causal flags, alibi_mask, dropout_probability, the node
compute type and every tensor's alignment placeholders. A runtime
pass-by-value scale patches the template's constant scale tensor.

ASM_SDPA_ENGINE.toml: the two dtype rows become one row per tolerance
class and dtype (12 rows), written between the generator's markers.
Each case id ends with its class token, so every id matches one row.
A [[test_skips]] entry skips the fp16 DEF-03 probes on ASM (fp16 dV
loses precision at Skv <= 2, Sq >= 512 in the kernel; tracking issue to
be filed). The probes stay in their levels so the skip is reported on
every run and other engines run them.

The DEF-01, DEF-02, DEF-04 and DEF-05 probes expect a typed decline
from ASM_SDPA_ENGINE (companion engine pull request); the DEF-06
probes expect the decline being diagnosed. Land those first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
test_generate_sdpa_bwd_bundles.py (pytest) checks that:

- the checked-in SdpaBackward sweeps and the generated block of
  ASM_SDPA_ENGINE.toml equal the generator output, and the generator is
  deterministic;
- every written case is legal (WF or EXT; rejection probes in U) and its
  sweep values and metadata match the case;
- not-run cases are not written and each has a known gate;
- the cases up to nightly cover every required pair of axis values, and
  every pair of claim values with a claim-only case;
- every case id matches exactly one [[tolerance_overrides]] row, the row
  of its class, and no other graph name matches a row; every
  SdpaBackward [[test_skips]] filter still selects a written case;
- every metadata.plan_items entry is a known feature, shape or plan row,
  and every feature has a case or a disposition;
- the per-case ceilings and the cumulative budgets hold;
- kept_pairs matches a brute-force count, the model reduction meets its
  target, and (with numpy) the estimator reproduces the calibration.

Registered as hipdnn_sdpa_bwd_bundle_generator_python_tests, a pytest
suite like the other pytest-style suites, and labelled quick and
ffm-full through test_categories_external.yaml.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… passes on gfx942

Adds 272 claims (ASM_SDPA_ENGINE, gfx942, linux) to seven SdpaBackward
sidecars. They come from one gfx942 run of the generated bundles:

- Node: MI300X (gfx942), 2026-10-26
  23:48 UTC.
- Binaries: hipdnn_integration_tests and the backend from the #14312 CI
  build (run 40350338181, head 186a38f). The ASM plugin comes from
  asm-sdpa-bwd-decline-strides (7c8f12a871d; its engine source equals
  9c1d25e). That branch only adds declines, so the develop plugin
  accepts every claimed case too.
- Settings as in CI: device fill, auto verification (the CPU reference),
  enforcing claims, a fresh process per level.

Results:

| Level | Cases | Pass | Skip | Fail |
|---|---|---|---|---|
| quick | 57 | 50 | 7 | 0 |
| standard | 151 | 71 | 77 | 3 |
| comprehensive | 222 | 109 | 113 | 0 |
| full | 70 | 45 | 25 | 0 |

The three failures are the DEF-06 probes (scale <= 0). The engine
returns NaN or Inf for them.

harvest_support_claims.py read the four level logs. No block was
rejected and no claim failed. It kept 275 cells. Three of them are
probes that passed (prbg01, prbr01, h12). RFC 0022 section 9 never
claims a probe, so they are left out. That leaves 260 claim cases and
12 regression cases.

A second run with atol 1e-9 and device fill printed the error of every
passing case. Each claimed case passes its tolerance class with margin
2.4 or more (median 4.2). A rerun of quick, standard and comprehensive
with these sidecars confirmed all 227 of their claims, with no claim
failure.

SUPPORT_MATRIX_OVERVIEW.md is not re-rendered.
support_features/feature_matrix.py does not catalogue 43 SdpaBackward
cases (head dims such as 80 and 256, FLOAT and FP8 IO, both deprecated
causal flags, a transposed Q), so it renders nothing. This has been so
since the bundles were generated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eview)

Adds dnn-providers/integration-tests/docs/test-plans/sdpa-bwd.md, the
human-readable half of the SdpaBackward plan (ALMIOPEN-2894).
sdpa_bwd_plan.py, generate_sdpa_bwd_bundles.py and the README already
point at this path.

The plan covers the feature inventory, the shape catalog (S, L, M, H,
X), how the sweep is built (core cells, all-pairs, probes,
regressions, budgets), the golden reference choice and the pass
criteria.

It is marked as a draft for review. The case counts in section 4.1
match the generator's --dry-run --report at this commit: 580 cases,
500 written (quick 57, PR 151, nightly 222, full 70) and 80 gated.
The banner maps the plan's engine defects DEF-01 to DEF-08 to their
ALMIOPEN tickets.

The methodology and index links resolve once the first phase of RFC 0022
(#13937) lands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The DEF-03 [[test_skips]] entry in ASM_SDPA_ENGINE.toml said its
tracking issue was still to be filed. It is ALMIOPEN-3046.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n's current sections

The generator and plan-module comments, the calibration note and the
generated TOML block still cited section numbers from an earlier draft
of the plan (for example §4.8, §4.11 and §6.2 for the tolerance
classes, which are now §6.1). They now cite the sections of
docs/test-plans/sdpa-bwd.md as it stands. No case changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… model probes

The plan's trim rule (§4.4, register R-M6) moves probes up a level,
largest first, until a level is inside its 5 % budget reserve. The plan
already describes the result, but the generator never applied it, so PR
(115.6 s of 120) and nightly (476.0 s of 480) ran over the reserve.

M09.pr, M28.pr and M31.pr (6.6 s) move from PR to nightly; M03.n, M12.n,
M20.n, M36.n and M43.n (25.4 s) move from nightly to full. All eight are
probes, so no support claim moves. Cumulative budgets are now quick 18.4,
PR 109.0, nightly 450.6 and full 1698.4 s, each inside its reserve; the
all-pairs cover is unchanged (669 of 669 pairs). Case ids do not change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… until the declines land

The PR level holds the open-defect probes of the SDPA backward test plan
(§4.2): valid graphs ASM_SDPA_ENGINE accepts today and computes wrongly.
Without a skip, every gfx942 PR run fails 20 of them.

One [[test_skips]] entry per defect, each naming its ticket and the
branch whose decline replaces it:

- DEF-01, head-dim stride other than 1: ALMIOPEN-3036
- DEF-02, non-packed Stats: ALMIOPEN-3037
- DEF-04, Hk = Hq > Hv: ALMIOPEN-3039
- DEF-05 and H61, odd element strides: ALMIOPEN-3038
- DEF-06, attention scale of 0 or below: ALMIOPEN-3043

The pull request that adds each decline deletes its entry. Other engines
still run these cases. None of them carries a support claim.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ne with the generator

The level counts, size classes, topology counts, legality counts, cost
table and shard split are recomputed from the generator after the trim
(generate_sdpa_bwd_bundles.py --report and its case records):
500 written cases, quick 57, PR 148, nightly 220, full 75; 444 WF, 113
EXT and 23 U; PR 109.0 s and nightly 450.6 s cumulative.

The open-defect section now describes the interim disposition the
engine TOML uses: a DEF case sits in its level, and an engine that has
the defect skips it, naming the ticket, until its decline lands. DEF-08
is marked as listed but not generated yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
RFC 0022 §9 tags each generated sweep case with a purpose. A probe
exercises a value no engine claims, or an undefined graph a correct
engine rejects, and the published support matrices exclude probes.

The support-matrix units still took every sweep case, so the
SdpaBackward test-plan probes (head dims outside the SDPA feature
catalogue, fp32 IO, a transposed q, both deprecated causal flags)
reached support_features/ and failed hipdnn_support_features_python_tests
with "is not catalogued" errors. collect_sweep_units() now skips a case
whose metadata.purpose is "probe", after the template and patch checks,
so a broken probe is still reported. Cases without a purpose, claims
and regressions are unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…undles

#14483 gave the SDPA left_bound the cuDNN meaning on develop (SEM-001):
left_bound = L keeps the L keys ending at the diagonal, and 0 is illegal.
The frontend, both references and ASM_SDPA_ENGINE moved with it. The
generator still wrote develop's old form, left_bound = W - 1, so every
window case described a window one key narrower than its id says, and the
W = 1 cases wrote the now-illegal 0.

WINDOW_SEMANTICS is now "after_sem001": the 117 window cases are
regenerated with left_bound = W. Case ids, levels, tolerance classes and
the TOML block are unchanged, and the claims still describe the same
windows. The plan and the generator now cite #14483, which replaced the
closed #14287, including in regression_of; the window-semantics test
sets both meanings explicitly instead of assuming the default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he SdpaBackward claims

The SdpaBackward test plan added 272 ASM_SDPA_ENGINE claims on gfx942 and
264 SdpaBackward graphs that are claims or regressions; probes are left
out of the matrices. Regenerated with
support_features/feature_matrix.py, which
test_committed_overview_is_current checks: Attention on gfx942 goes from
16 % to 42 % of its options, and SdpaBackward appears under
ASM_SDPA_ENGINE at 64 %.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brockhargreaves-amd and others added 3 commits November 2, 2026 13:45
…es ASM accepts

The first gfx942 PR run of the SdpaBackward bundles on develop's
ASM_SDPA_ENGINE failed three rejection probes of the PR level. The
engine accepts each undefined graph instead of declining it:

- prbu01 (O and dO with half the head dim) and prbu03 (dQ with half the
  sequence length): the CPU reference then throws on the shape. These
  are the dims mismatches of ALMIOPEN-3039.
- prbu13 (dQ with a sequence stride below D, so its rows overlap): the
  aliased dQ fails the comparison on 74 % of its elements. This is the
  short-row class of ALMIOPEN-3038.

The 2026-10-26 run used the asm-sdpa-bwd-decline-strides plugin, which
declines all three, so it did not see them. Two temporary [[test_skips]]
entries name the tickets and the fix branch, as for the DEF probes. The
plan's list of rejection probes that reach a failing check, and the
generator's recorded verdicts, now include these three.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…es as UTF-8

hipdnn_sdpa_bwd_bundle_generator_python_tests failed on the Windows
superbuild: test_engine_toml_block_is_generated read ASM_SDPA_ENGINE.toml
with the platform default encoding, so the section sign in the generated
comment ("sdpa-bwd.md §6.1") did not round-trip. Every read_text and
write_text in the generator, the plan module and the tests now names
UTF-8, and writes use "\n" line endings so a Windows run writes the same
bytes. The tests also pass under an ASCII locale.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The UTF-8 change left three lines over black's limit, which failed the
pre-commit job.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@brockhargreaves-amd
brockhargreaves-amd force-pushed the users/brockhargreaves-amd/sdpa-bwd-test-plan branch from 138218c to 5744d47 Compare November 2, 2026 18:46
brockhargreaves-amd added a commit that referenced this pull request Nov 3, 2026
…ales

SdpaFwdPlanBuilder::isApplicable and SdpaBwdPlanBuilder::isApplicable
accepted any attention scale, and execute passed it to the kernels
unchecked. cuDNN and hipDNN accept any scale value. On gfx942 (MI300X)
a scale of 0, -0.0, a negative value or a subnormal gave NaN or Inf
outputs and gradients instead of a decline.

The mechanism comes from the .co disassembly. The forward and backward
kernels write -inf into every masked score (causal and sliding-window
masks, and the padding past S_kv in the last K tile), and only then
multiply the scores by scale * log2(e). A scale of 0 turns those scores
into NaN, and a negative scale turns them into +inf. The bf16 forward
kernels also start the running row max at -FLT_MAX / (scale * log2(e)),
which is positive for a negative scale or -0.0, so every exp2 overflows
even with no mask. 32-bit denormals are flushed, so a subnormal scale
acts as 0. An infinite scale gives NaN everywhere.

The gfx942 runs used the plugin from a CI build of #14312, which
accepts all of these scales, and compared results with the CPU reference:
- Backward: 0, -0.0, 1e-40 and -1.2 gave NaN or Inf dQ, dK and dV with
  top-left or bottom-right causal masks and sliding windows, in bf16
  and fp16, hd128 and hd192. With no mask and S_kv = 128 (the hd128 K
  tile is 192), all of dQ was NaN.
- Forward: -1.2, -0.088 and -0.0 gave NaN O and Inf LSE even with no
  mask. 0 gave NaN O with a bottom-right causal mask or S_kv = 200.
- A runtime pass-by-value scale tensor gave the same results as
  attn_scale_value.

Both isApplicable functions now decline a scale that is not a finite,
positive, normal float (FLT_MIN <= scale <= FLT_MAX; NaN fails). The
check covers attn_scale_value, and the value of a compile-time constant
or runtime-with-default pass-by-value scale tensor, narrowed to the f32
kernarg as execute narrows it. They also decline a scale tensor whose
value the plugin SDK cannot read, on which buildPlan would throw. The
value of a pure runtime pass-by-value scale tensor arrives only at
execute, so both execute functions now throw BAD_PARAM for such a scale
before the first launch, as the gfx1151 WMMA attention pack does for its
runtime scale. The check is shared in SdpaPlanUtils.hpp.

An unset scale (1.0) and every finite, positive, normal scale stay
accepted; 1e-37 and 1/sqrt(128) were correct on gfx942. The rule also
declines some cases that happened to compute correctly: no mask with
S_kv a multiple of the K tile, for any of these scales in the backward
and for +0.0 or a subnormal scale in the forward. A rule keyed on the
mask and the tile would break once group mode makes the K tail
per-sequence, so the decline does not depend on them. Scales near
FLT_MAX (1e37, 1e38) still give NaN in the forward; that is a separate
issue.

New tests:
- TestSdpaPlanUtils (host only):
  IsSupportedAttnScaleRequiresFinitePositiveNormalFloat and
  AttnScaleBeforeExecute.
- TestSdpaFwdPlanBuilder and TestSdpaBwdPlanBuilder (gfx942, and gfx950
  for the forward, like the other isApplicable tests):
  IsApplicableRejectsUnsupportedAttnScale declines 0, -0.0, -1.2,
  -1/sqrt(128), -FLT_MIN, three subnormals, NaN and +-inf, each from
  attn_scale_value, a constant scale tensor and a runtime scale tensor
  default, plus an FP8_E4M3 scale tensor.
  IsApplicableAcceptsSupportedAttnScale accepts 1e-37, 1/sqrt(128) and
  1 from each source, the unset default and a pure runtime scale tensor.
- TestSdpaFwdPlanExecute and TestSdpaBwdPlanExecute: execute returns
  BAD_PARAM for each unsupported runtime scale (host only, on a plan
  with no loaded kernels), and passes supported ones on to the launch.

Checked on gfx942 (MI300X). This commit's plugin replaced the one in a CI
build of #14312, and results were compared with the CPU reference on
the 82 scale cases behind the results above:
- The 61 cases whose unsupported scale comes from attn_scale_value or a
  constant scale tensor are now declined. With the old plugin 48 of
  them failed, 12 passed (the no-mask cases named above) and one was
  already declined (fp16 forward).
- The 4 cases with an unsupported runtime scale tensor (0 and -1.2,
  forward and backward) now fail at execute with BAD_PARAM, and the
  message gives the scale. The old plugin gave NaN or Inf in 3 of them.
- The 15 cases with a supported scale pass with both plugins:
  1/sqrt(128) with each mask, dtype and scale source, and 1e-37. The
  forward with 1e37 or 1e38 fails with both, as noted above.
- On the develop CI build, develop's quick and standard SdpaFwd,
  SdpaFwdRuntimeScale and SdpaBackward bundles give the same result for
  each case as with develop's plugin: 42 pass and 39 are declined, for
  the same reasons, none of them the scale.
- The unit tests pass. Each of 14 mutants that removes, widens or
  narrows one arm of these checks makes one of the new tests fail.

Rebased onto develop 98b504d, after #14075, whose range gate now
runs first in isApplicable. The GPU results above are from develop
61c2675. On the new base, the four ALMIOPEN-3035 ASM SDPA fix
branches (backward layouts, attention scale, a16 accumulator, forward
layouts) were built and run together:
- hip_kernel_provider_tests: 912 pass and 7 skip on gfx942 (MI325X),
  886 pass and 33 skip on gfx950 (MI355X); none fail.
- hip_kernel_provider_integration_tests: none fail on either.
- develop's SDPA bundles on ASM_SDPA_ENGINE, run like the CI lane
  (claims enforced): 62 pass and 56 skip on gfx942, 15 pass and 103
  skip on gfx950, and no support claim fails. A host-side run of the
  real isApplicable over these bundles finds no outcome change from
  develop.
- #14622's SdpaBackward bundles (138218c) with its temporary
  [[test_skips]] removed: 275 pass and 225 skip on gfx942, none fail,
  and no support claim fails.
  This change declines def06a, def06b and def06c (scale 0 and -1.2),
  the cases behind the DEF-06 skip, and no other case (host-checked
  for this branch alone). The execute-path scale tests
  (PassesSupportedRuntimeAttnScaleToLaunch) pass on both GPUs.
- clang-tidy 20 and clang-format 18 are clean on the changed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brockhargreaves-amd and others added 5 commits November 4, 2026 10:19
Preserve both probe and expected-rejection matrix coverage, and regenerate the support overview from the merged bundle data.
Since #14358 the SDPA references decline every graph that sets
dropout_probability (isSupportedSdpaDropout), including 0 with no seed,
offset or mask. The input fill and ASM_SDPA_ENGINE read 0 as no dropout, so
ASM accepts PRB-R01 (prbr01) and nothing can check its output: PR CI on
2026-11-02 failed it as Unverifiable in the ASM standard lane.

PRB-R01 keeps quick as its target level but now waits on a new gate, p0: a
SEM entry for p = 0 and a reference that models it. ALMIOPEN-3149 (compute
it as no dropout) and ALMIOPEN-3150 (make it an invalid graph) are the two
ways to open it. The quick level drops from 57 to 56 cases (499 written,
81 gated); the plan's counts, budgets and oracle-gap row follow, and the
calibration entry is refreshed for the gated case.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ged references and flags

With #14358 and #14346 on develop:

- Every rejection probe now carries metadata.expected_rejection, so an engine
  that accepts one fails the lane instead of the case reporting SKIP. On gfx942
  ASM_SDPA_ENGINE declines 17 of the 23 and accepts six, which are quarantined
  in ASM_SDPA_ENGINE_test_categories_integration.yaml with their tickets, as
  RFC 0022 §6 asks: prbu01 and prbu03 (ALMIOPEN-3039), prbu13 (ALMIOPEN-3038),
  prbt04 and prbt04n (ALMIOPEN-3050), prbr05 (ALMIOPEN-3051). The two
  rejection-probe [[test_skips]] rows leave ASM_SDPA_ENGINE.toml; the DEF
  rows stay. A generator test keeps the quarantine to written rejection
  probes.
- PRB-M02 and PRB-M02f (right_bound = -2) leave the bundles: the frontend
  rejects them since #14358 (R14), and TestSdpaBwdNode's
  PreValidateChecksDiagonalBandBounds already asserts it. Legality is now
  checked against that frontend (F_R13R14).
- The five dBias probes (PRB-B11 to PRB-B14, PRB-B16) and the live GL-14 case
  enter PR: both references model dBias since #14358. The trim rule moves
  M07.pr to nightly and M26.n to full to keep PR and nightly inside their
  reserve. REG-08 (rank-3 Stats) waits on the derivation extension instead.

Written cases: 503 (quick 56, PR 152, nightly 220, full 75); 77 declared and
gated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rged RFC 0022 and develop

- The status note, the level and golden-criteria links point at the merged
  RFC 0022 (#13937); its methodology guide and test-plans index do not exist
  yet. The baseline is develop 961dd76, with #14358, #14346 and #14709.
- Deviations: the merged RFC adopted DV-1 (§7 exception) and DV-2 (§12.3
  uplift default) and lists DV-3 as an oracle gap (§11); only DV-4 still
  needs approval.
- Gates that named #14358 now name what is left (I6, I4, HG4, HG20, GPU
  forward, timing run); the reference-status table, the oracle columns and
  the §6.4 gap table show #14358's references as in place.
- §2.8 to §4: F_active is F_R13R14; PRB-M02 and PRB-M02f are frontend unit
  tests; rejection probes carry expected_rejection, and the six ASM accepts
  are quarantined in the tier YAML; the dBias probes and GL-14 are written;
  the second trim (M07.pr, M26.n); counts, budgets and topology rows from
  the generator.
- §4.5 records the 2026-11-04 measured run on gfx942 and the gfx950 run.
- §5: #14358's golden cases stay under quick/SdpaBackward/Golden; GT1 and
  the SEM-010 −inf exception are in place, so GL-09 and GL-16b can join the
  first golden data.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@brockhargreaves-amd
brockhargreaves-amd marked this pull request as ready for review November 4, 2026 21:22
@brockhargreaves-amd
brockhargreaves-amd requested a review from a team as a code owner November 4, 2026 21:22

@adickin-amd adickin-amd 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.

LGTM, This is a great start on the test bundles for SDPA BWD and it has already exposed issues were actively closing. Lets get this in an proceed with filling out more test cases as we see fit.

@brockhargreaves-amd
brockhargreaves-amd merged commit a860c78 into develop Nov 5, 2026
105 of 107 checks passed
@brockhargreaves-amd
brockhargreaves-amd deleted the users/brockhargreaves-amd/sdpa-bwd-test-plan branch November 5, 2026 19:17
AnaghaRaoAMD added a commit that referenced this pull request Nov 5, 2026
…2-dense-aot

The only conflict is the generated SUPPORT_MATRIX_OVERVIEW.md, which #14622 (SDPA
backward bundles) and this branch's stats bundles both changed; it is regenerated from
the merged tree with feature_matrix.py. The 224 shipped gfx942 dense kernels lower to
the same LLVM IR before and after the merge.

Co-Authored-By: Claude <noreply@anthropic.com>
adickin-amd added a commit that referenced this pull request Nov 6, 2026
… claim PRs (#15293)

## Summary
Stop regenerating `SUPPORT_MATRIX_OVERVIEW.md` in every PR that changes
bundles or support claims. Every such PR edited the same generated file,
so each merge made the other open claim PRs conflict on it and forced
another develop merge and regenerate (for example #14984 after #14259
and #14622 merged). The overview is now refreshed by hand in a PR of its
own, and no check fails when it lags.

JIRA ID : ALMIOPEN-3185

## Risk Assessment
Risk 1. Python tooling, a pre-commit hook and docs only; no product
code, no build change. The only behavior removed is the staleness check
on a generated file. Errors in the overview renderer and in the sidecars
it reads are still caught by the render hook and the
`hipdnn_support_features_python_tests` ctest.

## ASIC Coverage
None. Host-only Python tooling and docs; no GPU code path changes.

## Testing Summary
- Unit: `test_harvest_support_claims.py` and `test_support_features.py`,
including the real-tree render and size checks.
- Smoke: with the committed overview deliberately edited out of date,
the `TestRealBundleTree` ctest tests pass and `feature_matrix.py
--check` reports it as stale (exit 1).
- Pre-commit on the changed files, including the new
`render-support-matrix-overview` hook.

## Testing Checklist
- [x] Support-claim tooling tests - `python -m pytest
dnn-providers/integration-tests/scripts/test_harvest_support_claims.py
dnn-providers/integration-tests/scripts/test_support_features.py` -
Status: Passed (1914 tests)
- [x] Stale overview no longer fails - `pytest test_support_features.py
-k RealBundleTree` against an edited overview - Status: Passed
- [x] Pre-commit - `pre-commit run --files <changed files>` - Status:
Passed
- [ ] PR CI - GitHub PR checks - Status: Pending

## Technical Changes
- `test_support_features.py`: remove
`test_committed_overview_is_current`. The real-tree render and the size
limit stay.
- `.pre-commit-config.yaml`: replace `check-support-matrix-overview`
(`--check`) with `render-support-matrix-overview`, which renders to
stdout and discards, like `render-support-matrix`.
- `harvest_support_claims.py`: `--write` no longer re-renders the
overview; `refresh_overview` and its tests are removed, and a test
checks that `--write` leaves the overview alone.
- `feature_matrix.py`: the rendered overview states that it can lag
develop and points to the current copy in the `hipdnn-support-matrix` CI
artifact. `--check` stays for telling whether a refresh is due.
- `SUPPORT_MATRIX_OVERVIEW.md`: regenerated for that header note.
- `docs/support-matrix.md`, `docs/adding-tests.md`, RFC 0015: the
overview is not committed with sidecar or bundle changes; after a
harvest or a batch of claim PRs merges, whoever landed them refreshes it
in a PR with only that file.

Open claim PRs that already carry an overview change should drop it once
this merges: `git checkout origin/develop --
dnn-providers/integration-tests/SUPPORT_MATRIX_OVERVIEW.md`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants