diff --git a/stl/inc/limits b/stl/inc/limits index 7294c8e4781..3346c8126d3 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1063,8 +1063,6 @@ 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 @@ -1150,8 +1148,6 @@ _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { #endif // __AVX2__ } -#endif // _HAS_CXX20 - #endif // _HAS_TZCNT_BSF_INTRINSICS #if (defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ @@ -1202,16 +1198,39 @@ constexpr bool _Is_standard_unsigned_integer = _Is_any_of_v, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>; template , int> = 0> -_NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { -#if _HAS_CXX20 && _HAS_TZCNT_BSF_INTRINSICS - if (!_STD is_constant_evaluated()) { +_NODISCARD _CONSTEXPR20 int _Countr_zero(const _Ty _Val) noexcept { +#if _HAS_TZCNT_BSF_INTRINSICS +#if _HAS_CXX20 + if (!_STD is_constant_evaluated()) +#endif // _HAS_CXX20 + { return _Checked_x86_x64_countr_zero(_Val); } -#endif // _HAS_CXX20 && _HAS_TZCNT_BSF_INTRINSICS - // C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation. +#endif // _HAS_TZCNT_BSF_INTRINSICS return _Countr_zero_fallback(_Val); } +template +constexpr decltype(auto) _Select_countr_zero_impl(_Fn _Callback) { + // TRANSITION, DevCom-1527995: Lambdas in this function ensure inlining +#if _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 + if (!_STD is_constant_evaluated()) { +#ifdef __AVX2__ + return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); }); +#else // ^^^ AVX2 ^^^ / vvv not AVX2 vvv + const bool _Definitely_have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; + if (_Definitely_have_tzcnt) { + return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); }); + } else { + return _Callback([](_Ty _Val) { return _Countr_zero_bsf(_Val); }); + } +#endif // ^^^ not AVX2 ^^^ + } +#endif // ^^^ _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 ^^^ + // C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation. + return _Callback([](_Ty _Val) { return _Countr_zero_fallback(_Val); }); +} + template , int> _Enabled = 0> _NODISCARD _CONSTEXPR20 int _Popcount(const _Ty _Val) noexcept { #if _HAS_POPCNT_INTRINSICS || _HAS_NEON_INTRINSICS diff --git a/stl/inc/numeric b/stl/inc/numeric index 78426de63f1..44c62bda57b 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -548,35 +548,37 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) n // calculate greatest common divisor static_assert(_Is_nonbool_integral<_Mt> && _Is_nonbool_integral<_Nt>, "GCD requires nonbool integral types"); - using _Common = common_type_t<_Mt, _Nt>; - using _Common_unsigned = make_unsigned_t<_Common>; - _Common_unsigned _Mx_magnitude = _Abs_u(_Mx); - _Common_unsigned _Nx_magnitude = _Abs_u(_Nx); - if (_Mx_magnitude == 0U) { - return static_cast<_Common>(_Nx_magnitude); - } - - if (_Nx_magnitude == 0U) { - return static_cast<_Common>(_Mx_magnitude); - } + using _Common = common_type_t<_Mt, _Nt>; + using _Common_unsigned = make_unsigned_t<_Common>; + + return _Select_countr_zero_impl<_Common_unsigned>([=](auto _Countr_zero_impl) { + _Common_unsigned _Mx_magnitude = _Abs_u(_Mx); + _Common_unsigned _Nx_magnitude = _Abs_u(_Nx); + if (_Mx_magnitude == 0U) { + return static_cast<_Common>(_Nx_magnitude); + } - const auto _Mx_trailing_zeroes = static_cast(_Countr_zero(_Mx_magnitude)); - const auto _Common_factors_of_2 = - (_STD min)(_Mx_trailing_zeroes, static_cast(_Countr_zero(_Nx_magnitude))); - _Nx_magnitude >>= _Common_factors_of_2; - _Mx_magnitude >>= _Mx_trailing_zeroes; - do { - _Nx_magnitude >>= static_cast(_Countr_zero(_Nx_magnitude)); - if (_Mx_magnitude > _Nx_magnitude) { - _Common_unsigned _Temp = _Mx_magnitude; - _Mx_magnitude = _Nx_magnitude; - _Nx_magnitude = _Temp; + if (_Nx_magnitude == 0U) { + return static_cast<_Common>(_Mx_magnitude); } - _Nx_magnitude -= _Mx_magnitude; - } while (_Nx_magnitude != 0U); + const auto _Mx_trailing_zeroes = static_cast(_Countr_zero_impl(_Mx_magnitude)); + const auto _Common_factors_of_2 = + (_STD min)(_Mx_trailing_zeroes, static_cast(_Countr_zero_impl(_Nx_magnitude))); + _Nx_magnitude >>= _Common_factors_of_2; + _Mx_magnitude >>= _Mx_trailing_zeroes; + do { + _Nx_magnitude >>= static_cast(_Countr_zero_impl(_Nx_magnitude)); + if (_Mx_magnitude > _Nx_magnitude) { + _Common_unsigned _Temp = _Mx_magnitude; + _Mx_magnitude = _Nx_magnitude; + _Nx_magnitude = _Temp; + } - return static_cast<_Common>(_Mx_magnitude << _Common_factors_of_2); + _Nx_magnitude -= _Mx_magnitude; + } while (_Nx_magnitude != 0U); + return static_cast<_Common>(_Mx_magnitude << _Common_factors_of_2); + }); } template diff --git a/tests/std/tests/Dev11_1074023_constexpr/test.cpp b/tests/std/tests/Dev11_1074023_constexpr/test.cpp index 3b2cec30167..5bd52e78b6a 100644 --- a/tests/std/tests/Dev11_1074023_constexpr/test.cpp +++ b/tests/std/tests/Dev11_1074023_constexpr/test.cpp @@ -30,6 +30,7 @@ #include #endif // _M_CEE #include +#include #include #include #include @@ -956,6 +957,27 @@ static_assert(hardware_constructive_interference_size == 64); static_assert(hardware_destructive_interference_size == 64); #endif // _HAS_CXX17 +// P0295R0 gcd(), lcm() +constexpr bool test_gcd_lcm() { +#if _HAS_CXX17 + assert(gcd(0, 0) == 0); + assert(gcd(3125, 2401) == 1); + assert(gcd(3840, 2160) == 240); + assert(gcd(4096, 8192) == 4096); + assert(gcd(19937, 19937) == 19937); + + assert(lcm(0, 0) == 0); + assert(lcm(0, 1729) == 0); + assert(lcm(1729, 0) == 0); + assert(lcm(1729, 1729) == 1729); + assert(lcm(4096, 8192) == 8192); + assert(lcm(1920, 1200) == 9600); + assert(lcm(25, 49) == 1225); +#endif // _HAS_CXX17 + + return true; +} + int main() { test_all_constants(); test_all_bitmasks(); @@ -1020,4 +1042,8 @@ int main() { == "1111111011011100101110101001100001110110010101000011001000010000"); assert(bitset<75>(0xFEDCBA9876543210ULL).to_string() == "000000000001111111011011100101110101001100001110110010101000011001000010000"); + + // P0295R0 gcd(), lcm() + test_gcd_lcm(); + STATIC_ASSERT(test_gcd_lcm()); }