diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -287,6 +287,12 @@ "Build libc++ with an externalized threading library. This option may only be set to ON when LIBCXX_ENABLE_THREADS=ON" OFF) +if (LIBCXX_ENABLE_THREADS) + set(LIBCXX_PSTL_CPU_BACKEND "std_thread" CACHE STRING "Which PSTL CPU backend to use") +else() + set(LIBCXX_PSTL_CPU_BACKEND "serial" CACHE STRING "Which PSTL CPU backend to use") +endif() + # Misc options ---------------------------------------------------------------- # FIXME: Turn -pedantic back ON. It is currently off because it warns # about #include_next which is used everywhere. @@ -804,6 +810,15 @@ config_define(0 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT) endif() +if (LIBCXX_PSTL_CPU_BACKEND STREQUAL "serial") + config_define(1 _LIBCPP_PSTL_CPU_BACKEND_SERIAL) +elseif(LIBCXX_PSTL_CPU_BACKEND STREQUAL "std_thread") + config_define(1 _LIBCPP_PSTL_CPU_BACKEND_THREAD) +else() + message(FATAL_ERROR "LIBCXX_PSTL_CPU_BACKEND is set to ${LIBCXX_PSTL_CPU_BACKEND}, which is not a valid backend. + Valid backends are: serial, std_thread") +endif() + if (LIBCXX_ABI_DEFINES) set(abi_defines) foreach (abi_define ${LIBCXX_ABI_DEFINES}) diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -78,6 +78,7 @@ __algorithm/pstl_backends/cpu_backends/find_if.h __algorithm/pstl_backends/cpu_backends/for_each.h __algorithm/pstl_backends/cpu_backends/serial.h + __algorithm/pstl_backends/cpu_backends/thread.h __algorithm/pstl_fill.h __algorithm/pstl_find.h __algorithm/pstl_for_each.h diff --git a/libcxx/include/__algorithm/pstl_backend.h b/libcxx/include/__algorithm/pstl_backend.h --- a/libcxx/include/__algorithm/pstl_backend.h +++ b/libcxx/include/__algorithm/pstl_backend.h @@ -75,7 +75,8 @@ }; # endif -# if defined(_PSTL_CPU_BACKEND_SERIAL) +# if defined(_LIBCPP_PSTL_CPU_BACKEND_SERIAL) || defined(_LIBCPP_PSTL_CPU_BACKEND_THREAD) +# include <__algorithm/pstl_backends/cpu_backend.h> template <> struct __select_backend { using type = __cpu_backend_tag; diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h @@ -11,8 +11,10 @@ #include <__config> -#if defined(_LIBCPP_HAS_NO_THREADS) || defined(_PSTL_CPU_BACKEND_SERIAL) +#if defined(_LIBCPP_PSTL_CPU_BACKEND_SERIAL) # include <__algorithm/pstl_backends/cpu_backends/serial.h> +#elif defined(_LIBCPP_PSTL_CPU_BACKEND_THREAD) +# include <__algorithm/pstl_backends/cpu_backends/thread.h> #else # error "Invalid CPU backend choice" #endif diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_THREAD_H +#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_THREAD_H + +#include <__assert> +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __par_backend::inline __thread_cpu_backend { + +template +_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { + vector __threads; + __threads.reserve([&]() { + auto __max_thread_count = thread::hardware_concurrency(); + return __max_thread_count == 0 ? 1 : __max_thread_count; + }()); + + const auto __brick_size = ((__last - __first) / __threads.capacity()) + 1; + + for (size_t __i = 0; __i != __threads.capacity(); ++__i) { + if (__last - __first >= __brick_size) { + __threads.emplace_back([&__f, __brick_first = __first, __brick_last = __first + __brick_size]() { + __f(__brick_first, __brick_last); + }); + __first += __brick_size; + } else { + __threads.emplace_back([&__f, __brick_first = __first, __brick_last = __last]() { + __f(__brick_first, __brick_last); + }); + __first = __last; + } + } + _LIBCPP_ASSERT(__first == __last, "__parallel_for didn't iterator over all elements!"); + + for (auto& __el : __threads) { + __el.join(); + } +} + +_LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} + +} // namespace __par_backend::inline __thread_cpu_backend + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_THREAD_H diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1273,7 +1273,6 @@ // TODO: Make this a proper configuration option #define _PSTL_PAR_BACKEND_SERIAL -#define _PSTL_CPU_BACKEND_SERIAL #define _PSTL_PRAGMA(x) _Pragma(# x) diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in --- a/libcxx/include/__config_site.in +++ b/libcxx/include/__config_site.in @@ -32,6 +32,10 @@ #cmakedefine01 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT #cmakedefine _LIBCPP_ENABLE_DEBUG_MODE +// PSTL backends +#cmakedefine _LIBCPP_PSTL_CPU_BACKEND_SERIAL +#cmakedefine _LIBCPP_PSTL_CPU_BACKEND_THREAD + // __USE_MINGW_ANSI_STDIO gets redefined on MinGW #ifdef __clang__ # pragma clang diagnostic push diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -121,6 +121,7 @@ #include <__algorithm/pstl_backends/cpu_backends/find_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/find_if.h'}} #include <__algorithm/pstl_backends/cpu_backends/for_each.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/for_each.h'}} #include <__algorithm/pstl_backends/cpu_backends/serial.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/serial.h'}} +#include <__algorithm/pstl_backends/cpu_backends/thread.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/thread.h'}} #include <__algorithm/push_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/push_heap.h'}} #include <__algorithm/ranges_adjacent_find.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_adjacent_find.h'}} #include <__algorithm/ranges_all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_all_of.h'}}