Files
d4r/kernels/rr/rrswin_enc5_epilogues.md
woutermans 0fe3a28cb7 kernels/rr: staged-image Swin layer engine prototypes
Per-layer staged-image engine for the eleven translated denoiser Swin
layers: descriptors (verified offsets per phase), cut recipes that splice an
isolated native phase into NVIDIA's PTX, wave templates, epilogue notes and
GPU probes. The isolated phase-8 splice produces a byte-identical final
4K frame but is slower than the translated body (14.90 vs 6.59 ms) - a
correctness experiment, not a shipping improvement; docs/rr-engine.md
records the design and the next direct-converter win (B operands built
from transposed accumulators).
2026-10-12 12:47:53 +02:00

928 lines
46 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `cuda_dldn_engine_swin_enc5_kernel` — the epilogues of phases 1…61
Companion to `kernels/rr/rr_layer_spec.py enc5`. Everything below was read out of
`~/.cache/d4r-rr-corpus/0018-PREPASS_ENTRYPOINT_NAME.ptx`, entry
`cuda_dldn_engine_swin_enc5_kernel` (file lines 1018–51175).
## 0. Conventions
* **`sNNNN` is a statement index** in the linearisation `rr_layer_spec.py`
documents (statements of the entry body; a wrapped `{ … }` block and a 4-line
`mma.sync` count as one statement, numbered at their first line). **`LNNNNN`
is the physical line** of the same instruction in the corpus file, so every
claim can be checked with `sed -n 'LNNNNN,LNNNNN p' …ptx`.
* An **epilogue** is the run of statements between one phase's last `mma` and
the next phase's first `mma`; `Exx` below means *the epilogue of phase xx*.
The phase table (`rr_layer_spec.py enc5`) gives the ranges.
* `W` denotes the prepared weight image: `ld.param.u64 %rd2,
[cuda_dldn_engine_swin_enc5_kernel_param_0+40]` (s9, L1037) and
`cvta.to.global.u64 %rd3, %rd2` (s10, L1038). Every `ld.weak.global.ca.v4.u32`
reads `W + 16*laneid + imm`; the table loads (see §1.1) read
`W + ((laneid<<2)&12) + imm`. Exception: the B loads of phases 2–10, the
phase-1 B load and the phase-11 C seeds carry an extra `%tid.z*27648` term
(see §1.1's last row and §2.3).
* `%rd1` = the parameter-block base at `+80`: `mov.b64 %rd6, param_0` (s1, L1018)
then `add.s64 %rd1, %rd6, 80` (s4, L1032). So `[%rd1+n]` is `param_0+80+n`
and `[%rd1-72]` is `param_0+8`.
* `smem` denotes the module's shared array
`_ZZ33cuda_dldn_engine_swin_enc5_kernel33DldnEngineSwinEncParamsStructBaseE4smem`,
declared 16384 bytes by the cut-ABI dump.
* The C/D register layout and the weight-addressing formula are fixed (see the
settled notes): `C/D reg0 = (row g, cols 2t,2t+1)`, `reg1 = (row g+8, same
cols)`, `g = laneid>>2`, `t = laneid&3`; the A fragment's four registers are
`reg0 = row g, k = 2t + (j&1) + 16*((j>>1)&1)`, `reg1 = row g+8, same k`,
`reg2 = row g, k+8`, `reg3 = row g+8, k+8`.
* Anything I could not pin down from the PTX is in §5 under **uncharacterised**.
## 1. Shared vocabulary
### 1.1 Addresses and parameters an epilogue touches
| symbol | how it is obtained | statements |
|---|---|---|
| `W` (weight image, 431124 bytes) | `ld.param.u64 %rd2, [param_0+40]` / `cvta.to.global.u64 %rd3, %rd2` | s9 / s10 |
| `smem` | `mov.u32 %r11623, _ZZ…BaseE4smem` | s7511 (L11833), s7405 (L11639), s20122 (L50821) |
| `%rd1` = `param_0+80` | `mov.b64 %rd6, param_0` + `add.s64 %rd1, %rd6, 80` | s1 / s4 |
| extents `(ex, ey)` | `ld.param.v2.u32 {%r446, %r447}, [param_0]` | s15 (L1043) |
| block offsets `(%rs119, %rs120)` | `ld.param.v2.u16 {%rs119, %rs120}, [param_0+80]` | s5 (L1033) |
| input buffer | `ld.param.u64 %rd8, [%rd1+-72]` = `param_0+8`, then `cvta %rd4` | s22 / s23 |
| plane arena | `ld.param.u64 %rd805, [%rd1+-32]` = `param_0+48`, then `cvta %rd5` | s19817 / s19818 |
| output surface (`sust`) | `ld.param.u64 %rd874, [%rd881+32]` = `param_0+112` | s20134 (L50833) |
| texture handle | `ld.param.u64 %rd872, [%rd881+8]` = `param_0+88` | s20229 (L51030) |
| per-lane weight address | `mul.wide.u32 %rdX, %laneid, 16` + `add.s64 %rdX, %rd3, %rdX` | every load block |
| per-lane weight address, phases 1–11 | `add.s64 %rd138, %rd2, %rd136` with `%rd136 = mul.wide(%tid.z*13824, 2)` then `+ 16*laneid` | s7507–s7508, s7545–s7546 |
| per-lane *table* address | `shl.b32 %rX, %laneid, 2` → `cvt.u64.u32` → `and.b64 %rdX, %rX, 12` → `add.s64 %rdX, %rd3, %rdX` = `W + ((laneid*4) & 12)` | s15140–s15142 and 60 copies |
The last line matters: every `ld.global.v2.u16` / `ld.global.u32` table load in
an epilogue reads `W + ((laneid<<2)&12) + off`, i.e. **the four lanes with equal
`laneid&3` read the same address, so one load instruction covers one 16-byte
word of the table and 32 lanes cover a 512-byte span**. A 20-load group with
`step 16` therefore covers 320 bytes = 160 f16 = the 160 columns of an
`N=160` GEMM's C operand (one f16 per column, replicated over the 16 rows of a
tile); a 4-load group covers 64 bytes = 32 f16 = the 32 columns of an `N=32`
GEMM's C operand.
### 1.2 Constants and helpers
| register | first definition | f32/f64 literal | f16 value used |
|---|---|---|---|
| `%f476` | s8077 L14399 `mov.f32 %f476, 0f3C8CCB50` | 0.017186790704727173 | `0x2466` = 0.017181396484375 |
| `%fd383` | s8081 L14410 `mov.f64 %fd383, 0dBFE1CC0000000000` | −0.55615234375 | `0xB873` |
| `%fd385` | s8086 L14424 `mov.f64 %fd385, 0d3FE1CC0000000000` | +0.55615234375 | `0x3873` |
| `%f478` | s8092 L14442 `mov.f32 %f478, 0f3F6D6000` | 0.92724609375 | `0x3B6B` |
| `%f480` | s8097 L14456 `mov.f32 %f480, 0f3FB00000` | 1.375 | `0x3D80` |
| `%f1117` | s13641 L29561 `mov.f32 %f1117, 0f3ED306EB` | 0.4121621549129486 | `0x3698` |
| `%f1118` | s13644 L29568 `mov.f32 %f1118, 0f3DA60DD6` | 0.0810810774564743 | `0x2D30` |
| `%f1119` | s13647 L29575 `mov.f32 %f1119, 0f3F000000` | 0.5 | `0x3800` |
| `%f1120` | s13650 L29582 `mov.f32 %f1120, 0f40000000` | 2.0 | `0x4000` |
| `%fd770` | L8337 (prologue) `mov.f64 %fd770, 0d3F20000000000000` | 2⁻¹³ | `0x0800` = 0.0001220703125 |
`%f1117…%f1120` are materialised **inside E21** (s13641–s13652) and re-used by
E23 … E59, which contain no `mov.f32`/`mov.f64` of their own.
* `cvt.rn.satfinite.e4m3x2.f16x2` — the requantisation used everywhere
(`f16x2_to_e4m3x2_satfinite_bits` in `ptx/lib/zluda_ptx_impl.cpp`).
* `rcp.approx.ftz.f32`, `rsqrt.approx.ftz.f32`, `ex2.approx.ftz.f32`,
`div.approx.ftz.f32` — always wrapped as
`cvt.f32.f16 → op → cvt.rn.f16.f32` (each step rounded through f16).
* `mov.u32 %r11547, 0` (s7547, L11871) is the constant-zero C operand used by
every mma whose `C` field is `{%r11547, %r11547}`.
## 2. Phase table, geometry and weight image
### 2.1 The phase table
`rr_layer_spec.py enc5` prints 61 phases. The columns are reproduced here with
the M/N/K arithmetic of §2.2:
| # | stmt range | tool M | tool N | tool K | mma | grid | weight bytes | bias bytes | epi |
|---|---|---|---|---|---|---|---|---|---|
| 1 | s7554–s7577 | 96 | 32 | 32 | 24 | full | 320..844 | – | 7 |
| 2 | s7585–s7608 | 96 | 32 | 32 | 24 | full | 5440..5964 | – | 7 |
| 3 | s7616–s7639 | 96 | 32 | 32 | 24 | full | 1344..1868 | – | 7 |
| 4 | s7647–s7670 | 96 | 32 | 32 | 24 | full | 6464..6988 | – | 7 |
| 5 | s7678–s7701 | 96 | 32 | 32 | 24 | full | 2368..2892 | – | 7 |
| 6 | s7709–s7732 | 96 | 32 | 32 | 24 | full | 7488..8012 | – | 7 |
| 7 | s7740–s7763 | 96 | 32 | 32 | 24 | full | 3392..3916 | – | 7 |
| 8 | s7771–s7794 | 96 | 32 | 32 | 24 | full | 8512..9036 | – | 7 |
| 9 | s7802–s7825 | 96 | 32 | 32 | 24 | full | 4416..4940 | – | 7 |
| 10 | s7833–s7856 | 96 | 32 | 32 | 24 | full | 9536..10060 | – | 171 |
| 11 | s8028–s8075 | 64 | 96 | 32 | 48 | full | *(none)* | 10560..22348 | 3844 |
| 12 | s11920–s11967 | 192 | 96 | 96 | 48 | band | *(none)* | – | 274 |
| 13 | s12242–s12261 | 16 | 160 | 32 | 20 | full | 22848..27468 | – | 27 |
| 14 | s12289–s12308 | 16 | 160 | 32 | 20 | full | 50496..55116 | – | 27 |
| 15 | s12336–s12355 | 16 | 160 | 32 | 20 | full | 78144..82764 | – | 27 |
| 16 | s12383–s12402 | 16 | 160 | 32 | 20 | full | 105792..110412 | – | 27 |
| 17 | s12430–s12449 | 16 | 160 | 32 | 20 | full | 133440..138060 | – | 27 |
| 18 | s12477–s12496 | 16 | 160 | 32 | 20 | full | 161088..165708 | – | 27 |
| 19 | s12524–s12543 | 16 | 160 | 32 | 20 | full | 188736..193356 | – | 27 |
| 20 | s12571–s12590 | 16 | 160 | 32 | 20 | full | 216384..221004 | – | 1029 |
| 21 | s13620–s13639 | 80 | 160 | 160 | 20 | band | 222144..226764 | 227264..227312 | 321 |
| 22 | s13961–s13980 | 16 | 160 | 32 | 20 | full | 227328..231948 | – | 92 |
| 23 | s14073–s14092 | 80 | 160 | 160 | 20 | band | 232768..237388 | 237888..237936 | 172 |
| 24 | s14265–s14284 | 16 | 160 | 32 | 20 | full | 237952..242572 | – | 92 |
| 25 | s14377–s14396 | 80 | 160 | 160 | 20 | band | 243072..247692 | 248192..248240 | 172 |
| … | *(the 23/24 pair repeats with a fixed stride)* | | | | | | | | |
| 59 | s19545–s19564 | 80 | 160 | 160 | 20 | band | 418240..422860 | 423360..423408 | 172 |
| 60 | s19737–s19756 | 16 | 160 | 32 | 20 | full | 423424..428044 | – | 299 |
| 61 | s20056–s20065 | 80 | 80 | 160 | 10 | band | 428544..430604 | 431104..431120 | 234 |
The odd phases 25…59 follow the exact pattern of 23 (weight
`= 243072 + 10240*((n-23)/2)`, bias `= 248192 + 10240*((n-23)/2)`, 172
statements), and the even phases 26…60 follow 24 (weight
`= 237952 + 10240*((n-24)/2)`, 92 statements).
### 2.2 The M/N/K arithmetic (`M/16 · N/8 · K/32 == mma`)
Ranks hold for **53 of the 61 phases**. The eight failures are the banded
phases; in every one of them the tool's `M` (and, for P12, its `K`) is an
overcount because *18 of the 32 A/B register sets are k-slices, not distinct
row/column tiles*. The chain analysis that fixes them:
| # | mma | tool M×N×K | product | fails? | correct reading | evidence |
|---|---|---|---|---|---|---|
| 1–10 | 24 | 96×32×32 | 24 | – | 96×32×32, dense | s7554: 6 A quads × 4 B pairs × 1 k-step |
| 11 | 48 | 64×96×32 | 48 | – | 64×96×32, dense | s8028: 4 A × 12 B × 1 |
| **12** | 48 | 192×96×96 | 432 | **no** | **64×32×96** = 4 m-tiles × 4 n-tiles × 3 k-steps | 16 chains of length 3, `chains_of` at s11920–s11967 |
| 13–20 | 20 | 16×160×32 | 20 | – | 16×160×32, dense | s12242: 1 A quad × 20 B pairs |
| **21,23,…,59** | 20 | 80×160×160 | 500 | **no** | **16×32×160** = 1 m-tile × 4 n-tiles × 5 k-steps | 4 chains of length 5 (s13620–s13639): A advances one k-slice per step; B advances 512 B per step, 2 n-tiles inside each 512-byte tile |
| 22,24,…,60 | 20 | 16×160×32 | 20 | – | 16×160×32, dense | s13961: 1 A quad × 20 B pairs |
| **61** | 10 | 80×80×160 | 250 | **no** | **16×16×160** = 1 × 2 × 5 | 2 chains of length 5, s20056–s20065 |
For P12 the mma chain is
`s11920 A=%r11180 B=%r11474 → s11922 A=%r11200 B=%r11494 → s11924 A=%r11220
B=%r11514`: three *different* A quads and three *different* B pairs accumulate
into one D, so the three are k-slices (k = 0/32/64) of one 16-row tile. Chains
0…3 share the A triple and take four different B triples; chains 4…7 use a
second A triple, and so on. The grid is therefore 4 A-tiles × 4 B-tiles × 3
k-steps = 48, i.e. `(64×96)·(96×32)`, with `M=64, N=32, K=96`.
For phase 21 the chain is
`s13620 A=%r14257 B=%r14064@222144 → s13622 A=%r14277 B=%r14068@222656 →
s13624 A=%r14297 B=%r14072@223168 → s13626 A=%r14317 B=%r14076@223680 →
s13628 A=%r14337 B=%r14080@224192`. The A quads are the five k-slices of one
16-row tile (K = 5·32 = 160) and the B pairs step 512 bytes, i.e. one k-slice
each; chain 1 uses the same five A quads with the B pairs at `+8` (the second
n-tile of the same 512-byte tile), which is why a 512-byte weight tile is
shared by two chains. Four chains → N = 32.
The tool's own note on phase 12/21/61 (`grid: band`) is thus correct as a
*selection* remark but its `M`, `N`, `K` columns overcount by the k-slice
factor; the corrected shapes above are what a native replacement has to
produce.
### 2.3 Weight image extent
The prepared weight image is **431124 bytes**. The largest byte actually
loaded is `W+431120` (`ld.global.u32` at s20055, L50687), and 431120+4 = 431124;
no load reads past it. The corpus' largest `ld.weak.global.ca.v4.u32` offset is
`W+430592` (s20064, L50745) plus 12 bytes of the `v4` = 430604, inside the same
extent.
One caveat, established in §3/E1–E9: the B loads of phase 1, phases 2–10 and
the C seeds of phase 11 are issued from `W + %tid.z*27648 + 16*laneid + off`
(`%rd138 = %rd2 + mul.wide(%tid.z*13824, 2)`, s7507–s7580), so those
phase-table offsets name four interleaved `%tid.z` blocks rather than a single
contiguous run. The image is laid out as 27648-byte slots: slot `k` holds the
`%tid.z = k` group's phases-1…11 weights in its first 22848 bytes and one later
phase's weights in its tail (`%tid.z = 0` slot tail = phase 13 at 22848, `k = 1`
tail = phase 14 at 50496, `k = 2` tail = phase 15 at 78144, …). Phases 12 and
later read from the plain `W + 16*laneid + off` base (e.g. s12036 L25015
`add.s64 %rd641, %rd2, %rd640`).
### 2.4 Phases that read no weight operand
Every `B` operand of every phase resolves to the weight image **except two**:
* **phase 11** — its B registers `%r11474…%r11584` are written by `mov.b32` at
s11705… (inside E11) and carry the transposed V (see §3/E11); the phase-table
B column is `?`.
* **phase 12** — its B registers are the same `movmatrix`/pack output written in
E11; the phase-table B column is `?`.
Phase 11's *C* operand is a weight read (the 12288-byte score bias at
`W+10560…W+22348`, loaded in E10), and phase 12's C operand is the constant
`%r11547 = 0` (s7547), so neither phase reads a `B` from `W`.
## 3. The epilogues
| epilogue | range | stmts | named operation |
|---|---|---|---|
| E1–E9 | s7578–s7832 (nine 7-statement runs) | 7 each | next-B weight loads |
| E10 | s7857–s8027 | 171 | 24 B-fragment loads (phase 11's C bias) + pack phase 10's D |
| E11 | s8076–s11919 | 3844 | softmax of the 64×96 score block, V-transpose, pack |
| E12 | s11968–s12241 | 274 | pack phase 12's D → shared, 160-column table add, next B |
| E13–E19 | s12262–s12570 (seven 27-statement runs) | 27 each | shared A fetch + next-B loads |
| E20 | s12591–s13619 | 1029 | RMS norm (², sum, rsqrt, gain) + packs + next B/C |
| E21 | s13640–s13960 | 321 | clamped cubic activation + 160-column C build + pack |
| E23, E25, …, E59 | 172 statements each | 172 | clamped cubic activation + pack + next B |
| E22, E24, …, E58 | 92 statements each | 92 | pack the phase-20 output × gain → next odd phase's A + next B/C |
| E60 | s19757–s20055 | 299 | pack → plane-arena scatter → next B/C |
| E61 | s20066–s20299 | 234 | shared fade-in, softmax, texture gather, surface write |
---
### E1–E9 — s7578–s7832: next-B weight loads
Nine byte-identical 7-statement runs, each two `ld.weak.global.ca.v4.u32` at
`W + 16*laneid + {off, off+512}` = the *next* phase's B operand. The first
run:
```
s7578 L12051: mov.u32 %r5444, %laneid
s7579 L12053: mul.wide.u32 %rd140, %r5444, 16
s7580 L12054: add.s64 %rd141, %rd138, %rd140
s7581 L12055: add.s64 %rd94, %rd141, 5440
s7582 L12057: ld.weak.global.ca.v4.u32 { %r5445,%r5446,%r5447,%r5448},[%rd94]
s7583 L12059: add.s64 %rd95, %rd141, 5952
s7584 L12061: ld.weak.global.ca.v4.u32 { %r5449,%r5450,%r5451,%r5452},[%rd95]
```
The offsets, and the phase whose B they are, are:
| run | statement range | offsets | next phase (weight bytes) |
|---|---|---|---|
| E1 | s7578–s7584 | +5440, +5952 | P2 (5440..5964) |
| E2 | s7609–s7615 | +1344, +1856 | P3 (1344..1868) |
| E3 | s7640–s7646 | +6464, +6976 | P4 (6464..6988) |
| E4 | s7671–s7677 | +2368, +2880 | P5 (2368..2892) |
| E5 | s7702–s7708 | +7488, +8000 | P6 (7488..8012) |
| E6 | s7733–s7739 | +3392, +3904 | P7 (3392..3916) |
| E7 | s7764–s7770 | +8512, +9024 | P8 (8512..9036) |
| E8 | s7795–s7801 | +4416, +4928 | P9 (4416..4940) |
| E9 | s7826–s7832 | +9536, +10048 | P10 (9536..10060) |
The run base is `%rd138 = %rd2 + %rd136` (s7580), where
`%rd136 = mul.wide.u32(%r11621, 2)` and `%r11621 = %r9*13824` with
`%r9 = %tid.z` (s19 L1047, s7507 L11827, s7508 L11828). So the address these
nine runs and the prologue's phase-1 B load use is
```
W + %tid.z*27648 + 16*laneid + <offset>
```
**not** `W + 16*laneid + <offset>`: `%rd138` already carries a `%tid.z*27648`
term. (`rr_layer_spec.py`'s `track_weights` drops that term because it is the
result of a `mul.wide`, so the phase table's byte offsets for phase 1's B,
phases 2–10's B and phase 11's C bias are relative to
`W + %tid.z*27648`, whereas every other offset in the table is relative to
`W`. See §5 U7.)
---
### E10 — s7857–s8027: phase 11's C-seed loads + pack of phase 10's D
171 statements, 24 weight loads + 80 packs (histogram: `80 cvt.rn.satfinite`,
`40 mov.b32`, `25 add.s64`, `24 ld.weak.global.ca.v4.u32`).
```
s7861 L13686: ld.weak.global.ca.v4.u32 { %r7686,%r7687,%r7688,%r7689},[%rd112] // +10560
…
s7907 L13778: ld.weak.global.ca.v4.u32 { %r7778,%r7779,%r7780,%r7781},[%rd135] // +22336
s7908 L13781: cvt.rn.satfinite.e4m3x2.f16x2 %rs, %r… // first pack
```
* **24 loads** at `W + 16*laneid + 10560 + 512*i`, `i = 0…23` — the phase-11
score-bias C seeds, byte block `[10560, 22348)` = 12288 bytes = 6144 f16.
Same layout as enc0's E9: the four C registers of one mma are the four u32 of
one 16-byte lane slot, tile index `4*(n>>1) + m`, stride 512 bytes.
* **80 packs / 40 b32** at s7908–s8027, whose sources are registers written by
**phase 9 and phase 10's mma** (traced through the `mov.b32` packs: 38 packs
come from a register whose newest definition is an `mma` of P9, 2 from P10,
40 from sources the walk cannot resolve in one hop). These 40 b32 are
phase 11's A and B operands.
**Outputs:** phase 11's 4+24 operand registers plus the 24 C-seed registers
(`%r7686…%r7781`). **Memory:** 24 weight loads, nothing else.
---
### E11 — s8076–s11919: softmax of the 64×96 score block
**Phase 11** = 48 `mma` (s8028–s8075), D registers 96 f16x2 (64 rows × 96
columns, 8 rows × 8 cols per lane). The epilogue is byte-for-byte the same
algorithm as enc0's E5, with its own constants (they are *not* shared with any
other enc5 epilogue). Sub-sections, by first occurrence of each op class:
| range | stmts | what |
|---|---|---|
| s8076–s10193 | 2118 | 96 per-element groups: scale, clamp, cubic, exponent extract |
| s10194–s10277 | 84 | in-lane partial row-sum trees (`add.f16x2` ×104 back to s10194) |
| s10278–s10311 | 34 | 16 `shfl.sync.bfly` → 8 row sums (`s10281 L21268` … `s10402 L21572`) |
| s10409–s11174 | 766 | 192 `rcp.approx.ftz.f32` → 96 reciprocals (`s10411 L21594`) |
| s11178–s11654 | 477 | 192 `mul.f16` → 96 probabilities (`s11178 L22839`) |
| s11656–s11703 | 48 | `movmatrix.sync.trans.aligned.m8n8.b16` (V-transpose) `s11656 L23893` |
| s11704–s11918 | 215 | 144 packs (`s11704 L24037`) |
#### (a) per-element exponent, s8076–s10193
```
s8077 L14399: mov.f32 %f476, 0f3C8CCB50
s8080 L14407: mul.f16x2 %r8344,%r7862,%r8343
s8085 L14421: max.f16x2 %r8347,%r8344,%r8349
s8090 L14435: min.f16x2 %r8350,%r8347,%r8352
s8096 L14453: fma.rn.f16x2 %r8355,%r8350,%r8353,%r8358
s8101 L14467: fma.rn.f16x2 %r8359,%r8350,%r8355,%r8362
s8102 L14470: shl.b32 %r11745, %r8359, 5
s8103 L14471: and.b32 %r10264, %r11745, 2145419232 // 0x7FE07FE0
```
Per f16 half `x` of each of the 96 D registers:
```
m = clamp(f16(x * 0.017181396484375), -0.55615234375, +0.55615234375)
t = f16(m*(-m) + 0.92724609375)
u = f16(m*t + 1.375)
E = bits(u)[9:5] // floor(32*frac(u)) — the top five mantissa bits
F = bits(u)[4:0] // the low five mantissa bits
expval = f16 from bits (E << 10) | (F << 5) // = 2^(E-15) * (1 + F/32)
```
i.e. `((u_bits << 5) & 0x7FE07FE0)` keeps `u`'s mantissa and drops its sign and
exponent, so the mantissa lands in the exponent field. This is not `exp` and
not `exp2(x*log2e)`: the exponent is the *cubic*
`32*(0.375 + 0.92724609375*m − m³)` quantised to a 6-bit significand. The
clamp bounds are the guard: `d/dm [0.92724609375m − m³]` vanishes at
`m = √(0.92724609375/3) = 0.55615…`.
#### (b) in-lane partial sums, s10194–s10277
96 `expval` registers summed in groups with `add.f16x2` (104), giving 4 f16x2
(= 8 f16) per group, i.e. **each lane reduces its 96 values to 24 partial sums
in 12 f16x2 registers**.
#### (c) cross-lane row sums, s10278–s10311
```
s10281 L21268: shfl.sync.bfly.b32 %r…, %r…, 1, %r…, -1
s10290 L21292: add.f16 %rs2318,%rs2319,%rs2320
```
Eight times (one per row `g, g+8` of the four m-tiles): add the two f16x2
partials, butterfly over lane bits 0 and 1 (operands 1 and 2), add the two
halves with `add.f16`, then broadcast into both halves. Result: **8 row sums**,
covering all 96 columns because the four lanes with equal `laneid&7` hold
different column pairs.
**There is no row maximum anywhere in this epilogue.** `max.f16x2` (96×) and
`min.f16x2` (96×) are the clamp of (a); the only warp shuffles are the 16
`shfl.sync.bfly` above.
#### (d) reciprocal, s10409–s11174
192 `rcp.approx.ftz.f32` = 96 f16x2 reciprocals, each
`cvt.f32.f16 → rcp.approx.ftz.f32 → cvt.rn.f16.f32` on a row-sum register
(duplicated, so each row sum is inverted once per n-tile of that row):
```
s10408 L21591: mov.b32 {hl, hu}, %r10719
s10411 L21594: rcp.approx.ftz.f32 fl, fl
s10413 L21596: cvt.rn.f16.f32 hl, fl
```
#### (e) probabilities, s11178–s11654
192 `mul.f16` → 96 f16x2 results `p = expval * (1/rowsum)`; the column sums
computed in (b)/(c) cancel the constant `2⁻⁴⁷` of (a), so `p_ij ∝ 2^(32·u_ij)`
and `Σ_j p_ij = 1` up to the `rcp.approx` error.
#### (f) V-transpose, s11656–s11703
**48** `movmatrix.sync.trans.aligned.m8n8.b16` on 48 distinct phase-10 D
registers (`%r7445`, `%r7446`, `%r7455`, … each exactly once). Each
transposes one 8×8 b16 tile built from the 32 threads' `%r`, i.e. 48 × 64 =
3072 values = the whole 96×32 D tile.
#### (g) packs, s11704–s11918
144 packs in three groups:
1. s11704–s11775 — from the **movmatrix** results → **phase 12's B**
fragments (`%r11474 … %r11584`, traced: `%r11474` is written by
`mov.b32 @s11705`, `%r11584` by `@s11768`).
2. s11776–s11893 — from the **probabilities** → phase 12's A fragments.
3. s11894–s11918 — more probability packs whose destinations are not read
after s11919 (compiler spill).
**Inputs:** phase 11's 96 D f16x2, phase 10's 48 D f16x2, the three `shfl`
operands. **Outputs:** phase 12's 12 A quads / 12 B pairs and the five
constants of §1.2 (read again by E21–E59). **Memory:** none.
---
### E12 — s11968–s12241: pack phase 12's D → shared, 160-column table, next B
274 statements. Sub-sections:
```
s11968 L24876: bar.sync 0
s11974 L24885: cvt.rn.satfinite.e4m3x2.f16x2 %rs3929, %r11208
s11986 L24912: st.shared.v4.u32 [%r11876], {%r11880, %r11879, %r11878, %r11877}
s11999 L24941: st.shared.v4.u32 [%r11876+512], {…}
s12012: st.shared.v4.u32 [%r11876+1024], {…}
s12025: st.shared.v4.u32 [%r11876+1536], {…}
s12026 L25000: bar.sync 0
s12033 L25010: ld.shared.v4.u32 {%r29390, %r29391, %r29392, %r29393}, [%r29389]
s12038 L25018: ld.weak.global.ca.v4.u32 { %r11895,…},[%rd160] // +22848
… ten loads at +22848 + 512*i (i = 0…9), last s12056 L25054 (+27456)
s12062 L25063: ld.global.v2.u16 {%rs6407, %rs6408}, [%rd644+221520]
… twenty loads at +221520 + 16*i, last s12081 L25082 (+221808)
s12083 L25085: add.f16 %rs…, %rs6445, %rs… // first of 80
```
1. **32 packs** of phase 12's D (s11974–s12025) → 16 b32, stored by **4
`st.shared.v4.u32`** at `smem + %r9*512 + laneid*16` offsets
`0, 512, 1024, 1536` (`%r11876 = %r11623 + %r9<<11 + laneid*16`, s11969–
s11973). This is the A operand that E13–E19 fetch back.
2. **`bar.sync 0`**, then **one `ld.shared.v4.u32`** at `[%r29389]`
(`%r29387 = %r11623 + %r9<<9`, s12029) — a 512-byte reload of the same
staging, used as the source of the table add below.
3. **Ten weight loads** at `W + 16*laneid + 22848 + 512*i` → phase 13's 20 B
fragments.
4. **Twenty table loads** at `W + ((laneid<<2)&12) + 221520 + 16*i` (320 bytes,
160 f16 = one f16 per column) → the 160-column vector.
5. **80 `add.f16`** (s12083–s12240) `= table[column] + shared_operand` →
40 b32 = **phase 13's C seeds** (the epilogue's 96 `mov.b32` are the
pack/repack plumbing).
**Outputs:** phase 13's 20 B fragments, 40 C seeds, and the shared staging.
**Memory:** 4 shared stores, 1 shared load, 10 + 20 weight loads.
---
### E13–E19 — s12262–s12570: shared A fetch + next-B loads
Seven identical 27-statement runs. Each begins with one `ld.shared.v4.u32`
that fetches the *next* phase's single A quad from the E12 staging, at a
2048-byte stride:
| run | range | shared load | next-phase A base | B loads (phase, bytes) |
|---|---|---|---|---|
| E13 | s12262–s12288 | s12265 L25628 `[%r29396+2048]` | +2048 | P14, +50496 … |
| E14 | s12309–s12335 | s12312 `[%r29402+4096]` | +4096 | P15, +78144 … |
| E15 | s12356–s12382 | s12359 `[%r29408+6144]` | +6144 | P16, +105792 … |
| E16 | s12403–s12429 | s12406 `[%r29414+8192]` | +8192 | P17, +133440 … |
| E17 | s12450–s12476 | s12453 `[%r29420+10240]` | +10240 | P18, +161088 … |
| E18 | s12497–s12523 | s12500 `[%r29426+12288]` | +12288 | P19, +188736 … |
| E19 | s12544–s12570 | s12547 `[%r29432+14336]` | +14336 | P20, +216384 … |
Each run also contains **ten `ld.weak.global.ca.v4.u32`** at
`W + 16*laneid + base + 512*i`, `i = 0…9` — the next phase's 20 B fragments
(`s12270 L25636` is the first of E13's). The A quad itself is loaded by the
preceding phase's epilogue at `+0, +2048, …`, so the shared array holds eight
2048-byte A tiles. Nothing else happens.
---
### E20 — s12591–s13619: RMS norm before the MLP, and the odd phases' operand
1029 statements, no stores, 20 table loads, 10 weight loads, 4 bias loads,
40 packs. Op boundaries:
| range | op |
|---|---|
| s12591–s12596 | first of 240 `mul.f16` — 96 f16x2 squares of phase 20's D |
| s12753–s12817 | 42 `add.f16x2` + 4 `shfl.sync.bfly.b32` (`s12795 L27521`) → 8 row sums |
| s12804–s12940 | 82 `add.f16` |
| s12820–s12821 | `mov.f64 %fd386, 0d3F20000000000000` (L27587) + `cvt.rn.f16.f64 %rs4446, %fd386` — the `2⁻¹³` epsilon |
| s12944–s13261 | 80 `cvt.f32.f16` + 80 `rsqrt.approx.ftz.f32` (`s12946 L27961`) + 80 `cvt.rn.f16.f32` |
| s13268–s13287 | 20 `ld.global.v2.u16` at `W + ((laneid<<2)&12) + 221840 + 16*i` — the norm gain |
| s13300–s13528 | `mul.f16` ×(gain) |
| s13532–s13550 | 10 `ld.weak.global.ca.v4.u32` at `W + 16*laneid + 222144 + 512*i` → phase 21's B |
| s13556–s13559 | 4 `ld.global.u32` at `W + ((laneid<<2)&12) + 227264 + 16*i` → phase 21's C seed |
| s13560–s13618 | 40 packs |
**What it computes.** For each of the 8 rows a lane holds:
```
sumsq[row] = Σ_c x[row,c]² (f16, 4-lane butterfly)
inv = rsqrt.approx.ftz.f32(f32(f16(sumsq + 2⁻¹³))) // rounded to f16
out[row,c] = x[row,c] * inv * gain[c]
```
with **no mean subtraction and no `1/N`** (the quantity is the raw sum of
squares plus `2⁻¹³`), and `gain[c]` read per column from the 320-byte table at
`W+221840…W+222128`. The norm's bias is not added here; it arrives as a C
operand later.
The 40 packs are the crucial part: tracing each pack's source shows that
**19 packs read a register whose newest definition is a phase-20 `mma`, 1 reads
phase 20's last `mma`, and 20 read one of the 20 gain loads at
`W+221840…W+222128`**. So E20 produces **the odd phases' A operand**: the
normalised tile scaled by the gain table, packed to e4m3. This same pack
content is reproduced in E22, E24, …, E58 (§3).
**Outputs:** phase 21's B (`%r14064…`) and C (`%r14154, %r14164, %r14254,
%r14264`), phase 21's A (in E21), and the shared staging. **Memory:** 20 table
loads, 1 shared load, 10 + 4 weight loads.
---
### E21 — s13640–s13960: clamped cubic activation + 160-column C build
321 statements. This is the only epilogue that materialises the four activation
constants (s13641–s13652).
```
s13641 L29561: mov.f32 %f1117, 0f3ED306EB
s13648 L29578: cvt.rn.f16.f32 low, %f1119 // 0.5
s13650 L29582: mov.f32 %f1120, 0f40000000 // 2.0
s13653 L29590: neg.f16x2 %r14350,%r14349
s13654 L29594: max.f16x2 %r14352,%r14225,%r14350
s13655 L29598: min.f16x2 %r14355,%r14352,%r14349
s13656 L29602: abs.f16x2 %r14358,%r14355
s13657 L29606: mul.f16x2 %r14360,%r14347,%r14358
s13658 L29610: sub.f16x2 %r14363,%r14346,%r14360
s13659 L29614: mul.f16x2 %r14366,%r14355,%r14363
s13660 L29618: add.f16x2 %r14369,%r14348,%r14366
s13661 L29622: mul.f16x2 %r14372,%r14225,%r14369
```
Per element, over each of the 8 f16x2 D registers of phase 21 (its four chains,
two registers each):
```
y = clamp(x, -2, +2)
g = 0.5 + y * (0.412109375 - 0.0810546875 * |y|) // f16 throughout
out = x * g
```
`g` is a *cubic ramp*, not a sigmoid: `g(+2) = 1` ⇒ `out = x` for `x ≥ 2`;
`g(-2) = 0` ⇒ `out = 0` for `x ≤ -2`. **Reproduce the formula, not SiLU/GELU.**
Then, in this order:
| range | op |
|---|---|
| s13640–s13781 | 8 activation groups (each 4 `cvt` + 4 `mov.f32` + 10 f16x2 ops) |
| s13785–s13803 | 10 `ld.weak.global.ca.v4.u32` at `W + 16*laneid + 227328 + 512*i` → phase 22's B |
| s13809–s13828 | 20 `ld.global.v2.u16` at `W + ((laneid<<2)&12) + 232448 + 16*i` (320 bytes) |
| s13829–s13947 | 80 `add.f16` `= table[column] + residual` → 40 b32 |
| s13949–s13960 | 8 packs **of the activation outputs** → phase 22's A |
Evidence for the split:
```
s13829 L30118: add.f16 %rs5210,%rs6526,%rs5212 // table + residual
s13831 L30125: mov.b32 %r14636, {%rs5207, %rs5210} // → phase 22's C
s13949 L30478: cvt.rn.satfinite.e4m3x2.f16x2 %rs5448, %r14488 // activation output
s13960 L30504: mov.b32 %r14823, {%rs5453, %rs5454} // → phase 22's A
s13961 L30506: mma … {%r14820, %r14821, %r14822, %r14823}, {%r14579, %r14580}, {%r14636, %r14637}
```
**Outputs:** phase 22's A (8 b32), phase 22's C (40 b32), phase 22's B
(`%r14579…`), and the four constants (consumed again by E23 … E59).
---
### E23, E25, …, E59 — 172 statements each: activation + pack + next B
Twenty runs, one after each odd banded phase, byte-identical in shape
(histogram: 32 `cvt.rn.f16.f32`, 36 `mov.b32`, 8 each `neg/max/min/abs.f16x2`,
24 `mul.f16x2`, 8 `sub.f16x2`, 8 `add.f16x2`, 10 `ld.weak.global.ca.v4.u32`,
8 packs). Same clamped cubic as E21 but **no table add and no `ld.global`**:
```
s14094 L30986: cvt.rn.f16.f32 low, %f1117 // constant from E21
s14102 L31009: neg.f16x2 %r…,%r…
s14103 L31013: max.f16x2 %r…,%r…,%r… // phase 23's D
s14234 L31471: ld.weak.global.ca.v4.u32 {…},[%rd270] // +232768 … (phase 24's B)
s14253 L31510: cvt.rn.satfinite.e4m3x2.f16x2 %rs…, %r…
```
The 10 weight loads are at `W + 16*laneid + base + 512*i` for the next even
phase (232768 for E23, 243072 for E25, …); the 8 packs are the activation
outputs and become the next even phase's A. No `mov.f32`, no `ld.global`,
no shared access.
---
### E22, E24, …, E58 — 92 statements each: the shared odd-phase operand
Twenty runs (histogram: 40 `cvt.rn.satfinite`, 20 `mov.b32`, 12 `add.s64`,
10 `ld.weak.global.ca.v4.u32`, 4 `ld.global.u32`). Example:
```
s13985 L30652: ld.weak.global.ca.v4.u32 { %r14579,…},[%rd260] // +227328 … (phase 23's B)
s14009 L30697: ld.global.u32 %r14919, [%rd676+237888] // phase 23's C, 4 words
…
s14013 L30702: cvt.rn.satfinite.e4m3x2.f16x2 %rs…, %r…
```
Tracing the pack sources of every one of these runs gives the *same* answer as
E20's pack group: **19 packs read a phase-20 `mma` register, 1 reads phase 20's
last `mma`, and 20 read one of the gain loads at `W+221840…W+222128`**. So
E22 … E58 do **not** consume their own phase's D: they re-emit the shared
odd-phase A operand (phase 20's normalised-and-gained output) for the next odd
phase, plus that odd phase's B and C. This is why every odd phase 21…59 uses
the same A operand (cf. the `a_source` column of `rr_layer_spec.py`).
The four `ld.global.u32` are at `W + ((laneid<<2)&12) + {227264, 237888,
248192, …} + {0,16,32,48}` — a 64-byte, 32-column C seed for the next odd phase.
---
### E60 — s19757–s20055: pack → plane-arena scatter → next B/C
299 statements. Three sub-sections.
#### (a) requantise, s19757–s19816
40 `cvt.rn.satfinite.e4m3x2.f16x2` + 20 `mov.b32` → `%r370 … %r389` (phase 60's
64×32 output as 20 b32 = 40 e4m3 values per lane).
#### (b) plane-arena scatter, s19817–s20031
```
s19817 L50393: ld.param.u64 %rd805, [%rd1+-32] // param_0+48
s19818 L50394: cvta.to.global.u64 %rd5, %rd805
s19820 L50398: shr.u32 %r390, %r29384, 2 // g = laneid>>2
s19821 L50399: and.b32 %r391, %r29384, 3 // t = laneid&3
s19822 L50400: shr.u32 %r29468, %r29384, 5 // laneid>>5
s19823 L50401: and.b32 %r29469, %r390, 7
s19824 L50402: add.s32 %r29470, %r369, %r29468 // y = %r369 + (laneid>>5)
s19830 L50408: add.s32 %r29471, %r1, %r29469 // x = %r1 + (g&7)
s19836 L50414: mad.lo.s32 %r392, %r7, %r29470, r29472 // %r7 = 8*ex
s19841 L50420: mul.wide.s32 %rd806, %r393, 4
s19843 L50422: st.global.u32 [%rd807], %r370
```
**Twenty guarded stores** `st.global.u32 [%rd5 + 4*idx]`, in statement order
`idx = <base> + d` with `d = %r391 = t = laneid&3` for the first of a pair and
`d = %r394 = t|4` for the second:
| # | statement | value | base |
|---|---|---|---|
| 1 | s19843 L50422 | `%r370` | `%r392` |
| 2 | s19852 L50433 | `%r371` | `%r392` |
| 3 | s19885 L50468 | `%r372` | `%r396` |
| 4 | s19893 L50478 | `%r373` | `%r396` |
| 5 | s19902 L50489 | `%r374` | `%r399 = %r392 + %r8` |
| 6 | s19910 L50499 | `%r375` | `%r399` |
| 7 | s19919 L50510 | `%r376` | `%r402 = %r396 + %r8` |
| 8 | s19927 L50520 | `%r377` | `%r402` |
| 9 | s19936 L50531 | `%r378` | `%r405 = %r399 + %r8` |
| 10 | s19944 L50541 | `%r379` | `%r405` |
| 11 | s19953 L50552 | `%r380` | `%r408 = %r402 + %r8` |
| 12 | s19961 L50562 | `%r381` | `%r408` |
| 13 | s19970 L50573 | `%r382` | `%r411 = %r405 + %r8` |
| 14 | s19978 L50583 | `%r383` | `%r411` |
| 15 | s19987 L50594 | `%r384` | `%r414 = %r408 + %r8` |
| 16 | s19995 L50604 | `%r385` | `%r414` |
| 17 | s20004 L50615 | `%r386` | `%r417 = %r411 + %r8` |
| 18 | s20012 L50625 | `%r387` | `%r417` |
| 19 | s20021 L50636 | `%r388` | `%r420 = %r414 + %r8` |
| 20 | s20029 L50646 | `%r389` | `%r420` |
The two principal bases are built once:
```
s19823 L50401: and.b32 %r29469, %r390, 7 // g&7
s19824 L50402: add.s32 %r29470, %r369, %r29468 // y = %r369 + (laneid>>5)
s19830 L50408: add.s32 %r29471, %r1, %r29469 // x = %r1 + (g&7)
s19835 L50413: shl.b32 %r29472, %r29471, 3 // 8*x
s19836 L50414: mad.lo.s32 %r392, %r7, %r29470, %r29472 // = 8*ex*y + 8*x
s19862 L50444: shl.b32 %r29772, %r446, 3 // 8*ex
s19864 L50446: shr.u32 %r29476, %r29475, 3 // (g+8)>>3
s19865 L50447: and.b32 %r29477, %r29475, 7 // (g+8)&7
s19866 L50448: add.s32 %r29478, %r29774, %r29476
s19878 L50460: mad.lo.s32 %r396, %r29772, %r29478, %r29480
```
with `g = laneid>>2`, `t = laneid&3`, `%r7 = %r446<<3 = 8*ex` (s17 L1045),
`%r8 = %r447 * %r7 = ey*8*ex` (s18 L1046, the **plane stride**),
`%r369 = %r3 + (tid.z<<1)` (s12592 L26961), `%r1`/`%r3` the block origins
(s7 L1035, s14 L1042), and every store guarded by
`p1/p2 = (y<0) | (y≥ey) | (laneid>15) | (x<0) | (x≥ex)` (s19825–s19834,
s19867–s19877): a guard failure stores `-1` as the index and the following
`setp.lt.s32 …, -1` + `bra` skips the store. Consecutive pairs therefore walk
**one plane per two stores**, i.e. the arena is a stack of `8*ex*ey`-u32
planes.
#### (c) next B/C, s20032–s20055
```
s20032 L50650: ld.param.u64 %rd878, [param_0+40]
s20033 L50651: ld.param.u64 %rd877, [param_0+40]
s20040 L50661: ld.weak.global.ca.v4.u32 { %r29500,…},[%rd846] // +428544, phase 61's B
… five loads at +428544 + 512*i (last s20048 L50677, +430592)
s20054 L50686: ld.global.u32 %r29530, [%rd855+431104] // phase 61's C seed
s20055 L50687: ld.global.u32 %r29540, [%rd855+431120]
```
**Outputs:** phase 61's B (10 fragments) and C (`%r29530, %r29540`).
**Memory:** 20 plane-arena stores, 5 + 2 weight loads.
---
### E61 — s20066–s20299: the final epilogue
234 statements. It consumes the cut's four returned accumulators
(`%r29601, %r29611, %r29781, %r29782`).
#### (a) shared fade-in, s20066–s20135
```
s20066 L50758: bar.sync 0
s20078 L50772: st.shared.u32 [%r430], %r29601
s20082 L50777: st.shared.u32 [%r430+16], %r29611
s20093 L50789: st.shared.u32 [%r432], %r29602
s20095 L50792: st.shared.u32 [%r432+16], %r29612
s20100 L50798: bar.sync 0
s20129 L50828: ld.shared.u32 %r29649, [%r29759]
s20131 L50830: ld.shared.u32 %r29650, [%r29759+4]
s20132 L50831: ld.shared.u32 %r29653, [%r29759+8]
s20133 L50832: ld.shared.u32 %r29656, [%r29759+12]
s20135 L50834: ld.shared.u32 %r29670, [%r29759+16]
```
Four `st.shared.u32` write the returned accumulators (16 bytes apart) and five
`ld.shared.u32` read back a 20-byte window at
`%r29759 = smem + ((x*6 + y*48) << 2)` (s20125–s20128) — the two row groups'
values side by side.
#### (b) bounds check, s20101–s20121
`s20111–s20112` form `x = %r1 + %r433`, `y = %r3 + %r434`; `s20116` reads
`param_0+0` (`%r29646, %r29647` = `(ex, ey)`); `s20113–s20120` build
`p350 = (laneid>>5 > 1) | (x|y < 0) | (x ≥ ex) | (y ≥ ey)` and `s20121
bra $L__BB1_370` skips the rest.
#### (c) softmax over 5 shared values, s20136–s20212
```
s20138 L50838: max.f16x2 %r29648,%r29649,%r29650
s20140 L50846: max.f16x2 %r29654,%r29651,%r29656
s20142 L50851: max.f16 %rs…,%rs…,%rs…
s20145 L50860: sub.f16x2 %r29669,%r29670,%r29671
s20148 L50868: mul.ftz.f32 %f…, %f…, 0f3FB8AA3B // *log2(e)
s20149 L50869: ex2.approx.ftz.f32 %f…, %f…
s20153 L50876: add.ftz.f32 %f…, %f…, %f… // row sum
s20205 L50988: div.approx.ftz.f32 %f1141, %f1142, %f1160 // 1/rowsum
s20208 L50995: mul.f16x2 %r29672,%r29673,%r29686
… five f16x2 multiplies (s20208–s20212)
```
A real row max (`max.f16x2` ×3, `max.f16` ×2), `x − max`, `2^((x−max)·log2e)`
through `cvt.f32.f16 → mul → ex2.approx`, an f32 row sum, `div.approx.ftz.f32`
with `1.0`, and five `mul.f16x2` — a textbook f32 softmax, unlike E11's.
#### (d) texture gather, s20213–s20296
`ld.param.u64 %rd872, [%rd881+8]` = `param_0+88` (s20229 L51030) is the texture
handle; nine `tex.base.2d.v4.f16.s32` (s20231 L51033 … s20290 L51153) sample it
at integer coordinates clamped into `[1, ex−2] × [1, ey−2]` (s20213–s20228,
s20240–s20248), and each result is folded in with `fma.rn.f16x2` against the
softmax weights (s20235 L51041, …, 12 total f16x2 fma) starting from
`%r29702 = 0` (s20130 L50829).
#### (e) surface write, s20297
```
s20297 L51171: sust.b.2d.v4.b16.zero [%rd874, {%r29753,%r436}], {%rs6599,%rs6603,%rs6607,%rs6614}
```
`%rd874` = `param_0+112` (s20134 L50833). One 4-channel b16 surface write per
lane; the fourth channel is the constant `0` (`s20296 L51169: mov.u16 %rs6614,
0`). `ret` at s20299 L51175.
**Inputs:** the four returned accumulators, `param+0/+48/+88/+112`, the smem
window, `0f3FB8AA3B`, `0f3F800000`.
**Outputs:** none (the kernel returns).
## 4. Memory traffic of the whole entry
### 4.1 Global
* **Weight-image B fragments** — `ld.weak.global.ca.v4.u32` in the E1–E9 runs,
E12–E19 runs, E20–E60 runs, always `W + 16*laneid + imm`, `imm` a phase-table
byte offset. The largest is `W+430592` (E60, s20048).
* **Per-column tables** — `ld.global.v2.u16` / `ld.global.u32` at
`W + ((laneid<<2)&12) + imm`. The complete list:
| statements | offsets | loads | block | consumer |
|---|---|---|---|---|
| s6864–s6883 (prologue) | `W+0 … W+304`, step 16 | 20 × v2.u16 | 320 B | prologue normalise |
| s7861–s7907 (E10) | `W+10560 … W+22336`, step 512 | 24 × v4.u32 | 12288 B | phase 11's C (score bias) |
| s12062–s12081 (E12) | `W+221520 … W+221808`, step 16 | 20 × v2.u16 | 320 B | phase 13's C |
| s13268–s13287 (E20) | `W+221840 … W+222128`, step 16 | 20 × v2.u16 | 320 B | norm gain **and** odd-phase A |
| s13556–s13559 (E20) | `W+227264 … W+227312` | 4 × u32 | 64 B | phase 21's C |
| s13809–s13828 (E21) | `W+232448 … W+232752`, step 16 | 20 × v2.u16 | 320 B | phase 22's C |
| s14009–s14012 (E22) | `W+237888 … W+237936` | 4 × u32 | 64 B | phase 23's C |
| *(E24, E26, …, E58)* | `W + 237888 + 10240*k` | 4 × u32 | 64 B each | odd phases 25…61 at `W+431104` |
| s20054–s20055 (E60) | `W+431104, W+431120` | 2 × u32 | 8 B | phase 61's C |
* **Plane arena (param_0+48)** — read once, at s19817 L50393 (E60), and written
by E60's twenty `st.global.u32` (§3/E60). Nothing reads it back inside this
launch.
* **Input buffer (param_0+8)** — read once, at s22 L1051 (`%rd8`), converted to
`%rd4` (s23 L1052); the prologue's `ld.global.v2.u16` reads (s178 L1218 and 39
siblings, all `[%rd4 + mul.wide(%r29786, 4)]`) sample it at e4m3 pairs.
* **Texture handle (param_0+88)** — read once, at s20229 L51030 (E61).
* **Output surface (param_0+112)** — read once, at s20134 L50833 (E61), used as
the `sust.b.2d.v4.b16.zero` descriptor at s20297 L51171.
* **Extents (param_0+0)** — s15 L1043 (prologue) and s20116 L50814 (E61).
* **E61 does not read `param_0+24`, `+32`, `+48`, `+96` or `+104`.**
### 4.2 Shared
* **Prologue staging** — ten `st.shared.v4.u32` per `%tid.z` group, fed by 80
e4m3 packs of the input buffer (s7364–s7403):
* five at `%r5148 + {0,512,1024,1536,2048}` where
`%r5148 = smem + %tid.z*2560 + laneid*16` (s7404…s7422, L11638…L11674,
last s7474 L11790);
* five at `%r5173 + {10240,10752,11264,11776,12288}` where
`%r5173 = %r5146 + laneid*16 = smem + %tid.z*2560 + laneid*16`
(s7499 region, s7484 L11803 … s7504 L11823).
followed by a `bar.sync 0` (s7506 L11826). The staged A operands are read
back at s7513–s7542: thirty `ld.shared.v4.u32 [%r11624 + 512*i]`,
`i = 0…29`, with `%r11624 = smem + laneid*16` (s7510–s7512) — the read base
carries **no** `%tid.z` term, while the store base does; the correspondence
between the two is in §5 U8.
* **E12 staging** — 4 `st.shared.v4.u32` at
`smem + %tid.z*512 + laneid*16` offsets `0,512,1024,1536` (s11986 L24912 …
s12025), read back by the `ld.shared.v4.u32` of E12 (s12033) and E13–E19
(offsets 2048 … 14336).
* **E61 staging** — 4 `st.shared.u32` + 5 `ld.shared.u32` (§3/E61(a)).
Nothing else in the entry touches shared memory.
## 5. Uncharacterised
**U1. `param_0+24`, `+32`, `+96`, `+104`, `+120`, `+128` are never read.** A
grep of every `ld.param` in the entry (50 instructions, listed in §1.1) shows
exactly `param_0+0`, `+8`, `+40`, `+48`, `+80`, `+88`, `+112`; there is no read
at `+24`, `+32`, `+96`, `+104`, `+120` or `+128`. *Missing:* the parameter
struct's field names.
**U2. The identity of the tables.** The 320-byte blocks at
`W+221504`/`W+221840`/`W+232448` (and the prologue's `W+0…W+304`) are per-column
f16 vectors read with the `W + ((laneid<<2)&12)` pattern. Their role is
*computable* (§3/E12, E20, E21) but their names are not. *Missing:* the weight
image's `_prep` permutation or the model's parameter names.
**U3. Phase 11's and 12's B operands.** Both are register-resident (E11's
`movmatrix`/pack output, §3/E11), so the phase table's `?` weight/`band` columns
are correct; what the two operands *are* in model terms (V vs Vᵀ vs a
concatenation) is not determinable from the PTX alone. *Missing:* the
high-level attention formulation.
**U4. The exact residual subtracted in E21's C build.** The 80 `add.f16` at
s13829–s13947 add a per-column table to a register pair whose provenance the
one-hop walk does not resolve (`%rs5212` etc.). The *arithmetic* is
`C = table[column] + residual` (s13829 L30118, s13831 L30125), but which
register holds the residual is not established. *Missing:* a full def-use chain
through the phase-20 norm.
**U5. E22…E58's pack source.** The walk shows 20 of each run's 40 packs read
the gain loads at `W+221840…W+222128` and 20 read phase-20 `mma` registers, i.e.
the same content as E20's pack group. Whether that is a deliberate re-emission
of the shared A operand or an artefact of how the compiler scheduled one
operand across twenty uses cannot be decided from the PTX. *Missing:* the
source-level loop structure.
**U6. The plane-arena geometry in E60.** The index is
`idx = (8*ex)*y + 8*x + d` with `d ∈ [0,8)`, so one row-stride unit is
`8*ex` u32 = `32*ex` bytes, but whether the arena is the same object as
`param_0+8` (the input read in the prologue) is not established — the two
pointers are distinct fields of the parameter block. *Missing:* the harness.
**U7. The `%tid.z` weight-base term.** The B loads of phase 1, phases 2–10 and
the C seeds of phase 11 are issued from `W + %tid.z*27648 + 16*laneid + off`
(§2.3, §3/E1–E9), while every later phase uses `W + 16*laneid + off`. The
phase-table byte offsets for those eleven phases are therefore *not* absolute
image offsets. Whether the four `%tid.z` groups compute four different output
tiles of a 4×-wide GEMM, or four replicas of the same tile with different
weights, cannot be decided from the PTX: the A operands they read are
`%tid.z`-independent (shared reads at `smem + laneid*16`, §4.2), and their D
registers are physically the same registers. *Missing:* the block's launch
geometry (`%ntid.z`) and the high-level loop structure.
**U8. The prologue's staging regions.** The ten staging stores per `%tid.z`
group write `[%tid.z*2560, %tid.z*2560+2560)` and
`[%tid.z*2560+10240, %tid.z*2560+12800)`; for `%tid.z = 3` the second block
ends at 20480, which exceeds the 16384-byte declaration of the shared array
(`.shared .align 4 .b8 _ZZ…smem[16384]`, L1027). The read side uses a
`%tid.z`-independent base (`smem + laneid*16`) and spans `[0, 15360)`, so the
store and load regions do not obviously line up for every `%tid.z`. *Missing:*
the launch's `%ntid.z` and the source-level staging loop; I could not decide
whether some `%tid.z` values never reach the stores (`setp.gt.u32 %p3, %r9, 3`
at s20 L1048 only excludes `%tid.z > 3`) or whether the array is over-allocated
by the ABI.
## 6. Quick acceptance index
| requirement | where |
|---|---|
| phase table with M/N/K checked | §2.1, §2.2 |
| weight image extent | §2.3 (431124 bytes) |
| phases that read no weight operand | §2.4 (11 and 12) |
| norm (RMS, no mean, `2⁻¹³`, per-column gain) | §3/E20, s12591–s13619 |
| attention (score, softmax, V-transpose, P·V) | §3/E10, E11, E12 |
| activations (clamped cubic, not GELU) | §3/E21, E23…E59 |
| merge / patch expand | no 8-lane merge (that device appears only in enc0's E20(c)); this layer's per-pixel gather is E61's 5 shared loads + 9 texture reads (§3/E61) |
| per-launch table in the plane arena | §4.1 and §3/E60(b) |
| plane-arena writes, exact value and index | §3/E60(b) |
| final epilogue | §3/E61 |