Hardware e4m3 decode in dec0's tail on the native-FP8 build

make_ptx.py turns the 32 cvt.rn.f16x2.e4m3x2 of rrlite_dec0_4x4_folded into calls of d4r_dec_e4m3x2 (tex_common.h) when D4R_TEX_FP8=1: v_cvt_pk_f32_fp8 and two conversions to f16 instead of ZLUDA's integer lowering (about 25 instructions each; the kernel goes from 4058 to 3418 instructions). The conversion equals ZLUDA's e4m3_to_f16_bits for every code except the NaN codes 0x7f / 0xff, checked over all 65536 code pairs on an RX 9070 XT, and the head never stages those codes (it clamps to +-448 before encoding). Harness frames are byte-identical in the accuracy and the fast set, over a 16-frame moving sequence in the accuracy set. dec0 at 2227x1253 render: 0.43 -> 0.38 ms (accuracy), 0.36 -> 0.30 ms (fast). -DD4R_TEX_SOFT_E4M3 gives ZLUDA's lowering; builds without D4R_TEX_FP8 keep the PTX instruction.
This commit is contained in:
woutermans committed 2026-10-07 01:15:36 +02:00
1 parent 5198fd38b3
commit 1038825225
4 files changed
+65 -1

No files matched your search

+26
View File
@@ -151,6 +151,32 @@ __attribute__((device)) static inline uint32_t e4m3x4_f32(float a, float b, floa
}
#endif
// cvt.rn.f16x2.e4m3x2 for the kernels whose PTX make_ptx.py points here (dec0's tail on the native-FP8 build):
// two e4m3 codes -> an f16 pair. The hardware conversion equals ZLUDA's e4m3_to_f16_bits for every code except
// the NaN codes 0x7f / 0xff (a different NaN), which the head never stages: it clamps to +-448 before encoding.
DEV __attribute__((always_inline)) uint32_t d4r_dec_e4m3x2(uint16_t codes)
{
#ifdef D4R_TEX_HW_E4M3
typedef float dec_f2v __attribute__((ext_vector_type(2)));
typedef _Float16 dec_h2v __attribute__((ext_vector_type(2)));
const dec_f2v f = __builtin_amdgcn_cvt_pk_f32_fp8((int)codes, false);
return __builtin_bit_cast(uint32_t, (dec_h2v){(_Float16)f[0], (_Float16)f[1]});
#else
uint32_t out = 0;
#pragma unroll
for (int i = 0; i < 2; ++i)
{
const uint32_t code = (codes >> (8 * i)) & 0xffu, magnitude = code & 0x7fu;
const uint32_t normal = (magnitude << 7) + 0x2000u;
const uint32_t subnormal = __builtin_bit_cast(uint16_t, (_Float16)((float)(magnitude & 7u) * 0x1p-9f));
uint32_t half = magnitude >= 8u ? normal : subnormal;
half = magnitude == 0x7fu ? 0x7fffu : half;
out |= (((code & 0x80u) << 8) | half) << (16 * i);
}
return out;
#endif
}
// ZLUDA's f16x2_to_e4m3x2_satfinite_bits: RNE satfinite e4m3 of both halves, low half -> low byte.
__attribute__((device)) static inline uint32_t e4m3x2(uint32_t bits)
{