Centralized, dispatchable conversion funnel (cvt) with tables, bit-twiddles, and device overrides - #31
Open
AntonOresten wants to merge 2 commits into
Open
Centralized, dispatchable conversion funnel (cvt) with tables, bit-twiddles, and device overrides#31AntonOresten wants to merge 2 commits into
AntonOresten wants to merge 2 commits into
Conversation
AntonOresten
force-pushed
the
vectorized
branch
from
August 8, 2026 23:06
90c7364 to
72096ec
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #31 +/- ##
===========================================
- Coverage 94.94% 81.79% -13.15%
===========================================
Files 11 14 +3
Lines 336 456 +120
===========================================
+ Hits 319 373 +54
- Misses 17 83 +66 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Every conversion into a Microfloat — constructors, convert, broadcasts,
packed vectors — now reduces to one positional surface:
cvt(T, x, mode::RoundingMode, policy::OverflowPolicy) # scalar
cvt(NVector{T,N}, xs, mode::RoundingMode, policy::OverflowPolicy) # packed
Implementations stack by ordinary dispatch specificity:
- cvt_generic: the existing bit-level rounding kernel, made
device-portable by routing all throws through @noinline hooks that
device backends override (no more duplicated conversion body in ext).
- @cvt_table Src => Dst: @generated lookup-table methods, built lazily
per (mode, policy) by running every source bit pattern through
cvt_generic — correct by construction; registered for all built-in
pairs, opt-in for user @microfloat types (world-age safe since the
method is defined after the traits it consults).
- Hand bit-twiddles (specializations.jl): exact E2M1 -> E4M3/E4M3FN
widening, scalar and packed-storage FP4x2/x4 -> FP8x2/x4. ~9x faster
than the table and ~4x faster than generic in vectorized loops
(tables gather; twiddles autovectorize).
- CUDACoreExt (rewritten, now a directory matching main's layout):
@device_override on exactly the (target, source, mode, policy)
combinations with native PTX instructions, gated once per method on
compute capability (folds at kernel compile). All natively supported
cvts are .satfinite, i.e. SAT policy — the draft's OVF mapping was
wrong; OVF always takes the generic path. Native fp8 paths validated
bit-exact against the host on sm_89.
Vector entry points: NVector{T,N}(::StaticArray, [mode]; overflow=...)
constructors normalize sources and route through the funnel, with a
same-eltype repack disambiguator against BitPacking's constructors.
Also ports the bits-based BFloat16 widening fix from main (e9a6faa):
required here because table generation crosses dynamic call boundaries
with boxed BFloat16s, which Julia >= 1.12 corrupts on AVX-512 BF16 CPUs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces ad-hoc conversion entry points with a single dispatchable funnel that every conversion into a
Microfloatreduces to:Constructors (
T(x, mode; overflow=...), newNVector{T,N}(::SVector/NVector, [mode]; overflow=...)) are thin sugar that only resolve defaults. Optimized implementations stack by ordinary dispatch specificity:cvt_generic— the existing bit-level rounding kernel, now device-portable: every throw goes through@noinlinehooks (throw_no_nan, …) that device backends@device_override, so the ext no longer maintains a duplicated conversion body.@cvt_table Src => Dst—@generatedlookup-table methods built lazily per(mode, policy)by running every source bit pattern throughcvt_generic: correct by construction, single L1 load per conversion. Registered for all built-in pairs; user@microfloattypes opt in after definition (world-age safe by design — the generated method postdates the traits it consults).src/specializations.jl) — exactE2M1 → E4M3/E4M3FNwidening, scalar and packed-storageFP4x2/x4 → FP8x2/x4.ext/CUDACoreExt/, matching main's directory layout): narrow@device_overridemethods on exactly the(target, source, mode, policy)signatures with native PTXcvtinstructions, each gated once on compute capability (compute_capability()folds at kernel compile — the static CC check, expressed once).Semantics fixes over the draft ext
cvtinto fp8/fp6/fp4/ue8m0 destinations is.satfinite-only, i.e.SATpolicy; the draft mapped fp8 natives toOVF, which hardware cannot express.OVFnow always takes the generic path. ForSATthe native/host agreement is exact even at the floatmax boundary (round-then-clamp ≡ clamp); NaN payloads compared NaN-aware.isnan(hardware silently maps NaN where Microfloats throws); ue8m0 pre-guards negatives.<cuda_fp4.hpp>) instead ofllvm.nvvm.*intrinsics, so availability doesn't depend on the LLVM version Julia ships.Also ports the bits-based BFloat16 widening fix from main (e9a6faa) — table generation crosses dynamic call boundaries with boxed
BFloat16s, which Julia ≥ 1.12 corrupts on AVX-512 BF16 CPUs (BFloat16s.jl#107 family).Performance (1M-element broadcast, znver4)
Tables gather in vectorized loops; twiddles autovectorize. Hence: table = default for every pair, twiddle = opt-in where it matters.
Testing
17446/17446pass, including exhaustive sweeps: every table pair × every bit pattern × 6 rounding modes × both policies ≡ the generic path (values and thrown errors); twiddles ≡ generic over all packed storage patterns.cvt.rn.satfinite.e4m3x2/e5m2x2match the host bit-for-bit. fp6/fp4/ue8m0 natives need sm_100a and are exercised only through their generic fallback here — an on-device parity sweep on Blackwell is still needed before trusting those (ext header notes this).Notes for review
where Ton the device hook overrides is load-bearing (bare::Typeargs don't specialize → dynamic calls → InvalidIRError on device).src/conversion.jl/src/macro.jlwith e9a6faa (this branch re-applies it inside the rewrite) and trivially inext/CUDACoreExt/CUDACoreExt.jl(add main'sinclude("cudaDataType.jl")).@cvt_widengenerated exact-widening twiddles, f16x2/bf16x2 native sources, a PTX.jl-backed extension replacing the inline asm.🤖 Generated with Claude Code