vllm.models.deepseek_v41.amd.mono.common.gfx942
¶
gfx942 (MI300X, MI325X) replacements for the gfx950 instructions the mono kernels use.
FP8 on gfx942 is FNUZ: the same bit patterns as OCP e4m3 stand for half the
OCP value, and 0x80 is NaN instead of -0. The kernels quantize with an FP8
maximum of 224 there (arch.GFX942), which gives the same bit patterns as
OCP quantization with 448 and a scale code one higher. A product of two
bytes then needs 2^(code_a + code_b - 254) with the FNUZ codes, which is what
mx_factor returns.
gfx942 has no scaled MFMA. A GEMV runs one v_mfma_f32_16x16x32_fp8_fp8
per 32-wide K block (one scale block) with a zero accumulator and adds the
result times the block's scale factor (mfma_fp8_scaled). A lane holds 8
bytes of each block: K 8 (lane / 16) .. + 8 of the block, for its row (A) or
column (B).
Functions:
-
acc_scaled–acc+d*ffor the 4 accumulator values of a lane. -
bf16_hi_pair–Two f32 that a bf16 holds exactly -> one dword of their bf16 (a low).
-
fp4x8_fnuz–Eight e2m1 values in a dword (value i in bits 4 i .. 4 i + 3) -> two
-
fp8x2_f32–Two FNUZ bytes of a dword as f32: bytes 0 and 1, or 2 and 3 when
hi. -
mfma_bf16_k32–The 16x16x32 bf16 product of gfx950's
mfma_f32_16x16x32_bf16as two -
mfma_fp8–One v_mfma_f32_16x16x32_fp8_fp8: A and B are a lane's 8 FNUZ bytes as
-
mfma_fp8_scaled–accplus one 32-wide K block's product: the FP8 MFMA with a zero -
mx_factor–2^(code_sum - 254) as f32, for code_sum the sum of two E8M0 codes. The
-
ocp_to_fnuz–Four OCP e4m3 bytes -> the FNUZ bytes for half their values. Every bit
-
pair_i64–Two dwords as the 64-bit operand of an FP8 MFMA, lo in the low half.
-
pin_acc–The 4 accumulator values of a lane through opaque moves with side
acc_scaled(acc, d, f)
¶
acc + d * f for the 4 accumulator values of a lane.
bf16_hi_pair(a, b)
¶
Two f32 that a bf16 holds exactly -> one dword of their bf16 (a low). The bf16 of such a value is the top half of its f32 bits.
Source code in vllm/models/deepseek_v41/amd/mono/common/gfx942.py
fp4x8_fnuz(w)
¶
Eight e2m1 values in a dword (value i in bits 4 i .. 4 i + 3) -> two dwords of FNUZ e4m3 bytes: (values 0, 2, 4, 6) and (values 1, 3, 5, 7).
Each byte is the e2m1 value times 2^-7, exactly, the subnormal 0.5
included: the e2m1 sign goes to bit 7 and its exponent and mantissa bits
to bits 4 .. 2, which are the low two exponent bits and the top mantissa
bit of e4m3 with bias 8. A scale code for these bytes is the e8m0 code
plus 7. A negative zero nibble (0x8) would give 0x80, the FNUZ NaN, so
the weights must not hold one: weights942.fp4_drop_negative_zero_
rewrites them to +0 at load, which changes no product.
Source code in vllm/models/deepseek_v41/amd/mono/common/gfx942.py
fp8x2_f32(word, hi)
¶
Two FNUZ bytes of a dword as f32: bytes 0 and 1, or 2 and 3 when hi.
mfma_bf16_k32(a, b, c)
¶
The 16x16x32 bf16 product of gfx950's mfma_f32_16x16x32_bf16 as two
16x16x16 bf16 MFMAs: lane l holds K 8 (l // 16) .. + 8 in a and
b (8 bf16 each). The first MFMA takes elements 0 .. 3 of every lane,
the second elements 4 .. 7, so together they cover all 32 K.
Source code in vllm/models/deepseek_v41/amd/mono/common/gfx942.py
mfma_fp8(a, b, c)
¶
One v_mfma_f32_16x16x32_fp8_fp8: A and B are a lane's 8 FNUZ bytes as
an i64 (pair_i64), C a Vector of 4 f32.
Source code in vllm/models/deepseek_v41/amd/mono/common/gfx942.py
mfma_fp8_scaled(acc, a, b, code_sum)
¶
acc plus one 32-wide K block's product: the FP8 MFMA with a zero
accumulator, then times the block's scale factor (mx_factor).
Source code in vllm/models/deepseek_v41/amd/mono/common/gfx942.py
mx_factor(code_sum)
¶
2^(code_sum - 254) as f32, for code_sum the sum of two E8M0 codes. The f32 bits of 2^e are (e + 127) << 23, so this is (code_sum - 127) << 23. The sum must stay in [128, 381]: the factor is then a normal f32.
Source code in vllm/models/deepseek_v41/amd/mono/common/gfx942.py
ocp_to_fnuz(w)
¶
Four OCP e4m3 bytes -> the FNUZ bytes for half their values. Every bit pattern keeps its meaning (halved) except 0x80 and the OCP NaNs. 0x80, OCP's -0, is the FNUZ NaN and becomes 0x00. The NaNs 0x7F and 0xFF stay as they are and read as 240 and -240. A byte's magnitude plus 0x7F carries into its sign bit exactly when the magnitude is not zero, without reaching the next byte, so the sign survives only on nonzero bytes.
Source code in vllm/models/deepseek_v41/amd/mono/common/gfx942.py
pair_i64(lo, hi)
¶
Two dwords as the 64-bit operand of an FP8 MFMA, lo in the low half.
pin_acc(acc)
¶
The 4 accumulator values of a lane through opaque moves with side effects. An unrolled GEMV loop pins its accumulators after each round. The round's FMAs must then finish before the moves, and the next round's LDS reads (and the MFMAs that need them) cannot move above them. Without it LLVM runs every MFMA of the loop first and the scaling FMAs at the end, which needs a register for each MFMA result and spills them all.