Skip to content
Open
Show file tree
Hide file tree
Changes from 76 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
5621449
feat(hip-kernel-provider): add SdpaRequest contract for hipDNN SDPA f…
AnaghaRaoAMD Oct 13, 2026
d9d9fd2
feat(hip-kernel-provider): add keep() and sdpa_reference SDPA oracle
AnaghaRaoAMD Oct 13, 2026
a6c9cdc
feat(hip-kernel-provider): add epilogue and score coordinates to atte…
AnaghaRaoAMD Oct 13, 2026
dd3474f
docs(rocke): add DoD for hipDNN operators and new kernel operands
AnaghaRaoAMD Oct 14, 2026
47997b7
Merge origin/develop into users/anarao/hack/sdpa/st0-contract
AnaghaRaoAMD Oct 14, 2026
1bc6185
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 20, 2026
860cc78
refactor(hip-kernel-provider): layer the SDPA request oracle on devel…
ThruptiRajLakshmanaGowda Oct 20, 2026
ba1b9b5
fix(hip-kernel-provider): reject SDPA node keys from_hipdnn would sil…
ThruptiRajLakshmanaGowda Oct 20, 2026
349ccfe
fix(hip-kernel-provider): classify per-sequence bottom-right masks an…
ThruptiRajLakshmanaGowda Oct 20, 2026
80c96db
ci(hip-kernel-provider): run library/tests/sdpa in a host CTest lane
ThruptiRajLakshmanaGowda Oct 20, 2026
8653d4a
docs(rocke): point the hipDNN-operator DoD at the current SDPA oracle…
ThruptiRajLakshmanaGowda Oct 20, 2026
271c396
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 20, 2026
83d6891
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 21, 2026
dd8a18e
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 21, 2026
aa59c1b
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 21, 2026
379646e
fix(hip-kernel-provider): merge deprecated SDPA causal flags with the…
ThruptiRajLakshmanaGowda Oct 21, 2026
4a5f2e0
fix(hip-kernel-provider): reject SDPA band bounds below -1 instead of…
ThruptiRajLakshmanaGowda Oct 21, 2026
3e954e6
fix(hip-kernel-provider): reject generate_stats without a stats tenso…
ThruptiRajLakshmanaGowda Oct 21, 2026
5af36d3
fix(hip-kernel-provider): give equivalent SDPA graphs one request ide…
ThruptiRajLakshmanaGowda Oct 21, 2026
c348211
fix(hip-kernel-provider): bake only compile-time constant SDPA scale …
ThruptiRajLakshmanaGowda Oct 21, 2026
5317285
test(hip-kernel-provider): seed the SDPA case-table test deterministi…
ThruptiRajLakshmanaGowda Oct 21, 2026
501b1b5
test(hip-kernel-provider): find the hipDNN graph template and bundles…
ThruptiRajLakshmanaGowda Oct 21, 2026
72a258b
refactor(hip-kernel-provider): resolve SDPA node masks through one hi…
ThruptiRajLakshmanaGowda Oct 21, 2026
c388050
fix(hip-kernel-provider): report ragged and under-aligned auxiliary S…
ThruptiRajLakshmanaGowda Oct 21, 2026
3d30853
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 21, 2026
6601891
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 21, 2026
25ff1a7
fix(rocke): reject malformed SDPA request metadata and decode oracle …
ThruptiRajLakshmanaGowda Oct 23, 2026
51a97ce
fix(rocke): reject non-boolean SDPA flags and carry tuning_knobs on S…
ThruptiRajLakshmanaGowda Oct 27, 2026
cf0cde3
Merge remote-tracking branch 'origin/develop' into users/anarao/hack/…
ThruptiRajLakshmanaGowda Oct 27, 2026
6d69128
fix(rocke): treat empty SDPA paged, fp8 and dropout groups as absent
ThruptiRajLakshmanaGowda Oct 27, 2026
62ff9c2
feat(hip-kernel-provider): rebind SDPA unified binding onto the real …
ThruptiRajLakshmanaGowda Oct 28, 2026
63690a4
test(hip-kernel-provider): rebuild SDPA unified wiring tests on real …
ThruptiRajLakshmanaGowda Oct 28, 2026
faa6692
fix(hip-kernel-provider): defer d=256 admission to the attention regi…
ThruptiRajLakshmanaGowda Oct 28, 2026
db09a6a
refactor(hip-kernel-provider): split SDPA kernel binding out of the a…
ThruptiRajLakshmanaGowda Oct 28, 2026
16dbfa9
fix(hip-kernel-provider): never admit an SDPA request the unified pat…
ThruptiRajLakshmanaGowda Oct 28, 2026
6d2277c
test(hip-kernel-provider): check the unified SDPA gate over the case …
ThruptiRajLakshmanaGowda Oct 28, 2026
7f02a04
fix(hip-kernel-provider): check the SDPA band the unified problem builds
ThruptiRajLakshmanaGowda Oct 30, 2026
b80e151
feat(hip-kernel-provider): bind SDPA requests to the unified attentio…
ThruptiRajLakshmanaGowda Oct 28, 2026
14ecce7
fix(rocke): keep the gfx942 4-warp attention kernel inside its buffers
ThruptiRajLakshmanaGowda Oct 30, 2026
979fdf9
test(hip-kernel-provider): check every admitted SDPA case on GPU
ThruptiRajLakshmanaGowda Oct 30, 2026
ba9a215
Merge remote-tracking branch 'origin/develop' into users/tlakshma/hac…
ThruptiRajLakshmanaGowda Oct 30, 2026
cb8ccae
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Oct 30, 2026
b5c7410
refactor(hip-kernel-provider): share SDPA binding helpers
ThruptiRajLakshmanaGowda Oct 30, 2026
3a33c2b
feat(hip-kernel-provider): SDPA admission and binding for the dense a…
ThruptiRajLakshmanaGowda Oct 30, 2026
e7484f3
test(hip-kernel-provider): dense SDPA case table, binding and GPU tests
ThruptiRajLakshmanaGowda Oct 30, 2026
466d677
Merge remote-tracking branch 'origin/develop' into users/tlakshma/hac…
ThruptiRajLakshmanaGowda Oct 30, 2026
64bfb49
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Oct 30, 2026
1ff4318
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 1, 2026
d784ec9
fix(hip-kernel-provider): reject SDPA hipDNN nodes missing a type key
ThruptiRajLakshmanaGowda Nov 1, 2026
f7224e6
test(hip-kernel-provider): resolve the GPU test arch via base_arch_fr…
ThruptiRajLakshmanaGowda Nov 1, 2026
36e9a86
fix(hip-kernel-provider): update the gfx942 bottom-right dense test f…
ThruptiRajLakshmanaGowda Nov 1, 2026
80e03ee
fix(hip-kernel-provider): re-bless the gfx942 4-warp IR golden shards
ThruptiRajLakshmanaGowda Nov 1, 2026
811033e
refactor(hip-kernel-provider): route bind_dense's torch use through t…
ThruptiRajLakshmanaGowda Nov 1, 2026
de25330
feat(hip-kernel-provider): add registered_sdpa_combos/sdpa_sweep_spac…
ThruptiRajLakshmanaGowda Nov 1, 2026
0ad6c2c
fix(hip-kernel-provider): tag implementation-shortcut SDPA declines N…
ThruptiRajLakshmanaGowda Nov 1, 2026
49110d4
test(hip-kernel-provider): add a negative test for an out-of-range bl…
ThruptiRajLakshmanaGowda Nov 1, 2026
7ed4376
Merge remote-tracking branch 'origin/develop' into users/tlakshma/hac…
ThruptiRajLakshmanaGowda Nov 3, 2026
fd616b5
fix(hip-kernel-provider): follow hipDNN's cuDNN left bound in the SDP…
ThruptiRajLakshmanaGowda Nov 3, 2026
0bcbb6c
fix(hip-kernel-provider): gate the SDPA sweep entry points on the SDP…
ThruptiRajLakshmanaGowda Nov 3, 2026
7fbbc0f
fix(hip-kernel-provider): tag the remaining SDPA feature-gap declines…
ThruptiRajLakshmanaGowda Nov 3, 2026
9c489ef
fix(hip-kernel-provider): address SDPA routing review follow-ups
ThruptiRajLakshmanaGowda Nov 4, 2026
a5d2c1e
style(hip-kernel-provider): black-format declined_table
ThruptiRajLakshmanaGowda Nov 4, 2026
9db85ce
fix(hip-kernel-provider): drop torch imports from SDPA bindings; test…
ThruptiRajLakshmanaGowda Nov 4, 2026
90e50b7
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 4, 2026
a331ffa
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 4, 2026
b7ed469
fix(hip-kernel-provider): address 11-04 checklist re-review (N8-N12)
ThruptiRajLakshmanaGowda Nov 4, 2026
9599a54
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 4, 2026
b7e244b
style(hip-kernel-provider): apply black formatting to fix pre-commit CI
ThruptiRajLakshmanaGowda Nov 4, 2026
d19c06a
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 4, 2026
b7923d9
test(hip-kernel-provider): cover dispatch.attention.__all__, SDPA seq…
ThruptiRajLakshmanaGowda Nov 4, 2026
33013ea
fix(hip-kernel-provider): refuse non-integer seq_len tensors instead …
ThruptiRajLakshmanaGowda Nov 5, 2026
6daf7e6
Merge develop (after #14929); take its 4-warp bounds clamps, keep no-…
ThruptiRajLakshmanaGowda Nov 5, 2026
706e236
Merge develop (after #15024); take its runtime-head signatures, keep …
ThruptiRajLakshmanaGowda Nov 5, 2026
6a5761c
test(hip-kernel-provider): pin dispatch.attention.__all__ to its publ…
ThruptiRajLakshmanaGowda Nov 5, 2026
8ad171d
fix(hip-kernel-provider): refuse SDPA ragged offsets not of the reque…
ThruptiRajLakshmanaGowda Nov 5, 2026
7ad42fa
test(hip-kernel-provider): push a float32 seq_len_q through sdpa_unif…
ThruptiRajLakshmanaGowda Nov 5, 2026
0d91630
fix(hip-kernel-provider): align SDPA in-place Q/O, decline bad scale,…
ThruptiRajLakshmanaGowda Nov 6, 2026
53ef210
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 6, 2026
cf2b94a
fix(hip-kernel-provider): SDPA bindings honor the named current strea…
ThruptiRajLakshmanaGowda Nov 6, 2026
2127aff
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 9, 2026
ec9cf00
fix(hip-kernel-provider): unified SDPA views full-length K/V as the p…
ThruptiRajLakshmanaGowda Nov 9, 2026
e5e4cc9
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
cgmillette Nov 9, 2026
bd2e228
Merge branch 'users/tlakshma/hack/sdpa/st2-unified' (cgmillette's dev…
ThruptiRajLakshmanaGowda Nov 10, 2026
e6e4f64
Merge branch 'develop' into users/tlakshma/hack/sdpa/st2-unified
ThruptiRajLakshmanaGowda Nov 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion dnn-providers/hip-kernel-provider/rocke/KERNEL_AUTHORING.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ down to [platform/](platform/). It distills the conventions already encoded in
| Kernel emitters | [library/kernels/common/](library/kernels/common/), [library/kernels/gfx950/](library/kernels/gfx950/) | Build the typed SSA `KernelDef` (e.g. [attention_unified.py](library/kernels/common/attention_unified.py), [attention_tiled_2d.py](library/kernels/gfx950/attention_tiled_2d.py), [attention_tiled_3d.py](library/kernels/gfx950/attention_tiled_3d.py)) |
| Spec seam | [library/builders/common/attention_spec_builder.py](library/builders/common/attention_spec_builder.py) | Maps `UnifiedAttentionProblem` → arch tiled-spec; owns every knob decision |
| Dispatch | [library/dispatch/attention/](library/dispatch/attention/) | `ATTENTION_REGISTRY` + `dispatch_attention`; selects `(path, head_size, block_size)` |
| Routed families | [library/dispatch/sdpa/](library/dispatch/sdpa/) | hipDNN SDPA request contract; routes to `dispatch.attention`'s unified/dense candidates via a gate per family ([H](#h-route-a-family-over-dispatchattention)) — registers no kernel of its own |
| Builders / harnesses | [library/builders/gfx950/attention/](library/builders/gfx950/attention/) | Parity + benchmark drivers, captured shape JSONs, case studies |
| Benchmarks | [library/benchmarks/](library/benchmarks/) | Standalone perf sweeps (e.g. [benchmark_rocke_unified_attention.py](library/benchmarks/common/benchmark_rocke_unified_attention.py)) |
| Parity emitters | [library/tests/parity/](library/tests/parity/) | `.py`/`.c` emitter pairs, byte-compared |
Expand Down Expand Up @@ -350,7 +351,11 @@ scoped to library.
([sweep coverage](#a-new-kernel-family)). If it introduces a new
selection axis, extend `select_path` / `supports_native_unified_attention`
(keep the decision a **pure** function of the problem so it mirrors on the C
side).
side). Registering it here is not enough by itself for a family routed over
`dispatch.attention` (SDPA) to reach it: the routed family's gate names
which algorithms it routes among, so the new candidate stays unreachable
through that family until it is added there too
([H](#h-route-a-family-over-dispatchattention)).
5. **Add the parity pair.** Create `tests/parity/<family>_emit.py` (Python
reference, driven by `run_emit` from
[platform/tests/instances/parity/_emit_common.py](platform/tests/instances/parity/_emit_common.py))
Expand Down Expand Up @@ -583,6 +588,68 @@ paged addressing primitive (`global_ptr_add` / `offset_i64*`) — several of the
already live in platform; new ones that recur across families follow the same
path.

### H. Route a family over `dispatch.attention`

A family that has no kernel of its own but serves its requests by translating
them into `AttentionRequest` and asking `ATTENTION_ROUTE_REGISTRY` — SDPA
(`library/dispatch/sdpa/`) is the worked example — follows [E](#e-new-operator-with-a-hipdnn-graph-node)
and [F](#f-new-operand-or-output-on-an-existing-operator) for its own request
contract, plus this binding-layer checklist for the gate that sits in front of
`dispatch.attention`:

- [ ] **One `bind_<family>.py` per attention launch family** (e.g.
`bind_unified.py`, `bind_dense.py`), each exposing `<family>_admits`,
`<family>_candidates` and `<family>_bind` behind one shared reject
function, so admission and candidate enumeration cannot drift apart.
Translation only: the module adds no shape/dtype/head-size rule of its
own — "can it run" stays the attention candidates' own `admits()`. Dense
(opt-in) candidates are each probed with their own `algorithm` / `spec_id`
pinned (`opt_in_probe`), since they do not serve by default.
- [ ] **Every feature classified once per family**, either carried
(`SDPA_<FAMILY>_FEATURES`) or declined with a reason; a shortcut decline
(a feature no candidate implements yet, as opposed to an ABI limit) is
tagged `NOT_YET_IMPLEMENTED:`. A test asserts carried ∪ declined covers
every feature, so a newly added request field cannot silently fall
through both sets.
- [ ] **Check what the kernel computes, not just that it admits.** A candidate
that accepts the translated request may still build a different band
(e.g. bottom-right causal when top-left was asked) or the wrong scale
range; the gate must compare what gets computed against what was asked,
not only call `admits()`.
- [ ] **Decline a pinned dispatch choice** (`algorithm`, `spec_id`, `tuning_id`,
`tuning_knobs`) rather than forwarding it — the family's launch takes
only the automatic route, so a pin would be silently ignored.
- [ ] **The never-overclaim test**: nothing is admitted and then dropped. For
every admitted request, a kernel is actually reachable with it.
- [ ] **Four test layers**: wiring (one decline case per declined feature, the
value checks, the band comparison), a case-table test (every entry in
the family's shared case table gets a verdict), a CPU binding test (the
kernel replaced with the reference oracle, every layout/length mode), and
a GPU numeric test (binds every admitted case, compares against the
reference), enrolled in the GPU test lane.
- [F](#f-new-operand-or-output-on-an-existing-operator) **for a routed
family**: move the feature from the gate's decline table into
`SDPA_<FAMILY>_FEATURES`, and bind the request field in both the
`SdpaRequest` → `AttentionRequest` translation (`to_attention_request`) and
the launch plan that copies tensors through.
- **[A](#a-new-kernel-family) step 4, for a routed family**: registering a new
candidate in `ATTENTION_ROUTE_REGISTRY` is not enough by itself — a routed
family's gate names which algorithms it routes among (e.g.
`bind_unified.py`'s `_UNIFIED_ALGORITHMS`, built from the exported
`dispatch.attention.UNIFIED_ALGORITHMS`; `bind_dense.py`'s
`_DENSE_ALGORITHMS`, built from `dispatch.attention.DENSE_ALGORITHMS`), so a
new route candidate stays unreachable through the family until it is added
there too.

Known gaps in the current SDPA routing (tracked as "Not in this PR" on the
introducing change, not silently): choosing between the unified and dense
families for one request is not modeled — a request both admit goes to
whichever the caller picks; `sdpa_dense_bind` always launches the first
serving dense candidate in registry order, not the fastest; and the unified
binding always copies K and V into the paged cache rather than viewing them in
place when the layout and block size would allow it (Q already has the
in-place path).

### Attention specifics — quick reference

- **Parity families:** the 34 matched `library/tests/parity/*_emit.{py,c}` pairs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
attention_dispatch_result,
iter_dispatch_attention_all,
)
from dispatch.attention.common import _problem
from dispatch.attention.common import attention_problem
from rocke.dispatch.core import spec_identity
from rocke.dispatch.tuning.walk import sample_count, sweep_level
from benchmarks.common.attention_flops import attention_flops
Expand Down Expand Up @@ -206,7 +206,7 @@ def _unified_tensors(req, seed: int):
"cu_seqlens_q": cu,
"seqused_k": used,
"block_table": table,
"problem": _problem(req),
"problem": attention_problem(req),
"_dense_q": q_dense,
"_dense_k": k_dense,
"_dense_v": v_dense,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# exercise it; leave the variable unset to see the production default.

from dispatch.attention import AttentionRequest, registered_attention_combos
from dispatch.attention.common import _problem
from dispatch.attention.common import attention_problem
from kernels.common.attention_unified import (
_enable_3d_graph_replay,
_num_segments,
Expand Down Expand Up @@ -50,7 +50,7 @@ def dump_shape(label, req):
print(
f" spec.kernel_name={spec.kernel_name() if hasattr(spec, 'kernel_name') else spec}"
)
p = _problem(req)
p = attention_problem(req)
n2d = p.total_num_q_blocks_upper_bound * p.num_kv_heads
want_2d = use_2d_kernel(
head_size=p.head_size,
Expand Down Expand Up @@ -90,7 +90,7 @@ def probe_graph():
from rocke.runtime import no_fence, time_launches

req = _req()
p = _problem(req)
p = attention_problem(req)
dt = torch.bfloat16
B, Hq, Hkv, D, Sk, page = 1, 32, 8, 128, 1024, 16
q = torch.randn(B, Hq, D, dtype=dt, device="cuda")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@
)
from .candidate import (
DENSE_ALGORITHM,
DENSE_ALGORITHMS,
DENSE_GRID_ALGORITHM,
DENSE_PERSIST_ALGORITHM,
)
from .generic import D256_DECODE_ALGORITHM, UNIFIED_2D_ALGORITHM, UNIFIED_3D_ALGORITHM
from .gfx942_unified import GFX942_DENSE_PIPE_ALGORITHM
from .gfx950_unified import D256_GFX950_ALGORITHM
from .common import (
ATTENTION_ABI_VERSION,
ATTENTION_DIM_VOCABULARY,
Expand All @@ -63,11 +67,29 @@
AttentionTuningSpec,
FAMILY,
_device_num_cus,
_problem,
_request_errors,
_resolve_num_cus,
_selector_matches,
attention_band,
attention_problem,
canonical_arch,
dense_scale_range,
)

# Every algorithm that routes through the unified launch path
# (``run_unified_attention_torch``, no tuning spec): the two generic tiled
# paths, the two per-arch fast cohorts, and D256 decode. A routed family's
# gate (e.g. SDPA's ``bind_unified.py``) builds its own "which algorithms do
# I serve" set from this one, so a new unified route candidate cannot go
# unnoticed by only renaming a literal nobody re-checks.
UNIFIED_ALGORITHMS = frozenset(
{
UNIFIED_2D_ALGORITHM,
UNIFIED_3D_ALGORITHM,
D256_DECODE_ALGORITHM,
D256_GFX950_ALGORITHM,
GFX942_DENSE_PIPE_ALGORITHM,
}
)

_FAMILY = FAMILY
Expand Down Expand Up @@ -539,9 +561,16 @@ def dispatch_for_arches(

Comment thread
ThruptiRajLakshmanaGowda marked this conversation as resolved.
Resolved

__all__ = [
"D256_DECODE_ALGORITHM",
"D256_GFX950_ALGORITHM",
"DENSE_ALGORITHM",
"DENSE_ALGORITHMS",
"DENSE_GRID_ALGORITHM",
"DENSE_PERSIST_ALGORITHM",
"GFX942_DENSE_PIPE_ALGORITHM",
"UNIFIED_2D_ALGORITHM",
"UNIFIED_3D_ALGORITHM",
"UNIFIED_ALGORITHMS",
"ATTENTION_ABI_VERSION",
"ATTENTION_DIM_VOCABULARY",
"ATTENTION_EXECUTION_REGISTRY",
Expand All @@ -554,11 +583,14 @@ def dispatch_for_arches(
"AttentionRequest",
"AttentionSpec",
"AttentionTuningSpec",
"attention_band",
"attention_candidates",
"attention_execution_candidates",
"attention_dispatch_result",
"attention_problem",
"attention_sweep_space",
"attention_tuning_spec",
"dense_scale_range",
"dispatch_attention",
"dispatch_for_arches",
"dispatch_attention_all",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
DENSE_ALGORITHM = "attention_dense"
DENSE_GRID_ALGORITHM = "attention_dense_grid"
DENSE_PERSIST_ALGORITHM = "attention_dense_persist"
# Every algorithm that routes through the dense launch path (SDPA's dense
# gate, ``dispatch.sdpa.bind_dense``, builds its own "which algorithms do I
# serve" set from this one; so does the attention route-coverage test), so a
# new dense candidate cannot go unnoticed by only adding a literal nobody
# re-checks.
DENSE_ALGORITHMS = frozenset(
{DENSE_ALGORITHM, DENSE_GRID_ALGORITHM, DENSE_PERSIST_ALGORITHM}
)


def _tuning_precheck(variant: AttentionGeometryVariant):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -755,26 +755,27 @@ def normalize_band(
return AttentionBand(left_bound, right_bound, align)


def _attention_band(req: AttentionRequest) -> Tuple[bool, int]:
"""``(causal_top_left, right_bound)`` the unified kernels compute for ``req``.
def attention_band(req: AttentionRequest) -> AttentionBand:
"""The band the unified kernels compute for ``req``.

Requests the unified family does not serve (other arches, and the explicit
``window_*`` fields, which carry their own bounds) get the default mask: the
problem is then only a geometry carrier, e.g. for the gfx1151 launch grid.
The single home for this decision -- callers outside this package (e.g. the
SDPA gates) use the same function internal callers do.
"""
explicit = req.window_left is not None or (
req.window_right is not None and int(req.window_right) >= 0
)
if not _uses_band_dispatch(req, explicit):
return False, 0
band = normalize_band(req)
return band.top_left, band.kernel_right_bound
return AttentionBand(None, 0, Alignment.BOTTOM_RIGHT)
return normalize_band(req)


def _problem_with_num_cus(
req: AttentionRequest, num_cus: int
) -> UnifiedAttentionProblem:
top_left, right_bound = _attention_band(req)
band = attention_band(req)
# total_q = batch * seqlen_q (the flattened query rows). num_seqs = batch.
return UnifiedAttentionProblem(
total_q=int(req.batch) * int(req.seqlen_q),
Expand All @@ -792,14 +793,18 @@ def _problem_with_num_cus(
fp8_fnuz=bool(req.fp8_fnuz),
num_cus=int(num_cus),
target_ctas=int(req.target_ctas),
causal_top_left=top_left,
right_bound=right_bound,
causal_top_left=band.top_left,
right_bound=band.kernel_right_bound,
emit_lse=bool(req.emit_lse),
)


def _problem(req: AttentionRequest) -> UnifiedAttentionProblem:
"""The production-routing problem, including the live-device CU policy."""
def attention_problem(req: AttentionRequest) -> UnifiedAttentionProblem:
"""The production-routing problem, including the live-device CU policy.

The single home for this decision -- callers outside this package (e.g.
the SDPA gates) use the same function internal callers do.
"""
return _problem_with_num_cus(req, _resolve_num_cus(req))


Expand Down Expand Up @@ -919,6 +924,21 @@ def _dense_kernel_module(arch: str):
return attention_dense


def dense_scale_range(arch: str) -> Tuple[float, float] | None:
"""``(low, high)`` the ``arch`` dense kernels accept for ``scale``, or
``None`` when the kernel module declares no range.

Public, so a caller outside this package (e.g. the SDPA gate) names the
range instead of reaching for a kernel module's private ``_MIN_SCALE`` /
``_MAX_SCALE`` attributes, which would silently stop being checked if
those names moved.
"""
module = _dense_kernel_module(arch)
low = getattr(module, "_MIN_SCALE", None)
high = getattr(module, "_MAX_SCALE", None)
return None if low is None or high is None else (low, high)


@dataclass(frozen=True)
class AttentionTuningSpec:
"""Concrete dispatcher-owned spec for every executable tuned candidate.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
AttentionRequest,
AttentionSpec,
FAMILY,
_problem,
attention_problem,
_request_errors,
_selector_matches,
)
Expand Down Expand Up @@ -78,6 +78,16 @@
_UNIFIED_CAPABILITY, supports_features=ATTENTION_FEATURES | {"lse"}
)

# The two generic unified-path algorithms this module registers, named so a
# caller outside this package (the SDPA gate) does not have to reconstruct
# ``f"unified_{path}"`` itself.
UNIFIED_2D_ALGORITHM = "unified_2d"
UNIFIED_3D_ALGORITHM = "unified_3d"
_UNIFIED_PATH_ALGORITHMS = {"2d": UNIFIED_2D_ALGORITHM, "3d": UNIFIED_3D_ALGORITHM}

# The D256 bf16 decode candidate's algorithm (see _make_d256_decode_candidate).
D256_DECODE_ALGORITHM = "d256_decode"


def _make_candidate(*, path: str, priority: int) -> KernelCandidate:
spec_id = f"unified_{path}"
Expand All @@ -91,7 +101,7 @@ def support(req: OperatorRequest) -> Tuple[bool, str]:
ok, why = _selector_matches(req, candidate)
if not ok:
return False, why
problem = _problem(req)
problem = attention_problem(req)
# The scalar gate is the coverage check; it refuses LSE (the scalar
# kernel writes none), so ask it about the LSE-off problem and let the
# path's own gate rule on LSE below.
Expand Down Expand Up @@ -129,7 +139,7 @@ def select(req: OperatorRequest) -> AttentionSpec:
if not ok:
raise ValueError(f"{name} does not support request: {why}")
assert isinstance(req, AttentionRequest)
problem = _problem(req)
problem = attention_problem(req)
return AttentionSpec(
path=path,
head_size=problem.head_size,
Expand All @@ -148,7 +158,7 @@ def select(req: OperatorRequest) -> AttentionSpec:
candidate = KernelCandidate(
name=name,
family=FAMILY,
algorithm=f"unified_{path}",
algorithm=_UNIFIED_PATH_ALGORITHMS[path],
spec_id=spec_id,
abi_version=ATTENTION_ABI_VERSION,
priority=priority,
Expand Down Expand Up @@ -186,7 +196,7 @@ def support(req: OperatorRequest) -> Tuple[bool, str]:
ok, why = _selector_matches(req, candidate)
if not ok:
return False, why
problem = _problem(req)
problem = attention_problem(req)
ok, why = supports_native_unified_attention(problem, arch=req.arch)
if not ok:
return False, why
Expand All @@ -203,7 +213,7 @@ def select(req: OperatorRequest) -> AttentionSpec:
if not ok:
raise ValueError(f"{name} does not support request: {why}")
assert isinstance(req, AttentionRequest)
problem = _problem(req)
problem = attention_problem(req)
return AttentionSpec(
path="3d",
head_size=problem.head_size,
Expand All @@ -220,7 +230,7 @@ def select(req: OperatorRequest) -> AttentionSpec:
candidate = KernelCandidate(
name=name,
family=FAMILY,
algorithm="d256_decode",
algorithm=D256_DECODE_ALGORITHM,
spec_id=spec_id,
abi_version=ATTENTION_ABI_VERSION,
priority=5,
Expand Down
Loading
Loading