From b17789281d90317b0892973676ba656c7ace7537 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 31 Mar 2020 14:31:43 -0700 Subject: [PATCH 01/37] work on msvc bit enablement. update bit for msvc (more updates) fixup arm countr and popcount small comment about intended widening. --- stl/inc/bit | 183 +++++++++++++++++- .../test.cpp | 37 +++- 2 files changed, 205 insertions(+), 15 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 2700af09d4b..b61217b2d3a 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -12,6 +12,7 @@ #pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv +#include #include #include @@ -94,17 +95,177 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } } -template , int> _Enabled> -_NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { + +inline bool _Intel_is_popcnt_supported() { + int cpuinfo[4]; + __cpuid(cpuinfo, 0x01); + return cpuinfo[2] & (1 << 23); +} + +inline bool _Intel_is_lzcnt_supported() { + int cpuinfo[4]; + __cpuid(cpuinfo, 0x80000001); + return cpuinfo[2] & (1 << 5); +} + +inline bool _Intel_is_tzcnt_supported() { + // tzcnt and lzcnt support are indicated with + // different cpuid flags. + int cpuinfo[4]; + __cpuid(cpuinfo, 0x07); + return cpuinfo[1] & (1 << 3); +} + +// see "Hacker's Delight" section 5-3 +template +constexpr int _Countl_zero_helper(T x) { + T y = 0; + int n = numeric_limits::digits; + int c = numeric_limits::digits / 2; + do { + y = x >> c; + if (y != 0) { + n = n - c; + x = y; + } + c = c >> 1; + } while (c != 0); + return n - (int) x; +} + +// see "Hacker's Delight" section 5-4 +template +constexpr int _Countr_zero_helper(T x) { + return numeric_limits::digits - _Countl_zero_helper(~x & (x - 1)); +} + +template +constexpr int _Popcount_helper(T x) { + constexpr int _Digits = numeric_limits::digits; + // we static cast these bit patterns in order to truncate + // them to the correct size + x = x - ((x >> 1) & static_cast(0x5555555555555555ull)); + x = (x & static_cast(0x3333333333333333ull)) + ((x >> 2) & static_cast(0x3333333333333333ull)); + x = (x + (x >> 4)) & static_cast(0x0F0F0F0F0F0F0F0Full); + for (int _ShiftDigits = numeric_limits::digits; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { + x = x + (x >> _ShiftDigits); + } + // we want the bottom "slot" that's big enough to store _Digits + return x & (_Digits + _Digits - 1); +} + +#if defined(_M_IX86) || defined(_M_X64) + +template +inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { + static bool _Have_lzcnt = _Intel_is_lzcnt_supported(); + constexpr int _Digits = numeric_limits<_Ty>::digits; + // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero + if (!_Have_lzcnt && _Val == 0) { + return _Digits; + } + // we use lzcnt (actually bsr if lzcnt is not supported) for all cases now we know + // we're not zero. We can do this because lzcnt and bsr share the same instruction + // encoding. + if (_Digits <= 16) { + return __lzcnt16(_Val) - (16 - _Digits); + } else if (_Digits <= 32) { + return __lzcnt(_Val) - (32 - _Digits); + } else { +#ifdef _M_IX86 + if (_Have_lzcnt) { + return (__lzcnt(_Val >> 32) + __lzcnt(static_cast(_Val)) - (64 - _Digits); + } else { + unsigned int _High = _Val >> 32; + unsigned int _Low = static_cast(_Val); + int _Result = 0; + _Result += _High ? __lzcnt(_High) : 0; + _Result += _Low ? __lzcnt(_Low) : 0; + return result; + } +#else + return __lzcnt64(_Val) - (64 - _Digits); +#endif + } + // note we don't need to call a fallback here because + // all supported intel processors at least have bsr/bsf +} + +template +inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { + static bool _Have_tzcnt = _Intel_is_tzcnt_supported(); + constexpr int _Digits = numeric_limits<_Ty>::digits; + constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); + if (!_Have_tzcnt && _Val == 0) { + return _Digits; + } + if (_Digits <= 32) { + // intended widening to int + return _tzcnt_u32(~_Max | _Val); + } else { +#ifdef _M_IX86 + unsigned int _High = _Val >> 32; + unsigned int _Low = static_cast(_Val); + int _Result = 0; + _Result += _High ? _tzcnt_u32(_High) : 0; + _Result += _Low ? _tzcnt_u32(_Low) : 0; + return _Result; +#else + return _tzcnt_u64(_Val); +#endif + } +} + +template +inline int _Checked_x86_x86_64_popcount(_Ty _Val) { + static bool _Have_popcnt = _Intel_is_popcnt_supported(); + constexpr int _Digits = numeric_limits<_Ty>::digits; + if (_Have_popcnt) { + if constexpr (_Digits <= 16) { + return __popcnt16(_Val); + } else if (_Digits <= 32) { + return __popcnt(_Val); + } else { +#ifdef _M_IX86 + return __popcnt(_Val >> 32) + __popcnt(static_cast(_Val)); +#else + return __popcnt64(_Val); +#endif + } + } else { + _Popcount_helper(_Val); + } +} +#endif // defined(_M_IX86) || defined(_M_X64) + + +#if defined(_M_ARM) || defined(_M_ARM64) +template +inline int _Checked_arm_countl_zero(_Ty _Val) { constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Val == 0) { return _Digits; } + if constexpr (_Digits <= 32) { + return _CountLeadingZeros(_Val); + } else { + return _CountLeadingZeros64(_Val); + } +} +#endif // defined(_M_ARM) || defined(_M_ARM64) - if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { - return __builtin_clz(_Val) - (numeric_limits::digits - _Digits); +template , int> _Enabled> +_NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { + if (is_constant_evaluated()) { + return _Countl_zero_helper(_Val); } else { - return __builtin_clzll(_Val) - (numeric_limits::digits - _Digits); +#if defined(_M_IX86) || defined(_M_X64) + return _Checked_x86_x86_64_countl_zero(_Val); +#elif defined(_M_ARM) || defined(_M_ARM64) + return _Checked_arm_countl_zero(_Val); +#else + return _Countl_zero_helper(_Val); +#endif } } @@ -125,10 +286,16 @@ _NODISCARD constexpr int countr_one(const _Ty _Val) noexcept { template , int> _Enabled = 0> _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { - if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { - return __builtin_popcount(_Val); + if (is_constant_evaluated()) { + return _Popcount_helper(_Val); } else { - return __builtin_popcountll(_Val); +#if defined(_M_IX86) || defined(_M_X64) + return _Checked_x86_x86_64_popcount(_Val); +#else + // arm NEON has a popcount instruction, but we're not going to use that + // yet. + return _Popcount_helper(_Val); +#endif } } #endif // __cpp_lib_bitops diff --git a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp index c7e45f1f05c..b6b6540ddf9 100644 --- a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp +++ b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp @@ -105,6 +105,27 @@ constexpr bool test_rotr() { return true; } +// tests functions for 64bit operands that +// have either high or low halves as zero +// these may be split into two operations +// on 32bit platforms and we need to check +// if we handle the == zero or == ones cases +// correctly +constexpr bool test_64bit_split_ops() { + constexpr unsigned long long zero_one = 0x0000'0000'FFFF'FFFF; + constexpr unsigned long long one_zero = 0xFFFF'FFFF'0000'0000; + assert(popcount(zero_one) == 32); + assert(popcount(one_zero) == 32); + assert(countr_zero(zero_one) == 0); + assert(countr_zero(one_zero) == 32); + assert(countl_zero(zero_one) == 32); + assert(countl_zero(one_zero) == 0); + assert(countr_one(zero_one) == 32); + assert(countr_one(one_zero) == 0); + assert(countl_one(zero_one) == 0); + assert(countl_one(one_zero) == 32); + return true; +} template constexpr bool test_popcount_specialcases() { constexpr int digits = numeric_limits::digits; @@ -141,20 +162,22 @@ template void test_all() { static_assert(test_countl_zero()); test_countl_zero(); - static_assert(test_countr_zero()); + // static_assert(test_countr_zero()); test_countr_zero(); - static_assert(test_countl_one()); + // static_assert(test_countl_one()); test_countl_one(); - static_assert(test_countr_one()); + // static_assert(test_countr_one()); test_countr_one(); - static_assert(test_popcount()); + // static_assert(test_popcount()); test_popcount(); - static_assert(test_rotl()); + // static_assert(test_rotl()); test_rotl(); - static_assert(test_rotr()); + // static_assert(test_rotr()); test_rotr(); - static_assert(test_popcount_specialcases()); + // static_assert(test_popcount_specialcases()); test_popcount_specialcases(); + // static_assert(test_64bit_split_ops()); + test_64bit_split_ops(); } #endif // __cpp_lib_bitops From e7c0fb3d5b794c305c7390e9c5b116838a268ef2 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 20 Apr 2020 18:24:42 -0700 Subject: [PATCH 02/37] move some bit things to limtis --- stl/inc/bit | 56 -------------------------------------- stl/inc/limits | 74 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 63 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index b61217b2d3a..e7ffb7aa575 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -108,37 +108,6 @@ inline bool _Intel_is_lzcnt_supported() { return cpuinfo[2] & (1 << 5); } -inline bool _Intel_is_tzcnt_supported() { - // tzcnt and lzcnt support are indicated with - // different cpuid flags. - int cpuinfo[4]; - __cpuid(cpuinfo, 0x07); - return cpuinfo[1] & (1 << 3); -} - -// see "Hacker's Delight" section 5-3 -template -constexpr int _Countl_zero_helper(T x) { - T y = 0; - int n = numeric_limits::digits; - int c = numeric_limits::digits / 2; - do { - y = x >> c; - if (y != 0) { - n = n - c; - x = y; - } - c = c >> 1; - } while (c != 0); - return n - (int) x; -} - -// see "Hacker's Delight" section 5-4 -template -constexpr int _Countr_zero_helper(T x) { - return numeric_limits::digits - _Countl_zero_helper(~x & (x - 1)); -} - template constexpr int _Popcount_helper(T x) { constexpr int _Digits = numeric_limits::digits; @@ -191,31 +160,6 @@ inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { // all supported intel processors at least have bsr/bsf } -template -inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { - static bool _Have_tzcnt = _Intel_is_tzcnt_supported(); - constexpr int _Digits = numeric_limits<_Ty>::digits; - constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); - if (!_Have_tzcnt && _Val == 0) { - return _Digits; - } - if (_Digits <= 32) { - // intended widening to int - return _tzcnt_u32(~_Max | _Val); - } else { -#ifdef _M_IX86 - unsigned int _High = _Val >> 32; - unsigned int _Low = static_cast(_Val); - int _Result = 0; - _Result += _High ? _tzcnt_u32(_High) : 0; - _Result += _Low ? _tzcnt_u32(_Low) : 0; - return _Result; -#else - return _tzcnt_u64(_Val); -#endif - } -} - template inline int _Checked_x86_x86_64_popcount(_Ty _Val) { static bool _Have_popcnt = _Intel_is_popcnt_supported(); diff --git a/stl/inc/limits b/stl/inc/limits index 6bfa75c2b09..cd00874ad7b 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -11,6 +11,7 @@ #include #include #include +#include #include #pragma pack(push, _CRT_PACKING) @@ -1010,20 +1011,79 @@ public: }; #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 + +inline bool _Intel_is_tzcnt_supported() { + // tzcnt and lzcnt support are indicated with + // different cpuid flags. + int cpuinfo[4]; + __cpuid(cpuinfo, 0x07); + return cpuinfo[1] & (1 << 3); +} + +// see "Hacker's Delight" section 5-3 +template +constexpr int _Countl_zero_helper(T x) { + T y = 0; + int n = numeric_limits::digits; + int c = numeric_limits::digits / 2; + do { + y = x >> c; + if (y != 0) { + n = n - c; + x = y; + } + c = c >> 1; + } while (c != 0); + return n - (int) x; +} + +// see "Hacker's Delight" section 5-4 +template +constexpr int _Countr_zero_helper(T x) { + return numeric_limits::digits - _Countl_zero_helper(~x & (x - 1)); +} + +#if defined(_M_IX86) || defined(_M_X64) +template +inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { + static bool _Have_tzcnt = _Intel_is_tzcnt_supported(); + constexpr int _Digits = numeric_limits<_Ty>::digits; + constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); + if (!_Have_tzcnt && _Val == 0) { + return _Digits; + } + if (_Digits <= 32) { + // intended widening to int + return _tzcnt_u32(~_Max | _Val); + } else { +#ifdef _M_IX86 + unsigned int _High = _Val >> 32; + unsigned int _Low = static_cast(_Val); + int _Result = 0; + _Result += _High ? _tzcnt_u32(_High) : 0; + _Result += _Low ? _tzcnt_u32(_Low) : 0; + return _Result; +#else + return _tzcnt_u64(_Val); +#endif + } +} +#endif + template inline 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 (_Val == 0) { - return numeric_limits<_Ty>::digits; - } - - if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { - return __builtin_ctz(_Val); + if (is_constant_evaluated()) { + return _Countr_zero_helper(_Val); } else { - return __builtin_ctzll(_Val); +#if defined(_M_IX86) || defined(_M_X64) + return _Checked_x86_x86_64_countr_zero(_Val); +#else + return _Countr_zero_helper(_Val); +#endif } } #endif // __cpp_lib_bitops From c4d43186d8b51b0c7ada6509c31af13fd4237e4f Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 22 Apr 2020 20:54:13 -0700 Subject: [PATCH 03/37] activate bit on msvc --- stl/inc/bit | 38 +++++++++++++++++++------------------- stl/inc/limits | 16 +++++++++------- stl/inc/yvals_core.h | 6 +----- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index e7ffb7aa575..548f80a4237 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -96,13 +96,13 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } -inline bool _Intel_is_popcnt_supported() { +inline bool __Is_popcnt_supported() { int cpuinfo[4]; __cpuid(cpuinfo, 0x01); return cpuinfo[2] & (1 << 23); } -inline bool _Intel_is_lzcnt_supported() { +inline bool _Is_lzcnt_supported() { int cpuinfo[4]; __cpuid(cpuinfo, 0x80000001); return cpuinfo[2] & (1 << 5); @@ -113,21 +113,21 @@ constexpr int _Popcount_helper(T x) { constexpr int _Digits = numeric_limits::digits; // we static cast these bit patterns in order to truncate // them to the correct size - x = x - ((x >> 1) & static_cast(0x5555555555555555ull)); - x = (x & static_cast(0x3333333333333333ull)) + ((x >> 2) & static_cast(0x3333333333333333ull)); - x = (x + (x >> 4)) & static_cast(0x0F0F0F0F0F0F0F0Full); + x = static_cast(x - ((x >> 1) & static_cast(0x5555555555555555ull))); + x = static_cast((x & static_cast(0x3333333333333333ull)) + ((x >> 2) & static_cast(0x3333333333333333ull))); + x = static_cast((x + (x >> 4)) & static_cast(0x0F0F0F0F0F0F0F0Full)); for (int _ShiftDigits = numeric_limits::digits; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { - x = x + (x >> _ShiftDigits); + x = static_cast(x + static_cast(x >> _ShiftDigits)); } // we want the bottom "slot" that's big enough to store _Digits - return x & (_Digits + _Digits - 1); + return static_cast(x & (_Digits + _Digits - 1)); } #if defined(_M_IX86) || defined(_M_X64) template inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { - static bool _Have_lzcnt = _Intel_is_lzcnt_supported(); + static bool _Have_lzcnt = _Is_lzcnt_supported(); constexpr int _Digits = numeric_limits<_Ty>::digits; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero if (!_Have_lzcnt && _Val == 0) { @@ -136,10 +136,10 @@ inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { // we use lzcnt (actually bsr if lzcnt is not supported) for all cases now we know // we're not zero. We can do this because lzcnt and bsr share the same instruction // encoding. - if (_Digits <= 16) { - return __lzcnt16(_Val) - (16 - _Digits); - } else if (_Digits <= 32) { - return __lzcnt(_Val) - (32 - _Digits); + if constexpr (_Digits <= 16) { + return static_cast(__lzcnt16(_Val) - (16 - _Digits)); + } else if constexpr (_Digits <= 32) { + return static_cast(__lzcnt(_Val) - (32 - _Digits)); } else { #ifdef _M_IX86 if (_Have_lzcnt) { @@ -153,7 +153,7 @@ inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { return result; } #else - return __lzcnt64(_Val) - (64 - _Digits); + return static_cast(__lzcnt64(_Val) - (64 - _Digits)); #endif } // note we don't need to call a fallback here because @@ -162,18 +162,18 @@ inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { template inline int _Checked_x86_x86_64_popcount(_Ty _Val) { - static bool _Have_popcnt = _Intel_is_popcnt_supported(); + static bool _Have_popcnt = __Is_popcnt_supported(); constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Have_popcnt) { if constexpr (_Digits <= 16) { - return __popcnt16(_Val); - } else if (_Digits <= 32) { - return __popcnt(_Val); + return static_cast(__popcnt16(_Val)); + } else if constexpr (_Digits <= 32) { + return static_cast(__popcnt(_Val)); } else { #ifdef _M_IX86 - return __popcnt(_Val >> 32) + __popcnt(static_cast(_Val)); + return static_cast(__popcnt(_Val >> 32) + __popcnt(static_cast(_Val))); #else - return __popcnt64(_Val); + return static_cast(__popcnt64(_Val)); #endif } } else { diff --git a/stl/inc/limits b/stl/inc/limits index cd00874ad7b..789db244dff 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -1012,7 +1013,7 @@ public: #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 -inline bool _Intel_is_tzcnt_supported() { +inline bool _Is_tzcnt_supported() { // tzcnt and lzcnt support are indicated with // different cpuid flags. int cpuinfo[4]; @@ -1023,11 +1024,12 @@ inline bool _Intel_is_tzcnt_supported() { // see "Hacker's Delight" section 5-3 template constexpr int _Countl_zero_helper(T x) { - T y = 0; - int n = numeric_limits::digits; - int c = numeric_limits::digits / 2; + T y = 0; + + unsigned int n = numeric_limits::digits; + unsigned int c = numeric_limits::digits / 2; do { - y = x >> c; + y = static_cast(x >> c); if (y != 0) { n = n - c; x = y; @@ -1046,13 +1048,13 @@ constexpr int _Countr_zero_helper(T x) { #if defined(_M_IX86) || defined(_M_X64) template inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { - static bool _Have_tzcnt = _Intel_is_tzcnt_supported(); + static bool _Have_tzcnt = _Is_tzcnt_supported(); constexpr int _Digits = numeric_limits<_Ty>::digits; constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); if (!_Have_tzcnt && _Val == 0) { return _Digits; } - if (_Digits <= 32) { + if constexpr (_Digits <= 32) { // intended widening to int return _tzcnt_u32(~_Max | _Val); } else { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 62129945867..15213617437 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1141,11 +1141,7 @@ #define __cpp_lib_bind_front 201907L #define __cpp_lib_bit_cast 201806L -#ifdef __clang__ // TRANSITION, VSO-1020212 -// a future MSVC update will embed CPU feature detection into intrinsics -#define __cpp_lib_bitops 201907L -#endif // __clang__ - +#define __cpp_lib_bitops 201907L #define __cpp_lib_bounded_array_traits 201902L #ifdef __cpp_char8_t From 10ff9a253a306cf45323a8c6ce05d7d311fe37bd Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 30 Apr 2020 12:45:10 -0700 Subject: [PATCH 04/37] suppress warnings for now. --- stl/inc/bit | 10 +++++++--- stl/inc/limits | 12 +++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 548f80a4237..f32e99049fe 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -108,13 +108,17 @@ inline bool _Is_lzcnt_supported() { return cpuinfo[2] & (1 << 5); } +#pragma warning(push) +#pragma warning(disable : 4640) + template constexpr int _Popcount_helper(T x) { constexpr int _Digits = numeric_limits::digits; // we static cast these bit patterns in order to truncate // them to the correct size x = static_cast(x - ((x >> 1) & static_cast(0x5555555555555555ull))); - x = static_cast((x & static_cast(0x3333333333333333ull)) + ((x >> 2) & static_cast(0x3333333333333333ull))); + x = static_cast( + (x & static_cast(0x3333333333333333ull)) + ((x >> 2) & static_cast(0x3333333333333333ull))); x = static_cast((x + (x >> 4)) & static_cast(0x0F0F0F0F0F0F0F0Full)); for (int _ShiftDigits = numeric_limits::digits; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { x = static_cast(x + static_cast(x >> _ShiftDigits)); @@ -177,7 +181,7 @@ inline int _Checked_x86_x86_64_popcount(_Ty _Val) { #endif } } else { - _Popcount_helper(_Val); + return _Popcount_helper(_Val); } } #endif // defined(_M_IX86) || defined(_M_X64) @@ -212,7 +216,7 @@ _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { #endif } } - +#pragma warning(pop) template , int> = 0> _NODISCARD constexpr int countl_one(const _Ty _Val) noexcept { return _STD countl_zero(static_cast<_Ty>(~_Val)); diff --git a/stl/inc/limits b/stl/inc/limits index 789db244dff..065b1ca4c55 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1021,6 +1021,7 @@ inline bool _Is_tzcnt_supported() { return cpuinfo[1] & (1 << 3); } + // see "Hacker's Delight" section 5-3 template constexpr int _Countl_zero_helper(T x) { @@ -1036,7 +1037,7 @@ constexpr int _Countl_zero_helper(T x) { } c = c >> 1; } while (c != 0); - return n - (int) x; + return static_cast(n) - static_cast(x); } // see "Hacker's Delight" section 5-4 @@ -1044,7 +1045,8 @@ template constexpr int _Countr_zero_helper(T x) { return numeric_limits::digits - _Countl_zero_helper(~x & (x - 1)); } - +#pragma warning(push) +#pragma warning(disable : 4640) #if defined(_M_IX86) || defined(_M_X64) template inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { @@ -1056,7 +1058,7 @@ inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { } if constexpr (_Digits <= 32) { // intended widening to int - return _tzcnt_u32(~_Max | _Val); + return static_cast(_tzcnt_u32(static_cast(~_Max | _Val))); } else { #ifdef _M_IX86 unsigned int _High = _Val >> 32; @@ -1066,12 +1068,12 @@ inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { _Result += _Low ? _tzcnt_u32(_Low) : 0; return _Result; #else - return _tzcnt_u64(_Val); + return static_cast(_tzcnt_u64(_Val)); #endif } } #endif - +#pragma warning(pop) template inline constexpr bool _Is_standard_unsigned_integer = _Is_any_of_v, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>; From 66a8678dca9f2fb6b8919ca976d100491e2350ab Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 30 Apr 2020 14:15:05 -0700 Subject: [PATCH 05/37] activate feature test macros for msvc bit --- tests/std/tests/VSO_0157762_feature_test_macros/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index df60d451449..6e6be315c88 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -189,7 +189,7 @@ STATIC_ASSERT(__cpp_lib_bit_cast == 201806L); #endif #endif -#if _HAS_CXX20 && defined(__clang__) // TRANSITION, VSO-1020212 +#if _HAS_CXX20 #ifndef __cpp_lib_bitops #error __cpp_lib_bitops is not defined #elif __cpp_lib_bitops != 201907L @@ -641,7 +641,7 @@ STATIC_ASSERT(__cpp_lib_hypot == 201603L); STATIC_ASSERT(__cpp_lib_incomplete_container_elements == 201505L); #endif -#if _HAS_CXX20 && defined(__clang__) // TRANSITION, VSO-1020212 +#if _HAS_CXX20 #ifndef __cpp_lib_int_pow2 #error __cpp_lib_int_pow2 is not defined #elif __cpp_lib_int_pow2 != 202002L From 9b126dec87892dc8c5260a81bdc5804859957f37 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 30 Apr 2020 14:25:58 -0700 Subject: [PATCH 06/37] uglify names --- stl/inc/bit | 18 +++++++++--------- stl/inc/limits | 30 +++++++++++++++--------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index f32e99049fe..7b267364f68 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -111,20 +111,20 @@ inline bool _Is_lzcnt_supported() { #pragma warning(push) #pragma warning(disable : 4640) -template -constexpr int _Popcount_helper(T x) { - constexpr int _Digits = numeric_limits::digits; +template +constexpr int _Popcount_helper(_Ty _Val) { + constexpr int _Digits = numeric_limits<_Ty>::digits; // we static cast these bit patterns in order to truncate // them to the correct size - x = static_cast(x - ((x >> 1) & static_cast(0x5555555555555555ull))); - x = static_cast( - (x & static_cast(0x3333333333333333ull)) + ((x >> 2) & static_cast(0x3333333333333333ull))); - x = static_cast((x + (x >> 4)) & static_cast(0x0F0F0F0F0F0F0F0Full)); + _Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555555555555555ull))); + _Val = static_cast<_Ty>( + (_Val & static_cast<_Ty>(0x3333333333333333ull)) + ((_Val >> 2) & static_cast<_Ty>(0x3333333333333333ull))); + _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F0F0F0F0F0F0Full)); for (int _ShiftDigits = numeric_limits::digits; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { - x = static_cast(x + static_cast(x >> _ShiftDigits)); + _Val = static_cast<_Ty>(_Val + static_cast<_Ty>(_Val >> _ShiftDigits)); } // we want the bottom "slot" that's big enough to store _Digits - return static_cast(x & (_Digits + _Digits - 1)); + return static_cast(_Val & (_Digits + _Digits - 1)); } #if defined(_M_IX86) || defined(_M_X64) diff --git a/stl/inc/limits b/stl/inc/limits index 065b1ca4c55..013790f5fab 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1023,27 +1023,27 @@ inline bool _Is_tzcnt_supported() { // see "Hacker's Delight" section 5-3 -template -constexpr int _Countl_zero_helper(T x) { - T y = 0; +template +constexpr int _Countl_zero_helper(_Ty _Val) { + _Ty _Yy = 0; - unsigned int n = numeric_limits::digits; - unsigned int c = numeric_limits::digits / 2; + unsigned int _Nn = numeric_limits<_Ty>::digits; + unsigned int _Cc = numeric_limits<_Ty>::digits / 2; do { - y = static_cast(x >> c); - if (y != 0) { - n = n - c; - x = y; + _Yy = static_cast(_Val >> _Cc); + if (_Yy != 0) { + _Nn = _Nn - _Cc; + _Val = _Yy; } - c = c >> 1; - } while (c != 0); - return static_cast(n) - static_cast(x); + _Cc = _Cc >> 1; + } while (_Cc != 0); + return static_cast(_Nn) - static_cast(_Val); } // see "Hacker's Delight" section 5-4 -template -constexpr int _Countr_zero_helper(T x) { - return numeric_limits::digits - _Countl_zero_helper(~x & (x - 1)); +template +constexpr int _Countr_zero_helper(_Ty _Val) { + return numeric_limits<_Ty>::digits - _Countl_zero_helper(~_Val & (_Val - 1)); } #pragma warning(push) #pragma warning(disable : 4640) From 3a533547c0d233b1855839f0704c263088fe2db2 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 5 May 2020 12:12:55 -0700 Subject: [PATCH 07/37] even more casts --- stl/inc/bit | 4 ++-- stl/inc/limits | 5 +++-- .../test.cpp | 16 ++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 7b267364f68..197e74744fd 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -120,11 +120,11 @@ constexpr int _Popcount_helper(_Ty _Val) { _Val = static_cast<_Ty>( (_Val & static_cast<_Ty>(0x3333333333333333ull)) + ((_Val >> 2) & static_cast<_Ty>(0x3333333333333333ull))); _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F0F0F0F0F0F0Full)); - for (int _ShiftDigits = numeric_limits::digits; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { + for (int _ShiftDigits = numeric_limits::digits; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { _Val = static_cast<_Ty>(_Val + static_cast<_Ty>(_Val >> _ShiftDigits)); } // we want the bottom "slot" that's big enough to store _Digits - return static_cast(_Val & (_Digits + _Digits - 1)); + return static_cast(_Val & static_cast<_Ty>(_Digits + _Digits - 1)); } #if defined(_M_IX86) || defined(_M_X64) diff --git a/stl/inc/limits b/stl/inc/limits index 013790f5fab..3d0983b5644 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1030,7 +1030,7 @@ constexpr int _Countl_zero_helper(_Ty _Val) { unsigned int _Nn = numeric_limits<_Ty>::digits; unsigned int _Cc = numeric_limits<_Ty>::digits / 2; do { - _Yy = static_cast(_Val >> _Cc); + _Yy = static_cast<_Ty>(_Val >> _Cc); if (_Yy != 0) { _Nn = _Nn - _Cc; _Val = _Yy; @@ -1043,7 +1043,8 @@ constexpr int _Countl_zero_helper(_Ty _Val) { // see "Hacker's Delight" section 5-4 template constexpr int _Countr_zero_helper(_Ty _Val) { - return numeric_limits<_Ty>::digits - _Countl_zero_helper(~_Val & (_Val - 1)); + return numeric_limits<_Ty>::digits + - _Countl_zero_helper(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); } #pragma warning(push) #pragma warning(disable : 4640) diff --git a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp index b6b6540ddf9..7a25e9ad4ec 100644 --- a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp +++ b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp @@ -162,21 +162,21 @@ template void test_all() { static_assert(test_countl_zero()); test_countl_zero(); - // static_assert(test_countr_zero()); + static_assert(test_countr_zero()); test_countr_zero(); - // static_assert(test_countl_one()); + static_assert(test_countl_one()); test_countl_one(); - // static_assert(test_countr_one()); + static_assert(test_countr_one()); test_countr_one(); - // static_assert(test_popcount()); + static_assert(test_popcount()); test_popcount(); - // static_assert(test_rotl()); + static_assert(test_rotl()); test_rotl(); - // static_assert(test_rotr()); + static_assert(test_rotr()); test_rotr(); - // static_assert(test_popcount_specialcases()); + static_assert(test_popcount_specialcases()); test_popcount_specialcases(); - // static_assert(test_64bit_split_ops()); + static_assert(test_64bit_split_ops()); test_64bit_split_ops(); } #endif // __cpp_lib_bitops From 04825a10981a315cbe3853cd9c907e7dae41450b Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 5 May 2020 13:32:18 -0700 Subject: [PATCH 08/37] remove if constexpr --- stl/inc/bit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/bit b/stl/inc/bit index 197e74744fd..825e4d18122 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -120,7 +120,7 @@ constexpr int _Popcount_helper(_Ty _Val) { _Val = static_cast<_Ty>( (_Val & static_cast<_Ty>(0x3333333333333333ull)) + ((_Val >> 2) & static_cast<_Ty>(0x3333333333333333ull))); _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F0F0F0F0F0F0Full)); - for (int _ShiftDigits = numeric_limits::digits; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { + for (int _ShiftDigits = 8; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { _Val = static_cast<_Ty>(_Val + static_cast<_Ty>(_Val >> _ShiftDigits)); } // we want the bottom "slot" that's big enough to store _Digits From 0119974d105af91a03bba4b247040899ac4fd2d8 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 6 May 2020 13:20:09 -0700 Subject: [PATCH 09/37] some review changes --- stl/inc/bit | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 825e4d18122..20f0eef65c5 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -95,19 +95,6 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } } - -inline bool __Is_popcnt_supported() { - int cpuinfo[4]; - __cpuid(cpuinfo, 0x01); - return cpuinfo[2] & (1 << 23); -} - -inline bool _Is_lzcnt_supported() { - int cpuinfo[4]; - __cpuid(cpuinfo, 0x80000001); - return cpuinfo[2] & (1 << 5); -} - #pragma warning(push) #pragma warning(disable : 4640) @@ -129,6 +116,18 @@ constexpr int _Popcount_helper(_Ty _Val) { #if defined(_M_IX86) || defined(_M_X64) +inline bool __Is_popcnt_supported() { + int cpuinfo[4]; + __cpuid(cpuinfo, 0x01); + return cpuinfo[2] & (1 << 23); +} + +inline bool _Is_lzcnt_supported() { + int cpuinfo[4]; + __cpuid(cpuinfo, 0x80000001); + return cpuinfo[2] & (1 << 5); +} + template inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { static bool _Have_lzcnt = _Is_lzcnt_supported(); From b2313995a14de94ce3db17c647e53debf1c2507d Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 12 May 2020 14:27:18 -0700 Subject: [PATCH 10/37] more review feedback changes --- stl/inc/bit | 22 +++++++++++----------- stl/inc/limits | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 20f0eef65c5..833921b3d0c 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -98,8 +98,8 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { #pragma warning(push) #pragma warning(disable : 4640) -template -constexpr int _Popcount_helper(_Ty _Val) { +template +_NODISCARD constexpr int _Popcount_helper(_Ty _Val) { constexpr int _Digits = numeric_limits<_Ty>::digits; // we static cast these bit patterns in order to truncate // them to the correct size @@ -116,20 +116,20 @@ constexpr int _Popcount_helper(_Ty _Val) { #if defined(_M_IX86) || defined(_M_X64) -inline bool __Is_popcnt_supported() { +_NODISCARD inline bool _Is_popcnt_supported() { int cpuinfo[4]; __cpuid(cpuinfo, 0x01); return cpuinfo[2] & (1 << 23); } -inline bool _Is_lzcnt_supported() { +_NODISCARD inline bool _Is_lzcnt_supported() { int cpuinfo[4]; __cpuid(cpuinfo, 0x80000001); return cpuinfo[2] & (1 << 5); } -template -inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { +template +_NODISCARD inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { static bool _Have_lzcnt = _Is_lzcnt_supported(); constexpr int _Digits = numeric_limits<_Ty>::digits; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero @@ -163,9 +163,9 @@ inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { // all supported intel processors at least have bsr/bsf } -template -inline int _Checked_x86_x86_64_popcount(_Ty _Val) { - static bool _Have_popcnt = __Is_popcnt_supported(); +template +_NODISCARD inline int _Checked_x86_x86_64_popcount(_Ty _Val) { + static bool _Have_popcnt = _Is_popcnt_supported(); constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Have_popcnt) { if constexpr (_Digits <= 16) { @@ -187,8 +187,8 @@ inline int _Checked_x86_x86_64_popcount(_Ty _Val) { #if defined(_M_ARM) || defined(_M_ARM64) -template -inline int _Checked_arm_countl_zero(_Ty _Val) { +template +_NODISCARD inline int _Checked_arm_countl_zero(_Ty _Val) { constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Val == 0) { return _Digits; diff --git a/stl/inc/limits b/stl/inc/limits index 3d0983b5644..2f8b40bffa5 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1023,7 +1023,7 @@ inline bool _Is_tzcnt_supported() { // see "Hacker's Delight" section 5-3 -template +template constexpr int _Countl_zero_helper(_Ty _Val) { _Ty _Yy = 0; @@ -1041,7 +1041,7 @@ constexpr int _Countl_zero_helper(_Ty _Val) { } // see "Hacker's Delight" section 5-4 -template +template constexpr int _Countr_zero_helper(_Ty _Val) { return numeric_limits<_Ty>::digits - _Countl_zero_helper(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); @@ -1049,7 +1049,7 @@ constexpr int _Countr_zero_helper(_Ty _Val) { #pragma warning(push) #pragma warning(disable : 4640) #if defined(_M_IX86) || defined(_M_X64) -template +template inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { static bool _Have_tzcnt = _Is_tzcnt_supported(); constexpr int _Digits = numeric_limits<_Ty>::digits; From ac94b482bb505cbcc57e0a07be6cfbc0324dce15 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Tue, 16 Jun 2020 19:06:11 -0700 Subject: [PATCH 11/37] don't use intrin, just use intrin0 define intrinsics in consuming headers until next vs release --- stl/inc/bit | 37 +++++++++++++++++++------------------ stl/inc/limits | 25 ++++++++++++------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 833921b3d0c..45c38ac1bd6 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -12,7 +12,8 @@ #pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv -#include +#include +#include #include #include @@ -24,6 +25,7 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN + template , is_trivially_copyable<_To>, is_trivially_copyable<_From>>, @@ -33,6 +35,7 @@ _NODISCARD constexpr _To bit_cast(const _From& _Val) noexcept { } #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 + template , int> = 0> _NODISCARD constexpr int countl_zero(_Ty _Val) noexcept; @@ -116,22 +119,20 @@ _NODISCARD constexpr int _Popcount_helper(_Ty _Val) { #if defined(_M_IX86) || defined(_M_X64) -_NODISCARD inline bool _Is_popcnt_supported() { - int cpuinfo[4]; - __cpuid(cpuinfo, 0x01); - return cpuinfo[2] & (1 << 23); -} - -_NODISCARD inline bool _Is_lzcnt_supported() { - int cpuinfo[4]; - __cpuid(cpuinfo, 0x80000001); - return cpuinfo[2] & (1 << 5); +extern "C" { +__MACHINEX86_X64(unsigned int __lzcnt(unsigned int)) +__MACHINEX86_X64(unsigned short __lzcnt16(unsigned short)) +__MACHINEX64(unsigned __int64 __lzcnt64(unsigned __int64)) +__MACHINEX86_X64(unsigned int __popcnt(unsigned int)) +__MACHINEX86_X64(unsigned short __popcnt16(unsigned short)) +__MACHINEX64(unsigned __int64 __popcnt64(unsigned __int64)) +extern int __isa_available; } template _NODISCARD inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { - static bool _Have_lzcnt = _Is_lzcnt_supported(); - constexpr int _Digits = numeric_limits<_Ty>::digits; + const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX; + constexpr int _Digits = numeric_limits<_Ty>::digits; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero if (!_Have_lzcnt && _Val == 0) { return _Digits; @@ -146,14 +147,14 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { } else { #ifdef _M_IX86 if (_Have_lzcnt) { - return (__lzcnt(_Val >> 32) + __lzcnt(static_cast(_Val)) - (64 - _Digits); + return __lzcnt(_Val >> 32) + __lzcnt(static_cast(_Val)) - (64 - _Digits); } else { unsigned int _High = _Val >> 32; unsigned int _Low = static_cast(_Val); int _Result = 0; _Result += _High ? __lzcnt(_High) : 0; _Result += _Low ? __lzcnt(_Low) : 0; - return result; + return _Result; } #else return static_cast(__lzcnt64(_Val) - (64 - _Digits)); @@ -165,8 +166,8 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { template _NODISCARD inline int _Checked_x86_x86_64_popcount(_Ty _Val) { - static bool _Have_popcnt = _Is_popcnt_supported(); - constexpr int _Digits = numeric_limits<_Ty>::digits; + const bool _Have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42; + constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Have_popcnt) { if constexpr (_Digits <= 16) { return static_cast(__popcnt16(_Val)); @@ -248,8 +249,8 @@ _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { #endif // __cpp_lib_bitops enum class endian { little = 0, big = 1, native = little }; -_STD_END +_STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/stl/inc/limits b/stl/inc/limits index 2f8b40bffa5..0b37b83c1b7 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -11,7 +11,8 @@ #include #include #include -#include +#include +#include #include #include @@ -1013,15 +1014,6 @@ public: #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 -inline bool _Is_tzcnt_supported() { - // tzcnt and lzcnt support are indicated with - // different cpuid flags. - int cpuinfo[4]; - __cpuid(cpuinfo, 0x07); - return cpuinfo[1] & (1 << 3); -} - - // see "Hacker's Delight" section 5-3 template constexpr int _Countl_zero_helper(_Ty _Val) { @@ -1049,11 +1041,18 @@ constexpr int _Countr_zero_helper(_Ty _Val) { #pragma warning(push) #pragma warning(disable : 4640) #if defined(_M_IX86) || defined(_M_X64) + +extern "C" { +__MACHINEX86_X64(unsigned int _tzcnt_u32(unsigned int)) +__MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)) +extern int __isa_available; +} + template inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { - static bool _Have_tzcnt = _Is_tzcnt_supported(); - constexpr int _Digits = numeric_limits<_Ty>::digits; - constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); + const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX; + constexpr int _Digits = numeric_limits<_Ty>::digits; + constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); if (!_Have_tzcnt && _Val == 0) { return _Digits; } From a7bcf21b92931dc698accbe55deafbba86f82578 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 17 Jun 2020 17:17:21 -0700 Subject: [PATCH 12/37] fix the tests for x86 --- stl/inc/bit | 15 +++++---------- stl/inc/limits | 25 ++++++++++++++++++------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 45c38ac1bd6..82f692c7041 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -146,16 +146,11 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { return static_cast(__lzcnt(_Val) - (32 - _Digits)); } else { #ifdef _M_IX86 - if (_Have_lzcnt) { - return __lzcnt(_Val >> 32) + __lzcnt(static_cast(_Val)) - (64 - _Digits); - } else { - unsigned int _High = _Val >> 32; - unsigned int _Low = static_cast(_Val); - int _Result = 0; - _Result += _High ? __lzcnt(_High) : 0; - _Result += _Low ? __lzcnt(_Low) : 0; - return _Result; - } + unsigned int _High = _Val >> 32; + unsigned int _Low = static_cast(_Val); + int _Result = _Checked_x86_x86_64_countl_zero(_High); + _Result += !_High ? _Checked_x86_x86_64_countl_zero(_Low) : 0; + return _Result; #else return static_cast(__lzcnt64(_Val) - (64 - _Digits)); #endif diff --git a/stl/inc/limits b/stl/inc/limits index 0b37b83c1b7..2ba1f6c7b95 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1043,13 +1043,21 @@ constexpr int _Countr_zero_helper(_Ty _Val) { #if defined(_M_IX86) || defined(_M_X64) extern "C" { -__MACHINEX86_X64(unsigned int _tzcnt_u32(unsigned int)) -__MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)) extern int __isa_available; +#ifdef __clang__ +#define _TZCNT_U32(a) (__builtin_ia32_tzcnt_u32((a))) +#define _TZCNT_U64(a) (__builtin_ia32_tzcnt_u64((a))) +#else // ^^^ __clang__ / ! __clang__ vvv +__MACHINEX86_X64(unsigned int _tzcnt_u32(unsigned int)) +__MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)); +#define _TZCNT_U32(a) (_tzcnt_u32((a))) +#define _TZCNT_U64(a) (_tzcnt_u64((a))) +#endif // __clang__ } template inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { + const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX; constexpr int _Digits = numeric_limits<_Ty>::digits; constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); @@ -1058,20 +1066,23 @@ inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { } if constexpr (_Digits <= 32) { // intended widening to int - return static_cast(_tzcnt_u32(static_cast(~_Max | _Val))); + // this operation means that a narrow 0 will widen + // to 0xFFFF....FFFF0... instead of 0 + return static_cast(_TZCNT_U32(static_cast(~_Max | _Val))); } else { #ifdef _M_IX86 unsigned int _High = _Val >> 32; unsigned int _Low = static_cast(_Val); - int _Result = 0; - _Result += _High ? _tzcnt_u32(_High) : 0; - _Result += _Low ? _tzcnt_u32(_Low) : 0; + int _Result = _Checked_x86_x86_64_countr_zero(_Low); + _Result += !_Low ? _Checked_x86_x86_64_countr_zero(_High) : 0; return _Result; #else - return static_cast(_tzcnt_u64(_Val)); + return static_cast(_TZCNT_U64(_Val)); #endif } } +#undef _TZCNT_U32 +#undef _TZCNT_U32 #endif #pragma warning(pop) template From d05ebd85380bac2d009975b153054874856d422b Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 17 Jun 2020 20:44:12 -0700 Subject: [PATCH 13/37] apply code-review suggestions --- llvm-project | 2 +- stl/inc/bit | 50 +++++++------------ stl/inc/limits | 49 ++++++++---------- stl/inc/numeric | 14 ------ stl/inc/yvals_core.h | 5 +- .../test.cpp | 10 ++-- 6 files changed, 47 insertions(+), 83 deletions(-) diff --git a/llvm-project b/llvm-project index 634a0acb307..7e3ef299cb3 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit 634a0acb307ddad21c5542dc313e02b4df9b216e +Subproject commit 7e3ef299cb3fa9a1cbca316740c12029af62922c diff --git a/stl/inc/bit b/stl/inc/bit index 82f692c7041..46ec3aba7be 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -34,8 +34,6 @@ _NODISCARD constexpr _To bit_cast(const _From& _Val) noexcept { return __builtin_bit_cast(_To, _Val); } -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 - template , int> = 0> _NODISCARD constexpr int countl_zero(_Ty _Val) noexcept; @@ -98,18 +96,15 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } } -#pragma warning(push) -#pragma warning(disable : 4640) - template _NODISCARD constexpr int _Popcount_helper(_Ty _Val) { constexpr int _Digits = numeric_limits<_Ty>::digits; // we static cast these bit patterns in order to truncate // them to the correct size - _Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555555555555555ull))); - _Val = static_cast<_Ty>( - (_Val & static_cast<_Ty>(0x3333333333333333ull)) + ((_Val >> 2) & static_cast<_Ty>(0x3333333333333333ull))); - _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F0F0F0F0F0F0Full)); + _Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555'5555'5555'5555ull))); + _Val = static_cast<_Ty>((_Val & static_cast<_Ty>(0x3333'3333'3333'3333ull)) + + ((_Val >> 2) & static_cast<_Ty>(0x3333'3333'3333'3333ull))); + _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F'0F0F'0F0F'0F0Full)); for (int _ShiftDigits = 8; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { _Val = static_cast<_Ty>(_Val + static_cast<_Ty>(_Val >> _ShiftDigits)); } @@ -130,8 +125,8 @@ extern int __isa_available; } template -_NODISCARD inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { - const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX; +_NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) { + const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero if (!_Have_lzcnt && _Val == 0) { @@ -151,16 +146,16 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(_Ty _Val) { int _Result = _Checked_x86_x86_64_countl_zero(_High); _Result += !_High ? _Checked_x86_x86_64_countl_zero(_Low) : 0; return _Result; -#else +#else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(__lzcnt64(_Val) - (64 - _Digits)); -#endif +#endif // _M_IX86 } // note we don't need to call a fallback here because // all supported intel processors at least have bsr/bsf } template -_NODISCARD inline int _Checked_x86_x86_64_popcount(_Ty _Val) { +_NODISCARD inline int _Checked_x86_x86_64_popcount(const _Ty _Val) { const bool _Have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42; constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Have_popcnt) { @@ -171,9 +166,9 @@ _NODISCARD inline int _Checked_x86_x86_64_popcount(_Ty _Val) { } else { #ifdef _M_IX86 return static_cast(__popcnt(_Val >> 32) + __popcnt(static_cast(_Val))); -#else +#else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(__popcnt64(_Val)); -#endif +#endif // _M_IX86 } } else { return _Popcount_helper(_Val); @@ -184,7 +179,7 @@ _NODISCARD inline int _Checked_x86_x86_64_popcount(_Ty _Val) { #if defined(_M_ARM) || defined(_M_ARM64) template -_NODISCARD inline int _Checked_arm_countl_zero(_Ty _Val) { +_NODISCARD inline int _Checked_arm_countl_zero(const _Ty _Val) { constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Val == 0) { return _Digits; @@ -199,19 +194,16 @@ _NODISCARD inline int _Checked_arm_countl_zero(_Ty _Val) { template , int> _Enabled> _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { - if (is_constant_evaluated()) { - return _Countl_zero_helper(_Val); - } else { + if (!_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) return _Checked_x86_x86_64_countl_zero(_Val); #elif defined(_M_ARM) || defined(_M_ARM64) return _Checked_arm_countl_zero(_Val); -#else - return _Countl_zero_helper(_Val); #endif } + return _Countl_zero_helper(_Val) } -#pragma warning(pop) + template , int> = 0> _NODISCARD constexpr int countl_one(const _Ty _Val) noexcept { return _STD countl_zero(static_cast<_Ty>(~_Val)); @@ -229,19 +221,13 @@ _NODISCARD constexpr int countr_one(const _Ty _Val) noexcept { template , int> _Enabled = 0> _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { - if (is_constant_evaluated()) { - return _Popcount_helper(_Val); - } else { + if (!_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) return _Checked_x86_x86_64_popcount(_Val); -#else - // arm NEON has a popcount instruction, but we're not going to use that - // yet. - return _Popcount_helper(_Val); -#endif +#endif // defined(_M_IX86) || defined(_M_X64) } + return _Countl_zero_helper(_Val) } -#endif // __cpp_lib_bitops enum class endian { little = 0, big = 1, native = little }; diff --git a/stl/inc/limits b/stl/inc/limits index 2ba1f6c7b95..07a2772927f 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1012,8 +1012,6 @@ public: static constexpr int min_exponent10 = LDBL_MIN_10_EXP; }; -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 - // see "Hacker's Delight" section 5-3 template constexpr int _Countl_zero_helper(_Ty _Val) { @@ -1034,31 +1032,29 @@ constexpr int _Countl_zero_helper(_Ty _Val) { // see "Hacker's Delight" section 5-4 template -constexpr int _Countr_zero_helper(_Ty _Val) { - return numeric_limits<_Ty>::digits - - _Countl_zero_helper(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); +constexpr int _Countr_zero_helper(const _Ty _Val) { + constexpr int _Digits = std::numeric_limits<_Ty>::digits; + return _Digits - _Countl_zero_helper(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); } -#pragma warning(push) -#pragma warning(disable : 4640) + #if defined(_M_IX86) || defined(_M_X64) extern "C" { extern int __isa_available; #ifdef __clang__ -#define _TZCNT_U32(a) (__builtin_ia32_tzcnt_u32((a))) -#define _TZCNT_U64(a) (__builtin_ia32_tzcnt_u64((a))) +#define _TZCNT_U32 __builtin_ia32_tzcnt_u32 +#define _TZCNT_U64 __builtin_ia32_tzcnt_u64 #else // ^^^ __clang__ / ! __clang__ vvv __MACHINEX86_X64(unsigned int _tzcnt_u32(unsigned int)) __MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)); -#define _TZCNT_U32(a) (_tzcnt_u32((a))) -#define _TZCNT_U64(a) (_tzcnt_u64((a))) +#define _TZCNT_U32 _tzcnt_u32 +#define _TZCNT_U64 _tzcnt_u64 #endif // __clang__ } template -inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { - - const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX; +inline int _Checked_x86_x86_64_countr_zero(const _Ty _Val) { + const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); if (!_Have_tzcnt && _Val == 0) { @@ -1076,32 +1072,31 @@ inline int _Checked_x86_x86_64_countr_zero(_Ty _Val) { int _Result = _Checked_x86_x86_64_countr_zero(_Low); _Result += !_Low ? _Checked_x86_x86_64_countr_zero(_High) : 0; return _Result; -#else +#else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(_TZCNT_U64(_Val)); -#endif +#endif // _M_IX86 } } #undef _TZCNT_U32 -#undef _TZCNT_U32 -#endif -#pragma warning(pop) +#undef _TZCNT_U64 +#endif // defined(_M_IX86) || defined(_M_X64) + template -inline constexpr bool _Is_standard_unsigned_integer = +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 (is_constant_evaluated()) { - return _Countr_zero_helper(_Val); - } else { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { #if defined(_M_IX86) || defined(_M_X64) return _Checked_x86_x86_64_countr_zero(_Val); -#else - return _Countr_zero_helper(_Val); -#endif +#endif // _M_IX86 } + return _Countr_zero_helper(_Val); } -#endif // __cpp_lib_bitops _STD_END #pragma pop_macro("new") diff --git a/stl/inc/numeric b/stl/inc/numeric index 2733891bccc..2631686e1c4 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -563,21 +563,7 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept { // FUNCTION TEMPLATE _Stl_bitscan_forward template _NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 return static_cast(_Countr_zero(_Mask)); -#else // ^^^ __cpp_lib_bitops / !__cpp_lib_bitops vvv - // find the index of the least significant set bit (_BitScanForward isn't constexpr... yet :)) - static_assert(is_unsigned_v<_Unsigned>, "Bitscan only works on bits"); - unsigned long _Count = 0; - if (_Mask != 0) { - while ((_Mask & 1U) == 0) { - _Mask >>= 1; - ++_Count; - } - } - - return _Count; -#endif // !__cpp_lib_bitops } // FUNCTION TEMPLATE gcd diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 15213617437..c212305ed46 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1140,9 +1140,8 @@ #define __cpp_lib_atomic_shared_ptr 201711L #define __cpp_lib_bind_front 201907L #define __cpp_lib_bit_cast 201806L - -#define __cpp_lib_bitops 201907L -#define __cpp_lib_bounded_array_traits 201902L +#define __cpp_lib_bitops 201907L +#define __cpp_lib_bounded_array_traits 201902L #ifdef __cpp_char8_t #define __cpp_lib_char8_t 201907L diff --git a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp index 7a25e9ad4ec..fc70c2916a6 100644 --- a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp +++ b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp @@ -105,12 +105,9 @@ constexpr bool test_rotr() { return true; } -// tests functions for 64bit operands that -// have either high or low halves as zero -// these may be split into two operations -// on 32bit platforms and we need to check -// if we handle the == zero or == ones cases -// correctly +// tests functions for 64bit operands that have either high or low halves as zero +// these may be split into two operations on 32bit platforms and we need to check +// if we handle the == zero or == ones case correctly constexpr bool test_64bit_split_ops() { constexpr unsigned long long zero_one = 0x0000'0000'FFFF'FFFF; constexpr unsigned long long one_zero = 0xFFFF'FFFF'0000'0000; @@ -126,6 +123,7 @@ constexpr bool test_64bit_split_ops() { assert(countl_one(one_zero) == 32); return true; } + template constexpr bool test_popcount_specialcases() { constexpr int digits = numeric_limits::digits; From 664926676da81c28d000c30375b42d7522ac3b63 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 17 Jun 2020 21:14:32 -0700 Subject: [PATCH 14/37] add semicolons --- stl/inc/bit | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 46ec3aba7be..76f54bd111b 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -201,7 +201,7 @@ _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { return _Checked_arm_countl_zero(_Val); #endif } - return _Countl_zero_helper(_Val) + return _Countl_zero_helper(_Val); } template , int> = 0> @@ -226,7 +226,7 @@ _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { return _Checked_x86_x86_64_popcount(_Val); #endif // defined(_M_IX86) || defined(_M_X64) } - return _Countl_zero_helper(_Val) + return _Popcount_helper(_Val); } enum class endian { little = 0, big = 1, native = little }; From ae0f1df8720cfcb87452b34ea6aa5e24bf3b7df3 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 17 Jun 2020 21:29:05 -0700 Subject: [PATCH 15/37] apply stl suggestions --- stl/inc/bit | 32 ++++++++++++++++---------------- stl/inc/limits | 14 +++++++------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 76f54bd111b..3da161acbc5 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -97,10 +97,9 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } template -_NODISCARD constexpr int _Popcount_helper(_Ty _Val) { +_NODISCARD constexpr int _Popcount_helper(_Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; - // we static cast these bit patterns in order to truncate - // them to the correct size + // we static_cast these bit patterns in order to truncate them to the correct size _Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555'5555'5555'5555ull))); _Val = static_cast<_Ty>((_Val & static_cast<_Ty>(0x3333'3333'3333'3333ull)) + ((_Val >> 2) & static_cast<_Ty>(0x3333'3333'3333'3333ull))); @@ -125,43 +124,44 @@ extern int __isa_available; } template -_NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) { +_NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) noexcept { const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero + // bsr has indefined output for zero if (!_Have_lzcnt && _Val == 0) { return _Digits; } - // we use lzcnt (actually bsr if lzcnt is not supported) for all cases now we know + // We use lzcnt (actually bsr if lzcnt is not supported) now that we know // we're not zero. We can do this because lzcnt and bsr share the same instruction // encoding. if constexpr (_Digits <= 16) { return static_cast(__lzcnt16(_Val) - (16 - _Digits)); - } else if constexpr (_Digits <= 32) { - return static_cast(__lzcnt(_Val) - (32 - _Digits)); + } else if constexpr (_Digits == 32) { + return static_cast(__lzcnt(_Val)); } else { #ifdef _M_IX86 - unsigned int _High = _Val >> 32; - unsigned int _Low = static_cast(_Val); - int _Result = _Checked_x86_x86_64_countl_zero(_High); - _Result += !_High ? _Checked_x86_x86_64_countl_zero(_Low) : 0; + const unsigned int _High = _Val >> 32; + const auto _Low = static_cast(_Val); + int _Result = _Checked_x86_x86_64_countl_zero(_High); + _Result += _High == 0 ? _Checked_x86_x86_64_countl_zero(_Low) : 0; return _Result; #else // ^^^ _M_IX86 / !_M_IX86 vvv - return static_cast(__lzcnt64(_Val) - (64 - _Digits)); + return static_cast(__lzcnt64(_Val); #endif // _M_IX86 } - // note we don't need to call a fallback here because + // note: we don't need to call a fallback here because // all supported intel processors at least have bsr/bsf } template -_NODISCARD inline int _Checked_x86_x86_64_popcount(const _Ty _Val) { +_NODISCARD inline int _Checked_x86_x86_64_popcount(const _Ty _Val) noexcept { const bool _Have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42; constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Have_popcnt) { if constexpr (_Digits <= 16) { return static_cast(__popcnt16(_Val)); - } else if constexpr (_Digits <= 32) { + } else if constexpr (_Digits == 32) { return static_cast(__popcnt(_Val)); } else { #ifdef _M_IX86 @@ -179,7 +179,7 @@ _NODISCARD inline int _Checked_x86_x86_64_popcount(const _Ty _Val) { #if defined(_M_ARM) || defined(_M_ARM64) template -_NODISCARD inline int _Checked_arm_countl_zero(const _Ty _Val) { +_NODISCARD inline int _Checked_arm_countl_zero(const _Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Val == 0) { return _Digits; diff --git a/stl/inc/limits b/stl/inc/limits index 07a2772927f..d88e266f8cd 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1014,7 +1014,7 @@ public: // see "Hacker's Delight" section 5-3 template -constexpr int _Countl_zero_helper(_Ty _Val) { +constexpr int _Countl_zero_helper(_Ty _Val) noexcept { _Ty _Yy = 0; unsigned int _Nn = numeric_limits<_Ty>::digits; @@ -1032,7 +1032,7 @@ constexpr int _Countl_zero_helper(_Ty _Val) { // see "Hacker's Delight" section 5-4 template -constexpr int _Countr_zero_helper(const _Ty _Val) { +constexpr int _Countr_zero_helper(const _Ty _Val) noexcept { constexpr int _Digits = std::numeric_limits<_Ty>::digits; return _Digits - _Countl_zero_helper(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); } @@ -1053,17 +1053,17 @@ __MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)); } template -inline int _Checked_x86_x86_64_countr_zero(const _Ty _Val) { +inline int _Checked_x86_x86_64_countr_zero(const _Ty _Val) noexcept { const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); if (!_Have_tzcnt && _Val == 0) { return _Digits; } - if constexpr (_Digits <= 32) { - // intended widening to int - // this operation means that a narrow 0 will widen - // to 0xFFFF....FFFF0... instead of 0 + if constexpr (_Digits == 32) { + // Intended widening to int. This operation means that a narrow 0 will widen + // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros + // of the wider type. return static_cast(_TZCNT_U32(static_cast(~_Max | _Val))); } else { #ifdef _M_IX86 From 07c065b27c1708e467429cbfdcfb77dbba32bd2c Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 17 Jun 2020 21:45:59 -0700 Subject: [PATCH 16/37] more stl suggestions --- stl/inc/limits | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/limits b/stl/inc/limits index d88e266f8cd..a594dbad939 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1060,10 +1060,10 @@ inline int _Checked_x86_x86_64_countr_zero(const _Ty _Val) noexcept { if (!_Have_tzcnt && _Val == 0) { return _Digits; } - if constexpr (_Digits == 32) { + if constexpr (_Digits <= 32) { // Intended widening to int. This operation means that a narrow 0 will widen // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros - // of the wider type. + // of the wider type return static_cast(_TZCNT_U32(static_cast(~_Max | _Val))); } else { #ifdef _M_IX86 From 50ceef2b8983094ee2f866727951a158ed902917 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Wed, 17 Jun 2020 23:21:53 -0700 Subject: [PATCH 17/37] revert update to llvm submodule --- llvm-project | 2 +- tests/libcxx/expected_results.txt | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/llvm-project b/llvm-project index 7e3ef299cb3..634a0acb307 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit 7e3ef299cb3fa9a1cbca316740c12029af62922c +Subproject commit 634a0acb307ddad21c5542dc313e02b4df9b216e diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 1e1d62bcd84..4f719af0a47 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -454,15 +454,6 @@ std/utilities/time/time.hms/time.hms.members/subseconds.pass.cpp FAIL std/utilities/time/time.hms/time.hms.members/to_duration.pass.cpp FAIL std/utilities/time/time.hms/time.hms.members/width.pass.cpp FAIL -# C++20 P0553R4 " Rotating And Counting Functions" -std/numerics/bit/bitops.count/countl_one.pass.cpp:0 FAIL -std/numerics/bit/bitops.count/countl_zero.pass.cpp:0 FAIL -std/numerics/bit/bitops.count/countr_one.pass.cpp:0 FAIL -std/numerics/bit/bitops.count/countr_zero.pass.cpp:0 FAIL -std/numerics/bit/bitops.count/popcount.pass.cpp:0 FAIL -std/numerics/bit/bitops.rot/rotl.pass.cpp:0 FAIL -std/numerics/bit/bitops.rot/rotr.pass.cpp:0 FAIL - # C++20 P0608R3 "Improving variant's Converting Constructor/Assignment" std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp FAIL std/utilities/variant/variant.variant/variant.assign/T.pass.cpp FAIL From 673ec72a704537fdd79fe06f288864d9728829b6 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Thu, 18 Jun 2020 15:41:36 -0700 Subject: [PATCH 18/37] skip libcxx test that emits a warning on msvc --- tests/libcxx/expected_results.txt | 2 ++ tests/libcxx/skipped_tests.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 4f719af0a47..76d9742dc01 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -62,6 +62,8 @@ std/numerics/bit/bit.pow.two/floor2.pass.cpp FAIL std/numerics/bit/bit.pow.two/ispow2.pass.cpp FAIL std/numerics/bit/bit.pow.two/log2p1.pass.cpp FAIL +# test emits warning C4310: cast truncates constant value +std/numerics/bit/bitops.rot/rotl.pass.cpp:0 FAIL # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 17da4731102..ba7ae65fbe8 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -62,6 +62,8 @@ numerics\bit\bit.pow.two\floor2.pass.cpp numerics\bit\bit.pow.two\ispow2.pass.cpp numerics\bit\bit.pow.two\log2p1.pass.cpp +# test emits warning C4310: cast truncates constant value +numerics\bit\bitops.rot\rotl.pass.cpp # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" From 3ccc6e1d56fbb91edee8cd4281de6f9dacee7bf9 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Mon, 22 Jun 2020 16:33:19 -0700 Subject: [PATCH 19/37] fix x86 build and adopt code review suggestions --- stl/inc/bit | 4 ++-- stl/inc/limits | 5 +++-- tests/libcxx/skipped_tests.txt | 9 --------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 3da161acbc5..4dcc4e5484a 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -128,7 +128,7 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) noexcept { const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero - // bsr has indefined output for zero + // bsr has undefined output for zero if (!_Have_lzcnt && _Val == 0) { return _Digits; } @@ -147,7 +147,7 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) noexcept { _Result += _High == 0 ? _Checked_x86_x86_64_countl_zero(_Low) : 0; return _Result; #else // ^^^ _M_IX86 / !_M_IX86 vvv - return static_cast(__lzcnt64(_Val); + return static_cast(__lzcnt64(_Val)); #endif // _M_IX86 } // note: we don't need to call a fallback here because diff --git a/stl/inc/limits b/stl/inc/limits index a594dbad939..a5a04fccc6b 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1014,7 +1014,7 @@ public: // see "Hacker's Delight" section 5-3 template -constexpr int _Countl_zero_helper(_Ty _Val) noexcept { +_NODISCARD constexpr int _Countl_zero_helper(_Ty _Val) noexcept { _Ty _Yy = 0; unsigned int _Nn = numeric_limits<_Ty>::digits; @@ -1032,7 +1032,7 @@ constexpr int _Countl_zero_helper(_Ty _Val) noexcept { // see "Hacker's Delight" section 5-4 template -constexpr int _Countr_zero_helper(const _Ty _Val) noexcept { +_NODISCARD constexpr int _Countr_zero_helper(const _Ty _Val) noexcept { constexpr int _Digits = std::numeric_limits<_Ty>::digits; return _Digits - _Countl_zero_helper(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); } @@ -1060,6 +1060,7 @@ inline int _Checked_x86_x86_64_countr_zero(const _Ty _Val) noexcept { if (!_Have_tzcnt && _Val == 0) { return _Digits; } + if constexpr (_Digits <= 32) { // Intended widening to int. This operation means that a narrow 0 will widen // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index ba7ae65fbe8..63cbcf0e7a3 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -456,15 +456,6 @@ utilities\time\time.hms\time.hms.members\subseconds.pass.cpp utilities\time\time.hms\time.hms.members\to_duration.pass.cpp utilities\time\time.hms\time.hms.members\width.pass.cpp -# C++20 P0553R4 " Rotating And Counting Functions" -numerics\bit\bitops.count\countl_one.pass.cpp -numerics\bit\bitops.count\countl_zero.pass.cpp -numerics\bit\bitops.count\countr_one.pass.cpp -numerics\bit\bitops.count\countr_zero.pass.cpp -numerics\bit\bitops.count\popcount.pass.cpp -numerics\bit\bitops.rot\rotl.pass.cpp -numerics\bit\bitops.rot\rotr.pass.cpp - # C++20 P0608R3 "Improving variant's Converting Constructor/Assignment" utilities\variant\variant.variant\variant.assign\conv.pass.cpp utilities\variant\variant.variant\variant.assign\T.pass.cpp From b577808cd32bcaefa96228a431a54c2600ac70a3 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Mon, 22 Jun 2020 18:20:13 -0700 Subject: [PATCH 20/37] address some remaining review comments that got buried. --- stl/inc/bit | 16 +++++++++------- stl/inc/limits | 12 ++++++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 4dcc4e5484a..a86f2d2ab6d 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -96,6 +96,8 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } } +// Implementation of popcount without using specialized CPU instructions. +// Used at compile time and when said instructions are not supported. template _NODISCARD constexpr int _Popcount_helper(_Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; @@ -124,7 +126,7 @@ extern int __isa_available; } template -_NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) noexcept { +_NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept { const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero @@ -143,8 +145,8 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) noexcept { #ifdef _M_IX86 const unsigned int _High = _Val >> 32; const auto _Low = static_cast(_Val); - int _Result = _Checked_x86_x86_64_countl_zero(_High); - _Result += _High == 0 ? _Checked_x86_x86_64_countl_zero(_Low) : 0; + int _Result = _Checked_x86_x64_countl_zero(_High); + _Result += _High == 0 ? _Checked_x86_x64_countl_zero(_Low) : 0; return _Result; #else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(__lzcnt64(_Val)); @@ -155,7 +157,7 @@ _NODISCARD inline int _Checked_x86_x86_64_countl_zero(const _Ty _Val) noexcept { } template -_NODISCARD inline int _Checked_x86_x86_64_popcount(const _Ty _Val) noexcept { +_NODISCARD int _Checked_x86_x64_popcount(const _Ty _Val) noexcept { const bool _Have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42; constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Have_popcnt) { @@ -179,7 +181,7 @@ _NODISCARD inline int _Checked_x86_x86_64_popcount(const _Ty _Val) noexcept { #if defined(_M_ARM) || defined(_M_ARM64) template -_NODISCARD inline int _Checked_arm_countl_zero(const _Ty _Val) noexcept { +_NODISCARD int _Checked_arm_countl_zero(const _Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Val == 0) { return _Digits; @@ -196,7 +198,7 @@ template , int> _Enabl _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { if (!_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) - return _Checked_x86_x86_64_countl_zero(_Val); + return _Checked_x86_x64_countl_zero(_Val); #elif defined(_M_ARM) || defined(_M_ARM64) return _Checked_arm_countl_zero(_Val); #endif @@ -223,7 +225,7 @@ template , int> _Enabl _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { if (!_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) - return _Checked_x86_x86_64_popcount(_Val); + return _Checked_x86_x64_popcount(_Val); #endif // defined(_M_IX86) || defined(_M_X64) } return _Popcount_helper(_Val); diff --git a/stl/inc/limits b/stl/inc/limits index a5a04fccc6b..aff95c3fc7e 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1012,6 +1012,8 @@ public: static constexpr int min_exponent10 = LDBL_MIN_10_EXP; }; +// Implementation of countl_zero without using specialized CPU instructions. +// Used at compile time and when said instructions are not supported. // see "Hacker's Delight" section 5-3 template _NODISCARD constexpr int _Countl_zero_helper(_Ty _Val) noexcept { @@ -1030,6 +1032,8 @@ _NODISCARD constexpr int _Countl_zero_helper(_Ty _Val) noexcept { return static_cast(_Nn) - static_cast(_Val); } +// Implementation of countr_zero without using specialized CPU instructions. +// Used at compile time and when said instructions are not supported. // see "Hacker's Delight" section 5-4 template _NODISCARD constexpr int _Countr_zero_helper(const _Ty _Val) noexcept { @@ -1053,7 +1057,7 @@ __MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)); } template -inline int _Checked_x86_x86_64_countr_zero(const _Ty _Val) noexcept { +int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); @@ -1070,8 +1074,8 @@ inline int _Checked_x86_x86_64_countr_zero(const _Ty _Val) noexcept { #ifdef _M_IX86 unsigned int _High = _Val >> 32; unsigned int _Low = static_cast(_Val); - int _Result = _Checked_x86_x86_64_countr_zero(_Low); - _Result += !_Low ? _Checked_x86_x86_64_countr_zero(_High) : 0; + int _Result = _Checked_x86_x64_countr_zero(_Low); + _Result += !_Low ? _Checked_x86_x64_countr_zero(_High) : 0; return _Result; #else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(_TZCNT_U64(_Val)); @@ -1093,7 +1097,7 @@ _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { #endif // __cpp_lib_is_constant_evaluated { #if defined(_M_IX86) || defined(_M_X64) - return _Checked_x86_x86_64_countr_zero(_Val); + return _Checked_x86_x64_countr_zero(_Val); #endif // _M_IX86 } return _Countr_zero_helper(_Val); From c50d2375d4bad4b296a867d8b9696acd9462d91c Mon Sep 17 00:00:00 2001 From: Charlie Barto Date: Mon, 22 Jun 2020 19:46:30 -0700 Subject: [PATCH 21/37] x86-> intel Co-authored-by: Stephan T. Lavavej --- stl/inc/bit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/bit b/stl/inc/bit index a86f2d2ab6d..4001ab2eba0 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -153,7 +153,7 @@ _NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept { #endif // _M_IX86 } // note: we don't need to call a fallback here because - // all supported intel processors at least have bsr/bsf + // all supported x86 processors at least have bsr/bsf } template From 766cb570b9078848b1911e1352edab33cb295371 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Mon, 22 Jun 2020 19:56:56 -0700 Subject: [PATCH 22/37] grr github, address hidden sneaky comments --- stl/inc/bit | 7 +++++-- stl/inc/limits | 2 +- stl/inc/yvals_core.h | 12 ++++-------- .../test.cpp | 6 +++--- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 4001ab2eba0..512df00b73b 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -181,11 +181,12 @@ _NODISCARD int _Checked_x86_x64_popcount(const _Ty _Val) noexcept { #if defined(_M_ARM) || defined(_M_ARM64) template -_NODISCARD int _Checked_arm_countl_zero(const _Ty _Val) noexcept { +_NODISCARD int _Checked_arm_arm64_countl_zero(const _Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Val == 0) { return _Digits; } + if constexpr (_Digits <= 32) { return _CountLeadingZeros(_Val); } else { @@ -200,7 +201,9 @@ _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { #if defined(_M_IX86) || defined(_M_X64) return _Checked_x86_x64_countl_zero(_Val); #elif defined(_M_ARM) || defined(_M_ARM64) - return _Checked_arm_countl_zero(_Val); + return _Checked_arm_arm64_countl_zero(_Val); +#else +#error Unsupported Hardware #endif } return _Countl_zero_helper(_Val); diff --git a/stl/inc/limits b/stl/inc/limits index aff95c3fc7e..17cc42980ca 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1093,7 +1093,7 @@ constexpr bool _Is_standard_unsigned_integer = template , int> = 0> _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { #ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) + if (!__builtin_is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { #if defined(_M_IX86) || defined(_M_X64) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index c212305ed46..22612f65b01 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1169,14 +1169,10 @@ #define __cpp_lib_destroying_delete 201806L #endif // __cpp_impl_destroying_delete -#define __cpp_lib_endian 201907L -#define __cpp_lib_erase_if 202002L -#define __cpp_lib_generic_unordered_lookup 201811L - -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 -#define __cpp_lib_int_pow2 202002L -#endif - +#define __cpp_lib_endian 201907L +#define __cpp_lib_erase_if 202002L +#define __cpp_lib_generic_unordered_lookup 201811L +#define __cpp_lib_int_pow2 202002L #define __cpp_lib_integer_comparison_functions 202002L #define __cpp_lib_is_constant_evaluated 201811L #define __cpp_lib_is_nothrow_convertible 201806L diff --git a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp index fc70c2916a6..fa9ede3779d 100644 --- a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp +++ b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp @@ -105,9 +105,9 @@ constexpr bool test_rotr() { return true; } -// tests functions for 64bit operands that have either high or low halves as zero -// these may be split into two operations on 32bit platforms and we need to check -// if we handle the == zero or == ones case correctly +// Tests functions for 64-bit operands that have either high or low halves as zero. +// These may be split into two operations on 32-bit platforms and we need to check +// if we handle the == zero or == ones case correctly. constexpr bool test_64bit_split_ops() { constexpr unsigned long long zero_one = 0x0000'0000'FFFF'FFFF; constexpr unsigned long long one_zero = 0xFFFF'FFFF'0000'0000; From 95176fd7d30c4fba6c9500660b40aec53d6a7443 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Mon, 22 Jun 2020 20:01:16 -0700 Subject: [PATCH 23/37] move is_constant_evaluated to xtr1common --- stl/inc/limits | 3 +-- stl/inc/type_traits | 13 +++---------- stl/inc/xtr1common | 7 +++++++ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/stl/inc/limits b/stl/inc/limits index 17cc42980ca..0bf977d652b 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -13,7 +13,6 @@ #include #include #include -#include #include #pragma pack(push, _CRT_PACKING) @@ -1093,7 +1092,7 @@ constexpr bool _Is_standard_unsigned_integer = template , int> = 0> _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { #ifdef __cpp_lib_is_constant_evaluated - if (!__builtin_is_constant_evaluated()) + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { #if defined(_M_IX86) || defined(_M_X64) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index a6916bda1be..a0f5d317459 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1842,13 +1842,6 @@ inline constexpr bool is_nothrow_invocable_r_v = _Select_invoke_traits<_Callable, _Args...>::template _Is_nothrow_invocable_r<_Rx>::value; #endif // _HAS_CXX17 -#if _HAS_CXX20 -// FUNCTION is_constant_evaluated -_NODISCARD constexpr bool is_constant_evaluated() noexcept { - return __builtin_is_constant_evaluated(); -} -#endif // _HAS_CXX20 - // STRUCT TEMPLATE _Weak_types template struct _Weak_result_type {}; // default definition @@ -1946,7 +1939,7 @@ public: #if _HAS_CXX17 template -reference_wrapper(_Ty&) -> reference_wrapper<_Ty>; +reference_wrapper(_Ty&)->reference_wrapper<_Ty>; #endif // _HAS_CXX17 // FUNCTION TEMPLATES ref AND cref @@ -2041,7 +2034,7 @@ struct _Is_swappable : _Is_swappable_with, add_lvalu // STRUCT TEMPLATE _Swap_cannot_throw template struct _Swap_cannot_throw : bool_constant(), _STD declval<_Ty2>())) // - && noexcept(swap(_STD declval<_Ty2>(), _STD declval<_Ty1>()))> { + && noexcept(swap(_STD declval<_Ty2>(), _STD declval<_Ty1>()))> { // Determine if expressions with type and value category _Ty1 and _Ty2 // (presumed to satisfy is_swappable_with) can be swapped without emitting exceptions }; @@ -2359,7 +2352,7 @@ namespace _DEPRECATE_TR1_NAMESPACE tr1 { using _STD result_of; #endif // _HAS_DEPRECATED_RESULT_OF using _STD hash; -} // namespace tr1 +} // namespace _DEPRECATE_TR1_NAMESPACEtr1 _STL_RESTORE_DEPRECATED_WARNING #endif // _HAS_TR1_NAMESPACE diff --git a/stl/inc/xtr1common b/stl/inc/xtr1common index 7b25ecedca8..b7b3ef44eb9 100644 --- a/stl/inc/xtr1common +++ b/stl/inc/xtr1common @@ -175,6 +175,13 @@ template _INLINE_VAR constexpr bool _Is_any_of_v = // true if and only if _Ty is in _Types disjunction_v...>; +#if _HAS_CXX20 +// FUNCTION is_constant_evaluated +_NODISCARD constexpr bool is_constant_evaluated() noexcept { + return __builtin_is_constant_evaluated(); +} +#endif // _HAS_CXX20 + // STRUCT TEMPLATE is_integral template _INLINE_VAR constexpr bool is_integral_v = _Is_any_of_v, bool, char, signed char, unsigned char, From efd63e46b8b05ef34a029eb8cf7c1ebc2f463311 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Mon, 22 Jun 2020 20:19:17 -0700 Subject: [PATCH 24/37] use correct clang-format --- stl/inc/type_traits | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index a0f5d317459..329f238083c 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1939,7 +1939,7 @@ public: #if _HAS_CXX17 template -reference_wrapper(_Ty&)->reference_wrapper<_Ty>; +reference_wrapper(_Ty&) -> reference_wrapper<_Ty>; #endif // _HAS_CXX17 // FUNCTION TEMPLATES ref AND cref @@ -2034,7 +2034,7 @@ struct _Is_swappable : _Is_swappable_with, add_lvalu // STRUCT TEMPLATE _Swap_cannot_throw template struct _Swap_cannot_throw : bool_constant(), _STD declval<_Ty2>())) // - && noexcept(swap(_STD declval<_Ty2>(), _STD declval<_Ty1>()))> { + && noexcept(swap(_STD declval<_Ty2>(), _STD declval<_Ty1>()))> { // Determine if expressions with type and value category _Ty1 and _Ty2 // (presumed to satisfy is_swappable_with) can be swapped without emitting exceptions }; @@ -2352,7 +2352,7 @@ namespace _DEPRECATE_TR1_NAMESPACE tr1 { using _STD result_of; #endif // _HAS_DEPRECATED_RESULT_OF using _STD hash; -} // namespace _DEPRECATE_TR1_NAMESPACEtr1 +} // namespace tr1 _STL_RESTORE_DEPRECATED_WARNING #endif // _HAS_TR1_NAMESPACE From 971880f411158aa61b03f20df6214b7e8d705f08 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 23 Jun 2020 19:25:50 -0700 Subject: [PATCH 25/37] Unguard tests now that we unconditionally define __cpp_lib_bitops in C++20 mode --- .../P0553R4_bit_rotating_and_counting_functions/test.cpp | 4 ---- .../P0556R3_bit_integral_power_of_two_operations/test.cpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp index fa9ede3779d..53fc5bfb4da 100644 --- a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp +++ b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp @@ -6,7 +6,6 @@ using namespace std; -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 template constexpr bool test_countl_zero() { constexpr int digits = numeric_limits::digits; @@ -177,14 +176,11 @@ void test_all() { static_assert(test_64bit_split_ops()); test_64bit_split_ops(); } -#endif // __cpp_lib_bitops int main() { -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 test_all(); test_all(); test_all(); test_all(); test_all(); -#endif // __cpp_lib_bitops } diff --git a/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp b/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp index b6956d9a14e..40bbfc0f000 100644 --- a/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp +++ b/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp @@ -7,7 +7,6 @@ using namespace std; -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 template constexpr bool test_has_single_bit() { assert(!has_single_bit(T{0})); @@ -97,10 +96,8 @@ void test_all() { static_assert(test_bit_width()); test_bit_width(); } -#endif // __cpp_lib_bitops int main() { -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 test_all(); test_all(); test_all(); @@ -108,5 +105,4 @@ int main() { test_all(); test_bit_floor_specialcases_unsigned(); test_bit_ceil_specialcases_unsigned(); -#endif // __cpp_lib_bitops } From 42097f6ac5c27a98f4c3216825d874f100d69035 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Fri, 26 Jun 2020 12:47:37 -0700 Subject: [PATCH 26/37] fix more review comments --- stl/inc/bit | 42 +++++++++++-------- stl/inc/limits | 14 +++---- stl/inc/numeric | 12 ++---- .../test.cpp | 9 ++-- .../test.cpp | 4 -- 5 files changed, 37 insertions(+), 44 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 512df00b73b..cea73b3a00e 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -99,15 +99,15 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { // Implementation of popcount without using specialized CPU instructions. // Used at compile time and when said instructions are not supported. template -_NODISCARD constexpr int _Popcount_helper(_Ty _Val) noexcept { +_NODISCARD constexpr int _Popcount_fallback(_Ty _Val) noexcept { constexpr int _Digits = numeric_limits<_Ty>::digits; // we static_cast these bit patterns in order to truncate them to the correct size _Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555'5555'5555'5555ull))); _Val = static_cast<_Ty>((_Val & static_cast<_Ty>(0x3333'3333'3333'3333ull)) + ((_Val >> 2) & static_cast<_Ty>(0x3333'3333'3333'3333ull))); _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F'0F0F'0F0F'0F0Full)); - for (int _ShiftDigits = 8; _ShiftDigits < _Digits; _ShiftDigits <<= 1) { - _Val = static_cast<_Ty>(_Val + static_cast<_Ty>(_Val >> _ShiftDigits)); + for (int _Shift_digits = 8; _Shift_digits < _Digits; _Shift_digits <<= 1) { + _Val = static_cast<_Ty>(_Val + static_cast<_Ty>(_Val >> _Shift_digits)); } // we want the bottom "slot" that's big enough to store _Digits return static_cast(_Val & static_cast<_Ty>(_Digits + _Digits - 1)); @@ -115,6 +115,7 @@ _NODISCARD constexpr int _Popcount_helper(_Ty _Val) noexcept { #if defined(_M_IX86) || defined(_M_X64) +// TRANSITION, VS 2019 16.8 Preview 1 extern "C" { __MACHINEX86_X64(unsigned int __lzcnt(unsigned int)) __MACHINEX86_X64(unsigned short __lzcnt16(unsigned short)) @@ -127,13 +128,17 @@ extern int __isa_available; template _NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept { - const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; constexpr int _Digits = numeric_limits<_Ty>::digits; + +#ifndef __AVX2__ + const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; // lzcnt (when it doesn't fall back to bsr) is defined correctly for zero // bsr has undefined output for zero if (!_Have_lzcnt && _Val == 0) { return _Digits; } +#endif // !defined(__AVX2__ + // We use lzcnt (actually bsr if lzcnt is not supported) now that we know // we're not zero. We can do this because lzcnt and bsr share the same instruction // encoding. @@ -158,22 +163,23 @@ _NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept { template _NODISCARD int _Checked_x86_x64_popcount(const _Ty _Val) noexcept { - const bool _Have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42; constexpr int _Digits = numeric_limits<_Ty>::digits; - if (_Have_popcnt) { - if constexpr (_Digits <= 16) { - return static_cast(__popcnt16(_Val)); - } else if constexpr (_Digits == 32) { - return static_cast(__popcnt(_Val)); - } else { +#ifndef __AVX__ + const bool _Have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42; + if (!_Have_popcnt) { + return _Popcount_fallback(_Val); + } +#endif // !defined(__AVX__) + if constexpr (_Digits <= 16) { + return static_cast(__popcnt16(_Val)); + } else if constexpr (_Digits == 32) { + return static_cast(__popcnt(_Val)); + } else { #ifdef _M_IX86 - return static_cast(__popcnt(_Val >> 32) + __popcnt(static_cast(_Val))); + return static_cast(__popcnt(_Val >> 32) + __popcnt(static_cast(_Val))); #else // ^^^ _M_IX86 / !_M_IX86 vvv - return static_cast(__popcnt64(_Val)); + return static_cast(__popcnt64(_Val)); #endif // _M_IX86 - } - } else { - return _Popcount_helper(_Val); } } #endif // defined(_M_IX86) || defined(_M_X64) @@ -206,7 +212,7 @@ _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { #error Unsupported Hardware #endif } - return _Countl_zero_helper(_Val); + return _Countl_zero_fallback(_Val); } template , int> = 0> @@ -231,7 +237,7 @@ _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { return _Checked_x86_x64_popcount(_Val); #endif // defined(_M_IX86) || defined(_M_X64) } - return _Popcount_helper(_Val); + return _Popcount_fallback(_Val); } enum class endian { little = 0, big = 1, native = little }; diff --git a/stl/inc/limits b/stl/inc/limits index 0bf977d652b..43199c8f50b 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1015,7 +1015,7 @@ public: // Used at compile time and when said instructions are not supported. // see "Hacker's Delight" section 5-3 template -_NODISCARD constexpr int _Countl_zero_helper(_Ty _Val) noexcept { +_NODISCARD constexpr int _Countl_zero_fallback(_Ty _Val) noexcept { _Ty _Yy = 0; unsigned int _Nn = numeric_limits<_Ty>::digits; @@ -1023,10 +1023,10 @@ _NODISCARD constexpr int _Countl_zero_helper(_Ty _Val) noexcept { do { _Yy = static_cast<_Ty>(_Val >> _Cc); if (_Yy != 0) { - _Nn = _Nn - _Cc; + _Nn -= _Cc; _Val = _Yy; } - _Cc = _Cc >> 1; + _Cc >>= 1; } while (_Cc != 0); return static_cast(_Nn) - static_cast(_Val); } @@ -1035,9 +1035,9 @@ _NODISCARD constexpr int _Countl_zero_helper(_Ty _Val) noexcept { // Used at compile time and when said instructions are not supported. // see "Hacker's Delight" section 5-4 template -_NODISCARD constexpr int _Countr_zero_helper(const _Ty _Val) noexcept { +_NODISCARD constexpr int _Countr_zero_fallback(const _Ty _Val) noexcept { constexpr int _Digits = std::numeric_limits<_Ty>::digits; - return _Digits - _Countl_zero_helper(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); + return _Digits - _Countl_zero_fallback(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1))); } #if defined(_M_IX86) || defined(_M_X64) @@ -1047,7 +1047,7 @@ extern int __isa_available; #ifdef __clang__ #define _TZCNT_U32 __builtin_ia32_tzcnt_u32 #define _TZCNT_U64 __builtin_ia32_tzcnt_u64 -#else // ^^^ __clang__ / ! __clang__ vvv +#else // ^^^ __clang__ / !__clang__ vvv __MACHINEX86_X64(unsigned int _tzcnt_u32(unsigned int)) __MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)); #define _TZCNT_U32 _tzcnt_u32 @@ -1099,7 +1099,7 @@ _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { return _Checked_x86_x64_countr_zero(_Val); #endif // _M_IX86 } - return _Countr_zero_helper(_Val); + return _Countr_zero_fallback(_Val); } _STD_END diff --git a/stl/inc/numeric b/stl/inc/numeric index 2631686e1c4..34e4d743f75 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -560,12 +560,6 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept { } } -// FUNCTION TEMPLATE _Stl_bitscan_forward -template -_NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { - return static_cast(_Countr_zero(_Mask)); -} - // FUNCTION TEMPLATE gcd template _NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) noexcept /* strengthened */ { @@ -584,12 +578,12 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) n return static_cast<_Common>(_Mx_magnitude); } - const auto _Mx_trailing_zeroes = _Stl_bitscan_forward(_Mx_magnitude); - const auto _Common_factors_of_2 = (_STD min)(_Mx_trailing_zeroes, _Stl_bitscan_forward(_Nx_magnitude)); + const auto _Mx_trailing_zeroes = static_cast(_Countr_zero(_Mx_magnitude)); + const auto _Common_factors_of_2 = (_STD min)(_Mx_trailing_zeroes, _Countr_zero(_Nx_magnitude)); _Nx_magnitude >>= _Common_factors_of_2; _Mx_magnitude >>= _Mx_trailing_zeroes; do { - _Nx_magnitude >>= _Stl_bitscan_forward(_Nx_magnitude); + _Nx_magnitude >>= static_cast(_Countr_zero(_Nx_magnitude)); if (_Mx_magnitude > _Nx_magnitude) { _Common_unsigned _Temp = _Mx_magnitude; _Mx_magnitude = _Nx_magnitude; diff --git a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp index fa9ede3779d..e5978d45866 100644 --- a/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp +++ b/tests/std/tests/P0553R4_bit_rotating_and_counting_functions/test.cpp @@ -6,7 +6,6 @@ using namespace std; -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 template constexpr bool test_countl_zero() { constexpr int digits = numeric_limits::digits; @@ -172,19 +171,17 @@ void test_all() { test_rotl(); static_assert(test_rotr()); test_rotr(); - static_assert(test_popcount_specialcases()); - test_popcount_specialcases(); static_assert(test_64bit_split_ops()); test_64bit_split_ops(); + static_assert(test_popcount_specialcases()); + test_popcount_specialcases(); } -#endif // __cpp_lib_bitops + int main() { -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 test_all(); test_all(); test_all(); test_all(); test_all(); -#endif // __cpp_lib_bitops } diff --git a/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp b/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp index b6956d9a14e..40bbfc0f000 100644 --- a/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp +++ b/tests/std/tests/P0556R3_bit_integral_power_of_two_operations/test.cpp @@ -7,7 +7,6 @@ using namespace std; -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 template constexpr bool test_has_single_bit() { assert(!has_single_bit(T{0})); @@ -97,10 +96,8 @@ void test_all() { static_assert(test_bit_width()); test_bit_width(); } -#endif // __cpp_lib_bitops int main() { -#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 test_all(); test_all(); test_all(); @@ -108,5 +105,4 @@ int main() { test_all(); test_bit_floor_specialcases_unsigned(); test_bit_ceil_specialcases_unsigned(); -#endif // __cpp_lib_bitops } From 7cedac69fbdbec66cf35a1c0a9abc584784045a4 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Fri, 26 Jun 2020 13:29:18 -0700 Subject: [PATCH 27/37] fix lcm/gcd --- stl/inc/numeric | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index 34e4d743f75..7f9d88c6a59 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -578,8 +578,9 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) n return static_cast<_Common>(_Mx_magnitude); } - const auto _Mx_trailing_zeroes = static_cast(_Countr_zero(_Mx_magnitude)); - const auto _Common_factors_of_2 = (_STD min)(_Mx_trailing_zeroes, _Countr_zero(_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 { From a1dd5f20d944a85545108f1c4fddcd7d5c832588 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 29 Jun 2020 11:55:53 -0700 Subject: [PATCH 28/37] Fix #endif comment in --- stl/inc/bit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/bit b/stl/inc/bit index cea73b3a00e..c8a4e3f8415 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -137,7 +137,7 @@ _NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept { if (!_Have_lzcnt && _Val == 0) { return _Digits; } -#endif // !defined(__AVX2__ +#endif // __AVX2__ // We use lzcnt (actually bsr if lzcnt is not supported) now that we know // we're not zero. We can do this because lzcnt and bsr share the same instruction From 0448a8f4006901f7a70a27f3c7367599e1f2b689 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Mon, 29 Jun 2020 17:45:20 -0700 Subject: [PATCH 29/37] add teansition to limits --- stl/inc/limits | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/limits b/stl/inc/limits index 43199c8f50b..30a15cd3010 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1042,6 +1042,7 @@ _NODISCARD constexpr int _Countr_zero_fallback(const _Ty _Val) noexcept { #if defined(_M_IX86) || defined(_M_X64) +// TRANSITION, VS 2019 16.8 Preview 1 extern "C" { extern int __isa_available; #ifdef __clang__ From 9f4bed9e2c6d04634332d39459905ad36bfc7a56 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Tue, 30 Jun 2020 11:40:16 -0700 Subject: [PATCH 30/37] fix more review comments. --- stl/inc/bit | 6 ++++-- stl/inc/limits | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index cea73b3a00e..137bbd70bcf 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -170,6 +170,7 @@ _NODISCARD int _Checked_x86_x64_popcount(const _Ty _Val) noexcept { return _Popcount_fallback(_Val); } #endif // !defined(__AVX__) + if constexpr (_Digits <= 16) { return static_cast(__popcnt16(_Val)); } else if constexpr (_Digits == 32) { @@ -203,7 +204,9 @@ _NODISCARD int _Checked_arm_arm64_countl_zero(const _Ty _Val) noexcept { template , int> _Enabled> _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { - if (!_STD is_constant_evaluated()) { + if (_STD is_constant_evaluated()) { + return _Countl_zero_fallback(_Val); + } else { #if defined(_M_IX86) || defined(_M_X64) return _Checked_x86_x64_countl_zero(_Val); #elif defined(_M_ARM) || defined(_M_ARM64) @@ -212,7 +215,6 @@ _NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { #error Unsupported Hardware #endif } - return _Countl_zero_fallback(_Val); } template , int> = 0> diff --git a/stl/inc/limits b/stl/inc/limits index 30a15cd3010..593423887cc 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1057,13 +1057,17 @@ __MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)); } template -int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { +_NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { + + constexpr int _Digits = numeric_limits<_Ty>::digits; + constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); + +#ifndef __AVX2__ const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2; - constexpr int _Digits = numeric_limits<_Ty>::digits; - constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); if (!_Have_tzcnt && _Val == 0) { return _Digits; } +#endif // __AVX2__ if constexpr (_Digits <= 32) { // Intended widening to int. This operation means that a narrow 0 will widen @@ -1072,9 +1076,9 @@ int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { return static_cast(_TZCNT_U32(static_cast(~_Max | _Val))); } else { #ifdef _M_IX86 - unsigned int _High = _Val >> 32; - unsigned int _Low = static_cast(_Val); - int _Result = _Checked_x86_x64_countr_zero(_Low); + const unsigned int _High = _Val >> 32; + const unsigned int _Low = static_cast(_Val); + int _Result = _Checked_x86_x64_countr_zero(_Low); _Result += !_Low ? _Checked_x86_x64_countr_zero(_High) : 0; return _Result; #else // ^^^ _M_IX86 / !_M_IX86 vvv @@ -1093,14 +1097,16 @@ constexpr bool _Is_standard_unsigned_integer = template , int> = 0> _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { #ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { + if (_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) return _Checked_x86_x64_countr_zero(_Val); -#endif // _M_IX86 +#endif // defined(_M_IX86 ) || defined(_M_X64) + } else { + return _Countr_zero_fallback(_Val); } +#else // ^^^ defined(__cpp_lib_is_constant_evaluated) / !defined(__cpp_lib_is_constant_evaluated) vvv return _Countr_zero_fallback(_Val); +#endif // defined(__cpp_lib_is_constant_evaluated) } _STD_END From 6049f430fd721855ecffce60846b39df57097716 Mon Sep 17 00:00:00 2001 From: Charlie Barto Date: Tue, 30 Jun 2020 11:41:52 -0700 Subject: [PATCH 31/37] Apply suggestions from code review Co-authored-by: Stephan T. Lavavej --- stl/inc/bit | 2 +- stl/inc/limits | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 2bd75392bee..6cde5be0d33 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -115,7 +115,7 @@ _NODISCARD constexpr int _Popcount_fallback(_Ty _Val) noexcept { #if defined(_M_IX86) || defined(_M_X64) -// TRANSITION, VS 2019 16.8 Preview 1 +// TRANSITION, VS 2019 16.8 Preview 1, intrin0.h will declare __lzcnt* and __popcnt* extern "C" { __MACHINEX86_X64(unsigned int __lzcnt(unsigned int)) __MACHINEX86_X64(unsigned short __lzcnt16(unsigned short)) diff --git a/stl/inc/limits b/stl/inc/limits index 593423887cc..0dc20377403 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1072,14 +1072,14 @@ _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { if constexpr (_Digits <= 32) { // Intended widening to int. This operation means that a narrow 0 will widen // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros - // of the wider type + // of the wider type. return static_cast(_TZCNT_U32(static_cast(~_Max | _Val))); } else { #ifdef _M_IX86 const unsigned int _High = _Val >> 32; const unsigned int _Low = static_cast(_Val); int _Result = _Checked_x86_x64_countr_zero(_Low); - _Result += !_Low ? _Checked_x86_x64_countr_zero(_High) : 0; + _Result += _Low == 0 ? _Checked_x86_x64_countr_zero(_High) : 0; return _Result; #else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(_TZCNT_U64(_Val)); From f00a232902a40367baec025acca786f0f8ca93ba Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Tue, 30 Jun 2020 11:43:35 -0700 Subject: [PATCH 32/37] reword transition in limits. --- stl/inc/limits | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/limits b/stl/inc/limits index 0dc20377403..0cf733fe5d3 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1042,7 +1042,7 @@ _NODISCARD constexpr int _Countr_zero_fallback(const _Ty _Val) noexcept { #if defined(_M_IX86) || defined(_M_X64) -// TRANSITION, VS 2019 16.8 Preview 1 +// TRANSITION, VS 2019 16.8 Preview 1, intrin0.h will declare _tzcnt* extern "C" { extern int __isa_available; #ifdef __clang__ From 3e811826d2cefa0e6816143dd5f0f7313c2d66f4 Mon Sep 17 00:00:00 2001 From: Charlie Barto Date: Tue, 30 Jun 2020 17:39:10 -0700 Subject: [PATCH 33/37] Update stl/inc/limits Co-authored-by: Stephan T. Lavavej --- stl/inc/limits | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/limits b/stl/inc/limits index 0cf733fe5d3..dc2c3100b4a 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1100,7 +1100,7 @@ _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { if (_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) return _Checked_x86_x64_countr_zero(_Val); -#endif // defined(_M_IX86 ) || defined(_M_X64) +#endif // defined(_M_IX86) || defined(_M_X64) } else { return _Countr_zero_fallback(_Val); } From e16e7205133a48732efe5e9663f93972b3b47639 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Tue, 30 Jun 2020 18:12:22 -0700 Subject: [PATCH 34/37] fix failing tests. --- stl/inc/limits | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/stl/inc/limits b/stl/inc/limits index dc2c3100b4a..0514438f034 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1096,17 +1096,14 @@ constexpr bool _Is_standard_unsigned_integer = template , int> = 0> _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { -#ifdef __cpp_lib_is_constant_evaluated - if (_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) { return _Checked_x86_x64_countr_zero(_Val); -#endif // defined(_M_IX86) || defined(_M_X64) - } else { - return _Countr_zero_fallback(_Val); } -#else // ^^^ defined(__cpp_lib_is_constant_evaluated) / !defined(__cpp_lib_is_constant_evaluated) vvv - return _Countr_zero_fallback(_Val); #endif // defined(__cpp_lib_is_constant_evaluated) +#endif // defined(_M_IX86) || defined(_M_X64) + return _Countr_zero_fallback(_Val); } _STD_END From 3a66228f16c22f9b03b2579851be9d3a8f162ed5 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Tue, 30 Jun 2020 18:18:45 -0700 Subject: [PATCH 35/37] apply review suggestions for code structure --- stl/inc/bit | 4 ++-- stl/inc/limits | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 6cde5be0d33..dbe9d806422 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -234,11 +234,11 @@ _NODISCARD constexpr int countr_one(const _Ty _Val) noexcept { template , int> _Enabled = 0> _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { - if (!_STD is_constant_evaluated()) { #if defined(_M_IX86) || defined(_M_X64) + if (!_STD is_constant_evaluated()) { return _Checked_x86_x64_popcount(_Val); -#endif // defined(_M_IX86) || defined(_M_X64) } +#endif // defined(_M_IX86) || defined(_M_X64) return _Popcount_fallback(_Val); } diff --git a/stl/inc/limits b/stl/inc/limits index 0514438f034..65d67885801 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1103,6 +1103,7 @@ _NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { } #endif // defined(__cpp_lib_is_constant_evaluated) #endif // defined(_M_IX86) || defined(_M_X64) + // C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation. return _Countr_zero_fallback(_Val); } From 0ac43b42a3b9080dd2d62033d64ef34fc00515d2 Mon Sep 17 00:00:00 2001 From: Charles Barto Date: Tue, 30 Jun 2020 19:08:15 -0700 Subject: [PATCH 36/37] make the split count(r/l) implementation more clear. --- stl/inc/bit | 8 +++++--- stl/inc/limits | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index dbe9d806422..0aa8f4451d1 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -150,9 +150,11 @@ _NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept { #ifdef _M_IX86 const unsigned int _High = _Val >> 32; const auto _Low = static_cast(_Val); - int _Result = _Checked_x86_x64_countl_zero(_High); - _Result += _High == 0 ? _Checked_x86_x64_countl_zero(_Low) : 0; - return _Result; + if (_High == 0) { + return 32 + _Checked_x86_x64_countl_zero(_Low); + } else { + return _Checked_x86_x64_countl_zero(_High); + } #else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(__lzcnt64(_Val)); #endif // _M_IX86 diff --git a/stl/inc/limits b/stl/inc/limits index 65d67885801..e1e8f90032b 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1058,7 +1058,6 @@ __MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64)); template _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { - constexpr int _Digits = numeric_limits<_Ty>::digits; constexpr _Ty _Max = (numeric_limits<_Ty>::max)(); @@ -1078,9 +1077,11 @@ _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { #ifdef _M_IX86 const unsigned int _High = _Val >> 32; const unsigned int _Low = static_cast(_Val); - int _Result = _Checked_x86_x64_countr_zero(_Low); - _Result += _Low == 0 ? _Checked_x86_x64_countr_zero(_High) : 0; - return _Result; + if (_Low == 0) { + return 32 + _Checked_x86_x64_countr_zero(_High); + } else { + return _Checked_x86_x64_countr_zero(_Low); + } #else // ^^^ _M_IX86 / !_M_IX86 vvv return static_cast(_TZCNT_U64(_Val)); #endif // _M_IX86 From 4ea5e7a819cb0a5ef4ccb3c0e27766431ad1f2d9 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Wed, 1 Jul 2020 19:01:40 -0700 Subject: [PATCH 37/37] gcd needs _Countr_zero from in C++17 --- stl/inc/numeric | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index 7f9d88c6a59..bb22f2d3cda 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -10,9 +10,9 @@ #if _STL_COMPILER_PREPROCESSOR #include -#if _HAS_CXX20 +#if _HAS_CXX17 #include -#endif // _HAS_CXX20 +#endif // _HAS_CXX17 #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL)