diff --git a/stl/inc/limits b/stl/inc/limits index 9421c6d3088..bd7225aa540 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1051,9 +1051,20 @@ _NODISCARD constexpr int _Popcount_fallback(_Ty _Val) noexcept { return static_cast(_Val >> (_Digits - 8)); } -#if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) +#if (defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ + && !defined(__INTEL_COMPILER) +#define _HAS_TZCNT_BSF_INTRINSICS 1 +#else // ^^^ intrinsics available ^^^ / vvv intrinsics unavailable vvv +#define _HAS_TZCNT_BSF_INTRINSICS 0 +#endif // ^^^ intrinsics unavailable ^^^ + +#if _HAS_TZCNT_BSF_INTRINSICS extern "C" { extern int __isa_available; +} + +#if _HAS_CXX20 + #ifdef __clang__ #define _TZCNT_U32 __builtin_ia32_tzcnt_u32 #define _TZCNT_U64 __builtin_ia32_tzcnt_u64 @@ -1061,7 +1072,6 @@ extern int __isa_available; #define _TZCNT_U32 _tzcnt_u32 #define _TZCNT_U64 _tzcnt_u64 #endif // __clang__ -} template _NODISCARD int _Countr_zero_tzcnt(const _Ty _Val) noexcept { @@ -1088,6 +1098,9 @@ _NODISCARD int _Countr_zero_tzcnt(const _Ty _Val) noexcept { } } +#undef _TZCNT_U32 +#undef _TZCNT_U64 + template _NODISCARD int _Countr_zero_bsf(const _Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; @@ -1137,9 +1150,9 @@ _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { #endif // __AVX2__ } -#undef _TZCNT_U32 -#undef _TZCNT_U64 -#endif // defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) +#endif // _HAS_CXX20 + +#endif // _HAS_TZCNT_BSF_INTRINSICS #if (defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ && !defined(__INTEL_COMPILER) @@ -1190,13 +1203,11 @@ constexpr bool _Is_standard_unsigned_integer = template , int> = 0> _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { -#if defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) -#if _HAS_CXX20 +#if _HAS_CXX20 && _HAS_TZCNT_BSF_INTRINSICS if (!_STD is_constant_evaluated()) { return _Checked_x86_x64_countr_zero(_Val); } -#endif // _HAS_CXX20 -#endif // defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) +#endif // _HAS_CXX20 && _HAS_TZCNT_BSF_INTRINSICS // C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation. return _Countr_zero_fallback(_Val); } @@ -1243,6 +1254,7 @@ _CONSTEXPR20 decltype(auto) _Select_popcount_impl(_Fn _Callback) { } #undef _HAS_POPCNT_INTRINSICS +#undef _HAS_TZCNT_BSF_INTRINSICS #undef _HAS_NEON_INTRINSICS _STD_END diff --git a/tests/std/tests/GH_001103_countl_zero_correctness/test.cpp b/tests/std/tests/GH_001103_countl_zero_correctness/test.cpp index f9b389658e6..b2465871e13 100644 --- a/tests/std/tests/GH_001103_countl_zero_correctness/test.cpp +++ b/tests/std/tests/GH_001103_countl_zero_correctness/test.cpp @@ -3,13 +3,11 @@ #include #include +#include -// Indirectly test countl_zero on old x86/x64 processors by testing a private helper, +// Indirectly test countl_zero/countr_zero on old x86/x64 processors by testing a private helper, // which is different from the usual branch. -// Currently need this test only in C++20 mode; -// may update to older C++ if the helper is used internally too, for example in . - using namespace std; int main() { @@ -42,26 +40,31 @@ int main() { assert(_Countr_zero_bsf(static_cast(0x00)) == 8); assert(_Countr_zero_bsf(static_cast(0x13)) == 0); + assert(_Countr_zero_bsf(static_cast(0x82)) == 1); assert(_Countr_zero_bsf(static_cast(0x80)) == 7); assert(_Countr_zero_bsf(static_cast(0xF8)) == 3); assert(_Countr_zero_bsf(static_cast(0x0000)) == 16); assert(_Countr_zero_bsf(static_cast(0x0013)) == 0); + assert(_Countr_zero_bsf(static_cast(0x8002)) == 1); assert(_Countr_zero_bsf(static_cast(0x8000)) == 15); assert(_Countr_zero_bsf(static_cast(0xF008)) == 3); assert(_Countr_zero_bsf(static_cast(0x0000'0000)) == 32); assert(_Countr_zero_bsf(static_cast(0x0000'0013)) == 0); + assert(_Countr_zero_bsf(static_cast(0x8000'0002)) == 1); assert(_Countr_zero_bsf(static_cast(0x8000'0000)) == 31); assert(_Countr_zero_bsf(static_cast(0xF000'0008)) == 3); assert(_Countr_zero_bsf(static_cast(0x0000'0000)) == 32); assert(_Countr_zero_bsf(static_cast(0x0000'0013)) == 0); + assert(_Countr_zero_bsf(static_cast(0x8000'0002)) == 1); assert(_Countr_zero_bsf(static_cast(0x8000'0000)) == 31); assert(_Countr_zero_bsf(static_cast(0xF000'0008)) == 3); assert(_Countr_zero_bsf(static_cast(0x0000'0000'0000'0000)) == 64); assert(_Countr_zero_bsf(static_cast(0x0000'0000'0000'0013)) == 0); + assert(_Countr_zero_bsf(static_cast(0x8000'0000'0000'0002)) == 1); assert(_Countr_zero_bsf(static_cast(0x8000'0000'0000'0000)) == 63); assert(_Countr_zero_bsf(static_cast(0xF000'0000'0000'0008)) == 3); #endif // ^^^ defined(_M_IX86) || defined(_M_X64) ^^^