1*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric 9*0fca6ea1SDimitry Andric #ifndef _LIBCPP___PSTL_CPU_ALGOS_ANY_OF_H 10*0fca6ea1SDimitry Andric #define _LIBCPP___PSTL_CPU_ALGOS_ANY_OF_H 11*0fca6ea1SDimitry Andric 12*0fca6ea1SDimitry Andric #include <__algorithm/any_of.h> 13*0fca6ea1SDimitry Andric #include <__assert> 14*0fca6ea1SDimitry Andric #include <__atomic/atomic.h> 15*0fca6ea1SDimitry Andric #include <__atomic/memory_order.h> 16*0fca6ea1SDimitry Andric #include <__config> 17*0fca6ea1SDimitry Andric #include <__iterator/concepts.h> 18*0fca6ea1SDimitry Andric #include <__pstl/backend_fwd.h> 19*0fca6ea1SDimitry Andric #include <__pstl/cpu_algos/cpu_traits.h> 20*0fca6ea1SDimitry Andric #include <__type_traits/is_execution_policy.h> 21*0fca6ea1SDimitry Andric #include <__utility/move.h> 22*0fca6ea1SDimitry Andric #include <__utility/pair.h> 23*0fca6ea1SDimitry Andric #include <cstdint> 24*0fca6ea1SDimitry Andric #include <optional> 25*0fca6ea1SDimitry Andric 26*0fca6ea1SDimitry Andric _LIBCPP_PUSH_MACROS 27*0fca6ea1SDimitry Andric #include <__undef_macros> 28*0fca6ea1SDimitry Andric 29*0fca6ea1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 30*0fca6ea1SDimitry Andric namespace __pstl { 31*0fca6ea1SDimitry Andric 32*0fca6ea1SDimitry Andric template <class _Backend, class _Index, class _Brick> 33*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI optional<bool> __parallel_or(_Index __first, _Index __last, _Brick __f) { 34*0fca6ea1SDimitry Andric std::atomic<bool> __found(false); 35*0fca6ea1SDimitry Andric auto __ret = __cpu_traits<_Backend>::__for_each(__first, __last, [__f, &__found](_Index __i, _Index __j) { 36*0fca6ea1SDimitry Andric if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) { 37*0fca6ea1SDimitry Andric __found.store(true, std::memory_order_relaxed); 38*0fca6ea1SDimitry Andric __cpu_traits<_Backend>::__cancel_execution(); 39*0fca6ea1SDimitry Andric } 40*0fca6ea1SDimitry Andric }); 41*0fca6ea1SDimitry Andric if (!__ret) 42*0fca6ea1SDimitry Andric return nullopt; 43*0fca6ea1SDimitry Andric return static_cast<bool>(__found); 44*0fca6ea1SDimitry Andric } 45*0fca6ea1SDimitry Andric 46*0fca6ea1SDimitry Andric // TODO: check whether __simd_first() can be used here 47*0fca6ea1SDimitry Andric template <class _Index, class _DifferenceType, class _Pred> 48*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool __simd_or(_Index __first, _DifferenceType __n, _Pred __pred) noexcept { 49*0fca6ea1SDimitry Andric _DifferenceType __block_size = 4 < __n ? 4 : __n; 50*0fca6ea1SDimitry Andric const _Index __last = __first + __n; 51*0fca6ea1SDimitry Andric while (__last != __first) { 52*0fca6ea1SDimitry Andric int32_t __flag = 1; 53*0fca6ea1SDimitry Andric _PSTL_PRAGMA_SIMD_REDUCTION(& : __flag) 54*0fca6ea1SDimitry Andric for (_DifferenceType __i = 0; __i < __block_size; ++__i) 55*0fca6ea1SDimitry Andric if (__pred(*(__first + __i))) 56*0fca6ea1SDimitry Andric __flag = 0; 57*0fca6ea1SDimitry Andric if (!__flag) 58*0fca6ea1SDimitry Andric return true; 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric __first += __block_size; 61*0fca6ea1SDimitry Andric if (__last - __first >= __block_size << 1) { 62*0fca6ea1SDimitry Andric // Double the block _Size. Any unnecessary iterations can be amortized against work done so far. 63*0fca6ea1SDimitry Andric __block_size <<= 1; 64*0fca6ea1SDimitry Andric } else { 65*0fca6ea1SDimitry Andric __block_size = __last - __first; 66*0fca6ea1SDimitry Andric } 67*0fca6ea1SDimitry Andric } 68*0fca6ea1SDimitry Andric return false; 69*0fca6ea1SDimitry Andric } 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric template <class _Backend, class _RawExecutionPolicy> 72*0fca6ea1SDimitry Andric struct __cpu_parallel_any_of { 73*0fca6ea1SDimitry Andric template <class _Policy, class _ForwardIterator, class _Predicate> 74*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI optional<bool> 75*0fca6ea1SDimitry Andric operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept { 76*0fca6ea1SDimitry Andric if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> && 77*0fca6ea1SDimitry Andric __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { 78*0fca6ea1SDimitry Andric return __pstl::__parallel_or<_Backend>( 79*0fca6ea1SDimitry Andric __first, __last, [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { 80*0fca6ea1SDimitry Andric using _AnyOfUnseq = __pstl::__any_of<_Backend, __remove_parallel_policy_t<_RawExecutionPolicy>>; 81*0fca6ea1SDimitry Andric auto __res = _AnyOfUnseq()(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred); 82*0fca6ea1SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); 83*0fca6ea1SDimitry Andric return *std::move(__res); 84*0fca6ea1SDimitry Andric }); 85*0fca6ea1SDimitry Andric } else if constexpr (__is_unsequenced_execution_policy_v<_RawExecutionPolicy> && 86*0fca6ea1SDimitry Andric __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { 87*0fca6ea1SDimitry Andric return __pstl::__simd_or(__first, __last - __first, __pred); 88*0fca6ea1SDimitry Andric } else { 89*0fca6ea1SDimitry Andric return std::any_of(__first, __last, __pred); 90*0fca6ea1SDimitry Andric } 91*0fca6ea1SDimitry Andric } 92*0fca6ea1SDimitry Andric }; 93*0fca6ea1SDimitry Andric 94*0fca6ea1SDimitry Andric } // namespace __pstl 95*0fca6ea1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 96*0fca6ea1SDimitry Andric 97*0fca6ea1SDimitry Andric _LIBCPP_POP_MACROS 98*0fca6ea1SDimitry Andric 99*0fca6ea1SDimitry Andric #endif // _LIBCPP___PSTL_CPU_ALGOS_ANY_OF_H 100