diff --git a/cmake/modules/RootConfiguration.cmake b/cmake/modules/RootConfiguration.cmake index d2c4161c40b5e..f2d480428fcc2 100644 --- a/cmake/modules/RootConfiguration.cmake +++ b/cmake/modules/RootConfiguration.cmake @@ -378,6 +378,11 @@ if(ROOT_HAVE_EXPERIMENTAL_SIMD) else() set(hasstdexperimentalsimd undef) endif() +if(ROOT_EXPERIMENTAL_SIMD_PIN_AVX_ABI) + set(experimentalsimdpinavxabi define) +else() + set(experimentalsimdpinavxabi undef) +endif() if(dataframe) set(hasdataframe define) else() diff --git a/cmake/modules/SearchInstalledSoftware.cmake b/cmake/modules/SearchInstalledSoftware.cmake index fb3ba29c6804a..e53a39a5036e9 100644 --- a/cmake/modules/SearchInstalledSoftware.cmake +++ b/cmake/modules/SearchInstalledSoftware.cmake @@ -1706,6 +1706,52 @@ else() " ROOT_HAVE_EXPERIMENTAL_SIMD) endif() +# On platforms with AVX-512, the libstdc++ implementation of +# (from GCC up to at least 16) fails to compile with +# non-GCC front ends (Clang, Intel icpx) because of a static_assert in the +# _VecBltnBtmsk (AVX-512 mask) ABI that requires `long long` and `long` to be +# the same type. The bug fires only for the AVX-512 mask ABI path, so we work +# around it by pinning ROOT's simd alias (Math/Types.h) to the 256-bit AVX2 +# ABI variant instead of the platform-native ABI. That keeps the ABI of +# Float_v/Double_v/... consistent across all TUs (no `-mno-avx512f` needed) +# and lets the rest of ROOT keep its native AVX-512 codegen. +set(ROOT_EXPERIMENTAL_SIMD_PIN_AVX_ABI FALSE CACHE INTERNAL + "Pin alias to the 256-bit ABI to dodge libstdc++ AVX-512 bug") +if(ROOT_HAVE_EXPERIMENTAL_SIMD) + set(_simd_realistic_test " + #include + int main() { + std::experimental::native_simd a(1.0), b(2.0); + where(a > b, a) = b; + return 0; + } + ") + check_cxx_source_compiles("${_simd_realistic_test}" + ROOT_EXPERIMENTAL_SIMD_FULL_USAGE_OK) + if(NOT ROOT_EXPERIMENTAL_SIMD_FULL_USAGE_OK) + set(_simd_pinned_abi_test " + #include + namespace stx = std::experimental; + int main() { + stx::simd a(1.0), b(2.0); + where(a > b, a) = b; + return 0; + } + ") + check_cxx_source_compiles("${_simd_pinned_abi_test}" + ROOT_EXPERIMENTAL_SIMD_AVX_ABI_OK) + if(ROOT_EXPERIMENTAL_SIMD_AVX_ABI_OK) + set(ROOT_EXPERIMENTAL_SIMD_PIN_AVX_ABI TRUE CACHE INTERNAL "" FORCE) + message(STATUS "Working around libstdc++ AVX-512 bug " + "by pinning Math/Types.h to the 256-bit AVX ABI") + else() + message(STATUS "Disabling experimental/simd-based features: libstdc++ " + "header fails to compile in this configuration") + set(ROOT_HAVE_EXPERIMENTAL_SIMD FALSE CACHE INTERNAL "" FORCE) + endif() + endif() +endif() + #------------------------------------------------------------------------------------ # Check if the pyspark package is installed on the system. # Needed to run tests of the distributed RDataFrame module that use pyspark. diff --git a/config/RConfigure.in b/config/RConfigure.in index 7c81b9dd28025..7046c2e10c2e9 100644 --- a/config/RConfigure.in +++ b/config/RConfigure.in @@ -38,6 +38,7 @@ #@hascocoa@ R__HAS_COCOA /**/ #@hasvdt@ R__HAS_VDT /**/ #@hasstdexperimentalsimd@ R__HAS_STD_EXPERIMENTAL_SIMD /**/ +#@experimentalsimdpinavxabi@ R__EXPERIMENTAL_SIMD_PIN_AVX_ABI /**/ #@usecxxmodules@ R__USE_CXXMODULES /**/ #@uselibc++@ R__USE_LIBCXX /**/ #@has_found_attribute_always_inline@ R__HAS_ATTRIBUTE_ALWAYS_INLINE /**/ diff --git a/math/mathcore/inc/Math/Types.h b/math/mathcore/inc/Math/Types.h index f849d9af92bbc..ad5adb0393d54 100644 --- a/math/mathcore/inc/Math/Types.h +++ b/math/mathcore/inc/Math/Types.h @@ -13,8 +13,21 @@ namespace ROOT { namespace Internal { +#if defined(R__EXPERIMENTAL_SIMD_PIN_AVX_ABI) && defined(__AVX512F__) +// 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. When AVX-512 is +// enabled in this TU we'd otherwise hit that path, so pin to the 256-bit AVX +// ABI instead. The fallback is guarded by __AVX512F__ so that environments +// without AVX-512 in scope (notably rootcling/cling, which parses headers +// without -mavx*) still see the regular `native` ABI and pick the +// always-supported scalar fallback. +template +using SIMDTag = std::experimental::simd_abi::__avx; +#else template using SIMDTag = std::experimental::simd_abi::native; +#endif } // namespace Internal