Skip to content

Commit 0fd2998

Browse files
committed
[mathcore] Work around libstdc++ <experimental/simd> AVX-512 bug
The `libstdc++`'s `_VecBltnBtmsk` (AVX-512 mask) ABI fails to compile with non-GCC front ends (Clang, Intel icpx) due to a static_assert requiring `long long` and `long` to be the same type, reproducible at least with GCC 15 and 16. Detect this in CMake and, when the AVX-512 path is broken but the 256-bit AVX path compiles, pin ROOT's SIMD alias in `Math/Types.h` to `simd_abi::__avx` (which corresponds to AVX-256). ABI stays consistent across all translation units and interpreted contexts, no `-mno-avx512f` is needed, and the rest of ROOT keeps native AVX-512 codegen. Closes #22370. (cherry picked from commit 83dd2e4)
1 parent f3722ad commit 0fd2998

4 files changed

Lines changed: 65 additions & 0 deletions

File tree

cmake/modules/RootConfiguration.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@ if(ROOT_HAVE_EXPERIMENTAL_SIMD)
380380
else()
381381
set(hasstdexperimentalsimd undef)
382382
endif()
383+
if(ROOT_EXPERIMENTAL_SIMD_PIN_AVX_ABI)
384+
set(experimentalsimdpinavxabi define)
385+
else()
386+
set(experimentalsimdpinavxabi undef)
387+
endif()
383388
if(dataframe)
384389
set(hasdataframe define)
385390
else()

cmake/modules/SearchInstalledSoftware.cmake

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,6 +1792,52 @@ else()
17921792
" ROOT_HAVE_EXPERIMENTAL_SIMD)
17931793
endif()
17941794

1795+
# On platforms with AVX-512, the libstdc++ implementation of
1796+
# <experimental/simd> (from GCC up to at least 16) fails to compile with
1797+
# non-GCC front ends (Clang, Intel icpx) because of a static_assert in the
1798+
# _VecBltnBtmsk (AVX-512 mask) ABI that requires `long long` and `long` to be
1799+
# the same type. The bug fires only for the AVX-512 mask ABI path, so we work
1800+
# around it by pinning ROOT's simd alias (Math/Types.h) to the 256-bit AVX2
1801+
# ABI variant instead of the platform-native ABI. That keeps the ABI of
1802+
# Float_v/Double_v/... consistent across all TUs (no `-mno-avx512f` needed)
1803+
# and lets the rest of ROOT keep its native AVX-512 codegen.
1804+
set(ROOT_EXPERIMENTAL_SIMD_PIN_AVX_ABI FALSE CACHE INTERNAL
1805+
"Pin <experimental/simd> alias to the 256-bit ABI to dodge libstdc++ AVX-512 bug")
1806+
if(ROOT_HAVE_EXPERIMENTAL_SIMD)
1807+
set(_simd_realistic_test "
1808+
#include <experimental/simd>
1809+
int main() {
1810+
std::experimental::native_simd<double> a(1.0), b(2.0);
1811+
where(a > b, a) = b;
1812+
return 0;
1813+
}
1814+
")
1815+
check_cxx_source_compiles("${_simd_realistic_test}"
1816+
ROOT_EXPERIMENTAL_SIMD_FULL_USAGE_OK)
1817+
if(NOT ROOT_EXPERIMENTAL_SIMD_FULL_USAGE_OK)
1818+
set(_simd_pinned_abi_test "
1819+
#include <experimental/simd>
1820+
namespace stx = std::experimental;
1821+
int main() {
1822+
stx::simd<double, stx::simd_abi::__avx> a(1.0), b(2.0);
1823+
where(a > b, a) = b;
1824+
return 0;
1825+
}
1826+
")
1827+
check_cxx_source_compiles("${_simd_pinned_abi_test}"
1828+
ROOT_EXPERIMENTAL_SIMD_AVX_ABI_OK)
1829+
if(ROOT_EXPERIMENTAL_SIMD_AVX_ABI_OK)
1830+
set(ROOT_EXPERIMENTAL_SIMD_PIN_AVX_ABI TRUE CACHE INTERNAL "" FORCE)
1831+
message(STATUS "Working around libstdc++ <experimental/simd> AVX-512 bug "
1832+
"by pinning Math/Types.h to the 256-bit AVX ABI")
1833+
else()
1834+
message(STATUS "Disabling experimental/simd-based features: libstdc++ "
1835+
"header fails to compile in this configuration")
1836+
set(ROOT_HAVE_EXPERIMENTAL_SIMD FALSE CACHE INTERNAL "" FORCE)
1837+
endif()
1838+
endif()
1839+
endif()
1840+
17951841
#------------------------------------------------------------------------------------
17961842
# Check if the pyspark package is installed on the system.
17971843
# Needed to run tests of the distributed RDataFrame module that use pyspark.

config/RConfigure.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#@hascocoa@ R__HAS_COCOA /**/
3939
#@hasvdt@ R__HAS_VDT /**/
4040
#@hasstdexperimentalsimd@ R__HAS_STD_EXPERIMENTAL_SIMD /**/
41+
#@experimentalsimdpinavxabi@ R__EXPERIMENTAL_SIMD_PIN_AVX_ABI /**/
4142
#@usecxxmodules@ R__USE_CXXMODULES /**/
4243
#@uselibc++@ R__USE_LIBCXX /**/
4344
#@has_found_attribute_always_inline@ R__HAS_ATTRIBUTE_ALWAYS_INLINE /**/

math/mathcore/inc/Math/Types.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,21 @@ namespace ROOT {
1313

1414
namespace Internal {
1515

16+
#if defined(R__EXPERIMENTAL_SIMD_PIN_AVX_ABI) && defined(__AVX512F__)
17+
// libstdc++'s <experimental/simd> _VecBltnBtmsk (AVX-512 mask) ABI fails to
18+
// compile with non-GCC front ends (Clang, Intel icpx) due to a static_assert
19+
// requiring `long long` and `long` to be the same type. When AVX-512 is
20+
// enabled in this TU we'd otherwise hit that path, so pin to the 256-bit AVX
21+
// ABI instead. The fallback is guarded by __AVX512F__ so that environments
22+
// without AVX-512 in scope (notably rootcling/cling, which parses headers
23+
// without -mavx*) still see the regular `native` ABI and pick the
24+
// always-supported scalar fallback.
25+
template <typename T>
26+
using SIMDTag = std::experimental::simd_abi::__avx;
27+
#else
1628
template <typename T>
1729
using SIMDTag = std::experimental::simd_abi::native<T>;
30+
#endif
1831

1932
} // namespace Internal
2033

0 commit comments

Comments
 (0)