From 46f21a5956f85462208ff005e6cbc86f142f8046 Mon Sep 17 00:00:00 2001 From: Ma Mingfei Date: Thu, 4 Dec 2025 12:34:05 +0800 Subject: [PATCH] use faster covnersion from float8_e4m3fn to bfloat16 (#12316) --- sgl-kernel/csrc/cpu/gemm_fp8.cpp | 14 +++++++++----- sgl-kernel/csrc/cpu/vec.h | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/sgl-kernel/csrc/cpu/gemm_fp8.cpp b/sgl-kernel/csrc/cpu/gemm_fp8.cpp index 008f83298..b2821982a 100644 --- a/sgl-kernel/csrc/cpu/gemm_fp8.cpp +++ b/sgl-kernel/csrc/cpu/gemm_fp8.cpp @@ -56,7 +56,8 @@ inline void unpack_B( const int K2 = K >> 1; const int ldb2 = ldb; // ldb * 2 >> 1; const uint16_t* b_ptr = reinterpret_cast(packed_B); - const __m512 vd = _mm512_set1_ps(scale); + const __m512 vexp = _mm512_castsi512_ps(_mm512_set1_epi32(kFP8_BIAS)); + const __m512 vd = _mm512_mul_ps(_mm512_set1_ps(scale), vexp); constexpr int BLOCK_N = block_size_n(); static_assert(BLOCK_N == 32); @@ -74,8 +75,8 @@ inline void unpack_B( __m256i b8_0 = _mm512_extracti32x8_epi32(b8, 0); __m256i b8_1 = _mm512_extracti32x8_epi32(b8, 1); - __m512bh bf16_0 = CVT_FP8_TO_BF16(b8_0); - __m512bh bf16_1 = CVT_FP8_TO_BF16(b8_1); + __m512bh bf16_0 = CVT_FP8_TO_BF16_EXT(b8_0); + __m512bh bf16_1 = CVT_FP8_TO_BF16_EXT(b8_1); // Apply scale __m512 f0_lo = CVT_BF16_TO_FP32(_mm512_extracti32x8_epi32((__m512i)bf16_0, 0)); @@ -147,6 +148,8 @@ struct tinygemm_kernel_nn 0) { _mm_prefetch(b_ptr + (k + PREFETCH_SIZE_K) * ldb2 + col * 16, _MM_HINT_T0); } - vb[col + 0] = CVT_FP8_TO_BF16(_mm512_extracti32x8_epi32(b8, 0)); - vb[col + 1] = CVT_FP8_TO_BF16(_mm512_extracti32x8_epi32(b8, 1)); + vb[col + 0] = CVT_FP8_TO_BF16_EXT(_mm512_extracti32x8_epi32(b8, 0)); + vb[col + 1] = CVT_FP8_TO_BF16_EXT(_mm512_extracti32x8_epi32(b8, 1)); } } vsum[i] = _mm512_dpbf16_ps(vsum[i], va, vb[col]); @@ -191,6 +194,7 @@ struct tinygemm_kernel_nn> 1, kb_start + BLOCK_K2); // 1. load scale vector vscale = _mm512_set1_ps(scale[kb]); + vscale = _mm512_mul_ps(vscale, vexp); if constexpr (PREFETCH_SIZE_KB > 0) { _mm_prefetch(scale + kb + PREFETCH_SIZE_KB, _MM_HINT_T0); } diff --git a/sgl-kernel/csrc/cpu/vec.h b/sgl-kernel/csrc/cpu/vec.h index d0ec53d83..486ff260a 100644 --- a/sgl-kernel/csrc/cpu/vec.h +++ b/sgl-kernel/csrc/cpu/vec.h @@ -121,6 +121,30 @@ inline __m512bh CVT_FP8_TO_BF16(__m256i a) { #endif } +// faster version of float8_e4m3fn conversion to bfloat16 +// +// we mapped cuda implementation from below link and vectorized with avx512: +// https://github.com/thu-pacman/chitu/blob/1ed2078ec26581ebdca05b7306d4385f86edaa7c/csrc/cuda/marlin/marlin_gemm/dequant.h#L387 +// +inline __attribute__((always_inline)) __m512bh CVT_FP8_TO_BF16_EXT(__m256i a) { + const __m512i mask0 = _mm512_set1_epi16(0x80); // sign bit + const __m512i mask1 = _mm512_set1_epi16(0x7F); // exponent and mantissa + const __m512i mask2 = _mm512_set1_epi16(0x4000); + + __m512i x = _mm512_cvtepu8_epi16(a); + __m512i vsign = _mm512_and_si512(x, mask0); + vsign = _mm512_slli_epi16(vsign, 8); + + __m512i vexp_and_mant = _mm512_and_si512(x, mask1); + vexp_and_mant = _mm512_slli_epi16(vexp_and_mant, 4); + + // _MM_TERNLOG_A | _MM_TERNLOG_B | _MM_TERNLOG_C: 0b11111110 + return (__m512bh)(_mm512_ternarylogic_epi32(vsign, mask2, vexp_and_mant, 0b11111110)); +} + +// bias for conversion of fp8 to bf16 1/256 in float32 +#define kFP8_BIAS 0x3b800000 + #endif // vector to scalar reduction