Skip to content

feat(x86): AVX-512 low-precision float quantize lane — fp8/fp6/fp4 (S9) - #168

Merged
gstoner merged 2 commits into
mainfrom
s2/x86-quantize-fp
Jun 27, 2026
Merged

gstoner merged 2 commits into
mainfrom
s2/x86-quantize-fp

Conversation

@gstoner

@gstoner gstoner commented Jun 27, 2026

Copy link
Copy Markdown
Owner

PR-D of the campaign. Adds quantize/dequantize for fp8 (e4m3/e5m2), fp6 (e2m3/e3m2), fp4 (e2m1) to x86 — 6 ops that were reference-only on both devices. New x86_fpquant_compiled lane.

Kernel (avx512_fpquant_f32.cpp, new file)

Format-agnostic float-grid snap, parameterized by (max_normal, mantissa_bits):

ax  = min(|x|, max_normal)
ulp = 2^(floor(log2 ax) − mantissa_bits)
out = sign · min(round_RNE(ax/ulp)·ulp, max_normal)

mapped to the AVX-512 getexp (floor log2) / roundscale (RNE) / scalef (2ⁿ) intrinsics — no polynomial. The runtime applies the per-tensor symmetric scale (amax/max_normal, floored); dequantize is the fp32 passthrough (the forward already rescaled). Fake-quant in f32 storage.

Quant technique references (reimplemented, not wrapped — Decision #23): AMD Quark, ROCm Quantizer, Pi-Quant.

Validation (real hardware)

  • Standalone C++ test_fpquant.cppALL PASSED vs the scalar mantissa-snap across fp4/fp6/fp8 grids (incl. ax==0).
  • test_x86_fpquant_compiled.py15 passed; the quantize path matches tessera.ops.quantize_fp{8,6,4} EXACTLY (0 abs err — the AVX-512 RNE grid-snap matches even the ml_dtypes fp8 cast), explicit-scale, dequant passthrough, bad-format + unknown-op rejects.
  • ruff/mypy clean; manifest/matrix/coverage/audit consistency green (88 passed).

Wiring

runtime _X86_FPQUANT_OPS + _execute_x86_compiled_fpquant + symbol binding + executor table; execution_matrix catalog + row; backend_manifest _X86_KERNELS (fused, 6 ops) + _NUMERICAL_FIXTURES; dashboards regenerated. x86 lane count 93 → 99.

nvfp4 uses the block-scaled microscaling path — a separate follow-up lane (PR-D2).

🤖 Generated with Claude Code

…9, was 0/0)

PR-D of the campaign. Adds quantize/dequantize for fp8 (e4m3/e5m2), fp6
(e2m3/e3m2) and fp4 (e2m1) to x86 — 6 ops that were reference-only on both
devices. New x86_fpquant_compiled lane.

Kernel (avx512_fpquant_f32.cpp, new file) — format-agnostic float-grid snap,
parameterized by (max_normal, mantissa_bits):
  ax=min(|x|,max_normal); ulp=2^(floor(log2 ax)−mantissa_bits);
  out=sign·min(round_RNE(ax/ulp)·ulp, max_normal)
mapped to the AVX-512 getexp (floor log2) / roundscale (RNE) / scalef (2^n)
intrinsics — no polynomial. The runtime applies the per-tensor symmetric scale
(amax/max_normal, floored) around it; dequantize is the fp32 passthrough (the
forward already rescaled). Fake-quant in f32 storage.

Validation:
- Standalone C++ test_fpquant.cpp — ALL PASSED vs the scalar mantissa-snap across
  fp4/fp6/fp8 grids (incl. the ax==0 path).
- tests/unit/test_x86_fpquant_compiled.py — 15 passed; the quantize path matches
  tessera.ops.quantize_fp{8,6,4} EXACTLY (0 abs err — the AVX-512 RNE grid-snap
  matches even the ml_dtypes fp8 cast), explicit-scale, dequant passthrough,
  bad-format + unknown-op rejects.

Wiring: runtime `_X86_FPQUANT_OPS` + `_execute_x86_compiled_fpquant` + symbol
binding + executor table; execution_matrix catalog + row; backend_manifest
`_X86_KERNELS` (fused, 6 ops) + `_NUMERICAL_FIXTURES`; dashboards regenerated.
x86 lane count 93 → 99.

(nvfp4 uses the block-scaled microscaling path — a separate follow-up lane.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e8f5d4385

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread python/tessera/runtime.py Outdated
…eview)

Two P2 review fixes on the fp-quant lane:

1. NaN propagation: the kernel turned NaN lanes into max_normal (min(abs(NaN),
   max) / std::fmin saturate), silently destroying NaN sentinels the public
   fp4/fp6 fallback preserves. The kernel now detects NaN (_CMP_UNORD_Q /
   std::isnan) and propagates it through both the vector and scalar paths.

2. fp8 vs ml_dtypes subnormals: the generic mantissa-snap diverged from the
   ml_dtypes float8 cast in the subnormal range (e.g. e4m3, scale=1, ~1e-3) —
   the prior test only hit the normal range. Added a per-format `min_exp` clamp
   so the subnormal grid is FLAT below the smallest normal (e4m3 −6, e5m2 −14),
   matching IEEE gradual underflow / ml_dtypes exactly; fp4/fp6 pass a very
   negative min_exp (no clamp) to keep their reference's pure mantissa-snap.

Tests: + fp8 subnormal-range match vs ml_dtypes (scale=1, ~1e-3 inputs) +
NaN-sentinel propagation; standalone test_fpquant.cpp now exercises NaN and the
clamp. 17 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gstoner

gstoner commented Jun 27, 2026

Copy link
Copy Markdown
Owner Author

Thanks — both addressed in b76d9bb:

  1. NaN propagation — the kernel now detects NaN (_CMP_UNORD_Q / std::isnan) and propagates it through the vector and scalar paths, so NaN sentinels survive instead of becoming max_normal. Added a NaN-sentinel test.
  2. fp8 vs ml_dtypes subnormals — added a per-format min_exp clamp so the subnormal grid is flat below the smallest normal (e4m3 −6, e5m2 −14), matching IEEE gradual underflow / ml_dtypes exactly (the prior mantissa-snap diverged in the subnormal range, e.g. e4m3 scale=1 ~1e-3). fp4/fp6 keep their reference's pure mantissa-snap (no clamp). Added a fp8 subnormal-range test vs the public op.

17 passed; ruff/mypy clean.

@gstoner
gstoner merged commit 640df6a into main Jun 27, 2026
17 checks passed
@gstoner
gstoner deleted the s2/x86-quantize-fp branch June 27, 2026 23:08
gstoner added a commit that referenced this pull request Jun 28, 2026
…m loss/quant mirror (#172)

Final ROCm-mirror PR for the loss/quant families — closes the cross-device pair
for the S11 class-axis losses and the S9 quantize ops (x86 in #167/#168/#169).

class-axis loss (rocm_class_loss_compiled, pure composition — no new C++):
cross_entropy / kl / js / focal / label_smoothed_cross_entropy / z_loss; exp/log
run on the rocm unary lane (gfx1151), class-axis max/sum/gather/one-hot on the
host (same pattern as the x86 class-loss + ROCm attention/gemm-family lanes).

fpquant + nvfp4 (new GenerateROCMFpQuantKernel.cpp): tessera_rocm.fpquant — flat
1-operand float-grid mantissa-snap (ax=min(|x|,max); e=max(floor(log2 ax),
min_exp); ulp=2^(e-mant); roundeven; sign+NaN-propagate), log2/floor/exp2/
roundeven via math->ROCDL, parameterized for fp8 e4m3/e5m2, fp6 e2m3/e3m2,
fp4 e2m1. rocm_fpquant_compiled (per-tensor scale) + rocm_nvfp4_compiled
(per-block fp8-E4M3 scale + E2M1 codes, host block structure).

Validation (gfx1151):
- tessera-opt codegen + ROCDL lowering verified.
- test_rocm_class_loss_compiled.py + test_rocm_fpquant_compiled.py — 15 passed
  vs tessera.losses/tessera.ops (class-loss 2e-4; fpquant/nvfp4 2e-3 — the GPU
  log2/roundeven grid matches the reference on random data).

Wiring: runtime executors (class-loss / fpquant / nvfp4) + `_rocm_fpgrid` /
`_rocm_unary_t` / `_rocm_log_softmax` helpers + executor table; execution_matrix
catalog + 3 rows; backend_manifest _ROCM_COMPILED (6+6+2 ops) +
_NUMERICAL_FIXTURES; dashboards regenerated.

With this, loss (29) + rl_loss (4) + quantize (8) all run on BOTH gfx1151 and
AVX-512 — three of the four "0/0" categories fully cross-device. Only spectral
remains.

Co-authored-by: gstoner <angstroms01@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant