[libcxx-commits] [libcxx] [libc++][pstl] Implement pstl std::min_element (PR #173970)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 30 08:19:35 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Marcell Leleszi (mleleszi)
<details>
<summary>Changes</summary>
This patch implements the PSTL variant of `std::min_element` for all execution policies.
The `unseq` version uses a two pass SIMD approach, the first pass to find min value, and the second pass to find the index of the first min value.
The `par` version is built on transform_reduce provided by the backend. The `par_unseq` is the combination of the two, using the SIMD variant within bricks.
It also adds specializations of `__desugars_to` for `__totally_ordered_greater_tag`, so if `std::greater` or `std::less` is used with integral types we can use `==` for equality checks instead of a double comparison to save a comparison.
WIP
---
Patch is 29.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/173970.diff
16 Files Affected:
- (modified) libcxx/docs/Status/PSTLPaper.csv (+1-1)
- (modified) libcxx/include/CMakeLists.txt (+1)
- (modified) libcxx/include/__algorithm/pstl.h (+23)
- (modified) libcxx/include/__functional/operations.h (+6)
- (modified) libcxx/include/__functional/ranges_operations.h (+3)
- (modified) libcxx/include/__pstl/backend_fwd.h (+6)
- (modified) libcxx/include/__pstl/backends/libdispatch.h (+5)
- (modified) libcxx/include/__pstl/backends/serial.h (+10)
- (modified) libcxx/include/__pstl/backends/std_thread.h (+5)
- (added) libcxx/include/__pstl/cpu_algos/min_element.h (+216)
- (modified) libcxx/include/__type_traits/desugars_to.h (+8)
- (modified) libcxx/include/module.modulemap.in (+3)
- (added) libcxx/test/benchmarks/algorithms/pstl.min_element.bench.cpp (+116)
- (modified) libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp (+5)
- (added) libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element.nodiscard.verify.cpp (+35)
- (added) libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element.pass.cpp (+109)
``````````diff
diff --git a/libcxx/docs/Status/PSTLPaper.csv b/libcxx/docs/Status/PSTLPaper.csv
index 3fb5adfe3ec46..569eb81541468 100644
--- a/libcxx/docs/Status/PSTLPaper.csv
+++ b/libcxx/docs/Status/PSTLPaper.csv
@@ -33,7 +33,7 @@ Section,Description,Assignee,Complete
| `[alg.lex.comparison] <https://wg21.link/alg.lex.comparison>`_,std::lexicographical_compare,Nikolas Klauser,|Not Started|
| `[alg.min.max] <https://wg21.link/alg.min.max>`_,std::max_element,Nikolas Klauser,|Not Started|
| `[alg.merge] <https://wg21.link/alg.merge>`_,std::merge,Nikolas Klauser,|Complete|
-| `[alg.min.max] <https://wg21.link/alg.min.max>`_,std::min_element,Nikolas Klauser,|Not Started|
+| `[alg.min.max] <https://wg21.link/alg.min.max>`_,std::min_element,Marcell Leleszi,|Complete|
| `[alg.min.max] <https://wg21.link/alg.min.max>`_,std::minmax_element,Nikolas Klauser,|Not Started|
| `[mismatch] <https://wg21.link/mismatch>`_,std::mismatch,Nikolas Klauser,|Not Started|
| `[alg.move] <https://wg21.link/alg.move>`_,std::move,Nikolas Klauser,|Complete|
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 9df40eab678a2..348b3a9a6fd0b 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -659,6 +659,7 @@ set(files
__pstl/cpu_algos/find_if.h
__pstl/cpu_algos/for_each.h
__pstl/cpu_algos/merge.h
+ __pstl/cpu_algos/min_element.h
__pstl/cpu_algos/stable_sort.h
__pstl/cpu_algos/transform.h
__pstl/cpu_algos/transform_reduce.h
diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index eea07e2b96b64..804af4ef157b9 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -654,6 +654,29 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
std::move(__op));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Compare,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+min_element(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "min_element requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__min_element, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__comp));
+}
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+min_element(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "min_element requires ForwardIterators");
+ return std::min_element(std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), less{});
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/__functional/operations.h b/libcxx/include/__functional/operations.h
index 7f315ca851c08..882b0b0a8c737 100644
--- a/libcxx/include/__functional/operations.h
+++ b/libcxx/include/__functional/operations.h
@@ -462,6 +462,9 @@ _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(greater);
template <class _Tp>
inline const bool __desugars_to_v<__greater_tag, greater<_Tp>, _Tp, _Tp> = true;
+template <class _Tp>
+inline const bool __desugars_to_v<__totally_ordered_greater_tag, greater<_Tp>, _Tp, _Tp> = is_integral<_Tp>::value;
+
#if _LIBCPP_STD_VER >= 14
template <>
struct greater<void> {
@@ -477,6 +480,9 @@ struct greater<void> {
template <class _Tp, class _Up>
inline const bool __desugars_to_v<__greater_tag, greater<>, _Tp, _Up> = true;
+template <class _Tp>
+inline const bool __desugars_to_v<__totally_ordered_greater_tag, greater<>, _Tp, _Tp> = is_integral<_Tp>::value;
+
template <class _Tp>
struct __make_transparent<greater<_Tp>> {
using type _LIBCPP_NODEBUG = greater<>;
diff --git a/libcxx/include/__functional/ranges_operations.h b/libcxx/include/__functional/ranges_operations.h
index dc9da061af264..8368afa76591b 100644
--- a/libcxx/include/__functional/ranges_operations.h
+++ b/libcxx/include/__functional/ranges_operations.h
@@ -109,6 +109,9 @@ inline const bool __desugars_to_v<__less_tag, ranges::less, _Tp, _Up> = true;
template <class _Tp, class _Up>
inline const bool __desugars_to_v<__greater_tag, ranges::greater, _Tp, _Up> = true;
+template <class _Tp, class _Up>
+inline const bool __desugars_to_v<__totally_ordered_greater_tag, ranges::greater, _Tp, _Up> = true;
+
template <>
inline const bool __is_generic_transparent_comparator_v<ranges::less> = true;
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index a7d53b6a1c989..523ea73faff9e 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -297,6 +297,12 @@ struct __reduce;
// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last,
// _Tp __init, _BinaryOperation __op) const noexcept;
+template <class _Backend, class _ExecutionPolicy>
+struct __min_element;
+// template <class _Policy, class _ForwardIterator, class _Comp>
+// optional<_ForwardIterator>
+// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Comp __comp) const noexcept;
+
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 88d4231d29a0a..b73f0e6353033 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -33,6 +33,7 @@
#include <__pstl/cpu_algos/find_if.h>
#include <__pstl/cpu_algos/for_each.h>
#include <__pstl/cpu_algos/merge.h>
+#include <__pstl/cpu_algos/min_element.h>
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
@@ -392,6 +393,10 @@ template <class _ExecutionPolicy>
struct __fill<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_fill<__libdispatch_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __min_element<__libdispatch_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_min_element<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index f4142016ccc79..47a59ad02430c 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -13,6 +13,7 @@
#include <__algorithm/find_if.h>
#include <__algorithm/for_each.h>
#include <__algorithm/merge.h>
+#include <__algorithm/min_element.h>
#include <__algorithm/stable_sort.h>
#include <__algorithm/transform.h>
#include <__config>
@@ -175,6 +176,15 @@ struct __transform_reduce_binary<__serial_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __min_element<__serial_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator, class _Comp>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+ operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept {
+ return std::min_element(std::move(__first), std::move(__last), std::forward<_Comp>(__comp));
+ }
+};
+
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__pstl/backends/std_thread.h b/libcxx/include/__pstl/backends/std_thread.h
index dd2c3f15403e3..1b1f4f206e30d 100644
--- a/libcxx/include/__pstl/backends/std_thread.h
+++ b/libcxx/include/__pstl/backends/std_thread.h
@@ -17,6 +17,7 @@
#include <__pstl/cpu_algos/find_if.h>
#include <__pstl/cpu_algos/for_each.h>
#include <__pstl/cpu_algos/merge.h>
+#include <__pstl/cpu_algos/min_element.h>
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
@@ -129,6 +130,10 @@ template <class _ExecutionPolicy>
struct __fill<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_fill<__std_thread_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __min_element<__std_thread_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_min_element<__std_thread_backend_tag, _ExecutionPolicy> {};
+
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__pstl/cpu_algos/min_element.h b/libcxx/include/__pstl/cpu_algos/min_element.h
new file mode 100644
index 0000000000000..a3e440314bd74
--- /dev/null
+++ b/libcxx/include/__pstl/cpu_algos/min_element.h
@@ -0,0 +1,216 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_CPU_ALGOS_MIN_ELEMENT_H
+#define _LIBCPP___PSTL_CPU_ALGOS_MIN_ELEMENT_H
+
+#include <__algorithm/min_element.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/cpu_algos/cpu_traits.h>
+#include <__type_traits/desugars_to.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__type_traits/is_trivially_copyable.h>
+#include <__utility/move.h>
+#include <__utility/unreachable.h>
+#include <optional>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace __pstl {
+
+// Check if the comparator is totally ordered, and if it is,
+// we can use == instead of the double comparison !(comp(a,b) && !comp(b,a)).
+template <class _Compare, class _Tp>
+inline constexpr bool __desugars_to_totally_ordered_v =
+ __desugars_to_v<__totally_ordered_less_tag, _Compare, _Tp, _Tp> ||
+ __desugars_to_v<__totally_ordered_greater_tag, _Compare, _Tp, _Tp>;
+
+template <class _Backend, class _Index, class _DifferenceType, class _Compare>
+_LIBCPP_HIDE_FROM_ABI _Index __simd_min_element(_Index __first, _DifferenceType __n, _Compare __comp) noexcept {
+ if (__n == 0)
+ return __first;
+
+ using _ValueType = __iterator_value_type<_Index>;
+ constexpr size_t __lane_size = __cpu_traits<_Backend>::__lane_size;
+ const _DifferenceType __block_size = __lane_size / sizeof(_ValueType);
+
+ if (__n < 2 * __block_size || __block_size < 2) {
+ _Index __result = __first;
+ for (_DifferenceType __i = 1; __i < __n; ++__i) {
+ if (__comp(__first[__i], *__result)) {
+ __result = __first + __i;
+ }
+ }
+ return __result;
+ }
+
+ // Pass 1: find minimum value
+ alignas(__lane_size) char __lane_buffer[__lane_size];
+ _ValueType* __lane = reinterpret_cast<_ValueType*>(__lane_buffer);
+
+ // initializer
+ _PSTL_PRAGMA_SIMD
+ for (_DifferenceType __i = 0; __i < __block_size; ++__i) {
+ _ValueType __a = __first[__i];
+ _ValueType __b = __first[__block_size + __i];
+ ::new (__lane + __i) _ValueType(__comp(__a, __b) ? __a : __b);
+ }
+
+ // main loop
+ _DifferenceType __i = 2 * __block_size;
+ const _DifferenceType __last_iteration = __block_size * (__n / __block_size);
+ for (; __i < __last_iteration; __i += __block_size) {
+ _PSTL_PRAGMA_SIMD
+ for (_DifferenceType __j = 0; __j < __block_size; ++__j) {
+ if (__comp(__first[__i + __j], __lane[__j])) {
+ __lane[__j] = __first[__i + __j];
+ }
+ }
+ }
+
+ // remainder
+ for (_DifferenceType __j = 0; __j < __n - __last_iteration; ++__j) {
+ if (__comp(__first[__last_iteration + __j], __lane[__j])) {
+ __lane[__j] = __first[__last_iteration + __j];
+ }
+ }
+
+ // combiner
+ _ValueType __min_val = __lane[0];
+ for (_DifferenceType __j = 1; __j < __block_size; ++__j) {
+ if (__comp(__lane[__j], __min_val)) {
+ __min_val = __lane[__j];
+ }
+ }
+
+ // destroyer
+ _PSTL_PRAGMA_SIMD
+ for (_DifferenceType __j = 0; __j < __block_size; ++__j) {
+ __lane[__j].~_ValueType();
+ }
+
+ // Pass 2: find first index with minimum value
+ constexpr _DifferenceType __find_block_size = __lane_size / sizeof(_DifferenceType);
+ alignas(__lane_size) _DifferenceType __found_lane[__find_block_size] = {0};
+ _DifferenceType __begin = 0;
+
+ while (__n - __begin >= __find_block_size) {
+ _DifferenceType __found = 0;
+ _PSTL_PRAGMA_SIMD_REDUCTION(| : __found)
+ for (_DifferenceType __k = 0; __k < __find_block_size; ++__k) {
+ _DifferenceType __t;
+ if constexpr (__desugars_to_totally_ordered_v<_Compare, _ValueType>) {
+ __t = __first[__begin + __k] == __min_val;
+ } else {
+ __t = !__comp(__first[__begin + __k], __min_val) && !__comp(__min_val, __first[__begin + __k]);
+ }
+ __found_lane[__k] = __t;
+ __found |= __t;
+ }
+ if (__found) {
+ for (_DifferenceType __k = 0; __k < __find_block_size; ++__k) {
+ if (__found_lane[__k]) {
+ return __first + __begin + __k;
+ }
+ }
+ }
+ __begin += __find_block_size;
+ }
+
+ // remainder
+ while (__begin < __n) {
+ bool __is_equal;
+ if constexpr (__desugars_to_totally_ordered_v<_Compare, _ValueType>) {
+ __is_equal = __first[__begin] == __min_val;
+ } else {
+ __is_equal = !__comp(__first[__begin], __min_val) && !__comp(__min_val, __first[__begin]);
+ }
+ if (__is_equal) {
+ return __first + __begin;
+ }
+ ++__begin;
+ }
+
+ __libcpp_unreachable();
+}
+
+template <class _Backend, class _RawExecutionPolicy>
+struct __cpu_parallel_min_element {
+ template <class _Policy, class _ForwardIterator, class _Compare>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+ operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+ if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+ if (__first == __last) {
+ return __last;
+ }
+
+ return __cpu_traits<_Backend>::__transform_reduce(
+ std::move(__first),
+ __last,
+ [](_ForwardIterator __iter) { return __iter; },
+ __last,
+ [__comp, __last](_ForwardIterator __lhs_min, _ForwardIterator __rhs_min) {
+ if (__lhs_min == __last)
+ return __rhs_min;
+ if (__rhs_min == __last)
+ return __lhs_min;
+ if (__comp(*__lhs_min, *__rhs_min))
+ return __lhs_min;
+ if (__comp(*__rhs_min, *__lhs_min))
+ return __rhs_min;
+ return __lhs_min < __rhs_min ? __lhs_min : __rhs_min;
+ },
+ [__comp, __last](_ForwardIterator __brick_first, _ForwardIterator __brick_last, _ForwardIterator __acc) {
+ _ForwardIterator __local_min;
+ if constexpr (__is_unsequenced_execution_policy_v<__remove_parallel_policy_t<_RawExecutionPolicy>> &&
+ is_trivially_copyable_v<__iterator_value_type<_ForwardIterator>>) {
+ __local_min =
+ __pstl::__simd_min_element<_Backend>(std::move(__brick_first), __brick_last - __brick_first, __comp);
+ } else {
+ __local_min = std::min_element(std::move(__brick_first), __brick_last, __comp);
+ }
+ if (__local_min == __brick_last)
+ return __acc;
+ if (__acc == __last)
+ return __local_min;
+ if (__comp(*__local_min, *__acc))
+ return __local_min;
+ if (__comp(*__acc, *__local_min))
+ return __acc;
+ return __local_min < __acc ? __local_min : __acc;
+ });
+ } else if constexpr (__is_unsequenced_execution_policy_v<_RawExecutionPolicy> &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
+ is_trivially_copyable_v<__iterator_value_type<_ForwardIterator>>) {
+ return __pstl::__simd_min_element<_Backend>(__first, __last - __first, std::move(__comp));
+ } else {
+ return std::min_element(std::move(__first), std::move(__last), std::move(__comp));
+ }
+ }
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_CPU_ALGOS_MIN_ELEMENT_H
diff --git a/libcxx/include/__type_traits/desugars_to.h b/libcxx/include/__type_traits/desugars_to.h
index 029b3c6336837..fb0a458dc66bb 100644
--- a/libcxx/include/__type_traits/desugars_to.h
+++ b/libcxx/include/__type_traits/desugars_to.h
@@ -40,6 +40,14 @@ struct __greater_tag {};
// additional semantic requirements on that operation.
struct __totally_ordered_less_tag {};
+// syntactically, the operation is equivalent to calling `a > b`, and these expressions
+// have to be true for any `a` and `b`:
+// - `(a > b) == (b < a)`
+// - `(!(a > b) && !(b > a)) == (a == b)`
+// For example, this is satisfied for std::greater on integral types, but also for ranges::greater on all types due to
+// additional semantic requirements on that operation.
+struct __totally_ordered_greater_tag {};
+
// This class template is used to determine whether an operation "desugars"
// (or boils down) to a given canonical operation.
//
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index ce168f77dfea4..9a119f47cfb09 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2336,6 +2336,9 @@ module std [system] {
module merge {
header "__pstl/cpu_algos/merge.h"
}
+ module min_element {
+ header "__pstl/cpu_algos/min_element.h"
+ }
module stable_sort {
header "__pstl/cpu_algos/stable_sort.h"
export std_core.utility_core.empty
diff --git a/libcxx/test/benchmarks/algorithms/pstl.min_element.bench.cpp b/libcxx/test/benchmarks/algorithms/pstl.min_element.bench.cpp
new file mode 100644
index 0000000000000..f2496f0ad799c
--- /dev/null
+++ b/libcxx/test/benchmarks/algorithms/pstl.min_element.bench.cpp
@@ -0,0 +1,116 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+#include <algorithm>
+#include <cmath>
+#include <execution>
+#include <functional>
+#include <string>
+#include <vector>
+
+#include <benchmark/benchmark.h>
+
+struct Seq {
+ static constexpr const auto& policy() { return std::execution::seq; }
+};
+struct Unseq {
+ static constexpr const auto& policy() { return std::execution::unseq; }
+};
+struct Par {
+ static constexpr const auto& policy() { return std::execution::par; }
+};
+struct ParUnseq {
+ static constexpr const auto& policy() { return std::execution::par_unseq; }
+};
+
+struct MinFirst {
+ static size_t pos(size_t) { return 0; }
+};
+struct MinMiddle {
+ static size_t pos(size_t size) { return size / 2; }
+};
+struct MinLast {
+ static size_t pos(size_t size) { return size - 1; }
+};
+
+void run_sizes(auto benchmark) { benchmark->Arg(64)->Arg(512)->Arg(1024)->Arg(4096)->Arg(65536)->Arg(262144); }
+
+template <class T, class Policy, class Position>
+void BM_min_element(benchmark::State& state) {
+ std::vector<T> vec(state.range(), 3);
+ vec[Position::pos(vec.size())] = 1;
+
+ for (auto _ : state) {
+ bench...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/173970
More information about the libcxx-commits
mailing list