[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