From 06e6d39057cc304cd7e07176be8bfda913f0e48e Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 9 Mar 2020 22:07:48 +0100 Subject: [PATCH 1/6] [numerics] Optimize gcd to use builtins --- stl/inc/bit | 31 +++++++------------------------ stl/inc/limits | 21 +++++++++++++++++++++ stl/inc/numeric | 6 +++++- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index 86d4b41684..bc3d4b31d4 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -36,13 +36,10 @@ _NODISCARD constexpr _To bit_cast(const _From& _Val) noexcept { #endif // TRANSITION, VSO-1041044 #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 -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 countl_zero(_Ty _Val) noexcept; +_NODISCARD constexpr int countl_zero(_Ty _Val) noexcept { + return _Countl_zero(_Val); +} template , int> = 0> _NODISCARD constexpr bool has_single_bit(const _Ty _Val) noexcept { @@ -55,7 +52,7 @@ _NODISCARD constexpr _Ty bit_ceil(const _Ty _Val) noexcept /* strengthened */ { return 1; } - return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - _STD countl_zero(static_cast<_Ty>(_Val - 1)))); + return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - _Countl_zero(static_cast<_Ty>(_Val - 1)))); } template , int> = 0> @@ -64,12 +61,12 @@ _NODISCARD constexpr _Ty bit_floor(const _Ty _Val) noexcept { return 0; } - return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - 1 - _STD countl_zero(_Val))); + return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - 1 - _Countl_zero(_Val))); } template , int> = 0> _NODISCARD constexpr _Ty bit_width(const _Ty _Val) noexcept { - return static_cast<_Ty>(numeric_limits<_Ty>::digits - _STD countl_zero(_Val)); + return static_cast<_Ty>(numeric_limits<_Ty>::digits - _Countl_zero(_Val)); } template , int> = 0> @@ -103,23 +100,9 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } } -template , int> _Enabled> -_NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { - constexpr int _Digits = numeric_limits<_Ty>::digits; - if (_Val == 0) { - return _Digits; - } - - if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { - return __builtin_clz(_Val) - (numeric_limits::digits - _Digits); - } else { - return __builtin_clzll(_Val) - (numeric_limits::digits - _Digits); - } -} - template , int> = 0> _NODISCARD constexpr int countl_one(const _Ty _Val) noexcept { - return _STD countl_zero(static_cast<_Ty>(~_Val)); + return _Countl_zero(static_cast<_Ty>(~_Val)); } template , int> = 0> diff --git a/stl/inc/limits b/stl/inc/limits index 70cac0c25a..0977d4bd3c 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1011,6 +1011,27 @@ public: static constexpr int min_exponent = LDBL_MIN_EXP; static constexpr int min_exponent10 = LDBL_MIN_10_EXP; }; + +#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 +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 _Countl_zero(const _Ty _Val) noexcept { + constexpr int _Digits = numeric_limits<_Ty>::digits; + if (_Val == 0) { + return _Digits; + } + + if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { + return __builtin_clz(_Val) - (numeric_limits::digits - _Digits); + } else { + return __builtin_clzll(_Val) - (numeric_limits::digits - _Digits); + } +} +#endif // __cpp_lib_bitops + _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS diff --git a/stl/inc/numeric b/stl/inc/numeric index 09c0e6c8d1..d6d69fdd31 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -859,7 +859,10 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept { // FUNCTION TEMPLATE _Stl_bitscan_forward template -constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { +_NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { +#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 + return static_cast(_Countl_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; @@ -871,6 +874,7 @@ constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { } return _Count; +#endif // !__cpp_lib_bitops } // FUNCTION TEMPLATE gcd From d08ea4b9236bc34bb70578c093de9702c6ab4595 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 1 Apr 2020 14:04:05 +0200 Subject: [PATCH 2/6] Fix template argument deduction for _countl_zero --- stl/inc/numeric | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index d6d69fdd31..e826bad1a4 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -861,7 +861,7 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept { template _NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 - return static_cast(_Countl_zero(~_Mask)); + return static_cast(_Countl_zero<_Unsigned>(~_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"); From 6a87c3839864bc098f0bd405a7aa28a238f999c2 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 2 Apr 2020 09:43:15 +0200 Subject: [PATCH 3/6] Use the same casts as the other bit operations --- stl/inc/numeric | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index e826bad1a4..dd47114d05 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -861,7 +861,8 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept { template _NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 - return static_cast(_Countl_zero<_Unsigned>(~_Mask)); + return static_cast(_Countl_zero(static_cast<_Unsigned>(~_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"); From a269a90ee610cad8069499a6cf65472640bef6e9 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 2 Apr 2020 09:12:20 -0700 Subject: [PATCH 4/6] Update stl/inc/numeric Fix tpyo --- stl/inc/numeric | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index dd47114d05..8406311ff3 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -861,7 +861,7 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept { template _NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 - return static_cast(_Countl_zero(static_cast<_Unsigned>(~_Mask)); + return static_cast(_Countl_zero(static_cast<_Unsigned>(~_Mask))); #else // ^^^ __cpp_lib_bitops / !__cpp_lib_bitops vvv // find the index of the least significant set bit (_BitScanForward isn't constexpr... yet :)) From c8961dd19e50d1c7dd85dff6ae003c63747c5ebd Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 3 Apr 2020 10:33:27 +0200 Subject: [PATCH 5/6] Remove whitespace Co-Authored-By: Stephan T. Lavavej --- stl/inc/numeric | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index 8406311ff3..2ded8a07e1 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -862,7 +862,6 @@ template _NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 return static_cast(_Countl_zero(static_cast<_Unsigned>(~_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"); From c833caab2fcb1b9dbdff22297139345e464f9107 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 10 Apr 2020 17:52:14 -0700 Subject: [PATCH 6/6] _BitScanForward is countr_zero(x), not countl_zero(~x) --- stl/inc/bit | 41 ++++++++++++++++++++++------------------- stl/inc/limits | 9 ++++----- stl/inc/numeric | 2 +- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/stl/inc/bit b/stl/inc/bit index bc3d4b31d4..565dafb773 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -23,8 +23,6 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN -enum class endian { little = 0, big = 1, native = little }; - #ifdef __cpp_lib_bit_cast // TRANSITION, VSO-1041044 template , is_trivially_copyable<_To>, @@ -37,9 +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 { - return _Countl_zero(_Val); -} +_NODISCARD constexpr int countl_zero(_Ty _Val) noexcept; template , int> = 0> _NODISCARD constexpr bool has_single_bit(const _Ty _Val) noexcept { @@ -52,7 +48,7 @@ _NODISCARD constexpr _Ty bit_ceil(const _Ty _Val) noexcept /* strengthened */ { return 1; } - return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - _Countl_zero(static_cast<_Ty>(_Val - 1)))); + return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - _STD countl_zero(static_cast<_Ty>(_Val - 1)))); } template , int> = 0> @@ -61,12 +57,12 @@ _NODISCARD constexpr _Ty bit_floor(const _Ty _Val) noexcept { return 0; } - return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - 1 - _Countl_zero(_Val))); + return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - 1 - _STD countl_zero(_Val))); } template , int> = 0> _NODISCARD constexpr _Ty bit_width(const _Ty _Val) noexcept { - return static_cast<_Ty>(numeric_limits<_Ty>::digits - _Countl_zero(_Val)); + return static_cast<_Ty>(numeric_limits<_Ty>::digits - _STD countl_zero(_Val)); } template , int> = 0> @@ -100,27 +96,33 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { } } -template , int> = 0> -_NODISCARD constexpr int countl_one(const _Ty _Val) noexcept { - return _Countl_zero(static_cast<_Ty>(~_Val)); -} - -template , int> = 0> -_NODISCARD constexpr int countr_zero(const _Ty _Val) noexcept { +template , int> _Enabled> +_NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { + constexpr int _Digits = numeric_limits<_Ty>::digits; if (_Val == 0) { - return numeric_limits<_Ty>::digits; + return _Digits; } if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { - return __builtin_ctz(_Val); + return __builtin_clz(_Val) - (numeric_limits::digits - _Digits); } else { - return __builtin_ctzll(_Val); + return __builtin_clzll(_Val) - (numeric_limits::digits - _Digits); } } +template , int> = 0> +_NODISCARD constexpr int countl_one(const _Ty _Val) noexcept { + return _STD countl_zero(static_cast<_Ty>(~_Val)); +} + +template , int> = 0> +_NODISCARD constexpr int countr_zero(const _Ty _Val) noexcept { + return _Countr_zero(_Val); +} + template , int> _Enabled = 0> _NODISCARD constexpr int countr_one(const _Ty _Val) noexcept { - return _STD countr_zero(static_cast<_Ty>(~_Val)); + return _Countr_zero(static_cast<_Ty>(~_Val)); } template , int> _Enabled = 0> @@ -133,6 +135,7 @@ _NODISCARD constexpr int popcount(const _Ty _Val) noexcept { } #endif // __cpp_lib_bitops +enum class endian { little = 0, big = 1, native = little }; _STD_END #pragma pop_macro("new") diff --git a/stl/inc/limits b/stl/inc/limits index 0977d4bd3c..6b25bb3fe8 100644 --- a/stl/inc/limits +++ b/stl/inc/limits @@ -1018,16 +1018,15 @@ 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 _Countl_zero(const _Ty _Val) noexcept { - constexpr int _Digits = numeric_limits<_Ty>::digits; +_NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept { if (_Val == 0) { - return _Digits; + return numeric_limits<_Ty>::digits; } if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { - return __builtin_clz(_Val) - (numeric_limits::digits - _Digits); + return __builtin_ctz(_Val); } else { - return __builtin_clzll(_Val) - (numeric_limits::digits - _Digits); + return __builtin_ctzll(_Val); } } #endif // __cpp_lib_bitops diff --git a/stl/inc/numeric b/stl/inc/numeric index 2ded8a07e1..789286ba4a 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -861,7 +861,7 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept { template _NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept { #ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 - return static_cast(_Countl_zero(static_cast<_Unsigned>(~_Mask))); + 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");