[libcxx-commits] [libcxx] 260096e - [libc++][pstl] Introduce a "statpart" backend (#230540)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 30 03:16:19 PDT 2026


Author: Michael G. Kazakov
Date: 2026-10-30T10:16:13Z
New Revision: 260096e486b08edccd9c5db35c550029d65620b6

URL: https://github.com/llvm/llvm-project/commit/260096e486b08edccd9c5db35c550029d65620b6
DIFF: https://github.com/llvm/llvm-project/commit/260096e486b08edccd9c5db35c550029d65620b6.diff

LOG: [libc++][pstl] Introduce a "statpart" backend (#230540)

This PR introduces a simplified PSTL backend based on a static
partitioning scheme and on a single "parallelism" function
`__apply(size_t, void*, void (*)(void*, size_t))`. Currently the
underlying parallelism is only provided via the `libdispatch` library,
other mechanisms are assumed to be added later without changing the
API+ABI surface.

This backend is mostly a re-packaging of the code existing in
`libdispatch` and `cpu_algos`, currently placed in a dedicated
`__pstl/statpart/...` directory. `__pstl/statpart.h` serves as a purely
umbrella header.

The implementations of the algorithms with the STL APIs are identical to
the existing implementations in `__pstl/cpu_algos/...` modulo these
alterations:
- the naming is rebased to use the `__statpart` backend.
- the algorithms are presented directly under the
`__statpart_backend_tag` specialisation, without a re-introduction via
inheritance as currently done in `libdispatch` and `std_thread`.

There are a couple of differences in the backend basis as well:
- The partitioning logic is moved out of the ABI surface.
- The `__cpu_traits` API is not used, all backends' functions are
structured as free functions.
- The partitioning logic is changed. Instead of capping the number of
elements per partition, it now caps the maximum number of partitions per
available parallel workers and allows to specify the minimum number of
elements per partition. Partitioning that produces less than 2
sub-ranges is declared invalid, the caller should fall back to serial
processing in this case.
- The basis algorithm implementations are copied as-is with minimal
changes, with 2 exceptions:
- `__merge()` finds the cutpoints of each paired sub-ranges in parallel,
instead of sequentially as before. This costs 2 binary searches per
partition, comparing to 1 binary search per partition in the previous
implementation, but all these searches are now done in parallel, instead
being serial on a critical path.
- `__stable_sort()` no longer merges two the first partitions
sequentially in case of an odd number of partitions. Instead the last
span is carried over as-is in case of odd number of spans.

At the moment this backend is not enabled by default on any
configuration and needs to be explicitly picked via
`-DLIBCXX_PSTL_BACKEND=statpart`.

Fixes #229804.

---------

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>

Added: 
    libcxx/include/__pstl/backends/statpart.h
    libcxx/include/__pstl/backends/statpart/any_of.h
    libcxx/include/__pstl/backends/statpart/basis.h
    libcxx/include/__pstl/backends/statpart/fill.h
    libcxx/include/__pstl/backends/statpart/find_end.h
    libcxx/include/__pstl/backends/statpart/find_if.h
    libcxx/include/__pstl/backends/statpart/for_each.h
    libcxx/include/__pstl/backends/statpart/is_heap_until.h
    libcxx/include/__pstl/backends/statpart/merge.h
    libcxx/include/__pstl/backends/statpart/min_element.h
    libcxx/include/__pstl/backends/statpart/minmax_element.h
    libcxx/include/__pstl/backends/statpart/mismatch.h
    libcxx/include/__pstl/backends/statpart/reverse.h
    libcxx/include/__pstl/backends/statpart/search.h
    libcxx/include/__pstl/backends/statpart/search_n.h
    libcxx/include/__pstl/backends/statpart/stable_sort.h
    libcxx/include/__pstl/backends/statpart/swap_ranges.h
    libcxx/include/__pstl/backends/statpart/transform.h
    libcxx/include/__pstl/backends/statpart/transform_reduce.h
    libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
    libcxx/include/__pstl/backends/statpart/uninitialized_move.h
    libcxx/src/pstl/statpart.cpp
    libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp

Modified: 
    libcxx/CMakeLists.txt
    libcxx/include/CMakeLists.txt
    libcxx/include/__config_site.in
    libcxx/include/__pstl/backend.h
    libcxx/include/__pstl/backend_fwd.h
    libcxx/include/module.modulemap.in
    libcxx/src/CMakeLists.txt
    libcxx/utils/libcxx/test/features/libcxx_macros.py

Removed: 
    


################################################################################
diff  --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 7dc427dae77b28..ff6f8d1593fe2c 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -805,9 +805,11 @@ elseif(LIBCXX_PSTL_BACKEND STREQUAL "std_thread")
   config_define(1 _LIBCPP_PSTL_BACKEND_STD_THREAD)
 elseif(LIBCXX_PSTL_BACKEND STREQUAL "libdispatch")
   config_define(1 _LIBCPP_PSTL_BACKEND_LIBDISPATCH)
+elseif(LIBCXX_PSTL_BACKEND STREQUAL "statpart")
+  config_define(1 _LIBCPP_PSTL_BACKEND_STATPART)
 else()
   message(FATAL_ERROR "LIBCXX_PSTL_BACKEND is set to ${LIBCXX_PSTL_BACKEND}, which is not a valid backend.
-                       Valid backends are: serial, std_thread and libdispatch")
+                       Valid backends are: serial, std_thread, libdispatch and statpart")
 endif()
 
 if (LIBCXX_ABI_DEFINES)

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fcb66d5fe2f48a..44aa0604947fdf 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -696,6 +696,27 @@ set(files
   __pstl/backends/default.h
   __pstl/backends/libdispatch.h
   __pstl/backends/serial.h
+  __pstl/backends/statpart.h
+  __pstl/backends/statpart/any_of.h
+  __pstl/backends/statpart/basis.h
+  __pstl/backends/statpart/fill.h
+  __pstl/backends/statpart/find_end.h
+  __pstl/backends/statpart/find_if.h
+  __pstl/backends/statpart/for_each.h
+  __pstl/backends/statpart/is_heap_until.h
+  __pstl/backends/statpart/merge.h
+  __pstl/backends/statpart/min_element.h
+  __pstl/backends/statpart/minmax_element.h
+  __pstl/backends/statpart/mismatch.h
+  __pstl/backends/statpart/reverse.h
+  __pstl/backends/statpart/search.h
+  __pstl/backends/statpart/search_n.h
+  __pstl/backends/statpart/stable_sort.h
+  __pstl/backends/statpart/swap_ranges.h
+  __pstl/backends/statpart/transform.h
+  __pstl/backends/statpart/transform_reduce.h
+  __pstl/backends/statpart/uninitialized_copy.h
+  __pstl/backends/statpart/uninitialized_move.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h

diff  --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index 785c1562de7bd4..b003f1c2ddc49a 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/include/__config_site.in
@@ -37,6 +37,7 @@
 #cmakedefine _LIBCPP_PSTL_BACKEND_SERIAL
 #cmakedefine _LIBCPP_PSTL_BACKEND_STD_THREAD
 #cmakedefine _LIBCPP_PSTL_BACKEND_LIBDISPATCH
+#cmakedefine _LIBCPP_PSTL_BACKEND_STATPART
 
 // Hardening.
 #cmakedefine _LIBCPP_HARDENING_MODE_DEFAULT @_LIBCPP_HARDENING_MODE_DEFAULT@

diff  --git a/libcxx/include/__pstl/backend.h b/libcxx/include/__pstl/backend.h
index 8708e492fcc23e..aa01dcb5cf19a0 100644
--- a/libcxx/include/__pstl/backend.h
+++ b/libcxx/include/__pstl/backend.h
@@ -32,6 +32,10 @@ _LIBCPP_PUSH_MACROS
 #    include <__pstl/backends/default.h>
 #    include <__pstl/backends/libdispatch.h>
 #    include <__pstl/backends/serial.h>
+#  elif defined(_LIBCPP_PSTL_BACKEND_STATPART)
+#    include <__pstl/backends/default.h>
+#    include <__pstl/backends/serial.h>
+#    include <__pstl/backends/statpart.h>
 #  endif
 
 #endif // _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index fbc6f9920bdedd..184d2b6df1dd1d 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -51,6 +51,7 @@ struct __default_backend_tag;
 struct __libdispatch_backend_tag;
 struct __serial_backend_tag;
 struct __std_thread_backend_tag;
+struct __statpart_backend_tag;
 
 #  if defined(_LIBCPP_PSTL_BACKEND_SERIAL)
 using __current_configuration _LIBCPP_NODEBUG = __backend_configuration<__serial_backend_tag, __default_backend_tag>;
@@ -60,6 +61,9 @@ using __current_configuration _LIBCPP_NODEBUG =
 #  elif defined(_LIBCPP_PSTL_BACKEND_LIBDISPATCH)
 using __current_configuration _LIBCPP_NODEBUG =
     __backend_configuration<__libdispatch_backend_tag, __default_backend_tag, __serial_backend_tag>;
+#  elif defined(_LIBCPP_PSTL_BACKEND_STATPART)
+using __current_configuration _LIBCPP_NODEBUG =
+    __backend_configuration<__statpart_backend_tag, __default_backend_tag, __serial_backend_tag>;
 #  else
 
 // ...New vendors can add parallel backends here...

diff  --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
new file mode 100644
index 00000000000000..82665e66557ec1
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_H
+
+#include <__pstl/backends/statpart/any_of.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__pstl/backends/statpart/fill.h>
+#include <__pstl/backends/statpart/find_end.h>
+#include <__pstl/backends/statpart/find_if.h>
+#include <__pstl/backends/statpart/for_each.h>
+#include <__pstl/backends/statpart/is_heap_until.h>
+#include <__pstl/backends/statpart/merge.h>
+#include <__pstl/backends/statpart/min_element.h>
+#include <__pstl/backends/statpart/minmax_element.h>
+#include <__pstl/backends/statpart/mismatch.h>
+#include <__pstl/backends/statpart/reverse.h>
+#include <__pstl/backends/statpart/search.h>
+#include <__pstl/backends/statpart/search_n.h>
+#include <__pstl/backends/statpart/stable_sort.h>
+#include <__pstl/backends/statpart/swap_ranges.h>
+#include <__pstl/backends/statpart/transform.h>
+#include <__pstl/backends/statpart/transform_reduce.h>
+#include <__pstl/backends/statpart/uninitialized_copy.h>
+#include <__pstl/backends/statpart/uninitialized_move.h>
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_H

diff  --git a/libcxx/include/__pstl/backends/statpart/any_of.h b/libcxx/include/__pstl/backends/statpart/any_of.h
new file mode 100644
index 00000000000000..d962feca112293
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/any_of.h
@@ -0,0 +1,112 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_ANY_OF_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_ANY_OF_H
+
+#include <__algorithm/any_of.h>
+#include <__assert>
+#include <__atomic/atomic.h>
+#include <__atomic/memory_order.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+#include <cstdint>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+namespace __statpart {
+
+template <class _Index, class _Brick>
+_LIBCPP_HIDE_FROM_ABI optional<bool> __parallel_or(_Index __first, _Index __last, _Brick __f) {
+  std::atomic<bool> __found(false);
+  auto __ret = __statpart::__for_each(__first, __last, [__f, &__found](_Index __i, _Index __j) {
+    if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) {
+      __found.store(true, std::memory_order_relaxed);
+    }
+  });
+  if (!__ret)
+    return nullopt;
+  return static_cast<bool>(__found);
+}
+
+// TODO: check whether __simd_first() can be used here
+template <class _Index, class _DifferenceType, class _Pred>
+_LIBCPP_HIDE_FROM_ABI bool __simd_or(_Index __first, _DifferenceType __n, _Pred __pred) noexcept {
+  _DifferenceType __block_size = 4 < __n ? 4 : __n;
+  const _Index __last          = __first + __n;
+  while (__last != __first) {
+    int32_t __flag = 1;
+    _PSTL_PRAGMA_SIMD_REDUCTION(& : __flag)
+    for (_DifferenceType __i = 0; __i < __block_size; ++__i)
+      if (__pred(*(__first + __i)))
+        __flag = 0;
+    if (!__flag)
+      return true;
+
+    __first += __block_size;
+    if (__last - __first >= __block_size << 1) {
+      // Double the block _Size.  Any unnecessary iterations can be amortized against work done so far.
+      __block_size <<= 1;
+    } else {
+      __block_size = __last - __first;
+    }
+  }
+  return false;
+}
+
+} // namespace __statpart
+
+template <class _ExecutionPolicy>
+struct __any_of<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<bool>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__parallel_or(
+          __first, __last, [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            using _AnyOfUnseq = __pstl::__any_of<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            auto __res = _AnyOfUnseq()(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+            return *std::move(__res);
+          });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__simd_or(__first, __last - __first, __pred);
+    } else {
+      return std::any_of(__first, __last, __pred);
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_ANY_OF_H

diff  --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
new file mode 100644
index 00000000000000..a678d5c3e5a181
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -0,0 +1,519 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_BASIS_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_BASIS_H
+
+#include <__algorithm/lower_bound.h>
+#include <__algorithm/merge.h>
+#include <__algorithm/min.h>
+#include <__algorithm/move.h>
+#include <__algorithm/upper_bound.h>
+#include <__assert>
+#include <__atomic/atomic.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/identity.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/move_iterator.h>
+#include <__memory/allocator.h>
+#include <__memory/construct_at.h>
+#include <__memory/destroy.h>
+#include <__memory/unique_ptr.h>
+#include <__numeric/reduce.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__thread/hardware_concurrency.h>
+#include <__type_traits/is_assignable.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_trivially_copyable.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+namespace __statpart {
+
+// The backbone of the backend: applies the function to each of the indices [0, __chunk_count) in parallel.
+// The actual number of parallel workers and the order of application is unspecified.
+_LIBCPP_EXPORTED_FROM_ABI void
+__apply(size_t __chunk_count, void* __context, void (*__func)(void* __context, size_t __chunk)) noexcept;
+
+// The maximum number of partitions to be processed per CPU
+constexpr inline size_t __max_partitions_per_cpu = 8;
+
+// The minimum number of elements to sort serially in a single partition
+constexpr inline size_t __min_sort_partition_size = 256;
+
+constexpr inline size_t __lane_size = 64;
+
+enum class __partitioning_status {
+  // Returned when the partitioning result is not a nullopt.
+  __ok,
+  // Returned when there are not enough element to produce a single partition or the final number of partitions is fewer
+  // than 2, i.e. there's no reason to process the input in parallel.
+  __not_enough_elements,
+  // There's fewer than 2 processors available in the system, or their number is unknown, which is treated as having
+  // a single processor. In either case, fall back to serial processing.
+  __no_parallelism,
+  // Reserved for later: returned when memory could not be allocated for the stashed forward iterators.
+  __bad_alloc
+};
+
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __partitioning_result;
+
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __iterator_range {
+  _Iterator __first;
+  _Iterator __last;
+};
+
+// __iterator_partitions<Iter> holds a finite pre-determined set of partitions and allows querying each iterator range
+// in O(1) time.
+// TODO: Support forward iterators later via a second implicit template argument and its specializations.
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
+  _LIBCPP_HIDE_FROM_ABI size_t __partitions_count() const { return __partitions_count_; }
+
+  _LIBCPP_HIDE_FROM_ABI __iterator_range<_Iterator> __partition(size_t __n) const {
+    _Iterator __first = __base_ + __n * __partition_size_ + (__n < __remainder_ ? __n : __remainder_);
+    _Iterator __last  = __first + __partition_size_ + (__n < __remainder_ ? 1 : 0);
+    return __iterator_range<_Iterator>{__first, __last};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI _Iterator __end() const { return __base_ + __count_; }
+
+private:
+  _Iterator __base_;
+  size_t __count_;
+  size_t __partition_size_;
+  size_t __remainder_;
+  size_t __partitions_count_;
+
+  template <class _Iter>
+  friend __partitioning_result<_Iter> _LIBCPP_HIDE_FROM_ABI
+  __partition(_Iter, _Iter, size_t, size_t, size_t, size_t) noexcept;
+};
+
+// This is basically a barebones std::expected<__iterator_partitions<_Iterator>, __partitioning_status>.
+// __partition() uses this to avoid resorting to return arguments.
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __partitioning_result {
+  optional<__iterator_partitions<_Iterator>> __value_;
+  __partitioning_status __status_ = __partitioning_status::__ok;
+};
+
+// This function allows basis.h to compile when _LIBCPP_HAS_THREADS=0
+_LIBCPP_HIDE_FROM_ABI inline unsigned __thread_hardware_concurrency() noexcept {
+#  if _LIBCPP_HAS_THREADS
+  return std::__thread_hardware_concurrency();
+#  else
+  return 0;
+#  endif // _LIBCPP_HAS_THREADS
+}
+
+// Splits the input iterator range into a finite set of partitions, such that every iterator sub-range can be queried in
+// a O(1) time later.
+// If partitioning fails, returns nullopt and reports the reason in __result.
+// __min_partition_size specifies the minimal number of elements in every partition.
+// __prefix_to_skip and __suffix_to_skip allows optionally trimming the input range by the specified number of elements
+// before partitioning.
+// __workers_count is normally implicitly queried from hardware_concurrency() and should be explicitly specified only in
+// unit tests.
+template <class _Iterator>
+_LIBCPP_HIDE_FROM_ABI __partitioning_result<_Iterator>
+__partition(_Iterator __first,
+            _Iterator __last,
+            size_t __min_partition_size = 1,
+            size_t __prefix_to_skip     = 0,
+            size_t __suffix_to_skip     = 0,
+            size_t __workers_count      = __statpart::__thread_hardware_concurrency()) noexcept {
+  // Forward iterators will be supported later.
+  static_assert(__has_random_access_iterator_category_or_concept<_Iterator>::value);
+
+  _LIBCPP_ASSERT_INTERNAL(__min_partition_size >= 1, "minimum partition size must be at least 1 element");
+
+  if (__workers_count < 2) {
+    // There's no available parallelism in the system, no reason to perform partitioning.
+    return {nullopt, __partitioning_status::__no_parallelism};
+  }
+
+  size_t __count = static_cast<size_t>(std::distance(__first, __last));
+  if (__count <= __prefix_to_skip + __suffix_to_skip) {
+    return {nullopt, __partitioning_status::__not_enough_elements};
+  }
+
+  size_t __effective_count = __count - __prefix_to_skip - __suffix_to_skip;
+  size_t __max_partitions  = __workers_count * __max_partitions_per_cpu;
+  size_t __partition_count = std::min(__max_partitions, __effective_count / __min_partition_size);
+
+  if (__partition_count < 2) {
+    // not enough input data to process in parallel => no reason to build partitions
+    return {nullopt, __partitioning_status::__not_enough_elements};
+  }
+
+  __iterator_partitions<_Iterator> __p;
+  __p.__base_             = __first + __prefix_to_skip;
+  __p.__count_            = __effective_count;
+  __p.__partition_size_   = __effective_count / __partition_count;
+  __p.__remainder_        = __effective_count % __partition_count;
+  __p.__partitions_count_ = __partition_count;
+  return {std::move(__p), __partitioning_status::__ok};
+}
+
+// for_each with explicit partitioning:
+// calls __func in parallel with every iterator range provided in __partitions.
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI void __for_each_partition(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
+  struct __ctx_t {
+    const __iterator_partitions<_Iterator>& __partitions_;
+    _Functor& __func_;
+  } __ctx{__partitions, __func};
+  __statpart::__apply(__partitions.__partitions_count(), &__ctx, [](void* __context, size_t __partition) {
+    __ctx_t& __ctx = *static_cast<__ctx_t*>(__context);
+    auto __range   = __ctx.__partitions_.__partition(__partition);
+    __ctx.__func_(__range.__first, __range.__last);
+  });
+}
+
+// Calls __func(index) for every index in [0, __count) in parallel.
+template <class _Functor>
+_LIBCPP_HIDE_FROM_ABI void __for_each_index(size_t __count, _Functor __func) {
+  __statpart::__apply(__count, &__func, [](void* __context, size_t __index) {
+    (*static_cast<_Functor*>(__context))(__index);
+  });
+}
+
+// for_each that calls __func in parallel for every partition index available in __partitions.
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI void
+__for_each_partition_index(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
+  __statpart::__for_each_index(__partitions.__partitions_count(), std::move(__func));
+}
+
+// for_each with default implicit partitioning:
+// calls __func in parallel with every element in [__first, __last), provided as iterator ranges.
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each(_Iterator __first, _Iterator __last, _Functor __func) {
+  if (__first == __last)
+    return __empty{};
+  auto __partitions = __statpart::__partition(__first, __last);
+  if (__partitions.__value_) {
+    __statpart::__for_each_partition(*__partitions.__value_, std::move(__func));
+    return __empty{};
+  } else if (__partitions.__status_ == __partitioning_status::__bad_alloc) {
+    return nullopt;
+  } else {
+    __func(__first, __last);
+    return __empty{};
+  }
+}
+
+// Applies the 3-legged function to sub-ranges of the input ranges in parallel:
+//   f(sub_range1_first, sub_range1_last, sub_range2_first)
+template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BrickFunction>
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each_iter_pair(
+    _RandomAccessIterator1 __first1,
+    _RandomAccessIterator1 __last1,
+    _RandomAccessIterator2 __first2,
+    _BrickFunction __f) {
+  return __statpart::__for_each(
+      __first1,
+      __last1,
+      [__first1, __first2, __f = std::move(__f)](
+          _RandomAccessIterator1 __brick_first1, _RandomAccessIterator1 __brick_last1) {
+        _RandomAccessIterator2 __brick_first2 = __first2 + (__brick_first1 - __first1);
+        __f(__brick_first1, __brick_last1, __brick_first2);
+      });
+}
+
+template <class _Index, class _Brick, class _Compare>
+_LIBCPP_HIDE_FROM_ABI optional<_Index>
+__find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) {
+  typedef typename std::iterator_traits<_Index>::
diff erence_type _DifferenceType;
+  const _DifferenceType __n      = __last - __first;
+  _DifferenceType __initial_dist = __b_first ? __n : -1;
+  std::atomic<_DifferenceType> __extremum(__initial_dist);
+  // TODO: find out what is better here: parallel_for or parallel_reduce
+  auto __res = __statpart::__for_each(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
+    // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
+    // why using a shared variable scales fairly well in this situation.
+    if (__comp(__i - __first, __extremum)) {
+      _Index __result = __f(__i, __j);
+      // If not '__last' returned then we found what we want so put this to extremum
+      if (__result != __j) {
+        const _DifferenceType __k = __result - __first;
+        for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) {
+          __extremum.compare_exchange_weak(__old, __k);
+        }
+      }
+    }
+  });
+  if (!__res)
+    return nullopt;
+  return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last;
+}
+
+template <class _RandomAccessIterator, class _Transform, class _Value, class _Combiner, class _Reduction>
+_LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
+    _RandomAccessIterator __first,
+    _RandomAccessIterator __last,
+    _Transform __transform,
+    _Value __init,
+    _Combiner __combiner,
+    _Reduction __reduction) {
+  if (__first == __last)
+    return __init;
+
+  // Split into partitions with at least 3 elements in each
+  auto __partitions = __statpart::__partition(__first, __last, 3);
+  if (!__partitions.__value_) {
+    if (__partitions.__status_ == __partitioning_status::__bad_alloc) {
+      // Failed to allocate memory for the partitions, propagate the error up.
+      return nullopt;
+    } else {
+      // Not enough elements to run in parallel, switch to serial implementation.
+      return __reduction(std::move(__first), std::move(__last), std::move(__init));
+    }
+  }
+
+  auto __destroy = [__count = __partitions.__value_->__partitions_count()](_Value* __ptr) {
+    std::destroy_n(__ptr, __count);
+    std::allocator<_Value>().deallocate(__ptr, __count);
+  };
+
+  // TODO: use __uninitialized_buffer
+  // TODO: allocate one element per worker instead of one element per chunk
+  unique_ptr<_Value[], decltype(__destroy)> __values(
+      std::allocator<_Value>().allocate(__partitions.__value_->__partitions_count()), __destroy);
+
+  // __dispatch_apply is noexcept
+  __statpart::__for_each_partition_index(*__partitions.__value_, [&](size_t __index) {
+    auto __range = __partitions.__value_->__partition(__index);
+    std::__construct_at(
+        __values.get() + __index,
+        __reduction(__range.__first + 2,
+                    __range.__last,
+                    __combiner(__transform(__range.__first), __transform(__range.__first + 1))));
+  });
+
+  return std::reduce(
+      std::make_move_iterator(__values.get()),
+      std::make_move_iterator(__values.get() + __partitions.__value_->__partitions_count()),
+      std::move(__init),
+      __combiner);
+}
+
+template <class _RandomAccessIterator1,
+          class _RandomAccessIterator2,
+          class _RandomAccessIterator3,
+          class _Compare,
+          class _LeafMerge>
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__merge(_RandomAccessIterator1 __first1,
+        _RandomAccessIterator1 __last1,
+        _RandomAccessIterator2 __first2,
+        _RandomAccessIterator2 __last2,
+        _RandomAccessIterator3 __result,
+        _Compare __comp,
+        _LeafMerge __leaf_merge) noexcept {
+  // Run the merge such that the longest range is partitioned.
+  // __merge_sub_ranges swaps the ranges implicitly in case the second range was the longest one.
+  auto __run =
+      [__result](auto __long_first,
+                 auto __long_last,
+                 auto __short_first,
+                 auto __short_last,
+                 auto __find_cutpoint,
+                 auto __merge_sub_ranges) -> optional<__empty> {
+    // Partition the longest input range evenly.
+    auto __partitions = __statpart::__partition(__long_first, __long_last);
+    if (!__partitions.__value_) {
+      if (__partitions.__status_ == __partitioning_status::__bad_alloc)
+        return nullopt;
+      // Not enough elements to run in parallel, merge everything serially.
+      __merge_sub_ranges(__long_first, __long_last, __short_first, __short_last, __result);
+      return __empty{};
+    }
+
+    // Process the partitions of the longest range in parallel.
+    __statpart::__for_each_partition_index(*__partitions.__value_, [&](size_t __index) {
+      // Get the sub-range inside the longer input range.
+      auto __range = __partitions.__value_->__partition(__index);
+
+      // Find the matching sub-range of the shorter input range: it will hold the elements that come after the last
+      // element of the previous long partition and up to the last element of this partition.
+      // This generally runs two binary searches in the smaller input range, edge partitions use existing bounds.
+      auto __short_begin =
+          __index == 0 ? __short_first : __find_cutpoint(__short_first, __short_last, __range.__first[-1]);
+      auto __short_end =
+          __index == __partitions.__value_->__partitions_count() - 1
+              ? __short_last
+              : __find_cutpoint(__short_first, __short_last, __range.__last[-1]);
+
+      // Derive the position in the output range and merge the sub-ranges.
+      auto __result_first = __result + (__range.__first - __long_first) + (__short_begin - __short_first);
+      __merge_sub_ranges(__range.__first, __range.__last, __short_begin, __short_end, __result_first);
+    });
+    return __empty{};
+  };
+
+  if (__last1 - __first1 > __last2 - __first2) {
+    // Preserve the order of the input ranges, partition the first range.
+    // Equal elements of the second range go after the cut => use lower_bound when cutting.
+    return __run(
+        __first1,
+        __last1,
+        __first2,
+        __last2,
+        [&](auto __first, auto __last, const auto& __value) {
+          return std::lower_bound(__first, __last, __value, __comp);
+        },
+        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
+          __leaf_merge(__long_first, __long_last, __short_first, __short_last, __result_first, __comp);
+        });
+  } else {
+    // Swap the order of the input ranges, partition the second range.
+    // Equal elements of the first range go before the cut => use upper_bound when cutting.
+    return __run(
+        __first2,
+        __last2,
+        __first1,
+        __last1,
+        [&](auto __first, auto __last, const auto& __value) {
+          return std::upper_bound(__first, __last, __value, __comp);
+        },
+        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
+          __leaf_merge(__short_first, __short_last, __long_first, __long_last, __result_first, __comp);
+        });
+  }
+}
+
+template <class _RandomAccessIterator, class _Comp, class _LeafSort>
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
+  const auto __size = __last - __first;
+
+  auto __partitions = __statpart::__partition(__first, __last, __min_sort_partition_size);
+  if (!__partitions.__value_) {
+    if (__partitions.__status_ == __partitioning_status::__bad_alloc)
+      return nullopt;
+    // Not enough elements to run in parallel, sort everything serially.
+    __leaf_sort(__first, __last, __comp);
+    return __empty{};
+  }
+
+  using _Value = __iterator_value_type<_RandomAccessIterator>;
+
+  auto __destroy = [__size](_Value* __ptr) {
+    std::destroy_n(__ptr, __size);
+    std::allocator<_Value>().deallocate(__ptr, __size);
+  };
+
+  // TODO: use __uninitialized_buffer
+  unique_ptr<_Value[], decltype(__destroy)> __values(std::allocator<_Value>().allocate(__size), __destroy);
+
+  // Initialize all elements to a moved-from state
+  // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928
+  std::__construct_at(__values.get(), std::move(*__first));
+  for (__iterator_
diff erence_type<_RandomAccessIterator> __i = 1; __i != __size; ++__i) {
+    std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1]));
+  }
+  *__first = std::move(__values.get()[__size - 1]);
+
+  __statpart::__for_each_partition(
+      *__partitions.__value_,
+      [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
+        __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp);
+      });
+
+  // A chunk span is a run of __chunk_span_size consecutive partitions, the last chunk can be shorter in case of odd
+  // number of chunk spans. Each pass merges the chunk spans pairwise, so the chunk span size doubles and the chunk
+  // count is halved (rounded up).
+  const size_t __partition_count = __partitions.__value_->__partitions_count();
+  size_t __chunk_span_size       = 1;
+  size_t __chunk_spans           = __partition_count;
+
+  // Offsets of the beginning and the end of the chunk from __first
+  auto __chunk_begin = [&](size_t __chunk) {
+    return __partitions.__value_->__partition(__chunk * __chunk_span_size).__first - __first;
+  };
+  auto __chunk_end = [&](size_t __chunk) {
+    return __partitions.__value_->__partition(std::min((__chunk + 1) * __chunk_span_size, __partition_count) - 1)
+               .__last -
+           __first;
+  };
+
+  bool __objects_are_in_buffer = false;
+  do {
+    size_t __chunk_spans_pairs = (__chunk_spans + 1) / 2;
+    auto __merge_chunks        = [&](auto __from_first, auto __to_first) {
+      __statpart::__for_each_index(__chunk_spans_pairs, [&](size_t __span_pair_index) {
+        size_t __left_chunk  = 2 * __span_pair_index;
+        size_t __right_chunk = __left_chunk + 1;
+        auto __pair_first    = __chunk_begin(__left_chunk);
+        if (__right_chunk == __chunk_spans) {
+          // The odd chunk has no counterpart to merge with => carry it over to the other buffer as-is.
+          std::move(__from_first + __pair_first, __from_first + __chunk_end(__left_chunk), __to_first + __pair_first);
+        } else {
+          // Merge the two chunk spans into the other buffer
+          auto __pair_mid  = __chunk_begin(__right_chunk);
+          auto __pair_last = __chunk_end(__right_chunk);
+          std::merge(std::make_move_iterator(__from_first + __pair_first),
+                     std::make_move_iterator(__from_first + __pair_mid),
+                     std::make_move_iterator(__from_first + __pair_mid),
+                     std::make_move_iterator(__from_first + __pair_last),
+                     __to_first + __pair_first,
+                     __comp);
+        }
+      });
+    };
+
+    if (__objects_are_in_buffer)
+      __merge_chunks(__values.get(), __first);
+    else
+      __merge_chunks(__first, __values.get());
+    __objects_are_in_buffer = !__objects_are_in_buffer;
+
+    __chunk_span_size *= 2;
+    __chunk_spans = __chunk_spans_pairs;
+  } while (__chunk_spans > 1);
+
+  if (__objects_are_in_buffer) {
+    std::move(__values.get(), __values.get() + __size, __first);
+  }
+
+  return __empty{};
+}
+
+} // namespace __statpart
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_BASIS_H

diff  --git a/libcxx/include/__pstl/backends/statpart/fill.h b/libcxx/include/__pstl/backends/statpart/fill.h
new file mode 100644
index 00000000000000..91ab72f6a9c404
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/fill.h
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_FILL_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FILL_H
+
+#include <__algorithm/fill.h>
+#include <__assert>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+namespace __statpart {
+
+template <class _Index, class _DifferenceType, class _Tp>
+_LIBCPP_HIDE_FROM_ABI _Index __simd_fill_n(_Index __first, _DifferenceType __n, const _Tp& __value) noexcept {
+  _PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED
+  _PSTL_PRAGMA_SIMD
+  for (_DifferenceType __i = 0; __i < __n; ++__i)
+    __first[__i] = __value;
+  return __first + __n;
+}
+
+} // namespace __statpart
+
+template <class _ExecutionPolicy>
+struct __fill<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Tp>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__for_each(
+          __first, __last, [&__policy, &__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            using _FillUnseq = __pstl::__fill<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            [[maybe_unused]] auto __res =
+                _FillUnseq()(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __value);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+          });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      __statpart::__simd_fill_n(__first, __last - __first, __value);
+      return __empty{};
+    } else {
+      std::fill(__first, __last, __value);
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FILL_H

diff  --git a/libcxx/include/__pstl/backends/statpart/find_end.h b/libcxx/include/__pstl/backends/statpart/find_end.h
new file mode 100644
index 00000000000000..e0407783e845bc
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/find_end.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_FIND_END_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FIND_END_H
+
+#include <__algorithm/find_end.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __find_end<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _BinaryPredicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator1>::
diff erence_type _DifferenceType;
+      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
+      if (__size2 == 0) {
+        return __last1; // If the needle length is zero, the last iterator is returned.
+      }
+      _DifferenceType __size1 = __last1 - __first1;
+      if (__size1 < __size2) {
+        return __last1; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __size2 - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator1 __last1_cropped = __last1 - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first1,
+          __last1_cropped,
+          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            // Uncrop the range to allow std::find_end to find a full match, which can go beyond __brick_last.
+            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::find_end inside each of the chunks in parallel.
+            _ForwardIterator1 __ret = std::find_end(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __parallel_find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          greater<>{}, // `greater` here means the highest index among the matches
+          false        // `false` here means we want the last match, not the first
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last1_cropped) {
+        return __last1; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::find_end(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FIND_END_H

diff  --git a/libcxx/include/__pstl/backends/statpart/find_if.h b/libcxx/include/__pstl/backends/statpart/find_if.h
new file mode 100644
index 00000000000000..4ccd9fc88c9bae
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/find_if.h
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_FIND_IF_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FIND_IF_H
+
+#include <__algorithm/find_if.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+namespace __statpart {
+
+template <class _Index, class _DifferenceType, class _Compare>
+_LIBCPP_HIDE_FROM_ABI _Index
+__simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp) noexcept {
+  // Experiments show good block sizes like this
+  const _DifferenceType __block_size                                    = 8;
+  alignas(__statpart::__lane_size) _DifferenceType __lane[__block_size] = {0};
+  while (__end - __begin >= __block_size) {
+    _DifferenceType __found = 0;
+    _PSTL_PRAGMA_SIMD_REDUCTION(| : __found) for (_DifferenceType __i = __begin; __i < __begin + __block_size; ++__i) {
+      const _DifferenceType __t = __comp(__first, __i);
+      __lane[__i - __begin]     = __t;
+      __found |= __t;
+    }
+    if (__found) {
+      _DifferenceType __i;
+      // This will vectorize
+      for (__i = 0; __i < __block_size; ++__i) {
+        if (__lane[__i]) {
+          break;
+        }
+      }
+      return __first + __begin + __i;
+    }
+    __begin += __block_size;
+  }
+
+  // Keep remainder scalar
+  while (__begin != __end) {
+    if (__comp(__first, __begin)) {
+      return __first + __begin;
+    }
+    ++__begin;
+  }
+  return __first + __end;
+}
+
+} // namespace __statpart
+
+template <class _ExecutionPolicy>
+struct __find_if<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__find(
+          std::move(__first),
+          std::move(__last),
+          [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            using _FindIfUnseq =
+                __pstl::__find_if<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            auto __res = _FindIfUnseq()(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+            return *std::move(__res);
+          },
+          less<>{},
+          true);
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      using __
diff _t = __iterator_
diff erence_type<_ForwardIterator>;
+      return __statpart::__simd_first(
+          __first, __
diff _t(0), __last - __first, [&__pred](_ForwardIterator __iter, __
diff _t __i) {
+            return __pred(__iter[__i]);
+          });
+    } else {
+      return std::find_if(std::move(__first), std::move(__last), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FIND_IF_H

diff  --git a/libcxx/include/__pstl/backends/statpart/for_each.h b/libcxx/include/__pstl/backends/statpart/for_each.h
new file mode 100644
index 00000000000000..b1004231c0f7dc
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/for_each.h
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_FOR_EACH_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FOR_EACH_H
+
+#include <__algorithm/for_each.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+namespace __statpart {
+
+template <class _Iterator, class _DifferenceType, class _Function>
+_LIBCPP_HIDE_FROM_ABI _Iterator __simd_for_each(_Iterator __first, _DifferenceType __n, _Function __f) noexcept {
+  _PSTL_PRAGMA_SIMD
+  for (_DifferenceType __i = 0; __i < __n; ++__i)
+    __f(__first[__i]);
+
+  return __first + __n;
+}
+
+} // namespace __statpart
+
+template <class _ExecutionPolicy>
+struct __for_each<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Function>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__for_each(
+          std::move(__first), std::move(__last), [&](auto __partition_first, auto __partition_last) {
+            using _ForEachUnseq =
+                __pstl::__for_each<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            [[maybe_unused]] auto __res =
+                _ForEachUnseq()(std::__remove_parallel_policy(__policy), __partition_first, __partition_last, __func);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+          });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      __statpart::__simd_for_each(__first, __last - __first, __func);
+      return __empty{};
+    } else {
+      std::for_each(std::move(__first), std::move(__last), std::move(__func));
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FOR_EACH_H

diff  --git a/libcxx/include/__pstl/backends/statpart/is_heap_until.h b/libcxx/include/__pstl/backends/statpart/is_heap_until.h
new file mode 100644
index 00000000000000..6575ba54f89657
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/is_heap_until.h
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_IS_HEAP_UNTIL_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_IS_HEAP_UNTIL_H
+
+#include <__algorithm/is_heap_until.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __is_heap_until<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _RandomAccessIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<_RandomAccessIterator>
+  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
+      if (__last - __first < 2)
+        return __last; // Any sequence with less than 2 elements is a heap
+      // Run a parallel find in chunks over [first+1, last) to validate every element except the root.
+      return __statpart::__find(
+          __first + 1,
+          __last,
+          [__first, &__comp](_RandomAccessIterator __child_first, _RandomAccessIterator __child_last) {
+            // This algorithm assumes that __find() will never pass an empty brick,
+            // i.e. that __child_first != __child_last.
+            using _DifferenceType = typename std::iterator_traits<_RandomAccessIterator>::
diff erence_type;
+
+            // Derive the indices of the children and the iterators of their parents
+            _DifferenceType __child_first_idx   = __child_first - __first;
+            _DifferenceType __child_last_idx    = __child_last - __first;
+            _RandomAccessIterator __parent      = __first + (__child_first_idx - 1) / 2;
+            _RandomAccessIterator __parent_last = __first + (__child_last_idx - 1) / 2;
+
+            // If we're starting from a right child => process this element separately in a prologue
+            if (__child_first_idx % 2 == 0) {
+              if (__comp(*__parent, *__child_first)) // Check the right child
+                return __child_first;
+              ++__parent;
+              ++__child_first;
+            }
+
+            // Iterate over the parents and check their left and right children
+            for (; __parent != __parent_last; ++__parent) {
+              if (__comp(*__parent, *__child_first)) // Check the left child
+                return __child_first;
+              ++__child_first;
+
+              if (__comp(*__parent, *__child_first)) // Check the right child
+                return __child_first;
+              ++__child_first;
+            }
+
+            // If we're ending with a right child => __parent_last also includes the left child.
+            // Process this accessible element separately in an epilogue.
+            if (__child_last_idx % 2 == 0) {
+              if (__comp(*__parent, *__child_first)) // Check the left child
+                return __child_first;
+            }
+
+            return __child_last; // No violations found in this brick
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+    } else {
+      return std::is_heap_until(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_IS_HEAP_UNTIL_H

diff  --git a/libcxx/include/__pstl/backends/statpart/merge.h b/libcxx/include/__pstl/backends/statpart/merge.h
new file mode 100644
index 00000000000000..73ca5a324d0b99
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/merge.h
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_MERGE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MERGE_H
+
+#include <__algorithm/merge.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __merge<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardOutIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> operator()(
+      _Policy&&,
+      _ForwardIterator1 __first1,
+      _ForwardIterator1 __last1,
+      _ForwardIterator2 __first2,
+      _ForwardIterator2 __last2,
+      _ForwardOutIterator __result,
+      _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      auto __res = __statpart::__merge(
+          __first1,
+          __last1,
+          __first2,
+          __last2,
+          __result,
+          __comp,
+          [](_ForwardIterator1 __brick_first1,
+             _ForwardIterator1 __brick_last1,
+             _ForwardIterator2 __brick_first2,
+             _ForwardIterator2 __brick_last2,
+             _ForwardOutIterator __brick_result,
+             _Comp __g_comp) {
+            std::merge(std::move(__brick_first1),
+                       std::move(__brick_last1),
+                       std::move(__brick_first2),
+                       std::move(__brick_last2),
+                       std::move(__brick_result),
+                       std::move(__g_comp));
+          });
+      if (!__res)
+        return nullopt;
+      return __result + (__last1 - __first1) + (__last2 - __first2);
+    } else {
+      return std::merge(__first1, __last1, __first2, __last2, __result, __comp);
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MERGE_H

diff  --git a/libcxx/include/__pstl/backends/statpart/min_element.h b/libcxx/include/__pstl/backends/statpart/min_element.h
new file mode 100644
index 00000000000000..6d8b4192040b7d
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/min_element.h
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_MIN_ELEMENT_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MIN_ELEMENT_H
+
+#include <__algorithm/min_element.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/identity.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __min_element<__statpart_backend_tag, _ExecutionPolicy> {
+  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<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      if (__first == __last) {
+        return __last; // nothing to do
+      }
+
+      _ForwardIterator __init = __first;
+      ++__first;
+      if (__first == __last) {
+        return __init; // the only element is the minimum
+      }
+
+      // A reduction that returns an iterator pointing to the lowest element, left bias in case of a tie
+      auto __iter_reduce = [&__comp](_ForwardIterator __lhs, _ForwardIterator __rhs) {
+        return __comp(*__rhs, *__lhs) ? __rhs : __lhs;
+      };
+
+      // Perform a parallel reduction of iterators [first+1, last) with 'first' as init.
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          __identity{},      // No transformations
+          std::move(__init), // Use the first iterator as the init element
+          __iter_reduce,     // Reduction of 2 elements
+          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
+            // Reduction of an iterator range + init element: use the serial version to find the minimum among
+            // the iterators and then reduce with the init element.
+            return __iter_reduce(__brick_init, std::min_element(__brick_first, __brick_last, __comp));
+          });
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::min_element(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MIN_ELEMENT_H

diff  --git a/libcxx/include/__pstl/backends/statpart/minmax_element.h b/libcxx/include/__pstl/backends/statpart/minmax_element.h
new file mode 100644
index 00000000000000..7115dcc4d85c75
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/minmax_element.h
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_MINMAX_ELEMENT_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MINMAX_ELEMENT_H
+
+#include <__algorithm/minmax_element.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/identity.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __minmax_element<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Compare>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator, _ForwardIterator>>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      using _IterPair = pair<_ForwardIterator, _ForwardIterator>;
+
+      if (__first == __last) {
+        return _IterPair{__last, __last}; // Nothing to do
+      }
+
+      _IterPair __init = {__first, __first};
+      ++__first;
+      if (__first == __last) {
+        return __init; // The only element is both the minimum and the maximum
+      }
+
+      // A reduction that returns a pair of iterators pointing to the minimum and maximum elements.
+      // In a case of a tie the minimum iterators are biased left and the maximum iterators are biased right.
+      auto __iter_reduce = [&__comp](_IterPair __lhs, _IterPair __rhs) {
+        return _IterPair{__comp(*__rhs.first, *__lhs.first) ? __rhs.first : __lhs.first,
+                         __comp(*__rhs.second, *__lhs.second) ? __lhs.second : __rhs.second};
+      };
+
+      // Perform a parallel reduction of iterators [first+1, last) with {first, first} as init.
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          [](auto __it) { return _IterPair{__it, __it}; }, // Transform an iterator into an iterator pair
+          std::move(__init),                               // Use the pair of first iterators as the init element
+          __iter_reduce,                                   // Reduction of 2 minmax pairs
+          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
+            // Reduction of an iterator range + init element: use the serial version to find the minmax among
+            // the iterators and then reduce it with the init element.
+            return __iter_reduce(__brick_init, std::minmax_element(__brick_first, __brick_last, __comp));
+          });
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::minmax_element(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MINMAX_ELEMENT_H

diff  --git a/libcxx/include/__pstl/backends/statpart/mismatch.h b/libcxx/include/__pstl/backends/statpart/mismatch.h
new file mode 100644
index 00000000000000..cc0da82e59984e
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/mismatch.h
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_MISMATCH_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MISMATCH_H
+
+#include <__algorithm/min.h>
+#include <__algorithm/mismatch.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __mismatch<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      // Look for a mismatch only in the prefix of the two ranges.
+      auto __n = std::min(__last1 - __first1, __last2 - __first2);
+      // Find a position in the first range where the predicate is false against the corresponding position in the
+      // second range.
+      auto __res = __statpart::__find(
+          __first1,
+          __first1 + __n,
+          [&__pred, __first1, __first2](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1) {
+            // Run the sequential mismatch algorithm on these ranges:
+            //   [__brick_first1, __brick_last1) and
+            //   [__first2 + (__brick_first1 - __first1), __first2 + (__brick_last1 - __first1))
+            auto __brick_first2 = __first2 + (__brick_first1 - __first1);
+            return std::mismatch(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2), __pred)
+                .first;
+          },
+          less<>{}, // `less` here means the lowest index among the mismatches
+          true      // `true` here means we want the first mismatch, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      auto __idx = *__res - __first1;
+      return pair<_ForwardIterator1, _ForwardIterator2>{std::move(*__res), __first2 + __idx};
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      // Unsequenced execution is also implicitly covered by the sequential implementation.
+      return std::mismatch(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MISMATCH_H

diff  --git a/libcxx/include/__pstl/backends/statpart/reverse.h b/libcxx/include/__pstl/backends/statpart/reverse.h
new file mode 100644
index 00000000000000..1b3302da64b073
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/reverse.h
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_REVERSE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_REVERSE_H
+
+#include <__algorithm/reverse.h>
+#include <__algorithm/swap_ranges.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/reverse_iterator.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __reverse<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _BidirectionalIterator>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _BidirectionalIterator __first, _BidirectionalIterator __last) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_BidirectionalIterator>::value) {
+      // Perform a chunked for_each on the first half of the range.
+      // Odd-sized ranges will leave the middle element untouched, which is correct for this algorithm:
+      // its reversed position is the same.
+      auto __n = (__last - __first) / 2;
+      return __statpart::__for_each(
+          __first, __first + __n, [__first, __last](_BidirectionalIterator __i, _BidirectionalIterator __j) {
+            // Derive the last position of the mirrored range by counting from the end.
+            _BidirectionalIterator __mirror_last = __last - (__i - __first);
+            // Swap the elements in the range of the first half with their mirrored counterparts in the second half.
+            std::swap_ranges(std::move(__i),
+                             std::move(__j),
+                             std::reverse_iterator<_BidirectionalIterator>(std::move(__mirror_last)));
+          });
+    } else {
+      // Non-random access iterators currently cannot be processed in parallel, use the sequential implementation.
+      std::reverse(std::move(__first), std::move(__last));
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_REVERSE_H

diff  --git a/libcxx/include/__pstl/backends/statpart/search.h b/libcxx/include/__pstl/backends/statpart/search.h
new file mode 100644
index 00000000000000..5a9f7c549f148f
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/search.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_SEARCH_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_H
+
+#include <__algorithm/search.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __search<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _BinaryPredicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator1>::
diff erence_type _DifferenceType;
+      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
+      if (__size2 == 0) {
+        return __first1; // If the needle length is zero, the first iterator is returned.
+      }
+      _DifferenceType __size1 = __last1 - __first1;
+      if (__size1 < __size2) {
+        return __last1; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __size2 - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator1 __last1_cropped = __last1 - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first1,
+          __last1_cropped,
+          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            // Uncrop the range to allow std::search to find a full match, which can go beyond __brick_last.
+            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::search inside each of the chunks in parallel.
+            _ForwardIterator1 __ret = std::search(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last1_cropped) {
+        return __last1; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::search(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_H

diff  --git a/libcxx/include/__pstl/backends/statpart/search_n.h b/libcxx/include/__pstl/backends/statpart/search_n.h
new file mode 100644
index 00000000000000..a662bf83d0cdf8
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/search_n.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_SEARCH_N_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_N_H
+
+#include <__algorithm/search_n.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/convert_to_integral.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __search_n<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Size, class _Tp, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&&,
+             _ForwardIterator __first,
+             _ForwardIterator __last,
+             _Size __count,
+             const _Tp& __value,
+             _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator>::
diff erence_type _DifferenceType;
+      _DifferenceType __integral_count = std::__convert_to_integral(__count);
+      if (__integral_count <= 0) {
+        return __first; // If the count is non-positive, the first iterator is returned.
+      }
+      _DifferenceType __size = __last - __first;
+      if (__size < __integral_count) {
+        return __last; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __integral_count - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator __last2 = __last - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first,
+          __last2,
+          [__integral_count, __crop, &__value, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            // Uncrop the range to allow std::search_n to find a full match, which can go beyond __brick_last.
+            _ForwardIterator __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::search_n inside each of the chunks in parallel.
+            _ForwardIterator __ret =
+                std::search_n(__brick_first, __brick_last_uncropped, __integral_count, __value, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last2) {
+        return __last; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::search_n(std::move(__first), std::move(__last), __count, __value, std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_N_H

diff  --git a/libcxx/include/__pstl/backends/statpart/stable_sort.h b/libcxx/include/__pstl/backends/statpart/stable_sort.h
new file mode 100644
index 00000000000000..fc2e470aa5018a
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/stable_sort.h
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_STABLE_SORT_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_STABLE_SORT_H
+
+#include <__algorithm/stable_sort.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __stable_sort<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _RandomAccessIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
+      return __statpart::__stable_sort(
+          __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
+            std::stable_sort(__g_first, __g_last, __g_comp);
+          });
+    } else {
+      std::stable_sort(__first, __last, __comp);
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_STABLE_SORT_H

diff  --git a/libcxx/include/__pstl/backends/statpart/swap_ranges.h b/libcxx/include/__pstl/backends/statpart/swap_ranges.h
new file mode 100644
index 00000000000000..2ab8c30174ae7d
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/swap_ranges.h
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_SWAP_RANGES_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_SWAP_RANGES_H
+
+#include <__algorithm/swap_ranges.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __swap_ranges<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first1,
+          __last1,
+          __first2,
+          [](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1, _ForwardIterator2 __brick_first2) {
+            std::swap_ranges(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __first2 + (__last1 - __first1);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::swap_ranges(std::move(__first1), std::move(__last1), std::move(__first2));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_SWAP_RANGES_H

diff  --git a/libcxx/include/__pstl/backends/statpart/transform.h b/libcxx/include/__pstl/backends/statpart/transform.h
new file mode 100644
index 00000000000000..15f257810c0f79
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/transform.h
@@ -0,0 +1,162 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_TRANSFORM_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_H
+
+#include <__algorithm/transform.h>
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+namespace __statpart {
+
+template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Function>
+_LIBCPP_HIDE_FROM_ABI _Iterator2
+__simd_transform(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Function __f) noexcept {
+  _PSTL_PRAGMA_SIMD
+  for (_DifferenceType __i = 0; __i < __n; ++__i)
+    __f(__first1[__i], __first2[__i]);
+  return __first2 + __n;
+}
+
+template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Iterator3, class _Function>
+_LIBCPP_HIDE_FROM_ABI _Iterator3 __simd_transform(
+    _Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Iterator3 __first3, _Function __f) noexcept {
+  _PSTL_PRAGMA_SIMD
+  for (_DifferenceType __i = 0; __i < __n; ++__i)
+    __f(__first1[__i], __first2[__i], __first3[__i]);
+  return __first3 + __n;
+}
+
+} // namespace __statpart
+
+template <class _ExecutionPolicy>
+struct __transform<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
+  operator()(_Policy&& __policy,
+             _ForwardIterator __first,
+             _ForwardIterator __last,
+             _ForwardOutIterator __result,
+             _UnaryOperation __op) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      auto res = __statpart::__for_each(
+          __first,
+          __last,
+          [&__policy, __op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            using _TransformUnseq =
+                __pstl::__transform<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            _TransformUnseq()(
+                std::__remove_parallel_policy(__policy),
+                __brick_first,
+                __brick_last,
+                __result + (__brick_first - __first),
+                __op);
+          });
+      if (!res)
+        return nullopt; // Failed to perform "__for_each", propagate the error upwards
+      return __result + (__last - __first);
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
+                         __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      return __statpart::__simd_transform(
+          __first,
+          __last - __first,
+          __result,
+          [&](__iterator_reference<_ForwardIterator> __in_value,
+              __iterator_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in_value); });
+    } else {
+      return std::transform(__first, __last, __result, __op);
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_binary<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy,
+            class _ForwardIterator1,
+            class _ForwardIterator2,
+            class _ForwardOutIterator,
+            class _BinaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
+  operator()(_Policy&& __policy,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardOutIterator __result,
+             _BinaryOperation __op) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      auto __res = __statpart::__for_each(
+          __first1,
+          __last1,
+          [&__policy, __op, __first1, __first2, __result](
+              _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            using _TransformBinaryUnseq =
+                __pstl::__transform_binary<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            _TransformBinaryUnseq()(
+                std::__remove_parallel_policy(__policy),
+                __brick_first,
+                __brick_last,
+                __first2 + (__brick_first - __first1),
+                __result + (__brick_first - __first1),
+                __op);
+          });
+      if (!__res)
+        return nullopt;
+      return __result + (__last1 - __first1);
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
+                         __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      return __statpart::__simd_transform(
+          __first1,
+          __last1 - __first1,
+          __first2,
+          __result,
+          [&](__iterator_reference<_ForwardIterator1> __in1,
+              __iterator_reference<_ForwardIterator2> __in2,
+              __iterator_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in1, __in2); });
+    } else {
+      return std::transform(__first1, __last1, __first2, __result, __op);
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_H

diff  --git a/libcxx/include/__pstl/backends/statpart/transform_reduce.h b/libcxx/include/__pstl/backends/statpart/transform_reduce.h
new file mode 100644
index 00000000000000..452d17d157830b
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/transform_reduce.h
@@ -0,0 +1,228 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_TRANSFORM_REDUCE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_REDUCE_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__execution/is_execution_policy.h>
+#include <__functional/invoke.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__numeric/transform_reduce.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/desugars_to.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_arithmetic.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+namespace __statpart {
+
+template < typename _DifferenceType,
+           typename _Tp,
+           typename _BinaryOperation,
+           typename _UnaryOperation,
+           typename _UnaryResult = invoke_result_t<_UnaryOperation, _DifferenceType>,
+           __enable_if_t<__desugars_to_v<__plus_tag, _BinaryOperation, _Tp, _UnaryResult> && is_arithmetic_v<_Tp> &&
+                             is_arithmetic_v<_UnaryResult>,
+                         int>    = 0>
+_LIBCPP_HIDE_FROM_ABI _Tp
+__simd_transform_reduce(_DifferenceType __n, _Tp __init, _BinaryOperation, _UnaryOperation __f) noexcept {
+  _PSTL_PRAGMA_SIMD_REDUCTION(+ : __init)
+  for (_DifferenceType __i = 0; __i < __n; ++__i)
+    __init += __f(__i);
+  return __init;
+}
+
+template < typename _Size,
+           typename _Tp,
+           typename _BinaryOperation,
+           typename _UnaryOperation,
+           typename _UnaryResult = invoke_result_t<_UnaryOperation, _Size>,
+           __enable_if_t<!(__desugars_to_v<__plus_tag, _BinaryOperation, _Tp, _UnaryResult> && is_arithmetic_v<_Tp> &&
+                           is_arithmetic_v<_UnaryResult>),
+                         int>    = 0>
+_LIBCPP_HIDE_FROM_ABI _Tp
+__simd_transform_reduce(_Size __n, _Tp __init, _BinaryOperation __binary_op, _UnaryOperation __f) noexcept {
+  const _Size __block_size = __lane_size / sizeof(_Tp);
+  if (__n > 2 * __block_size && __block_size > 1) {
+    alignas(__lane_size) char __lane_buffer[__lane_size];
+    _Tp* __lane = reinterpret_cast<_Tp*>(__lane_buffer);
+
+    // initializer
+    _PSTL_PRAGMA_SIMD
+    for (_Size __i = 0; __i < __block_size; ++__i) {
+      ::new (__lane + __i) _Tp(__binary_op(__f(__i), __f(__block_size + __i)));
+    }
+    // main loop
+    _Size __i                    = 2 * __block_size;
+    const _Size __last_iteration = __block_size * (__n / __block_size);
+    for (; __i < __last_iteration; __i += __block_size) {
+      _PSTL_PRAGMA_SIMD
+      for (_Size __j = 0; __j < __block_size; ++__j) {
+        __lane[__j] = __binary_op(std::move(__lane[__j]), __f(__i + __j));
+      }
+    }
+    // remainder
+    _PSTL_PRAGMA_SIMD
+    for (_Size __j = 0; __j < __n - __last_iteration; ++__j) {
+      __lane[__j] = __binary_op(std::move(__lane[__j]), __f(__last_iteration + __j));
+    }
+    // combiner
+    for (_Size __j = 0; __j < __block_size; ++__j) {
+      __init = __binary_op(std::move(__init), std::move(__lane[__j]));
+    }
+    // destroyer
+    _PSTL_PRAGMA_SIMD
+    for (_Size __j = 0; __j < __block_size; ++__j) {
+      __lane[__j].~_Tp();
+    }
+  } else {
+    for (_Size __i = 0; __i < __n; ++__i) {
+      __init = __binary_op(std::move(__init), __f(__i));
+    }
+  }
+  return __init;
+}
+
+} // namespace __statpart
+
+template <class _ExecutionPolicy>
+struct __transform_reduce<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_Tp>
+  operator()(_Policy&& __policy,
+             _ForwardIterator __first,
+             _ForwardIterator __last,
+             _Tp __init,
+             _BinaryOperation __reduce,
+             _UnaryOperation __transform) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          [__transform](_ForwardIterator __iter) { return __transform(*__iter); },
+          std::move(__init),
+          __reduce,
+          [&__policy, __transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) {
+            using _TransformReduceUnseq =
+                __pstl::__transform_reduce<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            auto __res = _TransformReduceUnseq()(
+                std::__remove_parallel_policy(__policy),
+                std::move(__brick_first),
+                std::move(__brick_last),
+                std::move(__brick_init),
+                std::move(__reduce),
+                std::move(__transform));
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+            return *std::move(__res);
+          });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__simd_transform_reduce(
+          __last - __first,
+          std::move(__init),
+          std::move(__reduce),
+          [=, &__transform](__iterator_
diff erence_type<_ForwardIterator> __i) { return __transform(__first[__i]); });
+    } else {
+      return std::transform_reduce(
+          std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_reduce_binary<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy,
+            class _ForwardIterator1,
+            class _ForwardIterator2,
+            class _Tp,
+            class _BinaryOperation1,
+            class _BinaryOperation2>
+  _LIBCPP_HIDE_FROM_ABI optional<_Tp> operator()(
+      _Policy&& __policy,
+      _ForwardIterator1 __first1,
+      _ForwardIterator1 __last1,
+      _ForwardIterator2 __first2,
+      _Tp __init,
+      _BinaryOperation1 __reduce,
+      _BinaryOperation2 __transform) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      return __statpart::__transform_reduce(
+          __first1,
+          std::move(__last1),
+          [__first1, __first2, __transform](_ForwardIterator1 __iter) {
+            return __transform(*__iter, *(__first2 + (__iter - __first1)));
+          },
+          std::move(__init),
+          std::move(__reduce),
+          [&__policy, __first1, __first2, __reduce, __transform](
+              _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) {
+            using _TransformReduceBinaryUnseq =
+                __pstl::__transform_reduce_binary<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            auto __res = _TransformReduceBinaryUnseq()(
+                std::__remove_parallel_policy(__policy),
+                __brick_first,
+                std::move(__brick_last),
+                __first2 + (__brick_first - __first1),
+                std::move(__brick_init),
+                std::move(__reduce),
+                std::move(__transform));
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+            return *std::move(__res);
+          });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      return __statpart::__simd_transform_reduce(
+          __last1 - __first1,
+          std::move(__init),
+          std::move(__reduce),
+          [&](__iterator_
diff erence_type<_ForwardIterator1> __i) { return __transform(__first1[__i], __first2[__i]); });
+    } else {
+      return std::transform_reduce(
+          std::move(__first1),
+          std::move(__last1),
+          std::move(__first2),
+          std::move(__init),
+          std::move(__reduce),
+          std::move(__transform));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_REDUCE_H

diff  --git a/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h b/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
new file mode 100644
index 00000000000000..3fcbd30f5206de
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_UNITIALIZED_COPY_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_COPY_H
+
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/uninitialized_algorithms.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __uninitialized_copy<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first,
+          __last,
+          __result,
+          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
+            std::uninitialized_copy(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __result + (__last - __first);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::uninitialized_copy(std::move(__first), std::move(__last), std::move(__result));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_COPY_H

diff  --git a/libcxx/include/__pstl/backends/statpart/uninitialized_move.h b/libcxx/include/__pstl/backends/statpart/uninitialized_move.h
new file mode 100644
index 00000000000000..71f1620628e9f1
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/uninitialized_move.h
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BACKENDS_STATPART_UNITIALIZED_MOVE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_MOVE_H
+
+#include <__config>
+#include <__execution/is_execution_policy.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/uninitialized_algorithms.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__utility/move.h>
+
+#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
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __uninitialized_move<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first,
+          __last,
+          __result,
+          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
+            std::uninitialized_move(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __result + (__last - __first);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::uninitialized_move(std::move(__first), std::move(__last), std::move(__result));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_MOVE_H

diff  --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 6ca65ba556fa1c..397b7b5fdec623 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2415,6 +2415,69 @@ module std {
         header "__pstl/backends/serial.h"
         export std_core.utility_core.empty
       }
+      module statpart {
+        module any_of {
+          header "__pstl/backends/statpart/any_of.h"
+        }
+        module basis {
+          header "__pstl/backends/statpart/basis.h"
+        }
+        module fill {
+          header "__pstl/backends/statpart/fill.h"
+        }
+        module find_end {
+          header "__pstl/backends/statpart/find_end.h"
+        }
+        module find_if {
+          header "__pstl/backends/statpart/find_if.h"
+        }
+        module for_each {
+          header "__pstl/backends/statpart/for_each.h"
+        }
+        module is_heap_until {
+          header "__pstl/backends/statpart/is_heap_until.h"
+        }
+        module merge {
+          header "__pstl/backends/statpart/merge.h"
+        }
+        module min_element {
+          header "__pstl/backends/statpart/min_element.h"
+        }
+        module minmax_element {
+          header "__pstl/backends/statpart/minmax_element.h"
+        }
+        module mismatch {
+          header "__pstl/backends/statpart/mismatch.h"
+        }
+        module reverse {
+          header "__pstl/backends/statpart/reverse.h"
+        }
+        module search {
+          header "__pstl/backends/statpart/search.h"
+        }
+        module search_n {
+          header "__pstl/backends/statpart/search_n.h"
+        }
+        module stable_sort {
+          header "__pstl/backends/statpart/stable_sort.h"
+        }
+        module swap_ranges {
+          header "__pstl/backends/statpart/swap_ranges.h"
+        }
+        module transform {
+          header "__pstl/backends/statpart/transform.h"
+        }
+        module transform_reduce {
+          header "__pstl/backends/statpart/transform_reduce.h"
+        }
+        module uninitialized_copy {
+          header "__pstl/backends/statpart/uninitialized_copy.h"
+        }
+        module uninitialized_move {
+          header "__pstl/backends/statpart/uninitialized_move.h"
+        }
+        header "__pstl/backends/statpart.h"
+      }
       module std_thread {
         header "__pstl/backends/std_thread.h"
         export std.pstl.cpu_algos

diff  --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 99e6bfb5692f52..770b9ffa21d8b2 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -316,6 +316,12 @@ if (LIBCXX_PSTL_BACKEND STREQUAL "libdispatch")
     )
 endif()
 
+if (LIBCXX_PSTL_BACKEND STREQUAL "statpart")
+  list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
+    pstl/statpart.cpp
+    )
+endif()
+
 if (LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_TIME_ZONE_DATABASE)
   list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
     experimental/include/tzdb/time_zone_private.h

diff  --git a/libcxx/src/pstl/statpart.cpp b/libcxx/src/pstl/statpart.cpp
new file mode 100644
index 00000000000000..1bbf2406f99641
--- /dev/null
+++ b/libcxx/src/pstl/statpart.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <__config>
+#include <__pstl/backends/statpart.h>
+
+#if defined(__APPLE__)
+#  include <dispatch/dispatch.h>
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl::__statpart {
+
+void __apply(size_t chunk_count, void* context, void (*func)(void* context, size_t chunk)) noexcept {
+#if defined(__APPLE__)
+  ::dispatch_apply_f(chunk_count, DISPATCH_APPLY_AUTO, context, func);
+#else
+  // Currently there's no parallelism provider on non-Apple platforms.
+  // A basic task scheduler based on a thread pool will be added later to perform the application in parallel.
+  for (size_t i = 0; i < chunk_count; ++i)
+    func(context, i);
+#endif
+}
+
+} // namespace __pstl::__statpart
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp
new file mode 100644
index 00000000000000..457d97a39831de
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp
@@ -0,0 +1,171 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// REQUIRES: std-at-least-c++17
+// REQUIRES: libcpp-pstl-backend-statpart
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class Iterator>
+// __partitioning_result<Iterator>
+// __partition(Iterator __first,
+//             Iterator __last,
+//             size_t __min_partition_size,
+//             size_t __prefix_to_skip,
+//             size_t __suffix_to_skip,
+//             size_t __workers_count)
+
+#include <__pstl/backends/statpart.h>
+#include <algorithm>
+#include <iterator>
+#include <cassert>
+#include <cstddef>
+#include <vector>
+
+template <class Container>
+void test_partition() {
+  auto part_eq = [](const auto& partition, const auto& container, size_t first_pos, size_t last_pos) {
+    return partition.__first == std::next(container.begin(), first_pos) &&
+           partition.__last == std::next(container.begin(), last_pos);
+  };
+
+  { // 1 element, 8 workers: no partitions
+    Container v(1);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 0, 0, 8);
+    assert(partitions.__value_ == std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__not_enough_elements);
+  }
+  { // 2 elements, 8 workers: 2 partitions
+    // [0..1), [1..2)
+    Container v(2);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 0, 0, 8);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 2);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 1));
+    assert(part_eq(partitions.__value_->__partition(1), v, 1, 2));
+  }
+  { // 2 elements, min_size=2, 8 workers: no partitions
+    // [0..1), [1..2)
+    Container v(2);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 2, 0, 8);
+    assert(partitions.__value_ == std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__not_enough_elements);
+  }
+  { // 20 elements, 2 workers: 16 partitions
+    // [0..2), [2..4), [4..6), [6..8), [8..9), [9..10), ..., [19, 20)
+    Container v(20);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 0, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 16);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 2));
+    assert(part_eq(partitions.__value_->__partition(1), v, 2, 4));
+    assert(part_eq(partitions.__value_->__partition(2), v, 4, 6));
+    assert(part_eq(partitions.__value_->__partition(3), v, 6, 8));
+    assert(part_eq(partitions.__value_->__partition(4), v, 8, 9));
+    assert(part_eq(partitions.__value_->__partition(5), v, 9, 10));
+    assert(part_eq(partitions.__value_->__partition(6), v, 10, 11));
+    assert(part_eq(partitions.__value_->__partition(7), v, 11, 12));
+    assert(part_eq(partitions.__value_->__partition(8), v, 12, 13));
+    assert(part_eq(partitions.__value_->__partition(9), v, 13, 14));
+    assert(part_eq(partitions.__value_->__partition(10), v, 14, 15));
+    assert(part_eq(partitions.__value_->__partition(11), v, 15, 16));
+    assert(part_eq(partitions.__value_->__partition(12), v, 16, 17));
+    assert(part_eq(partitions.__value_->__partition(13), v, 17, 18));
+    assert(part_eq(partitions.__value_->__partition(14), v, 18, 19));
+    assert(part_eq(partitions.__value_->__partition(15), v, 19, 20));
+  }
+  { // 20 elements, min_size=2, 2 workers: 10 partitions
+    // [0..2), [2..4), [4..6), ..., [18, 20)
+    Container v(20);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 2, 0, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 10);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 2));
+    assert(part_eq(partitions.__value_->__partition(1), v, 2, 4));
+    assert(part_eq(partitions.__value_->__partition(2), v, 4, 6));
+    assert(part_eq(partitions.__value_->__partition(3), v, 6, 8));
+    assert(part_eq(partitions.__value_->__partition(4), v, 8, 10));
+    assert(part_eq(partitions.__value_->__partition(5), v, 10, 12));
+    assert(part_eq(partitions.__value_->__partition(6), v, 12, 14));
+    assert(part_eq(partitions.__value_->__partition(7), v, 14, 16));
+    assert(part_eq(partitions.__value_->__partition(8), v, 16, 18));
+    assert(part_eq(partitions.__value_->__partition(9), v, 18, 20));
+  }
+  { // 20 elements, min_size=3, 2 workers: 6 partitions
+    // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 0, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 4));
+    assert(part_eq(partitions.__value_->__partition(1), v, 4, 8));
+    assert(part_eq(partitions.__value_->__partition(2), v, 8, 11));
+    assert(part_eq(partitions.__value_->__partition(3), v, 11, 14));
+    assert(part_eq(partitions.__value_->__partition(4), v, 14, 17));
+    assert(part_eq(partitions.__value_->__partition(5), v, 17, 20));
+  }
+  { // 20 elements, min_size=3, prefix_skip=1, 2 workers: 6 partitions
+    // [1..5), [5..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 1, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 1, 5));
+    assert(part_eq(partitions.__value_->__partition(1), v, 5, 8));
+    assert(part_eq(partitions.__value_->__partition(2), v, 8, 11));
+    assert(part_eq(partitions.__value_->__partition(3), v, 11, 14));
+    assert(part_eq(partitions.__value_->__partition(4), v, 14, 17));
+    assert(part_eq(partitions.__value_->__partition(5), v, 17, 20));
+  }
+  { // 20 elements, min_size=3, suffix_skip=1, 2 workers: 6 partitions
+    // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 0, 1, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == std::prev(v.end(), 1));
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 4));
+    assert(part_eq(partitions.__value_->__partition(1), v, 4, 7));
+    assert(part_eq(partitions.__value_->__partition(2), v, 7, 10));
+    assert(part_eq(partitions.__value_->__partition(3), v, 10, 13));
+    assert(part_eq(partitions.__value_->__partition(4), v, 13, 16));
+    assert(part_eq(partitions.__value_->__partition(5), v, 16, 19));
+  }
+  { // 20 elements, min_size=3, prefix_skip=1, suffix_skip=1, 2 workers: 6 partitions
+    // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 1, 1, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == std::prev(v.end(), 1));
+    assert(part_eq(partitions.__value_->__partition(0), v, 1, 4));
+    assert(part_eq(partitions.__value_->__partition(1), v, 4, 7));
+    assert(part_eq(partitions.__value_->__partition(2), v, 7, 10));
+    assert(part_eq(partitions.__value_->__partition(3), v, 10, 13));
+    assert(part_eq(partitions.__value_->__partition(4), v, 13, 16));
+    assert(part_eq(partitions.__value_->__partition(5), v, 16, 19));
+  }
+}
+
+int main(int, char**) {
+  test_partition<std::vector<int>>();
+  // later: test_partition<std::list<int>>();
+}

diff  --git a/libcxx/utils/libcxx/test/features/libcxx_macros.py b/libcxx/utils/libcxx/test/features/libcxx_macros.py
index 38f761af009a7b..67531098972746 100644
--- a/libcxx/utils/libcxx/test/features/libcxx_macros.py
+++ b/libcxx/utils/libcxx/test/features/libcxx_macros.py
@@ -34,6 +34,7 @@
     "_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR": "libcpp-deprecated-abi-disable-pair-trivial-copy-ctor",
     "_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING": "libcpp-abi-no-compressed-pair-padding",
     "_LIBCPP_PSTL_BACKEND_LIBDISPATCH": "libcpp-pstl-backend-libdispatch",
+    "_LIBCPP_PSTL_BACKEND_STATPART": "libcpp-pstl-backend-statpart",
     "_LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE": "libcpp-abi-use-small-deque-block-size",
     "_LIBCPP_ABI_COMPACT_LOCALE_ID": "libcpp-abi-compact-locale-id",
 }


        


More information about the libcxx-commits mailing list