[libcxx-commits] [libcxx] [libc++] Optimize std::lexicographical_compare_three_way (PR #230336)

Advit Arora via libcxx-commits libcxx-commits at lists.llvm.org
Tue Oct 13 05:08:59 PDT 2026


https://github.com/advitrocks9 updated https://github.com/llvm/llvm-project/pull/230336

>From 2298d76b6ae2146eb7216af402be159a5f04b1c7 Mon Sep 17 00:00:00 2001
From: Advit Arora <advitarora2 at gmail.com>
Date: Thu, 8 Oct 2026 17:22:20 -0700
Subject: [PATCH 1/3] [libc++] Optimize std::lexicographical_compare_three_way

`std::lexicographical_compare_three_way` compares one element at a time, even with the default comparator on integers.

With `std::compare_three_way` on a type whose `==` compares bytes, the first unequal element is the first one whose bytes differ. So this finds it with `std::mismatch`, which is vectorized, or with `memcmp` for unsigned bytes, and calls the comparator once there. `lexicographical_compare` has done the same since #65279.

The fast path only applies to contiguous ranges compared with `std::compare_three_way` on trivially equality comparable types. Floating point, custom comparators and debug hardening keep the old loop. `compare_three_way` gets a `__desugars_to` tag for this, which is safe because `three_way_comparable_with` requires `a <=> b == 0` to match `a == b`.

```
ns, before -> after   n=1           n=16          n=1024        n=65536
unsigned char         0.68 -> 2.46  5.26 -> 2.39  229 -> 10.3   14293 -> 942
signed char           0.69 -> 2.29  5.50 -> 1.84  236 -> 22.6   14826 -> 1447
int                   0.67 -> 2.02  5.49 -> 2.72  238 -> 103    16807 -> 6438
```

Measured with the in-tree benchmark, clang -O3, Ryzen 9 5950X. One-element ranges are about 1.5 ns slower, the same tradeoff as the two-way version.

Container `operator<=>` uses a different comparator, so `vector<int> <=> vector<int>` isn't covered yet. I'll do that separately.

Fixes #129325

Assisted-by: Claude Code
---
 libcxx/docs/ReleaseNotes/24.rst               |  3 +
 .../lexicographical_compare_three_way.h       | 36 +++++++++-
 libcxx/include/__compare/compare_three_way.h  |  4 ++
 libcxx/include/__type_traits/desugars_to.h    |  3 +
 ...exicographical_compare_three_way.bench.cpp | 12 +++-
 ...lexicographical_compare_three_way.pass.cpp | 68 +++++++++++++++++++
 6 files changed, 122 insertions(+), 4 deletions(-)

diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index 04f02ab66a773c..d6d0a92619a5f4 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -62,6 +62,9 @@ Improvements and New Features
 -----------------------------
 
 - ``basic_filebuf`` now supports files larger than 2GB on 32-bit AIX and 32-bit glibc targets.
+- ``std::lexicographical_compare_three_way`` has been optimized for contiguous ranges of integers and other trivially
+  equality comparable types, resulting in a performance improvement of up to 22x for ``unsigned char`` and 2.5x for
+  ``int``.
 
 Deprecations and Removals
 -------------------------
diff --git a/libcxx/include/__algorithm/lexicographical_compare_three_way.h b/libcxx/include/__algorithm/lexicographical_compare_three_way.h
index 5be95c4d513471..46abf705b0710c 100644
--- a/libcxx/include/__algorithm/lexicographical_compare_three_way.h
+++ b/libcxx/include/__algorithm/lexicographical_compare_three_way.h
@@ -10,14 +10,22 @@
 #define _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_THREE_WAY_H
 
 #include <__algorithm/min.h>
+#include <__algorithm/mismatch.h>
 #include <__algorithm/three_way_comp_ref_type.h>
+#include <__algorithm/unwrap_iter.h>
 #include <__compare/compare_three_way.h>
 #include <__compare/ordering.h>
 #include <__concepts/arithmetic.h>
 #include <__config>
 #include <__iterator/iterator_traits.h>
+#include <__string/constexpr_c_functions.h>
 #include <__type_traits/common_type.h>
+#include <__type_traits/desugars_to.h>
+#include <__type_traits/enable_if.h>
 #include <__type_traits/is_constructible.h>
+#include <__type_traits/is_equality_comparable.h>
+#include <__type_traits/is_trivially_lexicographically_comparable.h>
+#include <__type_traits/is_volatile.h>
 #include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -62,6 +70,28 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_fast_pa
   return __len1 <=> __len2;
 }
 
+template <class _Tp,
+          class _Cmp,
+          __enable_if_t<__desugars_to_v<__compare_three_way_tag, _Cmp, _Tp, _Tp> && !is_volatile<_Tp>::value &&
+                            __is_trivially_equality_comparable_v<_Tp, _Tp>,
+                        int> = 0>
+_LIBCPP_HIDE_FROM_ABI constexpr auto
+__lexicographical_compare_three_way_fast_path(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Tp* __last2, _Cmp& __comp)
+    -> decltype(__comp(*__first1, *__first2)) {
+  auto __len1 = __last1 - __first1;
+  auto __len2 = __last2 - __first2;
+  if constexpr (__is_trivially_lexicographically_comparable_v<_Tp, _Tp>) {
+    auto __res = std::__constexpr_memcmp(__first1, __first2, __element_count(std::min(__len1, __len2)));
+    if (__res != 0)
+      return __res <=> 0;
+  } else {
+    auto __res = std::mismatch(__first1, __last1, __first2, __last2);
+    if (__res.first != __last1 && __res.second != __last2)
+      return __comp(*__res.first, *__res.second);
+  }
+  return __len1 <=> __len2;
+}
+
 // Unoptimized implementation which compares the iterators against the end in every loop iteration
 template <class _InputIterator1, class _InputIterator2, class _Cmp>
 _LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_slow_path(
@@ -101,7 +131,11 @@ template <class _InputIterator1, class _InputIterator2, class _Cmp>
   if constexpr (__has_random_access_iterator_category<_InputIterator1>::value &&
                 __has_random_access_iterator_category<_InputIterator2>::value) {
     return std::__lexicographical_compare_three_way_fast_path(
-        std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __wrapped_comp_ref);
+        std::__unwrap_iter(__first1),
+        std::__unwrap_iter(__last1),
+        std::__unwrap_iter(__first2),
+        std::__unwrap_iter(__last2),
+        __wrapped_comp_ref);
   } else {
     // Unoptimized implementation which compares the iterators against the end in every loop iteration
     return std::__lexicographical_compare_three_way_slow_path(
diff --git a/libcxx/include/__compare/compare_three_way.h b/libcxx/include/__compare/compare_three_way.h
index 6999000e9dceae..a0c4278629fcda 100644
--- a/libcxx/include/__compare/compare_three_way.h
+++ b/libcxx/include/__compare/compare_three_way.h
@@ -12,6 +12,7 @@
 
 #include <__compare/three_way_comparable.h>
 #include <__config>
+#include <__type_traits/desugars_to.h>
 #include <__utility/forward.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -33,6 +34,9 @@ struct compare_three_way {
   using is_transparent = void;
 };
 
+template <class _Tp, class _Up>
+inline const bool __desugars_to_v<__compare_three_way_tag, compare_three_way, _Tp, _Up> = true;
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__type_traits/desugars_to.h b/libcxx/include/__type_traits/desugars_to.h
index 029b3c6336837c..65744d1742b3a9 100644
--- a/libcxx/include/__type_traits/desugars_to.h
+++ b/libcxx/include/__type_traits/desugars_to.h
@@ -40,6 +40,9 @@ struct __greater_tag {};
 // additional semantic requirements on that operation.
 struct __totally_ordered_less_tag {};
 
+// syntactically, the operation is equivalent to calling `a <=> b`, and `a <=> b == 0` is equivalent to `a == b`
+struct __compare_three_way_tag {};
+
 // This class template is used to determine whether an operation "desugars"
 // (or boils down) to a given canonical operation.
 //
diff --git a/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp b/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp
index 75105c4fc1fd1a..36572ce527ed54 100644
--- a/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp
+++ b/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp
@@ -9,6 +9,8 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 
 #include <algorithm>
+#include <iterator>
+#include <vector>
 
 #include "benchmark/benchmark.h"
 #include "test_iterators.h"
@@ -17,12 +19,12 @@
 template <class IteratorT>
 static TEST_ALIGN_BENCHMARK void BM_lexicographical_compare_three_way(benchmark::State& state) {
   auto size = state.range(0);
-  std::vector<int> v1;
+  std::vector<std::iter_value_t<IteratorT>> v1;
   v1.resize(size);
   // v2 is identical except for the last value.
   // This means, that `lexicographical_compare_three_way` actually has to
   // compare the complete vector and cannot bail out early.
-  std::vector<int> v2 = v1;
+  auto v2 = v1;
   v2.back() += 1;
   auto b1 = IteratorT{v1.data()};
   auto e1 = IteratorT{v1.data() + v1.size()};
@@ -36,10 +38,14 @@ static TEST_ALIGN_BENCHMARK void BM_lexicographical_compare_three_way(benchmark:
 
 // Type alias to make sure the `*` does not appear in the benchmark name.
 // A `*` would confuse the Python test runner running this google benchmark.
-using IntPtr = int*;
+using IntPtr          = int*;
+using UnsignedCharPtr = unsigned char*;
+using SignedCharPtr   = signed char*;
 
 // `lexicographical_compare_three_way` has a fast path for random access iterators.
 BENCHMARK(BM_lexicographical_compare_three_way<IntPtr>)->RangeMultiplier(4)->Range(1, 1 << 20);
+BENCHMARK(BM_lexicographical_compare_three_way<UnsignedCharPtr>)->RangeMultiplier(4)->Range(1, 1 << 20);
+BENCHMARK(BM_lexicographical_compare_three_way<SignedCharPtr>)->RangeMultiplier(4)->Range(1, 1 << 20);
 BENCHMARK(BM_lexicographical_compare_three_way<random_access_iterator<IntPtr>>)->RangeMultiplier(4)->Range(1, 1 << 20);
 BENCHMARK(BM_lexicographical_compare_three_way<cpp17_input_iterator<IntPtr>>)->RangeMultiplier(4)->Range(1, 1 << 20);
 
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
index d7cd49987689db..739e56f2176d2c 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
@@ -19,6 +19,8 @@
 #include <cassert>
 #include <compare>
 #include <concepts>
+#include <cstddef>
+#include <limits>
 #include <vector>
 
 #include "test_macros.h"
@@ -108,6 +110,71 @@ constexpr void test_comparison_categories() {
       std::partial_ordering::unordered);
 }
 
+struct DefaultedOrder {
+  int i;
+  constexpr auto operator<=>(const DefaultedOrder&) const = default;
+};
+
+struct ReversedWeakOrder {
+  int i;
+  constexpr std::weak_ordering operator<=>(const ReversedWeakOrder& other) const { return other.i <=> i; }
+  constexpr bool operator==(const ReversedWeakOrder&) const = default;
+};
+
+template <class T, class Order>
+constexpr void test_long_range(T lhs, T rhs, Order expected) {
+  std::array<T, 300> a{};
+  std::array<T, 300> b{};
+  a[257] = lhs;
+  b[257] = rhs;
+  test_lexicographical_compare<const T*, const T*>(a, b, expected);
+  test_lexicographical_compare<const T*, const T*>(a, std::array<T, 257>{}, std::strong_ordering::greater);
+}
+
+constexpr void test_element_types() {
+  using SChar = signed char;
+  using UChar = unsigned char;
+  test_lexicographical_compare<const SChar*, const SChar*>(
+      std::array<SChar, 2>{0, -1}, std::array<SChar, 2>{0, 1}, std::strong_ordering::less);
+  test_lexicographical_compare<const UChar*, const UChar*>(
+      std::array<UChar, 2>{0, 255}, std::array<UChar, 2>{0, 1}, std::strong_ordering::greater);
+  test_lexicographical_compare<const UChar*, const UChar*>(
+      std::array<UChar, 2>{1, 2}, std::array<UChar, 3>{1, 2, 0}, std::strong_ordering::less);
+  test_lexicographical_compare<const UChar*, const UChar*>(
+      std::array<UChar, 0>{}, std::array<UChar, 0>{}, std::strong_ordering::equal);
+  test_lexicographical_compare<const std::byte*, const std::byte*>(
+      std::array{std::byte{0}, std::byte{255}}, std::array{std::byte{0}, std::byte{1}}, std::strong_ordering::greater);
+  test_lexicographical_compare<const char*, const char*>(
+      std::array{'a', 'b'}, std::array{'a', 'b', 'c'}, std::strong_ordering::less);
+  test_lexicographical_compare<const bool*, const bool*>(
+      std::array{true, false}, std::array{true, true}, std::strong_ordering::less);
+  test_lexicographical_compare<const int*, const int*>(std::array{-1}, std::array{1}, std::strong_ordering::less);
+  test_lexicographical_compare<const int*, const int*>(std::array{256}, std::array{1}, std::strong_ordering::greater);
+  test_lexicographical_compare<const long long*, const long long*>(
+      std::array{1LL, -1LL}, std::array{1LL, 1LL}, std::strong_ordering::less);
+
+  test_lexicographical_compare<const double*, const double*>(
+      std::array{-0.0, 1.0}, std::array{0.0, 2.0}, std::partial_ordering::less);
+  test_lexicographical_compare<const double*, const double*>(
+      std::array{1.0, std::numeric_limits<double>::quiet_NaN()},
+      std::array{1.0, std::numeric_limits<double>::quiet_NaN()},
+      std::partial_ordering::unordered);
+
+  test_lexicographical_compare<const DefaultedOrder*, const DefaultedOrder*>(
+      std::array<DefaultedOrder, 2>{{{1}, {-1}}},
+      std::array<DefaultedOrder, 2>{{{1}, {1}}},
+      std::strong_ordering::less);
+  test_lexicographical_compare<const ReversedWeakOrder*, const ReversedWeakOrder*>(
+      std::array<ReversedWeakOrder, 2>{{{1}, {2}}},
+      std::array<ReversedWeakOrder, 2>{{{1}, {3}}},
+      std::weak_ordering::greater);
+
+  test_long_range<SChar>(1, -1, std::strong_ordering::greater);
+  test_long_range<UChar>(1, 255, std::strong_ordering::less);
+  test_long_range<int>(256, 1, std::strong_ordering::greater);
+  test_long_range<long long>(-1, 1, std::strong_ordering::less);
+}
+
 // Check that it works with proxy iterators
 constexpr void test_proxy_iterators() {
     std::vector<bool> vec(10, true);
@@ -118,6 +185,7 @@ constexpr void test_proxy_iterators() {
 constexpr bool test() {
   test_iterator_types();
   test_comparison_categories();
+  test_element_types();
   test_proxy_iterators();
 
   return true;

>From 95f6c5c9106c6ede1cffb26a2caf1640c3dd143f Mon Sep 17 00:00:00 2001
From: Advit Arora <advitarora2 at gmail.com>
Date: Mon, 12 Oct 2026 11:54:24 -0700
Subject: [PATCH 2/3] Use if constexpr instead of SFINAE for the fast path

---
 .../lexicographical_compare_three_way.h       | 53 +++++++++----------
 1 file changed, 24 insertions(+), 29 deletions(-)

diff --git a/libcxx/include/__algorithm/lexicographical_compare_three_way.h b/libcxx/include/__algorithm/lexicographical_compare_three_way.h
index 46abf705b0710c..fbd86ebc98d391 100644
--- a/libcxx/include/__algorithm/lexicographical_compare_three_way.h
+++ b/libcxx/include/__algorithm/lexicographical_compare_three_way.h
@@ -21,11 +21,13 @@
 #include <__string/constexpr_c_functions.h>
 #include <__type_traits/common_type.h>
 #include <__type_traits/desugars_to.h>
-#include <__type_traits/enable_if.h>
 #include <__type_traits/is_constructible.h>
 #include <__type_traits/is_equality_comparable.h>
+#include <__type_traits/is_pointer.h>
+#include <__type_traits/is_same.h>
 #include <__type_traits/is_trivially_lexicographically_comparable.h>
 #include <__type_traits/is_volatile.h>
+#include <__type_traits/remove_pointer.h>
 #include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -58,37 +60,30 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_fast_pa
   _Len2 __len2      = __last2 - __first2;
   _Common __min_len = std::min<_Common>(__len1, __len2);
 
-  for (_Common __i = 0; __i < __min_len; ++__i) {
-    auto __c = __comp(*__first1, *__first2);
-    if (__c != 0) {
-      return __c;
+  using _Tp = remove_pointer_t<_InputIterator1>;
+  if constexpr (is_pointer_v<_InputIterator1> && is_same_v<_InputIterator1, _InputIterator2> &&
+                __desugars_to_v<__compare_three_way_tag, _Cmp, _Tp, _Tp> && !is_volatile_v<_Tp> &&
+                __is_trivially_equality_comparable_v<_Tp, _Tp>) {
+    if constexpr (__is_trivially_lexicographically_comparable_v<_Tp, _Tp>) {
+      auto __res = std::__constexpr_memcmp(__first1, __first2, __element_count(__min_len));
+      if (__res != 0)
+        return __res <=> 0;
+    } else {
+      auto __res = std::mismatch(__first1, __last1, __first2, __last2);
+      if (__res.first != __last1 && __res.second != __last2)
+        return __comp(*__res.first, *__res.second);
     }
-    ++__first1;
-    ++__first2;
-  }
-
-  return __len1 <=> __len2;
-}
-
-template <class _Tp,
-          class _Cmp,
-          __enable_if_t<__desugars_to_v<__compare_three_way_tag, _Cmp, _Tp, _Tp> && !is_volatile<_Tp>::value &&
-                            __is_trivially_equality_comparable_v<_Tp, _Tp>,
-                        int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__lexicographical_compare_three_way_fast_path(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Tp* __last2, _Cmp& __comp)
-    -> decltype(__comp(*__first1, *__first2)) {
-  auto __len1 = __last1 - __first1;
-  auto __len2 = __last2 - __first2;
-  if constexpr (__is_trivially_lexicographically_comparable_v<_Tp, _Tp>) {
-    auto __res = std::__constexpr_memcmp(__first1, __first2, __element_count(std::min(__len1, __len2)));
-    if (__res != 0)
-      return __res <=> 0;
   } else {
-    auto __res = std::mismatch(__first1, __last1, __first2, __last2);
-    if (__res.first != __last1 && __res.second != __last2)
-      return __comp(*__res.first, *__res.second);
+    for (_Common __i = 0; __i < __min_len; ++__i) {
+      auto __c = __comp(*__first1, *__first2);
+      if (__c != 0) {
+        return __c;
+      }
+      ++__first1;
+      ++__first2;
+    }
   }
+
   return __len1 <=> __len2;
 }
 

>From 83385cc7d31a0d18f30d61398663229e6fbcd7e1 Mon Sep 17 00:00:00 2001
From: Advit Arora <advitarora2 at gmail.com>
Date: Tue, 13 Oct 2026 04:48:52 -0700
Subject: [PATCH 3/3] Take the fast path for T* vs const T*

---
 .../lexicographical_compare_three_way.h          | 16 ++++++++++------
 libcxx/include/__string/constexpr_c_functions.h  |  2 +-
 .../lexicographical_compare_three_way.bench.cpp  | 16 +++++-----------
 .../lexicographical_compare_three_way.pass.cpp   |  1 +
 4 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/libcxx/include/__algorithm/lexicographical_compare_three_way.h b/libcxx/include/__algorithm/lexicographical_compare_three_way.h
index fbd86ebc98d391..183785380b04f4 100644
--- a/libcxx/include/__algorithm/lexicographical_compare_three_way.h
+++ b/libcxx/include/__algorithm/lexicographical_compare_three_way.h
@@ -27,6 +27,7 @@
 #include <__type_traits/is_same.h>
 #include <__type_traits/is_trivially_lexicographically_comparable.h>
 #include <__type_traits/is_volatile.h>
+#include <__type_traits/remove_const.h>
 #include <__type_traits/remove_pointer.h>
 #include <__utility/move.h>
 
@@ -60,18 +61,21 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_fast_pa
   _Len2 __len2      = __last2 - __first2;
   _Common __min_len = std::min<_Common>(__len1, __len2);
 
-  using _Tp = remove_pointer_t<_InputIterator1>;
-  if constexpr (is_pointer_v<_InputIterator1> && is_same_v<_InputIterator1, _InputIterator2> &&
+  using _Tp = remove_const_t<remove_pointer_t<_InputIterator1>>;
+  if constexpr (is_pointer_v<_InputIterator1> && is_pointer_v<_InputIterator2> &&
+                is_same_v<_Tp, remove_const_t<remove_pointer_t<_InputIterator2>>> &&
                 __desugars_to_v<__compare_three_way_tag, _Cmp, _Tp, _Tp> && !is_volatile_v<_Tp> &&
                 __is_trivially_equality_comparable_v<_Tp, _Tp>) {
+    const _Tp* __f1 = __first1;
+    const _Tp* __f2 = __first2;
     if constexpr (__is_trivially_lexicographically_comparable_v<_Tp, _Tp>) {
-      auto __res = std::__constexpr_memcmp(__first1, __first2, __element_count(__min_len));
+      auto __res = std::__constexpr_memcmp(__f1, __f2, __element_count(__min_len));
       if (__res != 0)
         return __res <=> 0;
     } else {
-      auto __res = std::mismatch(__first1, __last1, __first2, __last2);
-      if (__res.first != __last1 && __res.second != __last2)
-        return __comp(*__res.first, *__res.second);
+      auto __res = std::mismatch(__f1, __f1 + __min_len, __f2);
+      if (__res.first != __f1 + __min_len)
+        return *__res.first <=> *__res.second;
     }
   } else {
     for (_Common __i = 0; __i < __min_len; ++__i) {
diff --git a/libcxx/include/__string/constexpr_c_functions.h b/libcxx/include/__string/constexpr_c_functions.h
index 4b05e862b80e31..771968cdd48056 100644
--- a/libcxx/include/__string/constexpr_c_functions.h
+++ b/libcxx/include/__string/constexpr_c_functions.h
@@ -75,7 +75,7 @@ __constexpr_memcmp(const _Tp* __lhs, const _Up* __rhs, __element_count __n) {
 
   if (__libcpp_is_constant_evaluated()) {
 #ifdef _LIBCPP_COMPILER_CLANG_BASED
-    if (sizeof(_Tp) == 1 && !is_same<_Tp, bool>::value)
+    if (sizeof(_Tp) == 1 && !is_same<_Tp, bool>::value && !__is_std_byte_v<_Tp>)
       return __builtin_memcmp(__lhs, __rhs, __count * sizeof(_Tp));
 #endif
 
diff --git a/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp b/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp
index 36572ce527ed54..4fbb465ce89524 100644
--- a/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp
+++ b/libcxx/test/benchmarks/algorithms/lexicographical_compare_three_way.bench.cpp
@@ -36,17 +36,11 @@ static TEST_ALIGN_BENCHMARK void BM_lexicographical_compare_three_way(benchmark:
   }
 }
 
-// Type alias to make sure the `*` does not appear in the benchmark name.
-// A `*` would confuse the Python test runner running this google benchmark.
-using IntPtr          = int*;
-using UnsignedCharPtr = unsigned char*;
-using SignedCharPtr   = signed char*;
-
 // `lexicographical_compare_three_way` has a fast path for random access iterators.
-BENCHMARK(BM_lexicographical_compare_three_way<IntPtr>)->RangeMultiplier(4)->Range(1, 1 << 20);
-BENCHMARK(BM_lexicographical_compare_three_way<UnsignedCharPtr>)->RangeMultiplier(4)->Range(1, 1 << 20);
-BENCHMARK(BM_lexicographical_compare_three_way<SignedCharPtr>)->RangeMultiplier(4)->Range(1, 1 << 20);
-BENCHMARK(BM_lexicographical_compare_three_way<random_access_iterator<IntPtr>>)->RangeMultiplier(4)->Range(1, 1 << 20);
-BENCHMARK(BM_lexicographical_compare_three_way<cpp17_input_iterator<IntPtr>>)->RangeMultiplier(4)->Range(1, 1 << 20);
+BENCHMARK(BM_lexicographical_compare_three_way<int*>)->RangeMultiplier(4)->Range(1, 1 << 20);
+BENCHMARK(BM_lexicographical_compare_three_way<unsigned char*>)->RangeMultiplier(4)->Range(1, 1 << 20);
+BENCHMARK(BM_lexicographical_compare_three_way<signed char*>)->RangeMultiplier(4)->Range(1, 1 << 20);
+BENCHMARK(BM_lexicographical_compare_three_way<random_access_iterator<int*>>)->RangeMultiplier(4)->Range(1, 1 << 20);
+BENCHMARK(BM_lexicographical_compare_three_way<cpp17_input_iterator<int*>>)->RangeMultiplier(4)->Range(1, 1 << 20);
 
 BENCHMARK_MAIN();
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
index 739e56f2176d2c..4f48749b0bda33 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
@@ -128,6 +128,7 @@ constexpr void test_long_range(T lhs, T rhs, Order expected) {
   a[257] = lhs;
   b[257] = rhs;
   test_lexicographical_compare<const T*, const T*>(a, b, expected);
+  test_lexicographical_compare<T*, const T*>(a, b, expected);
   test_lexicographical_compare<const T*, const T*>(a, std::array<T, 257>{}, std::strong_ordering::greater);
 }
 



More information about the libcxx-commits mailing list