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).
46 KiB
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
sNNNNis a statement index in the linearisationrr_layer_spec.pydocuments (statements of the entry body; a wrapped{ … }block and a 4-linemma.synccount as one statement, numbered at their first line).LNNNNNis the physical line of the same instruction in the corpus file, so every claim can be checked withsed -n 'LNNNNN,LNNNNN p' …ptx.- An epilogue is the run of statements between one phase's last
mmaand the next phase's firstmma;Exxbelow means the epilogue of phase xx. The phase table (rr_layer_spec.py enc5) gives the ranges. Wdenotes the prepared weight image:ld.param.u64 %rd2, [cuda_dldn_engine_swin_enc5_kernel_param_0+40](s9, L1037) andcvta.to.global.u64 %rd3, %rd2(s10, L1038). Everyld.weak.global.ca.v4.u32readsW + 16*laneid + imm; the table loads (see §1.1) readW + ((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*27648term (see §1.1's last row and §2.3).%rd1= the parameter-block base at+80:mov.b64 %rd6, param_0(s1, L1018) thenadd.s64 %rd1, %rd6, 80(s4, L1032). So[%rd1+n]isparam_0+80+nand[%rd1-72]isparam_0+8.smemdenotes 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 arereg0 = 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_bitsinptx/lib/zluda_ptx_impl.cpp).rcp.approx.ftz.f32,rsqrt.approx.ftz.f32,ex2.approx.ftz.f32,div.approx.ftz.f32— always wrapped ascvt.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 whoseCfield 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…%r11584are written bymov.b32at 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 index4*(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.b32packs: 38 packs come from a register whose newest definition is anmmaof 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:
- s11704–s11775 — from the movmatrix results → phase 12's B
fragments (
%r11474 … %r11584, traced:%r11474is written bymov.b32 @s11705,%r11584by@s11768). - s11776–s11893 — from the probabilities → phase 12's A fragments.
- 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
- 32 packs of phase 12's D (s11974–s12025) → 16 b32, stored by 4
st.shared.v4.u32atsmem + %r9*512 + laneid*16offsets0, 512, 1024, 1536(%r11876 = %r11623 + %r9<<11 + laneid*16, s11969– s11973). This is the A operand that E13–E19 fetch back. bar.sync 0, then oneld.shared.v4.u32at[%r29389](%r29387 = %r11623 + %r9<<9, s12029) — a 512-byte reload of the same staging, used as the source of the table add below.- Ten weight loads at
W + 16*laneid + 22848 + 512*i→ phase 13's 20 B fragments. - Twenty table loads at
W + ((laneid<<2)&12) + 221520 + 16*i(320 bytes, 160 f16 = one f16 per column) → the 160-column vector. - 80
add.f16(s12083–s12240)= table[column] + shared_operand→ 40 b32 = phase 13's C seeds (the epilogue's 96mov.b32are 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.u32in the E1–E9 runs, E12–E19 runs, E20–E60 runs, alwaysW + 16*laneid + imm,imma phase-table byte offset. The largest isW+430592(E60, s20048). - Per-column tables —
ld.global.v2.u16/ld.global.u32atW + ((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'sld.global.v2.u16reads (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.zerodescriptor at s20297 L51171. - Extents (param_0+0) — s15 L1043 (prologue) and s20116 L50814 (E61).
- E61 does not read
param_0+24,+32,+48,+96or+104.
4.2 Shared
-
Prologue staging — ten
st.shared.v4.u32per%tid.zgroup, 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: thirtyld.shared.v4.u32 [%r11624 + 512*i],i = 0…29, with%r11624 = smem + laneid*16(s7510–s7512) — the read base carries no%tid.zterm, while the store base does; the correspondence between the two is in §5 U8. - five at
-
E12 staging — 4
st.shared.v4.u32atsmem + %tid.z*512 + laneid*16offsets0,512,1024,1536(s11986 L24912 … s12025), read back by theld.shared.v4.u32of E12 (s12033) and E13–E19 (offsets 2048 … 14336). -
E61 staging — 4
st.shared.u32+ 5ld.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 |