[libcxx-commits] [libcxx] [libc++] Optimize std::find if types are integral and have the same signedness (PR #70345)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sat Dec 23 02:21:13 PST 2023


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/70345

>From df126e2b86ca0f07677498f5f8c6267de5f6f1ae Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 26 Oct 2023 11:54:29 +0200
Subject: [PATCH] [libc++] Optimize std::find if types are integral

---
 libcxx/include/__algorithm/find.h             | 19 +++++++++
 .../alg.nonmodifying/alg.find/find.pass.cpp   | 42 +++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h
index 754e597130c5b1..7d7631b6e98a96 100644
--- a/libcxx/include/__algorithm/find.h
+++ b/libcxx/include/__algorithm/find.h
@@ -21,8 +21,11 @@
 #include <__fwd/bit_reference.h>
 #include <__iterator/segmented_iterator.h>
 #include <__string/constexpr_c_functions.h>
+#include <__type_traits/is_integral.h>
 #include <__type_traits/is_same.h>
+#include <__type_traits/is_signed.h>
 #include <__utility/move.h>
+#include <limits>
 
 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
 #  include <cwchar>
@@ -76,6 +79,22 @@ __find_impl(_Tp* __first, _Tp* __last, const _Up& __value, _Proj&) {
 }
 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 
+// TODO: This should also be possible to get right with different signedness
+// cast integral types to allow vectorization
+template <class _Tp,
+          class _Up,
+          class _Proj,
+          __enable_if_t<__is_identity<_Proj>::value && !__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value &&
+                            is_integral<_Tp>::value && is_integral<_Up>::value &&
+                            is_signed<_Tp>::value == is_signed<_Up>::value,
+                        int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp*
+__find_impl(_Tp* __first, _Tp* __last, const _Up& __value, _Proj& __proj) {
+  if (__value < numeric_limits<_Tp>::min() || __value > numeric_limits<_Tp>::max())
+    return __last;
+  return std::__find_impl(__first, __last, _Tp(__value), __proj);
+}
+
 // __bit_iterator implementation
 template <bool _ToFind, class _Cp, bool _IsConst>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, _IsConst>
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp
index 0afc573aa17713..0676da13e90f76 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+// ADDITIONAL_COMPILE_FLAGS(gcc): -Wno-bool-compare
 // ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-sign-compare
 // MSVC warning C4389: '==': signed/unsigned mismatch
 // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4389
@@ -162,6 +163,45 @@ void test_deque() {
   }
 }
 
+template <class T>
+struct TestIntegerPromotions1 {
+  template <class U>
+  TEST_CONSTEXPR_CXX20 void test(T val, U to_find) {
+    bool expect_match = val == to_find;
+    assert(std::find(&val, &val + 1, to_find) == (expect_match ? &val : &val + 1));
+  }
+
+  template <class U>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    test<U>(0, 0);
+    test<U>(0, 1);
+    test<U>(1, 1);
+    test<U>(0, -1);
+    test<U>(-1, -1);
+    test<U>(0, U(-127));
+    test<U>(T(-127), U(-127));
+    test<U>(T(-128), U(-128));
+    test<U>(T(-129), U(-129));
+    test<U>(T(255), U(255));
+    test<U>(T(256), U(256));
+    test<U>(T(257), U(257));
+    test<U>(0, std::numeric_limits<U>::min());
+    test<U>(T(std::numeric_limits<U>::min()), std::numeric_limits<U>::min());
+    test<U>(0, std::numeric_limits<U>::min() + 1);
+    test<U>(T(std::numeric_limits<U>::min() + 1), std::numeric_limits<U>::min() + 1);
+    test<U>(0, std::numeric_limits<U>::max());
+    test<U>(T(std::numeric_limits<U>::max()), std::numeric_limits<U>::max());
+    test<U>(T(std::numeric_limits<U>::max() - 1), std::numeric_limits<U>::max() - 1);
+  }
+};
+
+struct TestIntegerPromotions {
+  template <class T>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    types::for_each(types::integral_types(), TestIntegerPromotions1<T>());
+  }
+};
+
 TEST_CONSTEXPR_CXX20 bool test() {
   types::for_each(types::integer_types(), TestTypes<char>());
   types::for_each(types::integer_types(), TestTypes<int>());
@@ -181,6 +221,8 @@ TEST_CONSTEXPR_CXX20 bool test() {
   }
 #endif
 
+  types::for_each(types::integral_types(), TestIntegerPromotions());
+
   return true;
 }
 



More information about the libcxx-commits mailing list