public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] libstdc++: Optimize C++20 comparison category types
@ 2020-02-06 13:41 Jonathan Wakely
  2020-02-06 13:54 ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2020-02-06 13:41 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1319 bytes --]

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.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 21407 bytes --]

commit 556a60b573cd599d44f7dae3dccafb9d0694f088
Author: Jonathan Wakely <jwakely@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 );

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libstdc++: Optimize C++20 comparison category types
  2020-02-06 13:41 [PATCH] libstdc++: Optimize C++20 comparison category types Jonathan Wakely
@ 2020-02-06 13:54 ` Jonathan Wakely
  2020-02-06 14:28   ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2020-02-06 13:54 UTC (permalink / raw)
  To: libstdc++, gcc-patches

On 06/02/20 13:40 +0000, 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<std::partial_ordering, char> which would benefit.

Anybody want to argue for or against making them 8 bits?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libstdc++: Optimize C++20 comparison category types
  2020-02-06 13:54 ` Jonathan Wakely
@ 2020-02-06 14:28   ` Jonathan Wakely
  2020-02-07  9:05     ` Daniel Krügler
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2020-02-06 14:28 UTC (permalink / raw)
  To: libstdc++, gcc-patches

On 06/02/20 13:53 +0000, Jonathan Wakely wrote:
>On 06/02/20 13:40 +0000, 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<std::partial_ordering, char> which would benefit.
>
>Anybody want to argue for or against making them 8 bits?
>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libstdc++: Optimize C++20 comparison category types
  2020-02-06 14:28   ` Jonathan Wakely
@ 2020-02-07  9:05     ` Daniel Krügler
  2020-02-07 14:23       ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Krügler @ 2020-02-07  9:05 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches List

Am Do., 6. Feb. 2020 um 15:28 Uhr schrieb Jonathan Wakely <jwakely@redhat.com>:
>
> On 06/02/20 13:53 +0000, Jonathan Wakely wrote:
> >On 06/02/20 13:40 +0000, 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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libstdc++: Optimize C++20 comparison category types
  2020-02-07  9:05     ` Daniel Krügler
@ 2020-02-07 14:23       ` Jonathan Wakely
  2020-02-07 16:02         ` Daniel Krügler
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2020-02-07 14:23 UTC (permalink / raw)
  To: Daniel Krügler; +Cc: libstdc++, gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 2730 bytes --]

On 07/02/20 10:04 +0100, Daniel Krügler wrote:
>Am Do., 6. Feb. 2020 um 15:28 Uhr schrieb Jonathan Wakely <jwakely@redhat.com>:
>>
>> On 06/02/20 13:53 +0000, Jonathan Wakely wrote:
>> >On 06/02/20 13:40 +0000, 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 <compare>?

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.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 22813 bytes --]

commit 0d57370c9cc3c1fb68be96b8cc15b92496c4dd21
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Feb 6 13:31:36 2020 +0000

    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;
+    // less=0xff, equiv=0x00, greater=0x01, unordered=0x02
+    __cmp_cat::type _M_value;
 
     constexpr explicit
     partial_ordering(__cmp_cat::_Ord __v) noexcept
-    : _M_value(int(__v)), _M_is_ordered(true)
+    : _M_value(__cmp_cat::type(__v))
     { }
 
     constexpr explicit
     partial_ordering(__cmp_cat::_Ncmp __v) noexcept
-    : _M_value(int(__v)), _M_is_ordered(false)
+    : _M_value(__cmp_cat::type(__v))
     { }
 
+    friend class weak_ordering;
+    friend class strong_ordering;
+
   public:
     // valid values
     static const partial_ordering less;
@@ -83,42 +88,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 __cmp_cat::type(__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 __cmp_cat::type(__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 +132,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;
     }
@@ -151,12 +154,14 @@ namespace std
 
   class weak_ordering
   {
-    int _M_value;
+    __cmp_cat::type _M_value;
 
     constexpr explicit
-    weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(int(__v))
+    weak_ordering(__cmp_cat::_Ord __v) noexcept : _M_value(__cmp_cat::type(__v))
     { }
 
+    friend class strong_ordering;
+
   public:
     // valid values
     static const weak_ordering less;
@@ -164,14 +169,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 +217,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
@@ -241,11 +232,11 @@ namespace std
 
   class strong_ordering
   {
-    int _M_value;
+    __cmp_cat::type _M_value;
 
     constexpr explicit
     strong_ordering(__cmp_cat::_Ord __v) noexcept
-    : _M_value(int(__v))
+    : _M_value(__cmp_cat::type(__v))
     { }
 
   public:
@@ -256,24 +247,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 +298,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 );

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libstdc++: Optimize C++20 comparison category types
  2020-02-07 14:23       ` Jonathan Wakely
@ 2020-02-07 16:02         ` Daniel Krügler
  0 siblings, 0 replies; 6+ messages in thread
From: Daniel Krügler @ 2020-02-07 16:02 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches List

Am Fr., 7. Feb. 2020 um 15:23 Uhr schrieb Jonathan Wakely <jwakely@redhat.com>:
>
> On 07/02/20 10:04 +0100, Daniel Krügler wrote:
> >Am Do., 6. Feb. 2020 um 15:28 Uhr schrieb Jonathan Wakely <jwakely@redhat.com>:
> >>
> >> On 06/02/20 13:53 +0000, Jonathan Wakely wrote:
> >> >On 06/02/20 13:40 +0000, 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 <compare>?
>
> 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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-02-07 16:02 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-06 13:41 [PATCH] libstdc++: Optimize C++20 comparison category types Jonathan Wakely
2020-02-06 13:54 ` Jonathan Wakely
2020-02-06 14:28   ` Jonathan Wakely
2020-02-07  9:05     ` Daniel Krügler
2020-02-07 14:23       ` Jonathan Wakely
2020-02-07 16:02         ` Daniel Krügler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).