[CPU] Gate the AVX10.2 paths on compiler support (#58133)
Signed-off-by: R <Ganesh.R@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Li, Jiang <jiang1.li@intel.com>
Ganesh R committed
Sep 24, 2026 at 15:37 UTC
f34a0e07978eb78c2586b88ef660e7f5308c036e
3 files changed
+31
cmake/cpu_extension.cmake
+18
@@ -173,6 +173,18 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64" OR ENABLE_X86_ISA)
173
set(AMX_FP8_SUPPORTED FALSE)
174
message(STATUS "AMX-FP8 disabled by ENABLE_AMX_FP8=OFF")
175
endif()
176
+
177
+ # AVX10.2 arrived in GCC 15, so the target attribute, the fp8 convert
178
+ # intrinsics and __builtin_cpu_supports("avx10.2") are all hard errors on
179
+ # the 12.3+ the backend otherwise supports. Probe instead of assuming.
180
+ check_cxx_compiler_flag("-mavx10.2" COMPILER_SUPPORTS_AVX10_2_FLAG)
181
+ if (COMPILER_SUPPORTS_AVX10_2_FLAG)
182
+ set(AVX10_2_SUPPORTED TRUE)
183
+ else()
184
+ set(AVX10_2_SUPPORTED FALSE)
185
+ message(STATUS "AVX10.2 disabled: compiler does not support -mavx10.2 (compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION})")
186
+ endif()
187
+
188
list(APPEND CXX_COMPILE_FLAGS_AVX2
189
"-mavx2")
190
elseif (POWER9_FOUND OR POWER10_FOUND OR POWER11_FOUND)
@@ -629,6 +641,12 @@ if (ENABLE_X86_ISA)
641
message(STATUS "AMX-FP8 (Diamond Rapids) enabled")
642
endif()
643
644
+ # For the sgl-kernels AVX10.2 fp8 quantize paths
645
+ if (AVX10_2_SUPPORTED)
646
+ target_compile_definitions(_C PRIVATE "-DCPU_CAPABILITY_AVX10_2")
647
+ message(STATUS "AVX10.2 enabled")
648
+ endif()
649
+
650
# AVX512F
651
define_extension_target(
652
_C_AVX512
csrc/cpu/sgl-kernels/common.h
+7
@@ -532,10 +532,17 @@ void zero_buffer(T* data, int64_t size) {
532
#endif
533
534
#if defined(__x86_64__)
535
+// CPU_CAPABILITY_AVX10_2 is defined by cmake only when the compiler accepts
536
+// -mavx10.2; without it the builtin below is not merely absent but a hard
537
+// error, so the AVX512 paths have to stand in.
538
bool avx10_2_available() {
539
+#ifdef CPU_CAPABILITY_AVX10_2
540
// __builtin_cpu_supports returns the masked feature bit rather than 0/1.
541
static const bool available = __builtin_cpu_supports("avx10.2");
542
return available;
543
+#else
544
+ return false;
545
+#endif
546
}
547
#endif
548
csrc/cpu/sgl-kernels/gemm_fp8_w8a8.cpp
+6
@@ -772,6 +772,7 @@ inline __m128i cvtfp32_fp8e4m3(__m512& src) {
772
return _mm512_cvtepi32_epi8(packed);
773
}
774
775
+#ifdef CPU_CAPABILITY_AVX10_2
776
__attribute__((target("avx10.2"))) inline __m128i cvtfp32_fp8e4m3_avx10_2(__m512& src) {
777
__m256i f16_vec = _mm512_cvt_roundps_ph(src, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
778
return _mm256_cvtph_hf8(_mm256_castsi256_ph(f16_vec));
@@ -805,6 +806,7 @@ __attribute__((target("avx10.2"))) void quantize_bf16_block_avx10_2(
806
_mm_storeu_si128(reinterpret_cast<__m128i*>(dst + i + 16), fp8_vec2);
807
}
808
}
809
+#endif // CPU_CAPABILITY_AVX10_2
810
811
std::tuple<at::Tensor, at::Tensor> _quantize_fp8e4m3_bf16_per_tensor_no_scale(const at::Tensor& t) {
812
constexpr float quant_max = 448.0f; // torch.finfo(torch.float8_e4m3fn).max
@@ -861,10 +863,12 @@ std::tuple<at::Tensor, at::Tensor> _quantize_fp8e4m3_bf16_per_tensor_no_scale(co
863
scale_data[c] = scale_val;
864
865
// Step 3: Scale and clamp using AVX512 (reuse the same loop structure)
866
+#ifdef CPU_CAPABILITY_AVX10_2
867
if (avx10_2_available()) {
868
quantize_bf16_block_avx10_2(channel_src, quant_dst, elements_per_channel, scale_reciprocal);
869
continue;
870
}
871
+#endif
872
i = 0;
873
const __m512 scale_recip_vec = _mm512_set1_ps(scale_reciprocal);
874
const __m512 quant_max_vec = _mm512_set1_ps(quant_max);
@@ -939,10 +943,12 @@ _quantize_fp8e4m3_bf16_per_tensor_with_scale(const at::Tensor& t, at::Tensor& sc
943
const at::BFloat16* src_data = t_bf16.data_ptr<at::BFloat16>() + c * elements_per_channel;
944
at::Float8_e4m3fn* quant_t_data = quant_t.data_ptr<at::Float8_e4m3fn>() + c * elements_per_channel;
945
946
+#ifdef CPU_CAPABILITY_AVX10_2
947
if (avx10_2_available()) {
948
quantize_bf16_block_avx10_2(src_data, quant_t_data, elements_per_channel, scale_reciprocal);
949
continue;
950
}
951
+#endif
952
953
int64_t i = 0;
954
// Process 32 elements at a time using AVX512