Skip to content

Commit f70f001

Browse files
committed
[WIP][libc++] PSTL dispatching mechanism overhaul
The experimental PSTL's current dispatching mechanism was designed with flexibility in mind. However, while reviewing the in-progress OpenMP backend, I realized that the dispatching mechanism based on ADL and default definitions in the frontend had several downsides. To name a few: 1. The dispatching of an algorithm to the back-end and its default implementation is bundled together via `_LIBCPP_PSTL_CUSTOMIZATION_POINT`. This makes the dispatching really confusing and leads to annoyances such as variable shadowing and weird lambda captures in the front-end. 2. The distinction between back-end functions and front-end algorithms is not as clear as it could be, which led us to call one where we meant the other in a few cases. This is bad due to the exception requirements of the PSTL. 3. There are two levels of back-end dispatching in the PSTL, which treat CPU backends as a special case. This was confusing and not as flexible as we'd like. For example, there was no straightforward way to dispatch all uses of `unseq` to a specific back-end from the OpenMP backend, or for CPU backends to fall back on each other. This patch rewrites the backend dispatching mechanism to solve these problems, but doesn't touch any of the actual implementation of algorithms. Specifically, this rewrite has the following characteristics: - All back-ends are full top-level backends defining all the basis operations required by the PSTL. This is made realistic for CPU backends by providing the CPU-based basis operations as simple helpers that can easily be reused when defining the PSTL basis operations. - The default definitions for algorithms are separated from their dispatching logic and grouped in families instead, based on the basis operation they require for their default implementation. - The front-end is thus simplified a whole lot and made very consistent for all algorithms, which makes it easier to audit the front-end for things like exception-correctness. Fixes #70718
1 parent 8f3242a commit f70f001

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2549
-2332
lines changed

libcxx/CMakeLists.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,9 @@ option(LIBCXX_HAS_EXTERNAL_THREAD_API
301301
This option may only be set to ON when LIBCXX_ENABLE_THREADS=ON." OFF)
302302

303303
if (LIBCXX_ENABLE_THREADS)
304-
set(LIBCXX_PSTL_CPU_BACKEND "std_thread" CACHE STRING "Which PSTL CPU backend to use")
304+
set(LIBCXX_PSTL_BACKEND "std_thread" CACHE STRING "Which PSTL backend to use")
305305
else()
306-
set(LIBCXX_PSTL_CPU_BACKEND "serial" CACHE STRING "Which PSTL CPU backend to use")
306+
set(LIBCXX_PSTL_BACKEND "serial" CACHE STRING "Which PSTL backend to use")
307307
endif()
308308

309309
# Misc options ----------------------------------------------------------------
@@ -793,14 +793,14 @@ elseif (LIBCXX_HARDENING_MODE STREQUAL "debug")
793793
config_define(8 _LIBCPP_HARDENING_MODE_DEFAULT)
794794
endif()
795795

796-
if (LIBCXX_PSTL_CPU_BACKEND STREQUAL "serial")
797-
config_define(1 _LIBCPP_PSTL_CPU_BACKEND_SERIAL)
798-
elseif(LIBCXX_PSTL_CPU_BACKEND STREQUAL "std_thread")
799-
config_define(1 _LIBCPP_PSTL_CPU_BACKEND_THREAD)
800-
elseif(LIBCXX_PSTL_CPU_BACKEND STREQUAL "libdispatch")
801-
config_define(1 _LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH)
796+
if (LIBCXX_PSTL_BACKEND STREQUAL "serial")
797+
config_define(1 _LIBCPP_PSTL_BACKEND_SERIAL)
798+
elseif(LIBCXX_PSTL_BACKEND STREQUAL "std_thread")
799+
config_define(1 _LIBCPP_PSTL_BACKEND_STD_THREAD)
800+
elseif(LIBCXX_PSTL_BACKEND STREQUAL "libdispatch")
801+
config_define(1 _LIBCPP_PSTL_BACKEND_LIBDISPATCH)
802802
else()
803-
message(FATAL_ERROR "LIBCXX_PSTL_CPU_BACKEND is set to ${LIBCXX_PSTL_CPU_BACKEND}, which is not a valid backend.
803+
message(FATAL_ERROR "LIBCXX_PSTL_BACKEND is set to ${LIBCXX_PSTL_BACKEND}, which is not a valid backend.
804804
Valid backends are: serial, std_thread and libdispatch")
805805
endif()
806806

libcxx/cmake/caches/Apple.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ set(LIBCXX_ENABLE_STATIC ON CACHE BOOL "")
77
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
88
set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "")
99
set(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS ON CACHE BOOL "")
10-
set(LIBCXX_PSTL_CPU_BACKEND libdispatch CACHE STRING "")
10+
set(LIBCXX_PSTL_BACKEND libdispatch CACHE STRING "")
1111

1212
set(LIBCXX_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
1313
set(LIBCXXABI_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")

libcxx/include/CMakeLists.txt

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,27 +73,12 @@ set(files
7373
__algorithm/pop_heap.h
7474
__algorithm/prev_permutation.h
7575
__algorithm/pstl_any_all_none_of.h
76-
__algorithm/pstl_backend.h
77-
__algorithm/pstl_backends/cpu_backend.h
78-
__algorithm/pstl_backends/cpu_backends/any_of.h
79-
__algorithm/pstl_backends/cpu_backends/backend.h
80-
__algorithm/pstl_backends/cpu_backends/fill.h
81-
__algorithm/pstl_backends/cpu_backends/find_if.h
82-
__algorithm/pstl_backends/cpu_backends/for_each.h
83-
__algorithm/pstl_backends/cpu_backends/libdispatch.h
84-
__algorithm/pstl_backends/cpu_backends/merge.h
85-
__algorithm/pstl_backends/cpu_backends/serial.h
86-
__algorithm/pstl_backends/cpu_backends/stable_sort.h
87-
__algorithm/pstl_backends/cpu_backends/thread.h
88-
__algorithm/pstl_backends/cpu_backends/transform.h
89-
__algorithm/pstl_backends/cpu_backends/transform_reduce.h
9076
__algorithm/pstl_copy.h
9177
__algorithm/pstl_count.h
9278
__algorithm/pstl_equal.h
9379
__algorithm/pstl_fill.h
9480
__algorithm/pstl_find.h
9581
__algorithm/pstl_for_each.h
96-
__algorithm/pstl_frontend_dispatch.h
9782
__algorithm/pstl_generate.h
9883
__algorithm/pstl_is_partitioned.h
9984
__algorithm/pstl_merge.h
@@ -591,7 +576,28 @@ set(files
591576
__numeric/transform_exclusive_scan.h
592577
__numeric/transform_inclusive_scan.h
593578
__numeric/transform_reduce.h
579+
__pstl/backend_fwd.h
580+
__pstl/backends/libdispatch.h
581+
__pstl/backends/serial.h
582+
__pstl/backends/std_thread.h
583+
__pstl/configuration.h
584+
__pstl/cpu_algos/any_of.h
594585
__pstl/cpu_algos/cpu_traits.h
586+
__pstl/cpu_algos/fill.h
587+
__pstl/cpu_algos/find_if.h
588+
__pstl/cpu_algos/for_each.h
589+
__pstl/cpu_algos/merge.h
590+
__pstl/cpu_algos/stable_sort.h
591+
__pstl/cpu_algos/transform_reduce.h
592+
__pstl/cpu_algos/transform.h
593+
__pstl/defaults.h
594+
__pstl/defaults/find_if_family.h
595+
__pstl/defaults/for_each_family.h
596+
__pstl/defaults/merge_family.h
597+
__pstl/defaults/stable_sort_family.h
598+
__pstl/defaults/transform_family.h
599+
__pstl/defaults/transform_reduce_family.h
600+
__pstl/run_backend.h
595601
__random/bernoulli_distribution.h
596602
__random/binomial_distribution.h
597603
__random/cauchy_distribution.h

libcxx/include/__algorithm/pstl_any_all_none_of.h

Lines changed: 12 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
#ifndef _LIBCPP___ALGORITHM_PSTL_ANY_ALL_NONE_OF_H
1010
#define _LIBCPP___ALGORITHM_PSTL_ANY_ALL_NONE_OF_H
1111

12-
#include <__algorithm/pstl_find.h>
13-
#include <__algorithm/pstl_frontend_dispatch.h>
1412
#include <__config>
1513
#include <__iterator/cpp17_iterator_concepts.h>
14+
#include <__pstl/configuration.h>
15+
#include <__pstl/run_backend.h>
1616
#include <__type_traits/enable_if.h>
1717
#include <__type_traits/is_execution_policy.h>
1818
#include <__type_traits/remove_cvref.h>
19+
#include <__utility/forward.h>
1920
#include <__utility/move.h>
20-
#include <optional>
2121

2222
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2323
# pragma GCC system_header
@@ -30,29 +30,6 @@ _LIBCPP_PUSH_MACROS
3030

3131
_LIBCPP_BEGIN_NAMESPACE_STD
3232

33-
template <class>
34-
void __pstl_any_of(); // declaration needed for the frontend dispatch below
35-
36-
template <class _ExecutionPolicy,
37-
class _ForwardIterator,
38-
class _Predicate,
39-
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
40-
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
41-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool> __any_of(
42-
_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept {
43-
return std::__pstl_frontend_dispatch(
44-
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of, _RawPolicy),
45-
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional<bool> {
46-
auto __res = std::__find_if(__policy, __g_first, __g_last, __g_pred);
47-
if (!__res)
48-
return nullopt;
49-
return *__res != __g_last;
50-
},
51-
std::move(__first),
52-
std::move(__last),
53-
std::move(__pred));
54-
}
55-
5633
template <class _ExecutionPolicy,
5734
class _ForwardIterator,
5835
class _Predicate,
@@ -61,35 +38,9 @@ template <class _ExecutionPolicy,
6138
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
6239
any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
6340
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
64-
auto __res = std::__any_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
65-
if (!__res)
66-
std::__throw_bad_alloc();
67-
return *std::move(__res);
68-
}
69-
70-
template <class>
71-
void __pstl_all_of(); // declaration needed for the frontend dispatch below
72-
73-
template <class _ExecutionPolicy,
74-
class _ForwardIterator,
75-
class _Pred,
76-
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
77-
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
78-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
79-
__all_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
80-
return std::__pstl_frontend_dispatch(
81-
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of, _RawPolicy),
82-
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional<bool> {
83-
auto __res = std::__any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) {
84-
return !__g_pred(__value);
85-
});
86-
if (!__res)
87-
return nullopt;
88-
return !*__res;
89-
},
90-
std::move(__first),
91-
std::move(__last),
92-
std::move(__pred));
41+
using _Implementation = __pstl::__any_of<__pstl::__configured_backend, _RawPolicy>;
42+
return __pstl::__run_backend<_Implementation>(
43+
std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred));
9344
}
9445

9546
template <class _ExecutionPolicy,
@@ -100,33 +51,9 @@ template <class _ExecutionPolicy,
10051
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
10152
all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
10253
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
103-
auto __res = std::__all_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
104-
if (!__res)
105-
std::__throw_bad_alloc();
106-
return *std::move(__res);
107-
}
108-
109-
template <class>
110-
void __pstl_none_of(); // declaration needed for the frontend dispatch below
111-
112-
template <class _ExecutionPolicy,
113-
class _ForwardIterator,
114-
class _Pred,
115-
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
116-
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
117-
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
118-
__none_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
119-
return std::__pstl_frontend_dispatch(
120-
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of, _RawPolicy),
121-
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional<bool> {
122-
auto __res = std::__any_of(__policy, __g_first, __g_last, __g_pred);
123-
if (!__res)
124-
return nullopt;
125-
return !*__res;
126-
},
127-
std::move(__first),
128-
std::move(__last),
129-
std::move(__pred));
54+
using _Implementation = __pstl::__all_of<__pstl::__configured_backend, _RawPolicy>;
55+
return __pstl::__run_backend<_Implementation>(
56+
std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred));
13057
}
13158

13259
template <class _ExecutionPolicy,
@@ -137,10 +64,9 @@ template <class _ExecutionPolicy,
13764
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
13865
none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
13966
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
140-
auto __res = std::__none_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
141-
if (!__res)
142-
std::__throw_bad_alloc();
143-
return *std::move(__res);
67+
using _Implementation = __pstl::__none_of<__pstl::__configured_backend, _RawPolicy>;
68+
return __pstl::__run_backend<_Implementation>(
69+
std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred));
14470
}
14571

14672
_LIBCPP_END_NAMESPACE_STD

0 commit comments

Comments
 (0)