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 <jwak...@redhat.com> Date: Thu Feb 6 13:31:36 2020 +0000 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 > __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 <= __v._M_value; } + { 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 0 >= __v._M_value; } friend constexpr partial_ordering operator<=>(partial_ordering __v, __cmp_cat::__unspec) noexcept @@ -127,10 +129,8 @@ namespace std friend constexpr partial_ordering operator<=>(__cmp_cat::__unspec, partial_ordering __v) noexcept { - if (__v < 0) - return partial_ordering::greater; - else if (__v > 0) - return partial_ordering::less; + if (__v._M_value & 1) + return partial_ordering(__cmp_cat::_Ord(-__v._M_value)); else return __v; } @@ -157,6 +157,8 @@ namespace std weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(int(__v)) { } + friend class strong_ordering; + public: // valid values static const weak_ordering less; @@ -164,14 +166,7 @@ namespace std static const weak_ordering greater; constexpr operator partial_ordering() const noexcept - { - if (_M_value == 0) - return partial_ordering::equivalent; - else if (_M_value < 0) - return partial_ordering::less; - else - return partial_ordering::greater; - } + { return partial_ordering(__cmp_cat::_Ord(_M_value)); } // comparisons friend constexpr bool @@ -219,14 +214,7 @@ namespace std friend constexpr weak_ordering operator<=>(__cmp_cat::__unspec, weak_ordering __v) noexcept - { - if (__v < 0) - return weak_ordering::greater; - else if (__v > 0) - return weak_ordering::less; - else - return __v; - } + { return weak_ordering(__cmp_cat::_Ord(-__v._M_value)); } }; // valid values' definitions @@ -256,24 +244,10 @@ namespace std static const strong_ordering greater; constexpr operator partial_ordering() const noexcept - { - if (_M_value == 0) - return partial_ordering::equivalent; - else if (_M_value < 0) - return partial_ordering::less; - else - return partial_ordering::greater; - } + { return partial_ordering(__cmp_cat::_Ord(_M_value)); } constexpr operator weak_ordering() const noexcept - { - if (_M_value == 0) - return weak_ordering::equivalent; - else if (_M_value < 0) - return weak_ordering::less; - else - return weak_ordering::greater; - } + { return weak_ordering(__cmp_cat::_Ord(_M_value)); } // comparisons friend constexpr bool @@ -321,14 +295,7 @@ namespace std friend constexpr strong_ordering operator<=>(__cmp_cat::__unspec, strong_ordering __v) noexcept - { - if (__v < 0) - return strong_ordering::greater; - else if (__v > 0) - return strong_ordering::less; - else - return __v; - } + { return strong_ordering(__cmp_cat::_Ord(-__v._M_value)); } }; // valid values' definitions diff --git a/libstdc++-v3/testsuite/18_support/comparisons/categories/partialord.cc b/libstdc++-v3/testsuite/18_support/comparisons/categories/partialord.cc new file mode 100644 index 00000000000..01db2ca055e --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/categories/partialord.cc @@ -0,0 +1,86 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <compare> + +using std::partial_ordering; + +static_assert( partial_ordering::less == partial_ordering::less ); +static_assert( partial_ordering::less != partial_ordering::equivalent ); +static_assert( partial_ordering::less != partial_ordering::greater ); +static_assert( partial_ordering::less != partial_ordering::unordered ); +static_assert( partial_ordering::equivalent == partial_ordering::equivalent ); +static_assert( partial_ordering::equivalent != partial_ordering::greater ); +static_assert( partial_ordering::equivalent != partial_ordering::unordered ); +static_assert( partial_ordering::greater == partial_ordering::greater ); +static_assert( partial_ordering::greater != partial_ordering::unordered ); +static_assert( partial_ordering::unordered == partial_ordering::unordered ); + +static_assert( ! (partial_ordering::less == 0) ); +static_assert( partial_ordering::less < 0 ); +static_assert( ! (partial_ordering::less > 0) ); +static_assert( partial_ordering::less <= 0 ); +static_assert( ! (partial_ordering::less >= 0) ); +static_assert( ! (0 == partial_ordering::less) ); +static_assert( ! (0 < partial_ordering::less) ); +static_assert( 0 > partial_ordering::less ); +static_assert( ! (0 <= partial_ordering::less) ); +static_assert( 0 >= partial_ordering::less ); +static_assert( (partial_ordering::less <=> 0) == partial_ordering::less ); +static_assert( (0 <=> partial_ordering::less) == partial_ordering::greater ); + +static_assert( (partial_ordering::equivalent == 0) ); +static_assert( ! (partial_ordering::equivalent < 0) ); +static_assert( ! (partial_ordering::equivalent > 0) ); +static_assert( partial_ordering::equivalent <= 0 ); +static_assert( partial_ordering::equivalent >= 0 ); +static_assert( 0 == partial_ordering::equivalent ); +static_assert( ! (0 < partial_ordering::equivalent) ); +static_assert( ! (0 > partial_ordering::equivalent) ); +static_assert( 0 <= partial_ordering::equivalent ); +static_assert( 0 >= partial_ordering::equivalent ); +static_assert( (partial_ordering::equivalent <=> 0) == partial_ordering::equivalent ); +static_assert( (0 <=> partial_ordering::equivalent) == partial_ordering::equivalent ); + +static_assert( ! (partial_ordering::greater == 0) ); +static_assert( ! (partial_ordering::greater < 0) ); +static_assert( partial_ordering::greater > 0 ); +static_assert( ! (partial_ordering::greater <= 0) ); +static_assert( partial_ordering::greater >= 0 ); +static_assert( ! (0 == partial_ordering::greater) ); +static_assert( 0 < partial_ordering::greater ); +static_assert( ! (0 > partial_ordering::greater) ); +static_assert( 0 <= partial_ordering::greater ); +static_assert( ! (0 >= partial_ordering::greater) ); +static_assert( (partial_ordering::greater <=> 0) == partial_ordering::greater ); +static_assert( (0 <=> partial_ordering::greater) == partial_ordering::less ); + +static_assert( ! (partial_ordering::unordered == 0) ); +static_assert( ! (partial_ordering::unordered < 0) ); +static_assert( ! (partial_ordering::unordered > 0) ); +static_assert( ! (partial_ordering::unordered <= 0) ); +static_assert( ! (partial_ordering::unordered >= 0) ); +static_assert( ! (0 == partial_ordering::unordered) ); +static_assert( ! (0 < partial_ordering::unordered) ); +static_assert( ! (0 > partial_ordering::unordered) ); +static_assert( ! (0 <= partial_ordering::unordered) ); +static_assert( ! (0 >= partial_ordering::unordered) ); +static_assert( (partial_ordering::unordered <=> 0) == partial_ordering::unordered ); +static_assert( (0 <=> partial_ordering::unordered) == partial_ordering::unordered ); diff --git a/libstdc++-v3/testsuite/18_support/comparisons/categories/strongord.cc b/libstdc++-v3/testsuite/18_support/comparisons/categories/strongord.cc new file mode 100644 index 00000000000..0485e5a1463 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/categories/strongord.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <compare> + +using std::strong_ordering; + +static_assert( strong_ordering::less == strong_ordering::less ); +static_assert( strong_ordering::less != strong_ordering::equal ); +static_assert( strong_ordering::less != strong_ordering::equivalent ); +static_assert( strong_ordering::less != strong_ordering::greater ); +static_assert( strong_ordering::equivalent == strong_ordering::equivalent ); +static_assert( strong_ordering::equivalent == strong_ordering::equal ); +static_assert( strong_ordering::equivalent != strong_ordering::greater ); +static_assert( strong_ordering::equal == strong_ordering::equal ); +static_assert( strong_ordering::equal != strong_ordering::greater ); +static_assert( strong_ordering::greater == strong_ordering::greater ); + +static_assert( ! (strong_ordering::less == 0) ); +static_assert( strong_ordering::less < 0 ); +static_assert( ! (strong_ordering::less > 0) ); +static_assert( strong_ordering::less <= 0 ); +static_assert( ! (strong_ordering::less >= 0) ); +static_assert( ! (0 == strong_ordering::less) ); +static_assert( ! (0 < strong_ordering::less) ); +static_assert( 0 > strong_ordering::less ); +static_assert( ! (0 <= strong_ordering::less) ); +static_assert( 0 >= strong_ordering::less ); +static_assert( (strong_ordering::less <=> 0) == strong_ordering::less ); +static_assert( (0 <=> strong_ordering::less) == strong_ordering::greater ); + +static_assert( (strong_ordering::equal == 0) ); +static_assert( ! (strong_ordering::equal < 0) ); +static_assert( ! (strong_ordering::equal > 0) ); +static_assert( strong_ordering::equal <= 0 ); +static_assert( strong_ordering::equal >= 0 ); +static_assert( 0 == strong_ordering::equal ); +static_assert( ! (0 < strong_ordering::equal) ); +static_assert( ! (0 > strong_ordering::equal) ); +static_assert( 0 <= strong_ordering::equal ); +static_assert( 0 >= strong_ordering::equal ); +static_assert( (strong_ordering::equal <=> 0) == strong_ordering::equal ); +static_assert( (0 <=> strong_ordering::equal) == strong_ordering::equal ); + +static_assert( (strong_ordering::equivalent == 0) ); +static_assert( ! (strong_ordering::equivalent < 0) ); +static_assert( ! (strong_ordering::equivalent > 0) ); +static_assert( strong_ordering::equivalent <= 0 ); +static_assert( strong_ordering::equivalent >= 0 ); +static_assert( 0 == strong_ordering::equivalent ); +static_assert( ! (0 < strong_ordering::equivalent) ); +static_assert( ! (0 > strong_ordering::equivalent) ); +static_assert( 0 <= strong_ordering::equivalent ); +static_assert( 0 >= strong_ordering::equivalent ); +static_assert( (strong_ordering::equivalent <=> 0) == strong_ordering::equivalent ); +static_assert( (0 <=> strong_ordering::equivalent) == strong_ordering::equivalent ); + +static_assert( ! (strong_ordering::greater == 0) ); +static_assert( ! (strong_ordering::greater < 0) ); +static_assert( strong_ordering::greater > 0 ); +static_assert( ! (strong_ordering::greater <= 0) ); +static_assert( strong_ordering::greater >= 0 ); +static_assert( ! (0 == strong_ordering::greater) ); +static_assert( 0 < strong_ordering::greater ); +static_assert( ! (0 > strong_ordering::greater) ); +static_assert( 0 <= strong_ordering::greater ); +static_assert( ! (0 >= strong_ordering::greater) ); +static_assert( (strong_ordering::greater <=> 0) == strong_ordering::greater ); +static_assert( (0 <=> strong_ordering::greater) == strong_ordering::less ); + +// Conversions +using std::partial_ordering; +static_assert( partial_ordering(strong_ordering::less) == partial_ordering::less ); +static_assert( partial_ordering(strong_ordering::equal) == partial_ordering::equivalent ); +static_assert( partial_ordering(strong_ordering::equivalent) == partial_ordering::equivalent ); +static_assert( partial_ordering(strong_ordering::greater) == partial_ordering::greater ); +using std::weak_ordering; +static_assert( weak_ordering(strong_ordering::less) == weak_ordering::less ); +static_assert( partial_ordering(strong_ordering::equal) == weak_ordering::equivalent ); +static_assert( partial_ordering(strong_ordering::equivalent) == weak_ordering::equivalent ); +static_assert( weak_ordering(strong_ordering::greater) == weak_ordering::greater ); diff --git a/libstdc++-v3/testsuite/18_support/comparisons/categories/weakord.cc b/libstdc++-v3/testsuite/18_support/comparisons/categories/weakord.cc new file mode 100644 index 00000000000..0720e1f86af --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/categories/weakord.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <compare> + +using std::weak_ordering; + +static_assert( weak_ordering::less == weak_ordering::less ); +static_assert( weak_ordering::less != weak_ordering::equivalent ); +static_assert( weak_ordering::less != weak_ordering::greater ); +static_assert( weak_ordering::equivalent == weak_ordering::equivalent ); +static_assert( weak_ordering::equivalent != weak_ordering::greater ); +static_assert( weak_ordering::greater == weak_ordering::greater ); + +static_assert( ! (weak_ordering::less == 0) ); +static_assert( weak_ordering::less < 0 ); +static_assert( ! (weak_ordering::less > 0) ); +static_assert( weak_ordering::less <= 0 ); +static_assert( ! (weak_ordering::less >= 0) ); +static_assert( ! (0 == weak_ordering::less) ); +static_assert( ! (0 < weak_ordering::less) ); +static_assert( 0 > weak_ordering::less ); +static_assert( ! (0 <= weak_ordering::less) ); +static_assert( 0 >= weak_ordering::less ); +static_assert( (weak_ordering::less <=> 0) == weak_ordering::less ); +static_assert( (0 <=> weak_ordering::less) == weak_ordering::greater ); + +static_assert( (weak_ordering::equivalent == 0) ); +static_assert( ! (weak_ordering::equivalent < 0) ); +static_assert( ! (weak_ordering::equivalent > 0) ); +static_assert( weak_ordering::equivalent <= 0 ); +static_assert( weak_ordering::equivalent >= 0 ); +static_assert( 0 == weak_ordering::equivalent ); +static_assert( ! (0 < weak_ordering::equivalent) ); +static_assert( ! (0 > weak_ordering::equivalent) ); +static_assert( 0 <= weak_ordering::equivalent ); +static_assert( 0 >= weak_ordering::equivalent ); +static_assert( (weak_ordering::equivalent <=> 0) == weak_ordering::equivalent ); +static_assert( (0 <=> weak_ordering::equivalent) == weak_ordering::equivalent ); + +static_assert( ! (weak_ordering::greater == 0) ); +static_assert( ! (weak_ordering::greater < 0) ); +static_assert( weak_ordering::greater > 0 ); +static_assert( ! (weak_ordering::greater <= 0) ); +static_assert( weak_ordering::greater >= 0 ); +static_assert( ! (0 == weak_ordering::greater) ); +static_assert( 0 < weak_ordering::greater ); +static_assert( ! (0 > weak_ordering::greater) ); +static_assert( 0 <= weak_ordering::greater ); +static_assert( ! (0 >= weak_ordering::greater) ); +static_assert( (weak_ordering::greater <=> 0) == weak_ordering::greater ); +static_assert( (0 <=> weak_ordering::greater) == weak_ordering::less ); + +// Conversions +using std::partial_ordering; +static_assert( partial_ordering(weak_ordering::less) == partial_ordering::less ); +static_assert( partial_ordering(weak_ordering::equivalent) == partial_ordering::equivalent ); +static_assert( partial_ordering(weak_ordering::greater) == partial_ordering::greater );