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).
40 KiB
cuda_dldn_engine_swin_dec4_kernel — the epilogues of phases 1…62
Companion to kernels/rr/rr_layer_spec.py dec4. Everything below was read out of
~/.cache/d4r-rr-corpus/0019-PREPASS_ENTRYPOINT_NAME.ptx, entry
cuda_dldn_engine_swin_dec4_kernel (the entry opens at file line 1016, its body
holds statements s1…s24447, and s24447 is the ret).
dec4 is the widest of the eleven Swin layers: its attention/MLP width is 160 where dec3's is 128, so every count below is not interchangeable with dec3's. Where a region is the same code as dec3's, that is stated and the shared evidence is cited on dec4's own statements.
0. Conventions
sNNNNis a statement index in the linearisationrr_layer_spec.pydocuments;LNNNNNis the physical line of the same instruction, so every claim can be checked withsed -n 'LNNNNN,LNNNNN p' …ptx. (Example anchors: phase 1's 300mmaoccupy only L1707–L3799, and s871 = L3807.)- An epilogue is the run of statements between one phase's last
mmaand the next phase's firstmma; a phase's own weight loads live in the previous epilogue, and are named in place. Wdenotes the prepared weight image:ld.param.u64 %rd2, [cuda_dldn_engine_swin_dec4_kernel_param_0+40](s9) thencvta.to.global.u64 %rd3, %rd2(s10). Everyld.weak.global.ca.v4.u32readsW + 16*laneid + imm; tables and biases useW + ((laneid<<2)&12) + imm(canonical construction s16157–s16161).Sdenotes the plane arena:ld.param.u64 %rd1050, [%rd1+-32](s23917) thencvta.to.global.u64 %rd5, %rd1050(s23918), with%rd1 = param_0+80(s4), so%rd1-32isparam_0+48. This is the entry's only read ofparam_0+48.SMdenotes the 16384-byte shared array_ZZ33cuda_dldn_engine_swin_dec4_kernel33DldnEngineSwinEncParamsStructBaseE4smem(materialised bymov.u32at s11611 and others).%r9 = %tid.z(s19) is the slab index, and dec4 guards it to 0…3:s20 setp.gt.u32 %p3, %r9, 3/s21 @%p3 bra $L__BB1_121. It scales the input buffer ×25600 (s438), a second input stride ×160 (s543), ×40 (s1052), the shared tile ×16 (s2301), ×2560 (s11503), ×2048 (<<11, s16069), ×512 (<<9, s16128) and the phase-2…11 weight group ×27648 (%r16781 = %r9*13824s11607,%rd381 = %r16781*2s11608, consumed at s11645add.s64 %rd383, %rd2, %rd381).- Register conventions are the settled family ones:
C/D reg0= (row g, cols 2t,2t+1),reg1= (row g+8, same cols),g = laneid>>2(s37/s38),t = laneid&3. - Anything I could not pin down from the PTX is in §6.
1. Shared vocabulary
1.1 Addresses and parameters an epilogue touches
| symbol | how it is obtained | statements |
|---|---|---|
param+0, extents (ex, ey) |
ld.param.v2.u32 {%r1013, %r1014}, [param_0] |
s15 |
param+8, the e4m3 feature buffer |
ld.param.u64 %rd60, [%rd1+-72] → cvta.to.global.u64 %rd61, %rd60 |
s34–s35 |
param+24, the f16 image buffer (the skip input) |
ld.param.u64 %rd253, [%rd1+-56] → cvta.to.global.u64 %rd4, %rd253 |
s3640–s3641 |
param+40, W (weight image) |
ld.param.u64 %rd2, [param_0+40] → cvta.to.global.u64 %rd3, %rd2 |
s9–s10 |
param+48, S (plane arena) |
ld.param.u64 %rd1050, [%rd1+-32] → cvta.to.global.u64 %rd5, %rd1050 |
s23917–s23918 |
param+80, block origin (ox, oy) |
ld.param.v2.u16 {%rs222, %rs223}, [param_0+80] |
s5 |
param+88, low-res feature texture |
ld.param.u64 %rd1117, [%rd1129+8] with %rd1129 = param_0+80 (s24223) |
s24334 |
param+96, texture added unconditionally |
ld.param.u64 %rd1119, [%rd1129+16] |
s24410 |
param+104, texture added under a NaN guard |
ld.param.u64 %rd1121, [%rd1129+24] |
s24412 |
param+112, output surface |
ld.param.u64 %rd1123, [%rd1129+32] |
s24233 |
param+136, (sx, sy) pixel→uv scale |
ld.param.v2.f32 {%f1180, %f1181}, [%rd1129+56] |
s24328 |
SM (16384 B) |
mov.u32 %r16783, _ZZ33…E4smem |
s11611 |
| per-lane weight address | mul.wide.u32 %rd382, %laneid, 16 + add.s64 %rd384, %rd383, %rd382 |
s11644–s11646 |
| per-lane table address | shl.b32 %r, %laneid, 2 → cvt.u64.u32 → and.b64 %rd, %r, 12 → add.s64 %rd, W, %rd |
s16157–s16161 |
| block origins | %r1 = ctaid.x<<3 − ox (s7), %r2 = %r1 − 1 (s8), %r3 = ctaid.y<<3 − oy (s14), %r6 = %r3 − 1 (s16) |
s7–s16 |
%r7 = ex<<3, %r8 = ey*%r7 |
s17–s18 | s17–s18 |
The param+80-relative form is worth stressing: dec4 keeps %rd1127 and %rd1129
(both = %rd1128/%rd1130 + 80, s24198 / s24223) and then reads the decoder
parameters as [%rd1127-80] (= param+0), [%rd1129+8], [%rd1129+16],
[%rd1129+24], [%rd1129+32], [%rd1129+56]. So +96 and +104 are exactly
%rd1129+16 and %rd1129+24 (s24410 / s24412).
1.2 Constants
| register | first definition | literal | identity |
|---|---|---|---|
%f476 |
s12177 mov.f32 %f476, 0f3C8CCB50 |
0.017186790704727173 | score scale |
%fd383 |
s12181 mov.f64 %fd383, 0dBFE1CC0000000000 |
−0.55615234375 | clamp low |
%fd385 |
s12186 mov.f64 %fd385, 0d3FE1CC0000000000 |
+0.55615234375 | clamp high |
%f478 |
s12192 mov.f32 %f478, 0f3F6D6000 |
0.92724609375 | cubic coefficient |
%f480 |
s12197 mov.f32 %f480, 0f3FB00000 |
1.375 | cubic offset |
%fd1 |
s10075 mov.f64 %fd1, 0d3F20000000000000 |
2⁻¹³ | norm epsilon in E1 |
%fd386 |
s16920 mov.f64 %fd386, 0d3F20000000000000 |
2⁻¹³ | norm epsilon in E21 |
%f1117 |
s17741 mov.f32 %f1117, 0f3ED306EB |
0.4121621549129486 | activation ramp |
%f1118 |
s17744 mov.f32 %f1118, 0f3DA60DD6 |
0.0810810774564743 | activation width |
%f1119 |
s17747 mov.f32 %f1119, 0f3F000000 |
0.5 | activation offset |
%f1120 |
s17750 mov.f32 %f1120, 0f40000000 |
2.0 | activation clamp |
0f3FB8AA3B (log2e) occurs 9 times in the final epilogue, first at s24246; the
negated form 0fBFB8AA3B once at s24415; 0f3F800000 (1.0) at s24251's
add.ftz.f32. Neither layer ever uses the .relu requantiser: the string
satfinite.relu does not occur.
1.3 Two quantisation helpers
cvt.rn.satfinite.e4m3x2.f16x2— requantisation.cvt.rn.f16x2.e4m3x2— the inverse unpack (one e4m3 byte pair → f16x2).
2. Phase table summary
From rr_layer_spec.py dec4: 62 phases, 1606 mma, 24447 statements.
The tool prints M and N from the number of distinct A and B fragments, so the
identity M/16 * N/8 * K/32 == mma is the dense-GEMM check:
- holds for phases 2–12, 14–21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61;
- fails for 23 phases — 1, 13, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44,
46, 48, 50, 52, 54, 56, 58, 60, 62. For the even phases 22…60 the tool prints
M=80 N=160 K=160 (
5*20*5 = 500) against 20mma: those phases are 5-step cascades, not dense GEMMs (see E22). For P62 it prints M=80 N=80 K=160 against 10mma; P62 is a 5-fragment cascade (A =%r938…%r957) as §4/E62 describes.
Weight-image extent: the largest byte read from W is phase 62's second C seed at
W + ((laneid<<2)&12) + 534800, i.e. the image is at least 534804 bytes.
Phase 1's B block is [0, 25600), phase 1's C seeds are [102400, 102704], the
score bias (phase 12's C) is [114240, 126028), the per-slab copy of the phase-2…11
weight group starts at 104000 + z*27648, and phase 62's last weight tile is
[532224, 534796).
Phases that read no weight operand at all: 12 and 13. Phase 12's A and B both
come from e4m3 packs of phase 10's D (E11), and phase 13's B is the movmatrix
transpose of registers (E12); see §4/E11, E12.
3. Summary of epilogues
| epilogue | range | stmts | named operation |
|---|---|---|---|
| E1 | s871–s11653 | 10783 | requantise P1's D, scatter to SM, read back, blend param+24, inverse-std, requantise, stage for P2 |
| E2–E10 | 7 stmts each | 7 | next-B weight loads only (s11678–s11900) |
| E11 | s11957–s12127 | 171 | score-bias C-seed loads + 80 packs of P10's D → P12 A and B |
| E12 | s12176–s16019 | 3844 | softmax of the 64×96 score block, V-transpose, pack |
| E13 | s16068–s16341 | 274 | stage P·V, P14 A from SM, next-B loads, column table + skip → P14 C |
| E14–E20 | 27 stmts each | 27 | P15…P21 A from SM + next-B loads (s16362–s16670) |
| E21 | s16691–s17719 | 1029 | RMS norm (², sum, rsqrt, gain) + packs + next B/C |
| E22 | s17740–s18060 | 321 | clamped cubic activation + column-bias add + packs + next B |
| E23 | s18081–s18172 | 92 | 40 packs → P24 A, next-B, next-C bias |
| E24…E60 | 172/92 alternating | E22/E23 repeated for P24…P60 | |
| E61 | s23857–s24154 | 298 | pack → plane-arena scatter (param+48) → next B/C |
| E62 | s24165–s24446 | 282 | SM stage, softmax over 5 taps, 3×3 texture gather, aux textures, surface write |
4. The epilogues
E1 — s871–s11653: patch expand, image blend, inverse standard deviation
10783 statements (44 % of the entry), the same pipeline as dec3's E1 with every count scaled by 160/128 = 1.25.
Evidence:
s871 L3807 cvt.rn.satfinite.e4m3x2.f16x2 %rs226, %r1298
s875 L3818 mov.b32 %r10, {%rs228, %rs229}
s1090 L4268 st.shared.v2.u16 [%r4580], {%rs226, %rs227}
s1117 L4297 st.shared.u32 [%r4593], %r10
s2295 L5592 bar.sync 0
s2340 L5647 ld.shared.v2.u16 {%rs346, %rs347}, [%r5246]
s3640 L7252 ld.param.u64 %rd253, [%rd1+-56]
s3794 L7417 ld.global.v2.u16 {%rs426, %rs427}, [%rd255]
s9055 L12990 cvt.rn.f16x2.e4m3x2 %r9582, %rs426
s9217 L13472 add.f16 … // first of 324
s10018 L15459 shfl.sync.bfly.b32 %r9963,%r9959,%r10029,%r9966,%r10040
s10075 L15607 mov.f64 %fd1, 0d3F20000000000000
s10321 L16341 rsqrt.approx.ftz.f32 fl, fl
s10963 L17382 ld.global.v2.u16 {%rs3159, %rs3160}, [%rd336+103696]
s11503 L18962 mul.lo.s32 %r936, %r9, 2560
s11521 L18998 st.shared.v4.u32 [%r10307], {%r10311, %r10310, %r10309, %r10308}
s11606 L19151 bar.sync 0
s11613 L19160 ld.shared.v4.u32 {%r16785, %r16786, %r16787, %r16788}, [%r16784]
s11651 L19201 ld.weak.global.ca.v4.u32 { %r10356,%r10357,%r10358,%r10359},[%rd337]
| range | stmts | what | operations (count) |
|---|---|---|---|
| s871–s1048 | 178 | requantise phase 1's D and pack | 120 cvt.rn.satfinite.e4m3x2.f16x2, 58 mov.b32 → %r10…%r67 |
| s1049–s1089 | 41 | lane / %r9 → shared-index setup for the first store |
mov.u32 %r4338, %laneid (s1049), mul.wide.u32 %rd204, %r4338, -1431655765 (s1051) |
| s1090–s2295 | 1206 | guarded scatter into SM, one basic block per store |
58 st.shared.u32 + 2 st.shared.v2.u16 |
| s2295 | 1 | bar.sync 0 (L5592) |
— |
| s2296–s3639 | 1344 | read back a window from SM (5-way switch per load) |
40 ld.shared.v2.u16 (s2340…s3639) |
| s3640–s3641 | 2 | the param+24 buffer pointer |
ld.param.u64 %rd253, [%rd1+-56], cvta |
| s3642–s9054 | 5413 | clamped-coordinate gather from the param+24 buffer |
40 ld.global.v2.u16 (s3794…s9054) |
| s9055–s9214 | 160 | dequantise both sources | 160 cvt.rn.f16x2.e4m3x2 → %r9582…%r9741 |
| s9215–s10017 | 803 | blend + reduction tree | 480 mul.f16, 324 add.f16, 84 add.f16x2 |
| s10018–s10074 | 57 | cross-lane sums | 8 shfl.sync.bfly.b32 (s10018…s10071) |
| s10075–s10076 | 2 | epsilon 2⁻¹³ |
mov.f64 %fd1, 0d3F20000000000000 (s10075) |
| s10077–s10320 | 244 | epsilon add + packing of the sums | 160 add.f16, 81 mov.b32 |
| s10321–s10956 | 636 | inverse standard deviation | 160 rsqrt.approx.ftz.f32 (s10321…s10954) |
| s10957–s10982 | 26 | per-column gain read | 20 ld.global.v2.u16 at W + ((laneid<<2)&12) + {103680…103984} (s10963…s10982) |
| s10983–s11502 | 520 | normalise and combine | 320 mul.f16, 160 mov.b32, 40 cvt.rn.satfinite.e4m3x2.f16x2 |
| s11503–s11605 | 103 | requantise and stage for phase 2 | 10 st.shared.v4.u32 |
| s11606 | 1 | bar.sync 0 (L19151) |
— |
| s11607–s11642 | 36 | phase 2's A fragments | 30 ld.shared.v4.u32 → %r16785…%r16904 |
| s11643–s11653 | 11 | phase 2's B | 2 ld.weak.global.ca.v4.u32 at W + z*27648 + 16*laneid + {104000, 104512} |
The scatter (s1090–s2295). The 60 stores are guarded (setp.gt.u32 %p, …, 9
at s1052 and its siblings) and the index is
byte = 4 * ( (col & 3) | (40*row + 400*(col>>2)) ) into SM
(shr.u32 %r4584, %r79, 2 / mul.lo.s32 %r4585, %r4584, 400 /
mad.lo.s32 %r4586, %r80, 40, %r4585 / shl.b32 %r4587, %r81, 2 /
add.s32 %r4588, %r4587, %r4586 / and.b32 %r4589, %r79, 3 /
or.b32 %r4590, %r4589, %r4588 — s1107–s1113). So dec4 writes 10-by-10
sub-blocks of 400 bytes and 58 distinct (row, col) triples, versus dec3's
literal +{0,1600,…,11200} plane offsets. As in dec3 the (row, col) order is a
permutation of laneid derived with the golden-ratio multiplier
(mul.wide.u32 %rd204, %r4338, -1431655765, s1051). The store count differs from
dec3's 48 because dec4's phase 1 produces 800 columns instead of 640.
The param+24 gather (s3642–s9054). %rd1-56 is param_0+24 (s4, s3640);
%rd4 = cvta.to.global.u64(%rd253) (s3641). Each of the 40 loads computes a
clamped halo index and issues
mul.wide.u32 %rd254, %r34933, 4 / add.s64 %rd255, %rd4, %rd254 /
ld.global.v2.u16 {%rs426, %rs427}, [%rd255] (s3792–s3794). The gather's
interior index is clamped_row * %r7 + 8*clamped_col + min(laneid&3, 7), i.e. the
same 8-u32-per-image-row f16 buffer as dec3's (§4/E1 of rrswin_dec3_epilogues.md).
The inverse-std block. The residual add.f16 fold (first at s9217) yields a
value that is squared (mul.f16, s9620ff), reduced in-lane, summed with the
two-step butterfly shfl.sync.bfly (s10018, s10071), offset by 2⁻¹³ (s10075) and
inverted by 160 rsqrt.approx.ftz.f32 (s10321…s10954). The gain table is 20
ld.global.v2.u16 at W + ((laneid<<2)&12) + {103680…103984} (s10963…s10982) —
40 f16 per lane = 160 columns.
Staging for phase 2. %r936 = %r9*2560 (s11503); the 10 st.shared.v4.u32
write at SM + z*2048 + 16*laneid + {0,512,1024,1536} (s11521, s11533, s11545,
s11557) and at +{10240,10752,11264,11776,12288} in a second group guarded by
setp.gt.u32 %p626, %r10328, 31 with %r10328 = %r9<<4 (s11574–s11575), i.e. only
z ∈ {0,1}. After bar.sync (s11606) the 30 ld.shared.v4.u32 at
SM + 16*laneid + 512*i (s11613…s11642) become phase 2's A
%r16785…%r16904 (30 A fragments = 6 m-tiles × 5 k-steps), and the 2
ld.weak.global.ca.v4.u32 at s11651/s11653 are phase 2's B.
E2–E10 — s11678…s11900: next-B weight loads only
Seven statements each, exactly dec3's E2–E8 shape: 8 B fragments (16 registers) per
phase, read as W + z*27648 + 16*laneid + base + 512*i. The bases are
104000 (P2), 109120 (P3), 105024 (P4), 110144 (P5), 106048 (P6),
111168 (P7), 107072 (P8), 112192 (P9), 108096 (P10), 113216 (P11) — the
even phases walk 104000, 105024, 106048, 107072, 108096 and the odd phases
109120, 110144, 111168, 112192, 113216, i.e. five k-group pairs (dec3 had
four), so phases 2–11 together form one 96×64×160 GEMM split into ten
96×32×32 phases chained through C (verified from the operand sets: P2/P3 use A
fragment set 0, P4/P5 set 1, P6/P7 set 2, P8/P9 set 3, P10/P11 set 4; P2/P3 have
C = the single zero register %r16707 while P4…P11 take the previous phase's D).
E11 — s11957–s12127: score-bias seeds and 80 packs of phase 10's D
171 statements, 24 weight loads + 80 packs — the dec3 E9 design with the wider N.
s11961 L21128 ld.weak.global.ca.v4.u32 { … }, [%rd…] // first of 24
s12008 L21313 cvt.rn.satfinite.e4m3x2.f16x2 … // first of 80 packs
- 24 loads at
W + z*27648 + 16*laneid + 114240 + 512*i,i = 0…23(s11960add.s64 %rd357, %rd404, 114240with%rd404 = %rd383 + 16*laneid,%rd383 = W + z*27648; s11961 the first load, s11962 the next at+114752) → phase 12's C seeds (96 registers = 24 C pairs). The block is[114240, 126028). Note this is a different kind of C operand from phase 1's: phase 1 seeds each mma with a single u32 duplicated into both halves ({%r…, %r…}), loaded as 20ld.global.u32at[%rd203 + {102400, 102416, …, 102704}](s551–s570), whereas phase 12 takes 24 full 512-byte tiles. - 80 packs whose sources are phase 10's D, not phase 11's; they split into
phase 12's A fragments (
%r13134…%r13497, 16 registers) and B fragments (%r13388…%r13499, 24 registers = 12 fragments). Phase 11's own D reaches E12'smovmatrixblock instead. - The C-seed layout is the same as dec3's §4/E9:
byte = base + 512*(4*(n>>1) + m) + 16*laneid + 8*(n&1), so the tile index runs over 4 m-tiles and 6(n>>1)groups = 24 tiles = 12288 bytes.
E12 — s12176–s16019: softmax of the 64×96 score block, V-transpose, pack
Phase 12 = 48 mma of 64×96 with C = the 24 bias pairs (E11). The epilogue has
no memory access at all (0 ld.*, 0 st.*) and no bar.sync. Its op
histogram is byte-for-byte dec3's E10: 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, 112 shl.b32, 104 add.f16x2,
96 each of mul.f16x2 / max.f16x2 / min.f16x2 / neg.f16x2 / and.b32,
48 movmatrix, 16 shfl.sync.bfly.b32, 8 add.f16.
s12177 L21724 mov.f32 %f476, 0f3C8CCB50
s12178 L21727 cvt.rn.f16.f32 low, %f476
s12182 L21737 cvt.rn.f16.f64 %rs3280, %fd383
s14381 L28593 shfl.sync.bfly.b32 %r15668,%r15664,%r15820,%r15671,%r15831 // first of 16
s14511 L28919 rcp.approx.ftz.f32 fl, fl // first of 192
s15278 L30164 mul.f16 %rs4074,%rs4075,%rs4076 // first of 192
s15756 L31218 movmatrix.sync.trans.aligned.m8n8.b16 %r16028, %r12605 // first of 48
s15804 L31362 cvt.rn.satfinite.e4m3x2.f16x2 %rs4648, %r16036 // first of 144 packs
Sub-sections (the same partitioning dec3's §4/E10 documents):
| range | what |
|---|---|
| s12176–s14293 | 96 per-element groups: scale, clamp, cubic, exponent extract (all 96 max.f16x2 ≤ s14278, min.f16x2 ≤ s14282, neg.f16x2 ≤ s14283, and.b32 ≤ s14293) |
| s14294–s14508 | in-lane partial sums and the butterfly: 104 add.f16x2 (s14294–s14503), 16 add.s32 (s14378–s14500), 16 or.b32 (s14379–s14501), 16 shfl.sync.bfly.b32 (s14381–s14502) → 8 row sums, 8 add.f16 (s14390–s14505) |
| s14509–s15277 | 192 cvt.f32.f16 (s14509–s15270) → 192 rcp.approx.ftz.f32 (s14511–s15272) → 192 cvt.rn.f16.f32 (…s15274) = 96 reciprocals |
| s15278–s15755 | 192 mul.f16 (s15278–s15754) → 96 probabilities |
| s15756–s15803 | 48 movmatrix transposing phase 11's D |
| s15804–s16019 | 144 cvt.rn.satfinite.e4m3x2.f16x2 packs (s15804–s16018) |
(The boundaries above are the runs between the first/last occurrence of each op,
verified with the lineariser; the exponent region's end is fixed by the last
and.b32 at s14293 and the sum region's by the first add.f16x2 at s14294.)
Per element the exponent is the clamped cubic of dec3's §4/E10:
m = clamp(f16(x * 0.017181396484375), -0.55615234375, +0.55615234375)
t = f16(m*(-m) + 0.92724609375)
u = f16(m*t + 1.375)
expval = f16 from bits ((bits(u)<<5) & 0x7FE07FE0)
and there is no row maximum: max.f16x2 (96×) and min.f16x2 (96×) are the
clamp, and the only warp shuffles are the 16 shfl.sync.bfly above. Contrast E62,
which does compute a real row max over 5 taps.
E13 — s16068–s16341: stage P·V, seed phase 14
274 statements.
s16068 L32201 bar.sync 0
s16069 L32202 shl.b32 %r17033, %r9, 11
s16070 L32203 add.s32 %r17034, %r16783, %r17033
s16074 L32210 cvt.rn.satfinite.e4m3x2.f16x2 %rs4792, %r16368 // first of 32 packs
s16086 L32237 st.shared.v4.u32 [%r17036], {%r17040, %r17039, %r17038, %r17037}
s16128 L32328 shl.b32 %r34545, %r9, 9
s16133 L32335 ld.shared.v4.u32 {%r34550, %r34551, %r34552, %r34553}, [%r34549]
s16138 L32343 ld.weak.global.ca.v4.u32 { %r17055,%r17056,%r17057,%r17058},[%rd405]
s16162 L32388 ld.global.v2.u16 {%rs7270, %rs7271}, [%rd889+325200] // first of 20
s16183 L32410 add.f16 %rs4826,%rs7309,%rs4828 // first of 80
- s16068
bar.sync; s16069–s16073 build%r17036 = SM + z*2048 + 16*laneid; - 32
cvt.rn.satfinite.e4m3x2.f16x2packing phase 13's D and 4st.shared.v4.u32atSM + z*2048 + 16*laneid + {0,512,1024,1536}(s16086, s16100, s16114, s16127); - s16128–s16132
%r34549 = SM + z*512 + 16*laneid; s16133ld.shared.v4.u32→ phase 14's A fragment #0 (%r34550…%r34553); - s16137–s16156 10 weight loads at
W + 16*laneid + {126528, 127040, 128064, 128576, 129088, 129600, 130112, 130624, 131136}→ phase 14's B (20 fragments = 40 registers); - s16161–s16181 20 table loads at
W + ((laneid<<2)&12) + {325184, 325200, … 325488}(16-byte stride) → 40 f16 per lane = a per-column table; - s16182–s16341 80
add.f16→ 40 b32%r17104, %r17105, …= phase 14's C seeds, exactlytable[col] + residual(s16183add.f16 %rs4826,%rs7309,%rs4828where the second operand is the E1 residual register).
So phase 14: D = A·B + (skip_residual + column_table).
E14–E20 — s16362–s16670: A from SM + next-B, seven times
27 statements each: one ld.shared.v4.u32 (one A fragment, %r34557…%r34560 in
E14, then %r34563…, %r34569…, %r34575…, %r34581…, %r34587…, %r34593…),
10 ld.weak.global.ca.v4.u32 (the next phase's B, 20 fragments = 40 registers) and
the address arithmetic. Example, E14 (s16362–s16388): s16365 ld.shared.v4.u32,
s16370 ld.weak.global.ca.v4.u32 (first of 10).
Together with E13 this supplies the A k-fragments of phases 14–21, which are one
GEMM 16×160×256 split across eight mma phases chained through C (P15 C = P14's
D, …, P21 C = P20's D). The B blocks are 126528 (P14), 154176 (P15), 181824
(P16), 209472 (P17), 237120 (P18), 264768 (P19), 292416 (P20), 320064
(P21).
E21 — s16691–s17719: RMS norm before the MLP
1029 statements, no stores. The dec3 E15 design scaled by 160/128.
s16691 L34285 shl.b32 %r34597, %r9, 1
s16693 L34287 mov.b32 {%rs6072, %rs6075}, %r18790 // first of 302
s16694 L34289 mul.f16 %rs5066,%rs6075,%rs6075 // first of 240 squares
s16895 L34846 shfl.sync.bfly.b32 %r19103,%r19099,%r15820,%r19106,%r15831 // first of 4
s16920 L34912 mov.f64 %fd386, 0d3F20000000000000 // eps = 2^-13
s16921 L34914 cvt.rn.f16.f64 %rs5309, %fd386
s17046 L35286 rsqrt.approx.ftz.f32 fl, fl // first of 80
s17368 L35807 ld.global.v2.u16 {%rs7310, %rs7311}, [%rd906+325520] // first of 20 gain loads
s17632 L36554 ld.weak.global.ca.v4.u32 { %r19224,%r19225,%r19226,%r19227},[%rd485] // first of 10 next-B
s17656 L36599 ld.global.u32 %r19314, [%rd911+330944] // first of 4 next-C bias words
s17660 L36604 cvt.rn.satfinite.e4m3x2.f16x2 %rs6031, %r33783 // first of 40 packs
| range | stmts | op |
|---|---|---|
| s16691–s16903 | 213 | lane/origin setup and 160 mul.f16 squares (the remaining 80 of the 240 are in the normalise) |
| s16853–s17040 | 188 | in-lane/butterfly sums: 42 add.f16x2 (s16853–s16917), 4 or.b32 (s16894–s16915), 4 shfl.sync.bfly.b32 (s16895–s16916), 82 add.f16 (s16904–s17040) |
| s16920–s16921 | 2 | eps 2⁻¹³ in %fd386 (cvt.rn.f16.f64 %rs5309, %fd386 at s16921) |
| s17044–s17361 | 318 | 80 cvt.f32.f16 (s17044–s17357) → 80 rsqrt.approx.ftz.f32 (s17046–s17359) → 80 cvt.rn.f16.f32 (s17048–s17361) |
| s17368–s17387 | 20 | gain loads W + ((laneid<<2)&12) + {325504…325808} (+325504 appears last, +325520 first) |
| s17632–s17659 | 28 | 10 ld.weak.global.ca.v4.u32 (phase 22's B, 320064 + 512*i, s17632–s17650) then 4 ld.global.u32 at 330944/330960/330976/330992 (phase 22's C bias word, s17656–s17659) |
| s17660–s17718 | 59 | 40 packs → phase 22's A |
What it computes — the same expression as dec3's §4/E15:
sumsq[row] = Σ_c x[row,c]² (f16, in-lane tree + 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, and the gain is a per-column table read
with the W + ((laneid<<2)&12) + off pattern. The norm's bias is not added here:
it is phase 22's C seed, loaded at s17656.
E22 — s17740–s18060: clamped cubic activation + column bias
321 statements.
s17740 L36884 mov.u32 %r19505, %laneid
s17741 L36886 mov.f32 %f1117, 0f3ED306EB
s17744 L36893 mov.f32 %f1118, 0f3DA60DD6
s17747 L36900 mov.f32 %f1119, 0f3F000000
s17750 L36907 mov.f32 %f1120, 0f40000000
s17753 L36915 neg.f16x2 %r19510,%r19509 // first of 8
s17754 max.f16x2 … // first of 8
s17755 min.f16x2 … // first of 8
s17756 abs.f16x2 … // first of 8
s17757 L36931 mul.f16x2 %r19520,%r19507,%r19518 // first of 24
s17758 sub.f16x2 … // first of 8
s17760 add.f16x2 … // first of 8
s17883 add.s64 … // column-table addressing
s17885 L37377 ld.weak.global.ca.v4.u32 … // first of 10 next-B loads
s17909 L37422 ld.global.v2.u16 {%rs7350, %rs7351}, [%rd916+336144] // first of 20 table loads
s17929 L37469 add.f16 … // first of 80 bias adds
s18049 L37803 cvt.rn.satfinite.e4m3x2.f16x2 %rs6311, %r19648 // first of 8 packs
Per element, over each of the 8 f16x2 groups of phase 22's D:
y = clamp(x, -2, +2) // neg/max/min, s17753–s17755
g = 0.5 + y * (0.412109375 - 0.0810546875 * |y|) // abs/mul/sub/mul/add, s17756–s17760
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.
The constants %f1117…%f1120 are defined here and are re-read as
cvt.rn.f16.f32 low, %f1117…%f1120 by every later activation epilogue.
Then 20 table loads (s17909 = +336144) and 80 add.f16 (s17929–s18047) write the
table over the activation inputs, producing phase 23's C seeds; the final 8
packs (s18049…) build phase 23's A (one 4-register fragment); and the 10
ld.weak.global.ca.v4.u32 from s17885 are phase 23's B block [331008, 336128).
E23 — s18081–s18172: packs, then next B/C
92 statements:
s18081 L37971 mov.u32 %r19988, %laneid
s18085 L37979 ld.weak.global.ca.v4.u32 … // first of 10 next-B loads
s18109 L38022 ld.global.u32 %r20079, [%rd921+341568] // first of 4 next-C bias words
s18113 L38027 cvt.rn.satfinite.e4m3x2.f16x2 %rs6319, %r33783 // first of 40 packs
40 packs (20 b32) → phase 24's A; 10 ld.weak.global.ca.v4.u32 → phase 24's B
[336448, 341568); 4 ld.global.u32 at 341568/341584/341600/341616 → phase 24's
C bias.
E24 … E60 — the repeating MLP stack
The pattern (activation, first one with a table add) → (40 packs + next B/C)
repeats with a period of two phases. Numbering the phases: the even phases 22,
24, …, 60 each have a 321/172-statement activation epilogue; the odd phases 23,
25, …, 59 each have a 92-statement pack epilogue. Verified op histograms:
- P22 epi (s17740–s18060, 321): 80
add.f16, 76mov.b32, 32cvt.rn.f16.f32, 24mul.f16x2, 20ld.global.v2.u16, 10ld.weak, 8 each ofneg/max/min/abs/sub/add.f16x2, 8 packs. - P23 epi (s18081–s18172, 92): 40 packs, 20
mov.b32, 10ld.weak, 4ld.global.u32. - P24 epi (s18193–s18364, 172): 172 statements with 8 packs and 10
ld.weakand nold.global.v2.u16, i.e. no column table add — the residual is carried by the C operand that E23 loaded.
The B blocks advance 4128 bytes per phase: 336448 (P24), 341632 (P25),
346752 (P26), 351936 (P27), 357056 (P28), … 521920 (P60), 527104 (P61),
532224 (P62), and each phase's C bias words sit in the 48-byte window 48 bytes
below the next phase's B base (e.g. P24's C at 341568..341616, loaded at s18109).
E61 — s23857–s24154: pack → plane-arena scatter → next B/C
298 statements.
s23857 L57579 cvt.rn.satfinite.e4m3x2.f16x2 %rs7231, %r34324 // first of 40 packs
s23917 L57718 ld.param.u64 %rd1050, [%rd1+-32] // S = plane arena (param+48)
s23918 L57719 cvta.to.global.u64 %rd5, %rd1050
s23920 L57723 shr.u32 %r958, %r34544, 2 // g = laneid>>2
s23921 L57724 and.b32 %r959, %r34544, 3 // t = laneid&3
s23924 L57727 add.s32 %r34630, %r937, %r34628 // y = %r937 + (laneid>>5)
s23930 L57733 add.s32 %r34631, %r1, %r34629 // x = %r1 + (g&7)
s23943 L57747 st.global.u32 [%rd1052], %r938 // first of 20 stores
s24139 L57579-… ld.weak.global.ca.v4.u32 // first of 5 next-B loads
s24153 ld.global.u32 … // first of 2 next-C seeds
- 40 packs → 20 b32
%r938…%r957, which are simultaneously phase 62's A fragments — the same 20 registers are scattered to memory and fed to the last GEMM. S = cvta.to.global.u64(param_0+48)via%rd1-32(s23917–s23918) — the entry's only read ofparam_0+48.- 20
st.global.u32(first at s23943 with value%r938), each guarded bysetp.lt.s32 %p, %r34630, 0/setp.ge.u32 %p, %r34630, %r1014/setp.gt.u32 %p, %r34544, 63combined withor.pred(s23925–s23929) and the matching x guards, then aselp.b32 …, -1, …, %p1+setp.lt.s32+brathat turns a guard failure into "skip the store". - The index is
idx = (8*ex)*y + 8*x + dwith%r7 = ex<<3(s17),y = %r937 + (laneid>>5)where%r937 = %r3 + 2*%r9(s16691–s16692), andx = %r1 + ((laneid>>2)&7),d = t(ord = t|4), exactly dec3's §5 formula. - after the stores: 5
ld.weak.global.ca.v4.u32atW + 16*laneid + {532224, 532736, 533248, 533760, 534272}(s24138–s24147,%r34660…%r34679) = phase 62's B (10 fragments = 20 registers), then 2ld.global.u32atW + ((laneid<<2)&12) + {534784, 534800}(s24153–s24154,%r34690/%r34700) = phase 62's C seeds.
E62 — s24165–s24446: softmax over five taps, 3×3 texture gather, surface write
282 statements; the entry's last statement is the ret.
s24165 L58082 bar.sync 0
s24170 L58089 shl.b32 %r997, %r34888, 4
s24177 L58096 st.shared.u32 [%r998], %r34761
s24181 L58101 st.shared.u32 [%r998+16], %r34771
s24198 L58121 add.s64 %rd1127, %rd1128, 80
s24209 L58132 add.s32 %r1003, %r1, %r1001 // x
s24210 L58133 add.s32 %r1004, %r3, %r1002 // y
s24215 L58138 ld.param.v2.u32 {%r34806, %r34807}, [%rd1127+-80] // ex, ey
s24223 L58147 add.s64 %rd1129, %rd1130, 80
s24233 L58157 ld.param.u64 %rd1123, [%rd1129+32] // output surface (param+112)
s24246 L58191 (first of 12 mul.ftz.f32 by 0f3FB8AA3B)
s24247 L58192 ex2.approx.ftz.f32
s24328 L58360 ld.param.v2.f32 {%f1180, %f1181}, [%rd1129+56] // param+136 scale pair
s24334 L58366 ld.param.u64 %rd1117, [%rd1129+8] // param+88 low-res texture
s24336 L58369 tex.base.2d.v4.f16.f32 {%rs7418,…,}, [%rd1101, {%f1140,%f1141}]
s24410 L58541 ld.param.u64 %rd1119, [%rd1129+16] // param+96
s24411 L58543 tex.base.2d.v4.f16.s32 {%rs7562,…,}, [%rd1119, {%r1003,%r1004}]
s24412 L58545 ld.param.u64 %rd1121, [%rd1129+24] // param+104
s24413 L58547 tex.base.2d.v4.f16.s32 {%rs7566,…,}, [%rd1121, {%r1003,%r1004}]
s24445 L58635 sust.b.2d.v4.b16.zero [%rd1123, {%r34877,%r1004}], {%rs7619,%rs7620,%rs7621,%rs7618}
Op histogram (s24165–s24446): 30 fma.rn.f16, 17 mov.b32, 16 add.s32,
13 setp.lt.s32, 12 each of mul.ftz.f32 / cvt.rn.f16.f32 / selp.b32,
10 each of cvt.f32.f16 / ex2.approx.ftz.f32 / add.ftz.f32,
9 tex.base.2d.v4.f16.f32, 8 mov.u64, 6 each of mov.u32 / and.b32 /
shl.b32 / bra / cvt.rn.f32.s32 / fma.rn.ftz.f32, 5 ld.shared.u32,
5 sub.f16x2, 5 mul.f16x2, and 1 sust.
| range | stmts | what |
|---|---|---|
| s24165–s24197 | 33 | bar.sync (s24165) + stage phase 62's D into SM at (48*y + 6*x) slots (4 st.shared.u32, s24177–s24194) |
| s24198–s24227 | 30 | pointer setup: %rd1127 = %rd1128 + 80 (s24198), second bar.sync (s24199), the integer coordinates %r1003 = %r1+%r1001 / %r1004 = %r3+%r1002 (s24209–s24210), (ex, ey) read from %rd1127-80 (s24215), bounds guard (s24216–s24222), %rd1129 = %rd1130 + 80 (s24223) |
| s24228–s24241 | 14 | surface pointer param+112 = [%rd1129+32] (s24233), 5 ld.shared.u32 reading 5 consecutive taps (s24228–s24234), and the row max: 3 max.f16x2 (s24236–s24238) + 2 max.f16 (s24240–s24241) |
| s24233 / s24243–s24326 | — | surface pointer param+112 (s24233); softmax: 5 sub.f16x2 (s24243–s24295), 12 mul.ftz.f32 (s24246–), 10 ex2.approx.ftz.f32 (s24247–), div.approx.ftz.f32 (s24304, s24418), 5 mul.f16x2 (s24307–s24311), 3 cvt.rn.f16.s32 (s24312–s24314), 12 selp.b32 (s24319–) |
| s24327–s24333 | 7 | clamped coordinates clamp(p-1, 1, ex-2) / clamp(p-1, 1, ey-2) (6 cvt.rn.f32.s32 s24327–, 6 fma.rn.ftz.f32 s24330–, ld.param.v2.f32 s24328) |
| s24334–s24410 | 77 | 9 tex.base.2d.v4.f16.f32 (s24336–s24406) at the 3×3 stencil of param+88, accumulated with 30 fma.rn.f16 (s24338–s24427) |
| s24411–s24413 | 3 | 2 tex.base.2d.v4.f16.s32 at param+96 (s24410–s24411) and param+104 (s24412–s24413), both at {%r1003, %r1004} |
| s24414–s24444 | 31 | sigmoid-like blend (s24418 div.approx, s24421 sub.f16, 3 mul.f16 s24422–s24426, 3 fma.rn.f16) then the per-channel NaN guard on param+104: 3 set.nan.f16.f16 (s24428–s24438) → setp.ne.s16 → @p bra → 3 add.f16 (s24431–s24441) |
| s24445 | 1 | sust.b.2d.v4.b16.zero surface write |
Where the +96/+104 reads go. %rd1129+16 = param+96 (s24410) and
%rd1129+24 = param+104 (s24412). Both are tex.base.2d.v4.f16.s32 reads at the
same integer coordinate {%r1003, %r1004} = (x, y) (s24209–s24210);
param+96's channels are added unconditionally, while param+104's are added
per channel only when the channel is not NaN (set.nan.f16.f16). The surface
written is %rd1123 = param+112 (s24233), and the write lands at
(%r34877, %r1004) with 0 in the fourth channel (s24445).
What the +24 skip input supplies. param_0+24 (reached as %rd1-56, s3640)
supplies the f16 image values that E1 adds to the shared-staged features (s9217
onward) to form the residual. That residual is used in E1's own normalisation
(mul.f16) and is added to the per-column table at W+325184 in E13
(s16182–s16341) to seed phase 14's C operand.
5. The plane-arena writes (param_0+48)
S = cvta.to.global.u64(%rd1050) with %rd1050 = ld.param.u64 [%rd1+-32]
(s23917–s23918) is the only occurrence of param_0+48 in the entry. There are
exactly two store groups in the whole entry:
(i) E61, 20 × st.global.u32 [%rd1052 + …], v — s23943 … s24129. The first
is s23943 L57747 st.global.u32 [%rd1052], %r938 and the last is
s24129 L57971 st.global.u32 [%rd1090], %r957; the values are %r938…%r957 in
file order (the same 20 registers that become phase 62's A). Each is guarded as
described in §4/E61:
idx = (8*ex)*y + 8*x + d, guard y >= 0, y < ey, laneid <= 63, x >= 0, x < ex
y = %r937 + (laneid>>5), %r937 = %r3 + 2*%r9, x = %r1 + ((laneid>>2)&7),
d = t (first of each pair) | d = t|4, with t = laneid&3
where ex = %r1013, ey = %r1014 (s15), %r1 = block origin x (s7), %r3 = block origin y (s14)
(ii) E62, the shared staging at s24177/s24181/s24190/s24194: st.shared.u32
into SM, not the arena.
What is written: phase 61's requantised 16×160 output (20 u32 per lane).
What reads it back: nothing inside this kernel — param_0+48 is never the base
of an ld.*, and phase 62's A comes from registers (%r938…%r957, E61's own
packs). See §6.
6. Uncharacterised
U1. The shared-memory layout of E1's first scatter. dec4 writes with
byte = 4 * ((col&3) | (40*row + 400*(col>>2))) (s1107–s1113) into a 16 KB array,
rather than dec3's literal +{0,1600,…,11200} plane offsets. I did not reduce the
(row, col) permutation of laneid (built with mul.wide.u32 %rd204, %r4338, -1431655765, s1051) to a closed form, nor map each plane to a source element of the
800-column phase-1 output. Missing: a shared-memory dump or the producer's D
layout.
U2. %r16781 = %r9*13824 (s11607) feeding %rd381 (s11608). %rd381 is used
at s11645 as the slab term W + z*27648 for phase 2's B. The derivation 13824*2
looks like a per-slab stride expressed for a different tile width, so the constant
13824 is presumably the per-slab output-tile size divided by 2, but nothing in the
PTX states it. Missing: the weight-image layout description.
U3. The identity of the per-column tables. W+325184 (E13), W+336144 (E22),
W+103680…103984 (E1's gain), W+325504…325808 (E21's gain) are all read with the
same W + ((laneid<<2)&12) + off pattern. Their roles are computable (E13: added
to the skip before phase 14; E22: added after the activation; E1/E21: multiply the
inverse std) but their names are not. The same is true of the GEMM biases at
102400…102704 (P12), 126528-adjacent words and 534784/534800 (P62).
Missing: the weight image's _prep permutation or the model's parameter names.
U4. The identity of the 12288-byte score bias. Phase 12 adds a 12288-byte f16
table (W + z*27648 + 114240 … 126028) as its GEMM C operand, laid out as §4/E11
describes. Whether it is a relative position bias, a learned score bias, or a
per-lane constant cannot be decided from the PTX.
U5. The geometry of the banded phases. Twenty-three phases print an M/N/K that
fails M/16·N/8·K/32 == mma (P1, 13, 22–60 even, 62). For the even phases
22…60 I verified the 5-step cascade shape (A = 5 fragments, B = 20 fragments,
mma = 20 = 5*4 with the C-chain running over the A fragments), and for P62
likewise (A = 5 fragments, B = 10 fragments, mma = 10 = 5*2). For P1
(300 mma, 100 B fragments, 250 distinct C/D pairs) and P13 (48 mma, C set of 65
registers) I did not reduce the full (M, N, K) reading. The epilogue contracts
above do not depend on resolving this.
U6. The logical meaning of E62's blend. E62 computes a blend of a 3×3
tex.base.2d.v4.f16.f32 gather of param+88 (weighted by a 5-tap softmax) with the
param+96 texture and, per channel under a NaN guard, the param+104 texture, then
writes param+112 at (8·x, y). The PTX gives the arithmetic exactly but not
which model term this is. Missing: the high-level source or a reference.
U7. The count of distinct input-buffer strides. dec4's prologue/E1 use
×25600 (s438), ×160 (s543) and ×40 (s1052) for %r9 in addition to the shared and
weight strides. I did not determine which of the three addresses the prologue's
gather (param+8) versus E1's gather (param+24) versus some other buffer.
Missing: a mapping from %r9 to buffer identity.
7. Quick acceptance index
| requirement | where |
|---|---|
| patch expand | §4/E1 (s871–s11653) and phase 1 (§2) |
| the norms | E1's rsqrt block (s9215–s10956, eps s10075) and E21 (s16691–s17719, eps s16920) |
| the attention | E11 (score seeds + packs), E12 (softmax + movmatrix s15756–s15803 + packs), E13 (P·V staging) |
| the activations | E22, E24, …, E60 — the clamped cubic `x·(0.5 + y·(0.412109375 − 0.0810546875· |
| the per-launch table in the plane arena | §5, s23917/s23943ff (param_0+48) |
| every epilogue of every phase | §3 summary table + §4 (E1–E62) |
| texture reads at +96/+104 and where the surface write goes | §4/E62, s24410–s24413 and s24233/s24445 |
| what the skip input at +24 supplies | §1.1 (s3640) and §4/E1, E13 |
| phase table M/N/K arithmetic checked | §2 (23 phases fail; listed) |
| weight-image extent | §2 (≥ 534804 bytes; last read s24153 + 2 words) |
| phases with no weight operand | §2: 12 and 13 |
| uncharacterised | §6 |