Files
d4r/kernels/rr/rrswin_dec1_epilogues.md
T
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

51 KiB
Raw Blame History

cuda_dldn_engine_swin_dec1_kernel — the epilogues of phases 1…26

Companion to kernels/rr/rr_layer_spec.py dec1. Everything below was read out of ~/.cache/d4r-rr-corpus/0022-PREPASS_ENTRYPOINT_NAME.ptx, entry cuda_dldn_engine_swin_dec1_kernel (16304 statements, 44528 physical lines).

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. rr_layer_spec.py dec1 prints the ranges; this file names what each one computes. Because phase 1 is the first GEMM, the prologue (s1–s402) doubles as phase 1's prelude and is described here too.
  • W denotes the prepared weight image: ld.param.u64 %rd2, [cuda_dldn_engine_swin_dec1_kernel_param_0+40] (s8, L1036) and cvta.to.global.u64 %rd3, %rd2 (s9, L1037). Every ld.weak.global.ca.v4.u32 reads W + 16*laneid + imm.
  • Byte offsets are relative to W and (where noted) carry a tid.z term. Two epilogues' load chains add a per-tid.z stride that the rest of the entry does not, so the offsets in the phase table are not all on one base — §1.1 and §7/U6.
  • 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.
  • Anything I could not pin down from the PTX is in §7 under uncharacterised.

1. Shared vocabulary

1.1 Addresses and parameters an epilogue touches

symbol how it is obtained statements
param_0 mov.b64 %rd8, …_param_0 s1, L1018
W (weight image) ld.param.u64 %rd2, [param_0+40] → cvta… %rd3, %rd2 s8/s9, L1036–L1037
extents (ex, ey) ld.param.v2.u32 {%r2195, %r2196}, [param_0+0] s14, L1042
%r7 = 8·ex, %r8 = ey·8·ex shl.b32 %r7, %r2195, 3 / mul.lo.s32 %r8, %r2196, %r7 s15/s16, L1043–L1044
block origins %r1, %r2 sub.s32 %r1, %r2190, %r2191 / sub.s32 %r2, %r2194, %r2192 s7/s13, L1035/L1041
%rd1 = param_0+80 add.s64 %rd1, %rd8, 80 s4, L1032
input plane arena ld.param.u64 %rd34, [param_0+8] → cvta… %rd35, %rd34 s29/s30, L1057–L1058
texture / skip input ld.param.u64 %rd149, [%rd1+-56] = param_0+24 → cvta… %rd4, %rd149 s2215/s2216, L4641–L4642
output plane arena ld.param.u64 %rd388, [%rd8+48] → cvta… %rd5, %rd388 s15754/s15755, L38150/L38151
block-origin table ld.param.v2.u16 {%rs296, %rs297}, [param_0+80] s5, L1033
window index tid.z mov.u32 %r9, %tid.z s325, L1355
shared arena .shared .align 4 .b8 _ZZ33…dec1_kernel…E4smem[6400] L1027 (declaration; not a statement)
per-lane weight address mul.wide.u32 %rd, %laneid, 16 + add.s64 %rd, W, %rd every load block, e.g. s7214–s7215, L12685–L12686
per-lane table address shl.b32 %r, %laneid, 2 → cvt.u64.u32 → and.b64 %rd, %r, 12 → add.s64 %rd, %rd3, %rd = W + ((laneid·4)&12) e.g. s6684–s6686, L10864–L10866

The last row matters: the ld.global.v2.u16 / ld.global.u32 table loads in an epilogue read W + ((laneid<<2)&12) + off, i.e. the same 16-byte slot is read by the four lanes with equal laneid&3, and consecutive loads pick consecutive 4-byte words inside one 64-byte record — so those tables are indexed by column, not by row.

Two per-tid.z strides exist and are used by different groups:

group base statements
phase 1's B W + 12288·tid.z + 16·laneid s326–s331, L1356–L1363
phase 1's C bias W + 256·tid.z + ((laneid·4)&12) + 24576…24816 s379–s402, L1459–L1484
phases 2…5 B + phase 6's bias W + 18432·tid.z + 25216 (%rd307, s7073) s7068–s7073, L11935–L11940

%rd307 is written exactly once (s7073) and consumed only by s7092–s7095 (phase 2's B) and by the four load blocks of E2…E5 (s7122, s7153, s7184, s7215). Every other phase's loads go straight off W with absolute offsets.

1.2 Constants that survive between epilogues

register first definition f32/f64 literal value used (after the cvt to f16)
%f476 s7433 mov.f32 %f476, 0f3C8CCB50 0.017186790704727173 f16 0x2466 = 0.017181396484375
%fd383 s7437 mov.f64 %fd383, 0dBFE1CC0000000000 −0.55615234375 f16 0xB873
%fd385 s7442 mov.f64 %fd385, 0d3FE1CC0000000000 +0.55615234375 f16 0x3873
%f478 s7448 mov.f32 %f478, 0f3F6D6000 0.92724609375 f16 0x3B6B
%f480 s7453 mov.f32 %f480, 0f3FB00000 1.375 f16 0x3D80
%fd1 s6143 mov.f64 %fd1, 0d3F20000000000000 2⁻¹³ f16 0x0800 = 0.0001220703125
%f989 s12414 mov.f32 %f989, 0f3ED306EB 0.4121621549129486 f16 0x3698 = 0.412109375
%f990 s12417 mov.f32 %f990, 0f3DA60DD6 0.0810810774564743 f16 0x2D30 = 0.0810546875
%f991 s12420 mov.f32 %f991, 0f3F000000 0.5 f16 0x3800
%f992 s12423 mov.f32 %f992, 0f40000000 2.0 f16 0x4000

%f476/%fd383/%fd385/%f478/%f480 are defined inside E6 and reused by the second softmax — there is no second softmax here, so they are consumed by E6 alone. %f989…%f992 are defined inside E10 (s12414–s12425) and re-read by E12, E14, E16, E18, E20, E22, E24 (e.g. s12642 cvt.rn.f16.f32 low, %f989); E12 is the only one that materialises them; the others only cvt them.

Also live across the region (defined in the prologue, read by every warp reduction): %r5735 = 1 (s5579, L8209), %r5744 = 2 (s6061, L9582), %r5746 = -1 (s6054, L9566) — the three operands of every shfl.sync.bfly.b32 in the epilogues. (%r5746 is also reused as the membermask of the E6 shuffles.)

1.3 Two quantisation helpers

  • cvt.rn.satfinite.e4m3x2.f16x2 — the requantisation used everywhere (f16x2_to_e4m3x2_satfinite_bits in ptx/lib/zluda_ptx_impl.cpp).
  • cvt.rn.f16x2.e4m3x2 — its inverse, the unpack, used only when a shared or register tile that was stored e4m3-packed is read back (E1: 144 of them, s5590–s5676, L8241–L9556).
  • 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 (round each step through f16).

2. Summary

epilogue range stmts named operation
E1 s547–s7095 6549 patch expand into shared + per-column RMS norm + gain + restage
E2 s7120–s7126 7 next-B weight loads (P3)
E3 s7151–s7157 7 next-B weight loads (P4)
E4 s7182–s7188 7 next-B weight loads (P5)
E5 s7213–s7383 171 score-bias C-seed loads (24×512 B) + 80 packs of P2/P3's D
E6 s7432–s11274 3843 cubic-exponent softmax, V transpose, pack
E7 s11323–s11505 183 pack P7's D → shared, restage A, next-B, per-column table + residual → P8's C
E8 s11522–s11537 16 2 shared A fragments + 4 next-B loads (P9)
E9 s11554–s12396 843 RMS norm (squares, butterfly, +2⁻¹³, rsqrt, gain), packs, next B/C
E10 s12413–s12833 421 clamped-cubic activation + per-column table + residual, packs, next B
E11 s12850–s12917 68 32 packs → P12's A, next B/C
E12 s12934–s13241 308 clamped-cubic activation, packs, next B
E13 s13258–s13325 68 32 packs → P14's A, next B/C
E14 s13342–s13649 308 clamped-cubic activation, packs, next B
E15 s13666–s13733 68 32 packs → P16's A, next B/C
E16 s13750–s14057 308 clamped-cubic activation, packs, next B
E17 s14074–s14141 68 32 packs → P18's A, next B/C
E18 s14158–s14465 308 clamped-cubic activation, packs, next B
E19 s14482–s14549 68 32 packs → P20's A, next B/C
E20 s14566–s14873 308 clamped-cubic activation, packs, next B
E21 s14890–s14957 68 32 packs → P22's A, next B/C
E22 s14974–s15281 308 clamped-cubic activation, packs, next B
E23 s15298–s15365 68 32 packs → P24's A, next B/C
E24 s15382–s15689 308 clamped-cubic activation, packs, next B
E25 s15706–s15980 275 pack → 16 guarded plane-arena scatter → B/C for P26
E26 s15989–s16304 316 6 D stores → shared, row max, softmax, 9+2 texture reads, surface store

3. The epilogues

E1 — s547–s7095: patch expand, RMS norm, gain, restage

6549 statements; op histogram (top): 1102 add.s32, 523 shl.b32, 460 mov.b32, 438 $label, 414 sub.s32, 368 min.u32, 341 bra.uni, 288 mul.f16, 198 add.f16, 144 cvt.rn.satfinite.e4m3x2.f16x2, 96 cvt.rn.f16x2.e4m3x2, 96 rsqrt.approx.ftz.f32, 96 cvt.f32.f16, 96 cvt.rn.f16.f32, 54 add.f16x2, 54 st.shared.* (46 u32 + 2 v2.u16 + 6 v4.u32), 36 ld.shared.* (24 v2.u16 + 12 v4.u32), 32 ld.global.v2.u16, 12 shfl.sync.bfly.b32, 1 ld.param, 2 ld.weak….

Sub-sections (bounded by the first/last statement of each op):

range what
s547–s688 144 packs of phase 1's D → the 48 b32 %r10…%r55
s689–s1367 per-lane index arithmetic + the 48 guarded patch stores (46 st.shared.u32 s732–s1355 + 2 st.shared.v2.u16 s718/s1367); 1st bar.sync at s1369
s1413–s2214 24 ld.shared.v2.u16 read back of the packed patch
s2215–s2216 param_0+24 → %rd4: the patch-gather buffer
s2371–s5577 24 clamped ld.global.v2.u16 gathered from that buffer
s5578–s5674 96 cvt.rn.f16x2.e4m3x2 unpacks of the read-back patch
s5677–s6287 the sum-of-squares trees (198 add.f16, 54 add.f16x2)
s6143–s6144 the 2⁻¹³ round (s6143 mov.f64 %fd1, s6144 cvt.rn.f16.f64 %rs1082, %fd1)
s6293–s6670 96 rsqrt.approx.ftz.f32, each cvt.f32.f16 → rsqrt → cvt.rn.f16.f32
s6668–s6686 12 statements: gain loads W + ((laneid·4)&12) + {25088…25200} (8 ld.global.v2.u16)
s5868–s6973 the 288 mul.f16 (two groups: inv · gain then x · (inv·gain))
s6990–s7047 24 packs → the 6 st.shared.v4.u32 at s7008/7021/7034/7047/7061/7066
s7058–s7089 bar.sync (s7072) + 12 ld.shared.v4.u32 (s7077–s7089) → phase 2's A
s7068–s7095 %rd307 = W + 18432·tid.z + 25216 (s7073) and 2 ld.weak → phase 2's B

Evidence for the patch scatter (48 stores):

s718  L2859: st.shared.v2.u16 [%r2393], {%rs200, %rs201}
s732  L2875: st.shared.u32 [%r2400+1600], %r10
s771  L2916: st.shared.u32 [%r2418+1600], %r12
s783  L2932: st.shared.u32 [%r2425+3200], %r13
s797  L2948: st.shared.u32 [%r2432+4800], %r14
s7066 L11932: st.shared.v4.u32 [%r5949+4608], {%r5957, %r5956, %r5955, %r5954}

The 48 patch stores are 12 blocks of 4: base offsets {0, 1600, 3200, 4800} (12 stores each) plus two v2.u16 stores. Each block is guarded by

s708  L2848: setp.gt.u32 %p5, %r64, 9
s709  L2849: setp.gt.u32 %p6, %r62, 9
s711  L2851: @%p7 bra $L__BB1_2

and the index is (row_clamped·40 + col_clamped·8 + t)·4 bytes (s714 mad.lo.s32 %r2389, %r64, 40, %r2388, s715 or.b32 %r2390, %r57, %r2389, s716 shl.b32 %r2391, %r2390, 2), i.e. a 10×10 grid of 4-word cells × 4 sub-arrays = 6400 bytes = the whole shared allocation. (§7/U4: the guards bound row/col at 9; I did not reduce the 438-label duplication to a closed form.)

The gather from param_0+24 (s2215–s2371) uses

s2245 L4674: mad.lo.s32 %r3019, %r3009, %r7, %r3018     // clamp_row·(8·ex) + clamp_col·8
s2250 L4679: add.s32 %r19034, %r3023, %r3019            // + clamp(t, - , 7)
s2369 L4806: mul.wide.u32 %rd150, %r19034, 4
s2371 L4808: ld.global.v2.u16 {%rs346, %rs347}, [%rd151]

so the element stride of the +24 buffer is 4 bytes (one f16x2 = two channels), indexed row·(8·ex) + col·8 + clamp(t,0,7); the same buffer is read 24 times per lane, once per (row,col) of the stencil.

The norm itself:

s6143 L9797:  mov.f64 %fd1, 0d3F20000000000000        // 2^-13
s6144 L9799:  cvt.rn.f16.f64 %rs1082, %fd1
s6186 L9927:  add.f16 %rs1161,%rs1067,%rs1082         // ...+ eps
s6293 L10243: rsqrt.approx.ftz.f32 fl, fl
s6688 L10878: mul.f16 %rs1371,%rs1372,%rs2011         // inv * gain
s6832 L11313: mul.f16 %rs1659,%rs488,%rs1371          // value * (inv*gain)

There is no mean subtraction and no 1/N. The accumulated quantity is the raw sum of squares of the patch's 3 channels plus the constant 2⁻¹³, and the norm is applied per column (the gain is read at W + ((laneid<<2)&12) + off so it is constant across rows). The 12 shfl.sync.bfly.b32 sum across the four lanes of each laneid&3 group.

Inputs: phase 1's D (%r692…%r2083), W, param_0+8, param_0+24, %r1/%r2/%r7/%r8/%r2195/%r2196, %r9 (tid.z). Outputs (live past s7095): the 6 patch-expand st.shared regions, the 12 ld.shared.v4.u32 A fragments %r18458…%r18505, phase 2's B %r5960…%r5967, %rd307, the 5 constants of §1.2.

E2/E3/E4 — s7120–s7126, s7151–s7157, s7182–s7188: next-B loads

Three 7-statement blocks, each identical in shape:

s7120 L12140: mov.u32 %r6208, %laneid
s7121 L12142: mul.wide.u32 %rd309, %r6208, 16
s7122 L12143: add.s64 %rd310, %rd307, %rd309
s7123 L12144: add.s64 %rd203, %rd310, 2048
s7124 L12146: ld.weak.global.ca.v4.u32 { %r6209,…%r6212},[%rd203]     // +2560 as well
epilogue offsets added to %rd307 (W + 18432·tid.z + 25216) destination phase
E2 +2048, +2560 P3's B
E3 +1024, +1536 P4's B
E4 +3072, +3584 P5's B

Nothing else. The offsets are deliberately out of phase order: the weight sub-image is laid out P2, P4, P3, P5 (offset blocks 0, 1, 2, 3 of 1024 bytes).

E5 — s7213–s7383: score-bias C-seed loads + pack of P2/P3's D

171 statements; the only epilogue whose weight loads carry the tid.z stride.

  • 24 loads W + 18432·tid.z + 16·laneid + 25216 + 4096 + 512·i, i = 0…23, at s7217…s7263 (L12689…L12781), into %r6956…%r7051. Byte block [18432·tid.z + 29312, +41100) = 12288 bytes = 24 tiles × 512 — phase 6's C score-bias seed.
  • 80 packs / 40 b32, s7264–s7383, whose sources are registers written by phase 2's and phase 3's mma (%r6466/6467/6486/6487/… from s7096–s7126 and s7127–s7136). Two interleaved destinations — %r7498 %r7508 … and %r7244 %r7246 … — which become phase 6's B and A respectively (verified: %r7244 ← mov.b32 {%rs2061,%rs2062} at s7338 whose sources are cvt of %r6466/%r6486; %r7498 ← mov.b32 {%rs2013,%rs2014} at s7266 whose source is cvt of %r6466 at s7265).

The C-seed layout. The four C registers of one mma are the four u32 of one 16-byte lane slot, and the tile index runs 4·(n>>1) + m — the same scheme rrswin_enc0_epilogues.md §3/E9 established. Checked against phase 6's own operands: s7384 C=%r6956,%r6957, s7385 C=%r6958,%r6959, s7390 C=%r7004,%r7005, s7391 C=%r7006,%r7007 — consecutive pairs from the load block, i.e. mma (m, n) takes the slot (n>>1) of the load block.

E6 — s7432–s11274: cubic-exponent softmax, V transpose, pack

Identical in kind to cuda_dldn_engine_swin_enc0_kernel's E5 (see rrswin_enc0_epilogues.md §3/E5) and byte-for-byte the same op histogram: 1048 mov.b32, 672 cvt.rn.f16.f32, 384 cvt.rn.f16.f64, 192 each of fma.rn.f16x2 / cvt.f32.f16 / rcp.approx.ftz.f32 / mul.f16, 144 packs, 48 movmatrix, 16 shfl.sync.bfly.b32, 96 each of max/min/neg/abs.f16x2.

Sub-sections:

range stmts what
s7433–s7458 26 the 5 constants (§1.2): s7433 mov.f32 %f476, 0f3C8CCB50, s7437/s7442 the two f64 clamps, s7448/s7453 the cubic pair
s7459–s9549 2091 96 per-element groups (scale, clamp, cubic, and.b32 …,2145419232)
s9550–s9635 86 in-lane partial sums (add.f16x2)
s9636–s9765 130 16 shfl.sync.bfly → 8 row sums
s9766–s10587 822 192 rcp.approx.ftz.f32 → 96 reciprocals
s10588–s11010 423 192 mul.f16 → 96 probabilities
s11011–s11058 48 movmatrix.sync.trans.aligned.m8n8.b16 of phase 5's D
s11059–s11273 215 144 cvt.rn.satfinite.e4m3x2.f16x2 packs

Evidence:

s7459 L13474: and.b32 %r9534, %r18506, 2145419232          // 0x7FE07FE0
s9636 L20270: shfl.sync.bfly.b32 %r9778,%r9774,%r5735,%r9781,%r5746
s9766 L20596: rcp.approx.ftz.f32 fl, fl
s11011 L22895: movmatrix.sync.trans.aligned.m8n8.b16 %r10138, %r6715
s11059 L23039: cvt.rn.satfinite.e4m3x2.f16x2 %rs3462, %r10146

The transposed registers %r6715…%r6946 are exactly phase 5's D (s7189–s7212). %r10138/%r10146/… are the movmatrix results; the pack at s11059 takes %r10146, i.e. the transposed V is what becomes phase 7's B (checked: %r10744 ← mov.b32 {%rs3461,%rs3462} at s11061, and %r10744 is phase 7's first B pair; the probability packs, e.g. %r10450 ← mov.b32 {%rs3509,%rs3510} at s11133, feed phase 7's A). %r6715 is phase 5's first D and %r6946 its last, so all 48 movmatrix inputs are phase 5's D.

For the record, the per-element function (identical to enc0's E5(a), reproduced here because it is the only arithmetic in this file that is not obviously a named primitive):

m  = clamp(f16(x * 0.017181396484375), -0.55615234375, +0.55615234375)
u  = f16(1.375 + m*(0.92724609375 - m*m))
expval = f16 from bits  ((u_bits << 5) & 0x7FE07FE0)

There is no row maximum in E6 (the only max.f16x2/min.f16x2 are the 96 clamp pairs of (a)), and no bias add — the bias is phase 6's GEMM C operand.

Inputs: phase 6's 96 D f16x2, phase 5's 48 D f16x2, %r5735/%r5744/%r5746. Outputs: the 5 constants, phase 7's 12 A fragments + 12 B fragments. Memory: none (0 ld.*, 0 st.* in 3843 statements).

E7 — s11323–s11505: pack P7's D → shared, restage, next-B, table → P8's C

183 statements: 64 add.f16, 48 mov.b32, 32 packs, 8 ld.global.v2.u16, 4 st.shared.v4.u32, 4 ld.shared.v4.u32, 4 ld.weak, 6 add.s64.

s11323 L23878: bar.sync 0
s11339 L23912: st.shared.v4.u32 [%r18635], {%r18639, %r18638, %r18637, %r18636}
s11352 L23941: st.shared.v4.u32 [%r18635+512], {…}
s11365 L23970: st.shared.v4.u32 [%r18635+1024], {…}
s11378 L23999: st.shared.v4.u32 [%r18635+1536], {…}
s11379 L24000: bar.sync 0
s11384 L24007: ld.shared.v4.u32 {%r18655,…%r18658}, [%r18654]
s11385 L24008: ld.shared.v4.u32 {%r18659,…%r18662}, [%r18654+512]
s11390 L24016: ld.weak.global.ca.v4.u32 { %r10893,…%r10896},[%rd233]   // W+41600
s11402 L24037: ld.global.v2.u16 {%rs5218, %rs5219}, [%rd322+62096]
s11410 L24046: add.f16 %rs3640,%rs5233,%rs491
  • 32 packs of phase 7's D (%r10378…%r10428, the 192×96 banded P·V output) → 16 b32 → four st.shared.v4.u32 at [%r18635 + {0,512,1024,1536}]; the bar.sync pair makes them visible, then two ld.shared.v4.u32 give phase 8's A (%r18655…%r18662).
  • 4 ld.weak at W + 16·laneid + {41600, 42112, 42624, 43136} → phase 8's B.
  • 8 ld.global.v2.u16 at W + ((laneid·4)&12) + {62080…62192} — a per-column vector, 8 words per lane = 32 columns.
  • 64 add.f16 adding that vector to the f16 halves of phase 7's D which were unpacked at s6186–s6288 (%rs488/%rs491/%rs494…), producing %r10918 %r10919 %r10928 %r10929 … — phase 8's C operand (confirmed: s11506 C=%r10918,%r10919, s11507 C=%r10928,%r10929). So phase 8 computes D8 = A8·B8 + (D7 + column_table).

E8 — s11522–s11537: next-A and next-B for P9

s11525 L24450: ld.shared.v4.u32 {%r18666,…%r18669}, [%r18665+2048]
s11526 L24451: ld.shared.v4.u32 {%r18670,…%r18673}, [%r18665+2560]
s11531 L24459: ld.weak.global.ca.v4.u32 { %r11072,…%r11075},[%rd237]   // W+60032
s11537 L24471: ld.weak.global.ca.v4.u32 { %r11084,…%r11087},[%rd240]   // W+61568

Two shared A fragments (the upper half of the same staging region, offsets 2048 and 2560 relative to %r18652) and four weight fragments at W + {60032, 60544, 61056, 61568} → phase 9's A and B.

E9 — s11554–s12396: RMS norm before the second attention window

843 statements, no stores, 16 memory ops. Structure:

range stmts op
s11554–s11699 146 32 × x·x squares of phase 9's D
s11700–s11757 58 in-lane pairwise add.f16x2
s11714–s11757 44 8 shfl.sync.bfly (2 per row) → row sums
s11764–s11779 16 add.f16 of the two halves, then + 2⁻¹³ (§1.2 %fd1)
s11779–s11880 102 broadcast each row sum into 4 b32
s11883–s12128 246 64 rsqrt.approx.ftz.f32
s12129–s12136 8 gain loads W + ((laneid·4)&12) + {62208…62320}
s12137–s12232 96 mul.f16 — inv · gain
s12233–s12328 96 mul.f16 — x · (inv·gain) → 32 b32 %r17567…%r17598
s12332–s12339 8 next-B loads W + {62336, 62848, 63360, 63872} → phase 10's B
s12341–s12348 8 next-C loads W + ((laneid·4)&12) + {64384,64400,64416,64432} → phase 10's C
s12349–s12396 48 32 packs → phase 10's A (%r11574…%r11577, %r11594…, …)

Evidence:

s11557 L24589: mul.f16 %rs3832,%rs4647,%rs4647          // square of a D half
s11714 L25018: shfl.sync.bfly.b32 %r11325,%r11321,%r5735,%r11328,%r5746
s11776 L25176: cvt.rn.f16.f64 %rs4033, %fd1             // eps = 2^-13
s11883 L25588: rsqrt.approx.ftz.f32 fl, fl
s12129 L25883: ld.global.v2.u16 {%rs5234, %rs5235}, [%rd327+62224]
s12233 L26180: mul.f16 %rs4421,%rs4647,%rs4229          // D_half * (inv*gain)
s12332 L26472: add.s64 %rd241, %rd329, 62336
s12349 L26500: cvt.rn.satfinite.e4m3x2.f16x2 %rs4611, %r17568

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]
  • no mean subtraction and no 1/N — the quantity is the raw sum of squares plus the constant 2⁻¹³.
  • gain[c] is per column (the W + ((laneid<<2)&12) pattern) and constant across rows.
  • the inv register is duplicated into both halves of a b32 before use, so one row-sum serves every n-tile of that row (64 rsqrt for 16 row sums).
  • the norm's bias is not added here; it is phase 10's C, loaded at the end of this epilogue (s12345–s12348).

Outputs: %r11473 %r11477 (P10 B), %r11611 %r11621 %r11651 %r11661 (P10 C), 16 packed A registers, the 32 f16x2 normed values %r17567…%r17598 (re-packed by E11).

Shape of the attention region (E5–E9)

P2  A = patch(shared), B = W+25216+2048,  C = 0        → D2  (96×32)
P3  A = patch(shared), B = W+25216+   0,  C = 0        → D3  (96×32)
P4  A = patch(shared), B = W+25216+1024,  C = D2       → D4
P5  A = patch(shared), B = W+25216+3072,  C = D3       → D5
     E5 packs D2 ∪ D3 → P6 A and B;  E5 loads P6 C = bias@29312
P6  A = pack(D2∪D3), B = pack(D2∪D3), C = bias → scores 64×96
     E6: softmax over the 96 columns (no row max), 48 movmatrix(D5), pack
P7  A = pack(prob), B = pack(transpose(D5)), C = 0 → D7 (192×96)
     E7: pack D7 → shared;  P8 C = D7 + column table@62080;  P8 B = W+41600
P8  A = shared, B = W+41600, C = D7+table → D8
P9  A = shared+2048, B = W+60032, C = 0 → D9
     E9: RMS norm of D9 + gain, packs → P10 A

E10 — s12413–s12833: clamped-cubic activation, per-column table, residual

421 statements; this is the only epilogue that materialises %f989…%f992.

s12414 L26726: mov.f32 %f989, 0f3ED306EB
s12420 L26740: mov.f32 %f991, 0f3F000000          // 0.5
s12426 L26755: neg.f16x2 %r11687,%r11686
s12427 L26759: max.f16x2 %r11689,%r11542,%r11687
s12428 L26763: min.f16x2 %r11692,%r11689,%r11686
s12429 L26767: abs.f16x2 %r11695,%r11692
s12432 L26779: mul.f16x2 %r11703,%r11692,%r11700
s12433 L26783: add.f16x2 %r11706,%r11685,%r11703
s12434 L26787: mul.f16x2 %r11709,%r11542,%r11706

Per element, over each of the 16 f16x2 D registers of phase 10:

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:

range op
s12413–s12689 16 activation groups
s12693–s12700 next-B loads W + {64448,64960,65472,65984} → phase 11's B
s12701–s12713 ld.global.v2.u16 at W + ((laneid·4)&12) + {66496…66608}
s12714–s12809 64 add.f16 — residual add, written over the activation inputs (%rs4644/%rs4647, unpacked at s11556/… from phase 9's D)
s12810–s12833 16 packs of the activation outputs → phase 12's A

Evidence for the residual add:

s12706 L27718: ld.global.v2.u16 {%rs5250, %rs5251}, [%rd337+66512]
s12714 L27727: add.f16 %rs4645,%rs5265,%rs4647
s12716 L27734: mov.b32 %r12189, {%rs4642, %rs4645}
s12810 L28015: cvt.rn.satfinite.e4m3x2.f16x2 %rs4835, %r11825

The residual is phase 9's D, not phase 10's: %rs4644/%rs4647 are the halves of %r11088, unpacked at s11556 (mov.b32 {%rs4644, %rs4647}, %r11088) at the very start of E9, and %r11088 is written by phase 9's mma (s11538–s11553). The 32 such registers %r12189 %r12190 … %r12329 %r12330 are phase 11's C; %r12148 %r12152 … are phase 11's B.

Note the two pack streams: the activation outputs (%r11709, %r11825, …) go to phase 12's A, while the residual+table registers go to phase 11's C.

E11 — s12850–s12917: packs of the normed tile, next B/C

68 statements: 32 packs, 4 ld.weak, 4 ld.global.u32.

s12854 L28189: ld.weak.global.ca.v4.u32 { %r12342,…%r12345},[%rd249]
s12866 L28210: ld.global.u32 %r12480, [%rd342+68672]
s12870 L28216: cvt.rn.satfinite.e4m3x2.f16x2 %rs…, %r17567
  • four v4.u32 fragments at W + {66624, 67136, 67648, 68160} → phase 12's B;
  • four ld.global.u32 at W + ((laneid·4)&12) + {68672, 68688, 68704, 68720} → phase 12's C seed, each used in both halves of the C operand;
  • 32 packs of %r17567…%r17598 — the normalised tile E9 produced — so phase 12's A operand is bit-identical to phase 10's A. Phases 10 and 12 are two parallel GEMMs off the same normed tile.

E12 — s12934–s13241: clamped-cubic activation, no residual

308 statements; op mix 72 mov.b32, 64 cvt.rn.f16.f32, 48 mul.f16x2, 16 each neg/max/min/abs/sub/add.f16x2, 4 ld.weak, 16 packs. No constants of its own (it re-cvts %f989 etc. at s12642-equivalent sites) and no ld.global.

Same function as E10; 16 packs of the activation outputs (%r13046 at s13191, …) → phase 13's A, plus 4 weight loads at W + {68736, 69248, 69760, 70272} → phase 13's B. No table add and no residual, so phase 13's C is zero.

E13 — s13258–s13325: packs of the normed tile again, next B/C

68 statements, shape-identical to E11:

s13262 L29597: ld.weak.global.ca.v4.u32 { %r13210,…},[%rd257]
s13274 L29618: ld.global.u32 %r13348, [%rd349+72832]

B at W + {70784, 71296, 71808, 72320} → phase 14's B; 32 packs of %r17567…%r17598 — the normed tile for the second time; C at W + ((laneid·4)&12) + {72832, 72848, 72864, 72880} → phase 14's C.

E14/E16/E18/E20/E22/E24 — s13342–s13649, s13750–s14057, s14158–s14465, s14566–s14873, s14974–s15281, s15382–s15689: activation + packs + next B

Six shape-identical 308-statement epilogues (shape hash 4234ec4de215). Each applies the E10 activation to the D of its own phase, then 16 packs of the activation outputs → the next odd phase's A, and 4 weight loads → the next odd phase's B. Evidence (E14):

s13376 L30936: cvt.rn.f16.f32 low, %f989
s13393 L30985: mul.f16x2 %r13727,%r13634,%r13724
s13619 L30816: ld.weak.global.ca.v4.u32 { %r13885,…},[%rd261]   // W+70784
s13633 L30986: cvt.rn.satfinite.e4m3x2.f16x2 %rs…, %r13727

Offsets: E12→{68736,69248,69760,70272}, E14→{70784,71296,71808,72320}, E16→{72896,73408,73920,74432}, E18→{74944,75456,75968,76480}, E20→{77056,77568,78080,78592}, E21's targets … (from the phase table's weight column: P13=68736, P15=72896, P17=77056, P19=81216, P21=85376, P23=89536, P25=93696).

No ld.global, no table add, no residual: these six produce only A and B.

E15/E17/E19/E21/E23 — s13666–s13733, s14074–s14141, s14482–s14549, s14890–s14957, s15298–s15365: packs + next B/C

Five shape-identical 68-statement epilogues (shape hash 819f37d58cd2), the twin of E11/E13. Example (E15):

s13670 L31005: ld.weak.global.ca.v4.u32 { %r14078,…},[%rd265]
s13682 L31026: ld.global.u32 %r14216, [%rd356+76992]
s13686 L31031: cvt.rn.satfinite.e4m3x2.f16x2 %rs…, %r17567

B at W + {72896+1024…} etc. per the phase table; C at W + ((laneid·4)&12) + {76992, 77008, 77024, 77040} (E15 → phase 16's C); 32 packs of %r17567…%r17598, the normed tile — third, fourth, fifth, sixth and seventh time (E13, E15, E17, E19, E21, E23 all pack the same 32 f16x2).

Shape of the whole MLP region (E9–E25)

E9  normed tile N (32 f16x2, %r17567…%r17598, s12349 packs)
 ├─ pack → P10 A  (s12349)   P10: A=N, B=W10,  C=bias@64384   → act (E10)
 │                            pack of act → P12 A (s12870)
 │                            E10: P11 C = D9 + table@66496
 ├─ pack → P12 A  (s12870)   P12: A=N, B=W12,  C=bias@68672   → act (E12)
 │                            pack of act → P14 A (s13394)
 ├─ pack → P14 A  (s13394)   P14: A=N, B=W14,  C=bias@72832   → act (E14)
 ├─ pack → P16 A  (s13806)   P16: A=N, B=W16,  C=bias@76992   → act (E16)
 ├─ pack → P18 A  (s14218)   P18: A=N, B=W18,  C=bias@81152   → act (E18)
 ├─ pack → P20 A  (s14630)   P20: A=N, B=W20,  C=bias@85312   → act (E20)
 ├─ pack → P22 A  (s15042)   P22: A=N, B=W22,  C=bias@89472   → act (E22)
 └─ pack → P24 A  (s15454)   P24: A=N, B=W24,  C=bias@93632   → act (E24)
                              pack of act → P25 A (s15666)

The odd phases P11, P13, …, P25 take C = 0 and produce the residual pair that the following even phase's table adds.

E25 — s15706–s15980: pack → 16 guarded plane-arena stores → B/C for P26

275 statements; the only st.global in the entry (16 of them, all here).

(a) requantise, s15706–s15753. 24 groups of 2 cvt + 1 mov.b32 → 24 b32; the 16 consumed are %r489…%r504.

(b) plane-arena scatter, s15754–s15960.

s15754 L38150: ld.param.u64 %rd388, [%rd8+48]        // = param_0+48
s15755 L38151: cvta.to.global.u64 %rd5, %rd388
s15757 L38155: shr.u32 %r505, %r18449, 2             // g = laneid>>2
s15758 L38156: and.b32 %r506, %r18449, 3             // t = laneid&3
s15761 L38159: add.s32 %r18707, %r488, %r18705       // y = %r488 + (laneid>>5)
s15767 L38165: add.s32 %r18713, %r1, %r18706         // x = %r1 + (g&7)
s15772 L38170: shl.b32 %r18714, %r18713, 3           // x<<3
s15773 L38171: mad.lo.s32 %r507, %r7, %r18707, %r18714
s15775 L38173: selp.b32 %r508, -1, %r18715, %p1
s15780 L38179: st.global.u32 [%rd390], %r489

Stride register %r7 = 8·ex (s15). Every store is idx = 8·ex·y + 8·x + d, with d = t or t|4; each of the four base slices is guarded by its own predicate of the form (y<0)|(y≥ey)|(laneid>127)|(x<0)|(x≥ex) (e.g. s15762–s15771, L38160–L38169); a guard failure stores -1 as the index, which the following setp.lt.s32 %p, %idx, 0 + bra turns into "skip the store" (s15774–s15777).

Store values, bases and column offsets (g = laneid>>2, t = laneid&3, %r488 = %r2 + 4·tid.z at s11555/L24586, %r8 = ey·8·ex):

store stmt value index base d
1 s15780 %r489 idx1 t
2 s15789 %r490 idx1 t|4
3 s15815 %r491 idx2 t
4 s15823 %r492 idx2 t|4
5 s15832 %r493 idx1 + %r8 t
6 s15840 %r494 idx1 + %r8 t|4
7 s15849 %r495 idx2 + %r8 t
8 s15857 %r496 idx2 + %r8 t|4
9 s15883 %r497 idx3 t
10 s15891 %r498 idx3 t|4
11 s15917 %r499 idx4 t
12 s15925 %r500 idx4 t|4
13 s15934 %r501 idx3 + %r8 t
14 s15942 %r502 idx3 + %r8 t|4
15 s15951 %r503 idx4 + %r8 t
16 s15959 %r504 idx4 + %r8 t|4

with the four bases built as mad.lo.s32 %rBASE, 8·ex, y, 8·x:

base stmt y x
idx1 = %r507 s15773, L38171 %r488 + (laneid>>5) %r1 + (g&7)
idx2 = %r511 s15808, L38210 %r488 + ((g+8)>>3) %r1 + ((g+8)&7)
idx3 = %r520 s15876, L38290 %r488 + ((g+16)>>3) %r1 + ((g+16)&7)
idx4 = %r523 s15910, L38328 %r488 + ((g+24)>>3) %r1 + ((g+24)&7)

The g+8j slices come from add.s32 %r18717, %r18986, 8 (s15793, L38195), add.s32 %r18734, %r18988, 16 (s15861, L38275) and add.s32 %r18747, %r18990, 24 (s15895, L38313); each base carries its own guard predicate (p1…p4) of the form (y<0)|(y≥ey)|(slice>31)|(x<0)|(x≥ex).

(c) next B/C, s15961–s15980.

s15962 L38392: ld.param.u64 %rd456, [param_0+40]
s15969 L38401: add.s64 %rd424, %rd456, %rd423        // + 16*laneid
s15971 L38404: ld.weak.global.ca.v4.u32 { %r18765,…%r18768},[%rd421]   // +95744
s15973 L38408: ld.weak.global.ca.v4.u32 { %r18769,…%r18772},[%rd422]   // +96256
s15979 L38417: ld.global.u32 %r18823, [%rd428+96768]
s15980 L38418: ld.global.u32 %r18833, [%rd428+96784]

Note %rd424 is built from %rd456 (the uncvtad pointer) while %rd455 is cvtad; on this corpus both are the same address, and the offsets still read W + ….

Outputs: %r489…%r504 (re-read as P26's A, see s15981), %r18765 %r18769 (P26 B), %r18823 %r18833 (P26 C), %rd388 (param_0+48).

E26 — s15989–s16304: the final epilogue

316 statements; it consumes the six D accumulators of phase 26 (%r18794 %r18795 %r18804 %r18805 %r18834 %r18835 %r18844 %r18845 — the s15996…s15988 mma results) and writes the surface.

(a) staging, s15989–s16050. 12 guarded st.shared.u32 of the phase-26 D pairs into a shared scratch, indexed from %r540 = laneid>>2, %r541 = laneid&3 and %tid.z:

s16000 L38488: st.shared.u32 [%r542], %r18794
s16004 L38493: st.shared.u32 [%r542+16], %r18804
s16017 L38507: st.shared.u32 [%r544], %r18795
s16019 L38510: st.shared.u32 [%r544+16], %r18805

(b) coordinates and bounds check, s16051–s16084.

s16059 L38555: mov.u32 %r18897, %tid.x
s16060 L38556: add.s32 %r18898, %r19003, %r18897     // %r19003 = tid.z*32
s16065 L38561: sub.s32 %r547, %r18898, %r18902
s16067 L38563: add.s32 %r549, %r1, %r547             // x
s16068 L38564: add.s32 %r550, %r19004, %r548         // y, %r19004 = ctaid.y*8 - origin
s16073 L38569: ld.param.v2.u32 {%r18912, %r18913}, [%rd458]
s16078 L38574: @%p480 bra $L__BB1_534

Out-of-range lanes jump straight to $L__BB1_534 (s16303) and skip (c)…(g).

(c) row max over 5 shared values, s16085–s16100.

s16085 L38582: ld.shared.u32 %r18915, [%r18964]
s16087 L38584: ld.shared.u32 %r18916, [%r18964+4]
s16091 L38588: ld.shared.u32 %r18936, [%r18964+16]
s16093 L38591: max.f16x2 %r18914,%r18915,%r18916
s16097 L38604: max.f16 %rs5266,%rs5267,%rs5268
s16099 L38611: mov.b32 %r18937, {%rs5269, %rs5269}
s16100 L38613: sub.f16x2 %r18923,%r18915,%r18937

Five u32 (= 10 f16) are read per row and reduced in registers — no warp shuffle — giving the row max, which is subtracted.

(d) softmax, s16101–s16168. Textbook f32 softmax over the row's 5 values:

s16103 L38621: mul.ftz.f32 %f1033, %f993, 0f3FB8AA3B    // * log2(e)
s16104 L38622: ex2.approx.ftz.f32 %f995, %f1033
s16160 L38741: mov.f32 %f1032, 0f3F800000
s16161 L38742: div.approx.ftz.f32 %f1011, %f1032, %f1050
s16164 L38749: mul.f16x2 %r18938,%r18939,%r18952

y = 2^((x−max)·log2e), p = y · (1/Σy) in f16, five f16x2 registers (%r18938 %r18941 %r18944 %r18947 %r18950).

(e) texture gather, s16169–s16266. A 3×3 stencil of a colour texture:

s16184 L38789: cvt.rn.f32.s32 %f1051, %r18968
s16185 L38790: ld.param.v2.f32 {%f1052, %f1053}, [%rd459+136]
s16187 L38792: fma.rn.ftz.f32 %f1012, %f1052, %f1051, %f1056
s16191 L38796: ld.param.u64 %rd446, [%rd459+88]
s16193 L38799: tex.base.2d.v4.f16.f32 {%rs5294,%rs5295,%rs5296,%rs5297}, [%rd430, {%f1012,%f1013}]
s16195 L38803: fma.rn.f16 %rs5298,%rs5294,%rs5308,%rs5291

%rd459 = param_0 (s16079), so the texture handle is param_0+88, the scale/offset are param_0+136 (two f32: f1052·(k−0.5·?)) and the accumulator weights come from the softmax registers. Nine tex.base.2d.v4.f16.f32 are issued (s16193, 16205, 16217, 16229, 16234, 16240, 16252, 16258, 16263) for the 3×3 neighbourhood (clamped coordinates at s16172–s16183 compute (x−1, x, x+1) and (y−1, y, y+1)), accumulated with fma.rn.f16 into 3 channels.

(f) two integer-coordinate textures, s16267–s16270.

s16267 L38971: ld.param.u64 %rd448, [%rd459+96]
s16268 L38973: tex.base.2d.v4.f16.s32 {%rs5438,%rs5439,%rs5440,%rs5441}, [%rd448, {%r549,%r550}]
s16269 L38975: ld.param.u64 %rd450, [%rd459+104]
s16270 L38977: tex.base.2d.v4.f16.s32 {%rs5442,%rs5443,%rs5444,%rs5445}, [%rd450, {%r549,%r550}]

These are the +96 / +104 texture reads the brief asks about — handles at param_0+96 and param_0+104, sampled at the integer pixel coordinate (%r549, %r550), returning two 4-channel f16 vectors.

(g) combine, sigmoid gate, surface store, s16271–s16304.

s16271 L38980: cvt.f32.f16 %f1030, %rs5446
s16272 L38983: mul.ftz.f32 %f1063, %f1030, 0fBFB8AA3B
s16273 L38984: ex2.approx.ftz.f32 %f1064, %f1063
s16274 L38985: add.ftz.f32 %f1065, %f1064, 0f3F800000
s16275 L38986: div.approx.ftz.f32 %f1031, %f1032, %f1065     // 1/(1+2^(-log2e·v))
s16278 L38996: sub.f16 %rs5449,%rs5448,%rs5447               // 1 - sigmoid
s16279 L39000: mul.f16 %rs5452,%rs5426,%rs5447               // acc * sigmoid
s16280 L39004: fma.rn.f16 %rs5495,%rs5438,%rs5449,%rs5452    // + tex96 * (1-sig)
s16285 L39024: set.nan.f16.f16 %rs5473,%rs5442,%rs5442       // + tex104 unless NaN
s16302 L39065: sust.b.2d.v4.b16.zero [%rd453, {%r18983,%r550}], {%rs5495,%rs5496,%rs5497,%rs5494}

%rd453 = param_0+112 (s16090). The store address column is %r549·8 (s16300 shl.b32 %r18983, %r549, 3), the row %r550; the fourth channel is the zero literal 0x0000 (s16301 mov.u16 %rs5494, 0), so this is a 3-channel write into a 4-channel surface. The set.nan/bra triad (s16285–s16298) adds the +104 read only when it is not NaN.

Inputs: the 6 returned D registers, param_0+{48,88,96,104,112,136}, the shared scratch, constants 0f3FB8AA3B, 0fBFB8AA3B, 0f3F800000. Outputs: none (the kernel returns, s16304).


4. Texture reads, surface writes, and the +24 input

what where
param_0+8 — input feature plane arena, read by phase 1's A loads prologue s67…s324 (52 ld.global.u32)
param_0+24 — the patch-gather source E1 reads s2215 (ld.param.u64 %rd149, [%rd1+-56], %rd1 = param_0+80) and the 24 ld.global.v2.u16 at s2371…s5577
param_0+48 — the plane arena E25 scatters phase 25's output to s15754 / s15755, 16 st.global.u32 at s15780…s15959
param_0+88 — the colour texture handle s16191, 9 tex.base.2d.v4.f16.f32 at s16193…s16263
param_0+96 — texture handle #2 (integer coords) s16267/s16268
param_0+104 — texture handle #3 (integer coords) s16269/s16270
param_0+112 — the output surface s16090, sust.b.2d.v4.b16.zero s16302
param_0+136 — two f32 texture coordinate scales s16185

The skip input at +24 supplies the patch-gather source. E1 reads it once per lane per stencil position and never writes it; the buffer is addressed in elements of 4 bytes (one f16x2 = 2 channels) with index clamp(row)·8·ex + clamp(col)·8 + clamp(t,0,7) (s2245/s2250, L4674/L4679). It is the input the patch expand tile is built from — the same operand the window-1 patch is expanded out of.

The surface writes are param_0+112 (E26, s16302), a 4-channel b16 surface written with 3 live channels. The plane-arena writes are E25's 16 st.global.u32 to param_0+48 (s15780…s15959).

Nothing reads param_0+48 back in this entry: param_0+48 is the source of exactly one ld.param (s15754) and never the base of a load. Likewise the texture handles at +88/+96/+104 are only ever tex.* operands.

5. The phase table, M/N/K checked

rr_layer_spec.py dec1's phase table with the arithmetic M/16 · N/8 · K/32 == mma evaluated on every row (the brief's check):

# stmts M N K mma M/16·N/8·K/32 holds? weight bytes (rel. W) bias bytes
1 s403–s546 144 384 96 144 9·48·3 = 1296 no 0…11788 (+12288·tid.z) 24576…24816 (+256·tid.z)
2 s7096–s7119 96 32 32 24 6·4·1 = 24 yes 25216…25740 (+18432·tid.z) –
3 s7127–s7150 96 32 32 24 24 yes 27264…27788 (+18432·tid.z) –
4 s7158–s7181 96 32 32 24 24 yes 26240…26764 (+18432·tid.z) –
5 s7189–s7212 96 32 32 24 24 yes 28288…28812 (+18432·tid.z) –
6 s7384–s7431 64 96 32 48 4·12·1 = 48 yes none 29312…41100 (+18432·tid.z)
7 s11275–s11322 192 96 96 48 12·12·3 = 432 no none –
8 s11506–s11521 32 64 32 16 2·8·1 = 16 yes 41600…43148 –
9 s11538–s11553 32 64 32 16 16 yes 60032…61580 –
10 s12397–s12412 64 64 64 16 4·8·2 = 64 no 62336…63884 64384…64432
11 s12834–s12849 32 64 32 16 16 yes 64448…65996 –
12 s12918–s12933 64 64 64 16 64 no 66624…68172 68672…68720
13 s13242–s13257 32 64 32 16 16 yes 68736…70284 –
14 s13326–s13341 64 64 64 16 64 no 70784…72332 72832…72880
15 s13650–s13665 32 64 32 16 16 yes 72896…74444 –
16 s13734–s13749 64 64 64 16 64 no 74944…76492 76992…77040
17 s14058–s14073 32 64 32 16 16 yes 77056…78604 –
18 s14142–s14157 64 64 64 16 64 no 79104…80652 81152…81200
19 s14466–s14481 32 64 32 16 16 yes 81216…82764 –
20 s14550–s14565 64 64 64 16 64 no 83264…84812 85312…85360
21 s14874–s14889 32 64 32 16 16 yes 85376…86924 –
22 s14958–s14973 64 64 64 16 64 no 87424…88972 89472…89520
23 s15282–s15297 32 64 32 16 16 yes 89536…91084 –
24 s15366–s15381 64 64 64 16 64 no 91584…93132 93632…93680
25 s15690–s15705 32 64 32 16 16 yes 93696…95244 –
26 s15981–s15988 64 32 64 8 4·4·2 = 32 no 95744…96268 96768…96784

Every phase whose M/16·N/8·K/32 does not equal mma is one the tool also marks grid = band, and every phase that holds is marked full. The mismatching rows are not off by a constant factor (P1 is ×9, P7 ×9, P10/12/… ×4, P26 ×4), so M, N and K cannot all be taken at face value for those rows: nA counts distinct A register quads, which can be either distinct M-tiles or distinct K-slices of the same tile, and the tool cannot tell them apart. See §7/U1.

Which phases read no weight operand: P6 and P7. Both take B from registers that the preceding epilogue packed (E5 packs P2/P3's D for P6's A and B; E6 packs the probabilities and the transposed P5 for P7's A and B). Their bo is None for every mma.

Weight image extent as the tool measures it: the largest resolved offset is 96784 (s15980, 4 bytes wide) ⇒ 96788 bytes (634 distinct slots). This excludes the two tid.z-strided groups in §1.1: phase 1's B and bias are read at W + 12288·tid.z / W + 256·tid.z, and phases 2…5's B and phase 6's bias at W + 18432·tid.z + 25216. With tid.z ∈ {0,1} (E26 rejects tid.z > 1 at s16069 setp.gt.u32 %p474, %r19008, 1) the true image must reach at least 18432 + 41100 = 59532, which is inside 96788, so the two tid.z slices do not extend the image beyond what the tool already sees. (INFERENCE — the tool drops the tid.z term, so the per-window base cannot be read off it directly.)

6. The plane arena (param_0 + 48) and the per-launch tables

  • param_0+8 is read 52 times in the prologue (s67…s324) as the input feature plane that builds phase 1's 9 A fragments. The index arithmetic is (clamp_r·ey + clamp_c)·4 style (shl.b32 … 3, mad.lo.s32, mul.wide.u32 …, 4, add.s64 …, %rd35): the arena is a {ex, ey}-wide f16/byte plane read with 4-byte elements.
  • param_0+24 is the patch-gather source (see §4); it is read, never written.
  • param_0+48 is the output plane arena: written by E25's 16 st.global.u32 (s15780…s15959), never read. There is no second st.* group in the entry (the entry has exactly 16 st.global and 0 other global stores before L38179).
  • The only other ld.param sites are the 4 in the prologue (§1.1) and the 5 in E26 ([%rd459+88/96/104/112/136], s16191/16267/16269/16090/16185) plus [%rd8+48] (s15754) and the two param_0+40 re-reads (s15961/s15962).

There is no per-launch table generated into the plane arena by this kernel: the plane arena is only written (E25) and the tables that look like per-launch tables (the W + ((laneid<<2)&12) + off blocks at 25088, 62080, 66496) all live in the weight image, not the arena. See §7/U5.

7. Uncharacterised

U1. The true M/N/K of the nine banded phases (P1, P7, P10, P12, …, P24, P26). For those rows M/16·N/8·K/32 ≠ mma (§5). The reason is structural and checkable: the accumulator chains of a banded phase mix distinct B operands. For P10 the four chains are

s12397 D=%r11522 A=%r11574 B=%r11473 C=bias      (bo 62336)
s12399 D=%r11542 A=%r11594 B=%r11477 C=%r11522   (bo 62848)
s12401 D=%r11562 A=%r11574 B=%r11481 C=bias      (bo 63360)
s12403 D=%r11582 A=%r11594 B=%r11485 C=%r11562   (bo 63872)

— the same D accumulates products with B fragments from four different 512-byte blocks and two different A quads. Under the settled weight formula (n = 16·tt + 8·(b>>3) + (L>>2), verified on enc0) those four blocks span n = 0…63, so N = 64 is supported; but then the two-mma chains must be summing over M or K, and neither M nor K is separately readable from the fragment structure. For P1 the same argument gives N = 384 (48 B fragments = 24 blocks × 16 columns) while the arithmetic needs M/16 · K/32 = 3. Missing: either a run with a weight-image dump, or the _prep permutation that produces the image, or the high-level layer definition. Until then I will not assign M/K to these rows.

U2. The identity of the 12288-byte score bias (P6's C). E5 loads it as 24 tiles × 512 bytes at W + 18432·tid.z + 29312. Whether it is a relative position bias, a learned score bias, or a per-lane constant cannot be decided from the PTX: it is an opaque blob in a permuted weight image. Missing: the image's layout description (the _prep permutation) or the model's parameter names.

U3. The identity of the per-column tables. W+25088…25200 (E1 gain), W+62080…62192 (E7), W+62208…62320 (E9 gain), W+66496…66608 (E10) are all read with the same W + ((laneid<<2)&12) + off pattern and are 8 words per lane. Their role is computable (E1/E9: multiply the inverse RMS; E7/E10: added to a residual before the next GEMM) but their names are not. The GEMM biases at +24576, +64384, +68672, +72832, +76992, +81152, +85312, +89472, +93632, +96768 are the same case.

U4. E1's patch-expand geometry. The 48 st.shared of §3/E1 are guarded by row/col limits of 9 and index (row·40 + col·8 + t)·4 into four 1600-byte sub-arrays, but they are emitted as ~400 basic blocks with 438 labels and I could not reduce the lane→(row,col) map of the 10×10 patch to a closed form. What is established: the four sub-arrays, the 40-word row pitch, the t and t|4 column split, the two v2.u16 cells, and the total 6400 bytes. Missing: the source-level im2col/patchify expression, or a shared-memory dump.

U5. Whether param_0+8 is an input plane or a scratch table. The prologue reads it 52 times with 4-byte elements and never writes it, and E1 does not read it at all (E1 reads param_0+24). So +8 and +24 are two different input buffers; which one holds the noisy colour plane and which holds the feature planes cannot be decided from the PTX. Missing: the host-side launch arguments.

U6. The tid.z strides. Two different per-tid.z strides (12288 for phase 1, 18432 for phases 2…5 + phase 6's bias, 256 for phase 1's bias, 192 for phase 1's bias in the companion layout) appear, and no later phase carries one. Whether this means the weight image is a concatenation of per-window sub-images or that tid.z selects a batch element whose weights are interleaved cannot be decided from the PTX alone. Consequence: the "96788 bytes" of §5 is a lower bound for the image, not necessarily its size.

U7. The logical meaning of E26's final expression. The tail computes out = acc·σ(v) + tex96·(1−σ(v)) + tex104 on the three channels gathered from the 3×3 colour stencil and the two integer-coordinate textures. The PTX gives the arithmetic exactly (§3/E26(g)) but not what model term it corresponds to. Missing: the high-level source or a reference implementation.

U8. E12/E14/…/E24's %f989…%f992. These six epilogues re-cvt the four constants but never re-mov.f32 them, so they read the registers E10 wrote (s12414–s12425). That is only valid if the register allocator kept them live across phases 11…23; the PTX shows no redefinition, so it is consistent, but nothing in the file asserts the interference-freedom. Missing: an SSA check.

8. Quick acceptance index

requirement where
every epilogue named and ranged §2, §3 (E1…E26)
phase-1 epilogue's patch expand + norm §3/E1
the norm (E1, E9) §3/E1, §3/E9 — raw sum of squares + 2⁻¹³, no mean, no 1/N
the attention (score, softmax, P·V) §3/E5, E6, E7; §3/E9 (region diagram)
the activations §3/E10 (materialises %f989…%f992), E12, E14, E16, E18, E20, E22, E24
the patch expand §3/E1 (48 st.shared), §7/U4
the final epilogue, textures at +96/+104, surface §3/E26, §4
the texture reads at +96/+104 §3/E26(f), s16268 / s16270
the skip input at +24 §3/E1 (s2215), §4
the plane-arena writes §3/E25 (s15780…s15959), §4, §6
the phase table with M/N/K checked §5
weight image extent §5 (96788 bytes, 634 slots)
which phases read no weight §5 (P6, P7)
uncharacterised §7