# Round 9 Track C Audit: `load_tab<T_IQ3_S>` Dead `load_signs` Removal + Barrier-Free `TAB == 1` in `moe_gu` / `moe_down` + Decode `moe.metal` `NE == 1` `dn_body` Specialization

## 1. Summary of Changes (`metal/kernels/quant.metal` & `metal/kernels/moe.metal`)

- **Patch file:** `/tmp/argon_r9_quant/argon_r9_quant.patch` (verified clean via `git -C vendor/strata apply --check`).
- **Files touched:** Only `metal/kernels/quant.metal` and `metal/kernels/moe.metal` in scratch copy `/tmp/argon_r9_quant/strata` (tracked `vendor/strata/` untouched).

### Change 1: Remove Dead `load_signs` from `load_tab<T_IQ3_S>` & Shrink `fmt<T_IQ3_S>::TAB` (`quant.metal` lines 41 & 100–103)
- Every `T_IQ3_S` decoder across the Metal codebase (`deq<T_IQ3_S>` in `quant.metal`, `DW<T_IQ3_S>` in `mma.metal`, `W4<T_IQ3_S>` and `W8<T_IQ3_S>` in `moe_mm.metal`) reads raw 8-bit sign bytes directly from the block (`b[74 + 4 * ib + l]`) and never accesses `ksigns_iq2xs` (`tab + 512`).
- Changed `fmt<T_IQ3_S>::TAB` from `512 + 32` (`2176 B`) to `512` (`2048 B`) and removed `load_signs(tab, 512, tid, nth);` from `load_tab<T_IQ3_S>`.
- Saves `128 B` of threadgroup memory and `128` byte loads/stores per threadgroup across `gemv`, `moe_gu`, `mm_gu*`, `dq_f16`, and `mtp_chain`.

### Change 2: Eliminate Redundant `threadgroup_barrier` When `fmt<F>::TAB == 1` in `moe_gu` & `moe_down` (`moe.metal` lines 331 & 421)
- Guarded `load_tab<F>` + `threadgroup_barrier(mem_flags::mem_threadgroup)` with `if (fmt<F>::TAB > 1 && moe_probe != 1)` in `moe_gu` and `if (fmt<F>::TAB > 1)` in `moe_down` (matching `dq_f16` in `dense_mm.metal`).
- Since `fmt<F>::TAB` is a compile-time enum constant, the Metal compiler dead-code eliminates the barrier in all `TAB == 1` specializations (`T_Q2_0`, `T_Q2_0R`, `T_Q3_K`, `T_Q4_K`, `T_Q5_K`, `T_Q6_K`, `T_Q8_0`, `T_Q5_1`, `T_Q4_0`, `T_Q5_0`, `T_BF16`, `T_F32`).
- Eliminates 48 `moe_down` (`T_Q2_0` / `T_Q2_0R`) and 12 `moe_gu` (`T_Q6_K`) unconditional threadgroup barriers per decode / MTP verify step.

### Change 3: Specialize `NE == 1` in `dn_body` (`moe.metal` lines 373–382)
- Mirrored `gu_body`'s `if (NE == 1)` branch into `dn_body`: for single-entry expert groups (`NE == 1`, which is 100% of groups at `ntok = 1` and the majority of groups in `ntok = 2..4` verify windows), `X<F>::load(h + c * int(a.n_ff), ...)` is hoisted outside the `for (int r = 0; r < NR; ++r)` loop instead of reloading `xs[16]` inside the `r` loop (for `Q2_0` / `Q2_0R` with `NR = 2`) or allocating `float q[NR][UNIT]` across rows before loading `x`.
- **Ruled out:** Manual unrolling of `for (int l2 = 0; l2 < 2; ++l2)` in `deq<T_IQ2_XS>` (`quant.metal` lines 182–193) was benchmarked and rejected because it increased live register pressure across `NR` rows in `gu_body` on Apple M5, regressing `moe_gu` `IQ2_XS` (`QUANT_CTAB=1`) from `100.7 us` (`94.0 GB/s`) to `105.2 us` (`90.0 GB/s`) at `ntok = 1` and from `283.1 us` (`98.2 GB/s`) to `293.4 us` (`94.8 GB/s`) at `ntok = 3`. Keeping the loop form in `deq<T_IQ2_XS>` preserves optimal register allocation.

---

## 2. Bitwise Parity Verification (`100%` Bit-for-Bit Identical)

1. **`expert_parity` (48 configurations):**
   - Tested all combinations of `gu` in `{IQ3_S, IQ2_XS, Q6_K, Q2_0}`, `dn` in `{Q2_0, Q8_0, IQ4_NL}`, and `ntok` in `{1, 2, 3, 4}`.
   - Verified 64-bit FNV-1a hashes of GPU output buffers `h` (`4 * ntok * TOPK * N_FF` bytes) and `y` (`4 * ntok * N_EMBD` bytes) between baseline and patched kernels: **48 / 48 configurations matched with 0 bit differences (`mismatches: 0`)**.
2. **`moe_mm_parity --v3 --tile 16,64,32,2 --gu IQ3_S --dn Q2_0 --dump`:**
   - Verified `6,512,640`-byte dump of `HS` and `y`: **100% byte-for-byte identical** (`b1 == b2`).
3. **`gemv_parity`:**
   - All 13 formats (`F32`, `BF16`, `Q8_0`, `Q4_0`, `Q5_0`, `IQ4_NL`, `IQ4_XS`, `Q2_0`, `IQ3_S`, `Q3_K`, `Q4_K`, `Q5_K`, `Q6_K`), `n_in` in `{2560, 640, 10240}`, `ntok` in `{1, 3, 8}` across 20 tile configs: **`ALL PASS`** (bitwise window == one token).
4. **`dense_mm_parity`:**
   - All formats including `IQ3_S` (`2560 -> 100`, `2560 -> 48`, `6144 -> 100`, `6144 -> 48`): **`ALL PASS`** (`memcmp(wh)=0, memcmp(xh)=0`).

---

## 3. Decode `expert_parity --bench` Results on Apple M5 (`ntok = 1, 2, 3, 4`)

3-of-3 median GPU timings (`--layers 4 --reps 48 --share 0.3`, production tile configs: `gu = 32,1,4` for `ntok = 1,2` and `16,1,4` for `ntok = 3,4`; `dn = 8,2,4`):

| Config (`gu / dn`) | `ntok` | Base `gu` (us) | Patched `gu` (us) | Base `dn` (us) | Patched `dn` (us) | `dn` Speedup | Base `layer` (us) | Patched `layer` (us) |
|---|---:|---:|---:|---:|---:|---:|---:|---:|
| `IQ3_S / Q2_0` | 1 | 116.1 | 116.1 | 46.9 | 46.7 | **+0.4%** | 167.4 | 167.3 |
| `IQ3_S / Q2_0` | 2 | 205.0 | 206.1 | 81.6 | 81.1 | **+0.6%** | 293.1 | 292.8 |
| `IQ3_S / Q2_0` | 3 | 289.9 | 288.9 | 116.9 | 115.9 | **+0.9%** | 414.7 | 412.1 |
| `IQ3_S / Q2_0` | 4 | 375.8 | 374.2 | 152.2 | 150.8 | **+0.9%** | 536.9 | 534.2 |
| `Q6_K / Q2_0` | 1 | 206.3 | 205.7 | 46.8 | 46.8 | **0.0%** | 258.2 | 257.8 |
| `Q6_K / Q2_0` | 2 | 351.2 | 350.9 | 81.7 | 81.1 | **+0.7%** | 443.2 | 442.0 |
| `Q6_K / Q2_0` | 3 | 507.6 | 508.1 | 117.8 | 116.5 | **+1.1%** | 639.9 | 638.9 |
| `Q6_K / Q2_0` | 4 | 651.3 | 652.0 | 153.3 | 152.3 | **+0.7%** | 823.5 | 822.6 |
| `IQ2_XS / Q2_0 (ctab)` | 1 | 100.8 | 100.7 | 47.0 | 47.0 | **0.0%** | 151.6 | 151.5 |
| `IQ2_XS / Q2_0 (ctab)` | 2 | 179.1 | 179.0 | 81.9 | 81.3 | **+0.7%** | 266.0 | 265.3 |
| `IQ2_XS / Q2_0 (ctab)` | 3 | 247.1 | 247.0 | 117.0 | 116.1 | **+0.8%** | 371.0 | 370.1 |
| `IQ2_XS / Q2_0 (ctab)` | 4 | 320.9 | 320.5 | 152.4 | 151.1 | **+0.9%** | 481.4 | 479.9 |
| `IQ2_XS / Q2_0 (tg tab)` | 1 | 103.1 | 103.0 | 46.9 | 46.9 | **0.0%** | 154.4 | 154.3 |
| `IQ2_XS / Q2_0 (tg tab)` | 2 | 184.1 | 183.8 | 81.8 | 81.3 | **+0.6%** | 271.5 | 270.9 |
| `IQ2_XS / Q2_0 (tg tab)` | 3 | 245.3 | 245.2 | 117.3 | 116.3 | **+0.9%** | 369.9 | 368.7 |
| `IQ2_XS / Q2_0 (tg tab)` | 4 | 319.1 | 318.8 | 152.7 | 151.2 | **+1.0%** | 480.7 | 478.7 |
