Re: [PATCH] libstdc++: Optimize C++20 comparison category types
Am Fr., 7. Feb. 2020 um 15:23 Uhr schrieb Jonathan Wakely : > > On 07/02/20 10:04 +0100, Daniel Krügler wrote: > >Am Do., 6. Feb. 2020 um 15:28 Uhr schrieb Jonathan Wakely > >: > >> > >> On 06/02/20 13:53 +, Jonathan Wakely wrote: > >> >On 06/02/20 13:40 +, Jonathan Wakely wrote: > >> >>This reduces sizeof(std::partial_ordering) and optimizes conversion and > >> >>comparison operators to avoid conditional branches where possible. > >> >> > >> >> * libsupc++/compare (__cmp_cat::_Ncmp::unordered): Change value to > >> >> 2. > >> >> (partial_ordering::_M_is_ordered): Remove data member. > >> >> (partial_ordering): Use second bit of _M_value for unordered. > >> >> Adjust > >> >> comparison operators. > >> >> (weak_ordering::operator partial_ordering): Simplify to remove > >> >> branches. > >> >> (operator<=>(unspecified, weak_ordering)): Likewise. > >> >> (strong_ordering::operator partial_ordering): Likewise. > >> >> (strong_ordering::operator weak_ordering): Likewise. > >> >> (operator<=>(unspecified, strong_ordering)): Likewise. > >> >> * testsuite/18_support/comparisons/categories/partialord.cc: New > >> >> test. > >> >> * testsuite/18_support/comparisons/categories/strongord.cc: New > >> >> test. > >> >> * testsuite/18_support/comparisons/categories/weakord.cc: New test. > >> >> > >> >>Tested powerpc64le-linux and x86_64-linux. > >> >> > >> >>This is an ABI change for the partial_ordering type, but that is why I > >> >>think we should do it now, not after GCC 10 is released. The sooner > >> >>the better, before these types are being widely used. > >> >> > >> >>I plan to commit this in the next 12 hours or so, unless there are > >> >>(valid :-) objections. > >> >> > >> >>Thanks to Barry Revzin for pointing out there was room for these > >> >>operators to be improved. > >> > > >> >We could also change the int _M_value data member of all three > >> >comparison category types to be a signed char instead of int. That > >> >would reduce the size further. > >> > >> Or maybe std::int_fast8_t is the right type here. > > > >I like this suggestion. > > After discussing it with Jakub, I've decided to just use signed char. > > In theory int_fast8_t seems like the right choice, but it depends on > how "fast" is interpreted. Fast for which operations? Is it actually > going to be faster for the simple comparisons to constants and the > bit masks that I use in ? > > On a number of operating systems int_fast8_t is always int, even > though byte accesses are no slower on many of the processors whre that > OS runs. > > So we decided that unconditionally using a single byte will give us a > small size and alignment, without sacrificing any performance. Yes, I agree with your decision. - Daniel
Re: [PATCH] libstdc++: Optimize C++20 comparison category types
On 07/02/20 10:04 +0100, Daniel Krügler wrote: Am Do., 6. Feb. 2020 um 15:28 Uhr schrieb Jonathan Wakely : On 06/02/20 13:53 +, Jonathan Wakely wrote: >On 06/02/20 13:40 +, Jonathan Wakely wrote: >>This reduces sizeof(std::partial_ordering) and optimizes conversion and >>comparison operators to avoid conditional branches where possible. >> >> * libsupc++/compare (__cmp_cat::_Ncmp::unordered): Change value to 2. >> (partial_ordering::_M_is_ordered): Remove data member. >> (partial_ordering): Use second bit of _M_value for unordered. Adjust >> comparison operators. >> (weak_ordering::operator partial_ordering): Simplify to remove >> branches. >> (operator<=>(unspecified, weak_ordering)): Likewise. >> (strong_ordering::operator partial_ordering): Likewise. >> (strong_ordering::operator weak_ordering): Likewise. >> (operator<=>(unspecified, strong_ordering)): Likewise. >> * testsuite/18_support/comparisons/categories/partialord.cc: New test. >> * testsuite/18_support/comparisons/categories/strongord.cc: New test. >> * testsuite/18_support/comparisons/categories/weakord.cc: New test. >> >>Tested powerpc64le-linux and x86_64-linux. >> >>This is an ABI change for the partial_ordering type, but that is why I >>think we should do it now, not after GCC 10 is released. The sooner >>the better, before these types are being widely used. >> >>I plan to commit this in the next 12 hours or so, unless there are >>(valid :-) objections. >> >>Thanks to Barry Revzin for pointing out there was room for these >>operators to be improved. > >We could also change the int _M_value data member of all three >comparison category types to be a signed char instead of int. That >would reduce the size further. Or maybe std::int_fast8_t is the right type here. I like this suggestion. After discussing it with Jakub, I've decided to just use signed char. In theory int_fast8_t seems like the right choice, but it depends on how "fast" is interpreted. Fast for which operations? Is it actually going to be faster for the simple comparisons to constants and the bit masks that I use in ? On a number of operating systems int_fast8_t is always int, even though byte accesses are no slower on many of the processors whre that OS runs. So we decided that unconditionally using a single byte will give us a small size and alignment, without sacrificing any performance. Here's what I've tested (powerpc64le-linux and x86_64-linux) and committed to master. commit 0d57370c9cc3c1fb68be96b8cc15b92496c4dd21 Author: Jonathan Wakely Date: Thu Feb 6 13:31:36 2020 + libstdc++: Optimize C++20 comparison category types This reduces the size and alignment of all three comparison category types to a single byte. The partial_ordering::_M_is_ordered flag is replaced by the value 0x02 in the _M_value member. This also optimizes conversion and comparison operators to avoid conditional branches where possible, by comparing _M_value to constants or using bitwise operations to correctly handle the unordered state. * libsupc++/compare (__cmp_cat::type): Define typedef for underlying type of enumerations and comparison category types. (__cmp_cat::_Ord, __cmp_cat::_Ncmp): Add underlying type. (__cmp_cat::_Ncmp::unordered): Change value to 2. (partial_ordering::_M_value, weak_ordering::_M_value) (strong_ordering::_M_value): Change type to __cmp_cat::type. (partial_ordering::_M_is_ordered): Remove data member. (partial_ordering): Use second bit of _M_value for unordered. Adjust comparison operators. (weak_ordering::operator partial_ordering): Simplify to remove branches. (operator<=>(unspecified, weak_ordering)): Likewise. (strong_ordering::operator partial_ordering): Likewise. (strong_ordering::operator weak_ordering): Likewise. (operator<=>(unspecified, strong_ordering)): Likewise. * testsuite/18_support/comparisons/categories/partialord.cc: New test. * testsuite/18_support/comparisons/categories/strongord.cc: New test. * testsuite/18_support/comparisons/categories/weakord.cc: New test. diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index a7a29ef0440..b2d64ef74a4 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -48,9 +48,11 @@ namespace std namespace __cmp_cat { -enum class _Ord { equivalent = 0, less = -1, greater = 1 }; +using type = signed char; -enum class _Ncmp { _Unordered = -127 }; +enum class _Ord : type { equivalent = 0, less = -1, greater = 1 }; + +enum class _Ncmp : type { _Unordered = 2 }; struct __unspec { @@ -60,19 +62,22 @@ namespace std class partial_ordering { -int _M_value; -bool _M_is_ordered;
Re: [PATCH] libstdc++: Optimize C++20 comparison category types
Am Do., 6. Feb. 2020 um 15:28 Uhr schrieb Jonathan Wakely : > > On 06/02/20 13:53 +, Jonathan Wakely wrote: > >On 06/02/20 13:40 +, Jonathan Wakely wrote: > >>This reduces sizeof(std::partial_ordering) and optimizes conversion and > >>comparison operators to avoid conditional branches where possible. > >> > >> * libsupc++/compare (__cmp_cat::_Ncmp::unordered): Change value to 2. > >> (partial_ordering::_M_is_ordered): Remove data member. > >> (partial_ordering): Use second bit of _M_value for unordered. Adjust > >> comparison operators. > >> (weak_ordering::operator partial_ordering): Simplify to remove > >> branches. > >> (operator<=>(unspecified, weak_ordering)): Likewise. > >> (strong_ordering::operator partial_ordering): Likewise. > >> (strong_ordering::operator weak_ordering): Likewise. > >> (operator<=>(unspecified, strong_ordering)): Likewise. > >> * testsuite/18_support/comparisons/categories/partialord.cc: New test. > >> * testsuite/18_support/comparisons/categories/strongord.cc: New test. > >> * testsuite/18_support/comparisons/categories/weakord.cc: New test. > >> > >>Tested powerpc64le-linux and x86_64-linux. > >> > >>This is an ABI change for the partial_ordering type, but that is why I > >>think we should do it now, not after GCC 10 is released. The sooner > >>the better, before these types are being widely used. > >> > >>I plan to commit this in the next 12 hours or so, unless there are > >>(valid :-) objections. > >> > >>Thanks to Barry Revzin for pointing out there was room for these > >>operators to be improved. > > > >We could also change the int _M_value data member of all three > >comparison category types to be a signed char instead of int. That > >would reduce the size further. > > Or maybe std::int_fast8_t is the right type here. I like this suggestion. - Daniel
Re: [PATCH] libstdc++: Optimize C++20 comparison category types
On 06/02/20 13:53 +, Jonathan Wakely wrote: On 06/02/20 13:40 +, Jonathan Wakely wrote: This reduces sizeof(std::partial_ordering) and optimizes conversion and comparison operators to avoid conditional branches where possible. * libsupc++/compare (__cmp_cat::_Ncmp::unordered): Change value to 2. (partial_ordering::_M_is_ordered): Remove data member. (partial_ordering): Use second bit of _M_value for unordered. Adjust comparison operators. (weak_ordering::operator partial_ordering): Simplify to remove branches. (operator<=>(unspecified, weak_ordering)): Likewise. (strong_ordering::operator partial_ordering): Likewise. (strong_ordering::operator weak_ordering): Likewise. (operator<=>(unspecified, strong_ordering)): Likewise. * testsuite/18_support/comparisons/categories/partialord.cc: New test. * testsuite/18_support/comparisons/categories/strongord.cc: New test. * testsuite/18_support/comparisons/categories/weakord.cc: New test. Tested powerpc64le-linux and x86_64-linux. This is an ABI change for the partial_ordering type, but that is why I think we should do it now, not after GCC 10 is released. The sooner the better, before these types are being widely used. I plan to commit this in the next 12 hours or so, unless there are (valid :-) objections. Thanks to Barry Revzin for pointing out there was room for these operators to be improved. We could also change the int _M_value data member of all three comparison category types to be a signed char instead of int. That would reduce the size further. Or maybe std::int_fast8_t is the right type here. It probably doesn't matter for most uses, only when one of the types is used as a data member and the smaller type would allow a more compact layout. I'm not sure how common such uses will be, but I suppose it's plausible somebody could have a function returning a std::tuple which would benefit. Anybody want to argue for or against making them 8 bits?
Re: [PATCH] libstdc++: Optimize C++20 comparison category types
On 06/02/20 13:40 +, Jonathan Wakely wrote: This reduces sizeof(std::partial_ordering) and optimizes conversion and comparison operators to avoid conditional branches where possible. * libsupc++/compare (__cmp_cat::_Ncmp::unordered): Change value to 2. (partial_ordering::_M_is_ordered): Remove data member. (partial_ordering): Use second bit of _M_value for unordered. Adjust comparison operators. (weak_ordering::operator partial_ordering): Simplify to remove branches. (operator<=>(unspecified, weak_ordering)): Likewise. (strong_ordering::operator partial_ordering): Likewise. (strong_ordering::operator weak_ordering): Likewise. (operator<=>(unspecified, strong_ordering)): Likewise. * testsuite/18_support/comparisons/categories/partialord.cc: New test. * testsuite/18_support/comparisons/categories/strongord.cc: New test. * testsuite/18_support/comparisons/categories/weakord.cc: New test. Tested powerpc64le-linux and x86_64-linux. This is an ABI change for the partial_ordering type, but that is why I think we should do it now, not after GCC 10 is released. The sooner the better, before these types are being widely used. I plan to commit this in the next 12 hours or so, unless there are (valid :-) objections. Thanks to Barry Revzin for pointing out there was room for these operators to be improved. We could also change the int _M_value data member of all three comparison category types to be a signed char instead of int. That would reduce the size further. It probably doesn't matter for most uses, only when one of the types is used as a data member and the smaller type would allow a more compact layout. I'm not sure how common such uses will be, but I suppose it's plausible somebody could have a function returning a std::tuple which would benefit. Anybody want to argue for or against making them 8 bits?
[PATCH] libstdc++: Optimize C++20 comparison category types
This reduces sizeof(std::partial_ordering) and optimizes conversion and comparison operators to avoid conditional branches where possible. * libsupc++/compare (__cmp_cat::_Ncmp::unordered): Change value to 2. (partial_ordering::_M_is_ordered): Remove data member. (partial_ordering): Use second bit of _M_value for unordered. Adjust comparison operators. (weak_ordering::operator partial_ordering): Simplify to remove branches. (operator<=>(unspecified, weak_ordering)): Likewise. (strong_ordering::operator partial_ordering): Likewise. (strong_ordering::operator weak_ordering): Likewise. (operator<=>(unspecified, strong_ordering)): Likewise. * testsuite/18_support/comparisons/categories/partialord.cc: New test. * testsuite/18_support/comparisons/categories/strongord.cc: New test. * testsuite/18_support/comparisons/categories/weakord.cc: New test. Tested powerpc64le-linux and x86_64-linux. This is an ABI change for the partial_ordering type, but that is why I think we should do it now, not after GCC 10 is released. The sooner the better, before these types are being widely used. I plan to commit this in the next 12 hours or so, unless there are (valid :-) objections. Thanks to Barry Revzin for pointing out there was room for these operators to be improved. commit 556a60b573cd599d44f7dae3dccafb9d0694f088 Author: Jonathan Wakely Date: Thu Feb 6 13:31:36 2020 + libstdc++: Optimize C++20 comparison category types This reduces sizeof(std::partial_ordering) and optimizes conversion and comparison operators to avoid conditional branches where possible. * libsupc++/compare (__cmp_cat::_Ncmp::unordered): Change value to 2. (partial_ordering::_M_is_ordered): Remove data member. (partial_ordering): Use second bit of _M_value for unordered. Adjust comparison operators. (weak_ordering::operator partial_ordering): Simplify to remove branches. (operator<=>(unspecified, weak_ordering)): Likewise. (strong_ordering::operator partial_ordering): Likewise. (strong_ordering::operator weak_ordering): Likewise. (operator<=>(unspecified, strong_ordering)): Likewise. * testsuite/18_support/comparisons/categories/partialord.cc: New test. * testsuite/18_support/comparisons/categories/strongord.cc: New test. * testsuite/18_support/comparisons/categories/weakord.cc: New test. diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index a7a29ef0440..8ac446a9bc5 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -50,7 +50,7 @@ namespace std { enum class _Ord { equivalent = 0, less = -1, greater = 1 }; -enum class _Ncmp { _Unordered = -127 }; +enum class _Ncmp { _Unordered = 2 }; struct __unspec { @@ -61,18 +61,20 @@ namespace std class partial_ordering { int _M_value; -bool _M_is_ordered; constexpr explicit partial_ordering(__cmp_cat::_Ord __v) noexcept -: _M_value(int(__v)), _M_is_ordered(true) +: _M_value(int(__v)) { } constexpr explicit partial_ordering(__cmp_cat::_Ncmp __v) noexcept -: _M_value(int(__v)), _M_is_ordered(false) +: _M_value(int(__v)) { } +friend class weak_ordering; +friend class strong_ordering; + public: // valid values static const partial_ordering less; @@ -83,42 +85,42 @@ namespace std // comparisons friend constexpr bool operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept -{ return __v._M_is_ordered && __v._M_value == 0; } +{ return __v._M_value == 0; } friend constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default; friend constexpr bool operator< (partial_ordering __v, __cmp_cat::__unspec) noexcept -{ return __v._M_is_ordered && __v._M_value < 0; } +{ return __v._M_value == -1; } friend constexpr bool operator> (partial_ordering __v, __cmp_cat::__unspec) noexcept -{ return __v._M_is_ordered && __v._M_value > 0; } +{ return __v._M_value == 1; } friend constexpr bool operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept -{ return __v._M_is_ordered && __v._M_value <= 0; } +{ return __v._M_value <= 0; } friend constexpr bool operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept -{ return __v._M_is_ordered && __v._M_value >= 0; } +{ return (__v._M_value & 1) == __v._M_value; } friend constexpr bool operator< (__cmp_cat::__unspec, partial_ordering __v) noexcept -{ return __v._M_is_ordered && 0 < __v._M_value; } +{ return __v._M_value == 1; } friend constexpr bool operator> (__cmp_cat::__unspec, partial_ordering __v) noexcept -{ return __v._M_is_ordered && 0 >