15#ifndef GPUCOMMONALGORITHM_H
16#define GPUCOMMONALGORITHM_H
20#if !defined(GPUCA_GPUCODE) || defined(__CPUDEVICE__)
21#ifndef GPUCA_GPUCODE_DEVICE
24#define GPUCA_ALGORITHM_STD
35 GPUd() static
void sort(T* begin, T*
end);
39 GPUd() static
void sortDeviceDynamic(T* begin, T*
end);
40 template <class T, class
S>
42 template <class T, class
S>
44 template <class T, class
S>
45 GPUd() static
void sortDeviceDynamic(T* begin, T*
end, const
S&
comp);
46#if __cplusplus >= 202002L
47 template <
class T,
class S>
48 GPUh() static
void sortOnDevice(auto*
rec, int32_t
stream, T* begin,
size_t N, const
S&
comp);
52 template <class I, class
P>
57 GPUd() static
void QuickSort(I
f, I l) GPUnoexcept();
59 template <typename I, typename Cmp>
60 GPUd() static
void QuickSort(I
f, I l, Cmp
cmp) GPUnoexcept();
62 template <typename IndexType, typename I, typename Cmp>
63 GPUd() static
void QuickSortImpl(I
f, I l, Cmp
cmp) GPUnoexcept();
65 template <typename I, typename Cmp>
66 GPUd() static
void InsertionSort(I
f, I l, Cmp
cmp) GPUnoexcept();
68 template <typename I, typename Cmp>
69 GPUd() static I MedianOf3Select(I
f, I l, Cmp
cmp) GPUnoexcept();
71 template <typename I, typename T, typename Cmp>
72 GPUd() static I UnguardedPartition(I
f, I l, T piv, Cmp
cmp) GPUnoexcept();
75 GPUd() static
void IterSwap(I
a, I
b) GPUnoexcept();
78#ifndef GPUCA_ALGORITHM_STD
87template <
typename I,
typename Cmp>
95 while (it1 !=
f &&
cmp(tmp, it1[-1])) {
105template <
typename I,
typename Cmp>
106GPUdi() I GPUCommonAlgorithm::MedianOf3Select(I
f, I l, Cmp
cmp) GPUnoexcept()
108 auto m =
f + (l -
f) / 2;
115 }
else if (
cmp(*
f, *l)) {
120 }
else if (
cmp(*
f, *l)) {
122 }
else if (
cmp(*
m, *l)) {
129template <
typename I,
typename T,
typename Cmp>
130GPUdi() I GPUCommonAlgorithm::UnguardedPartition(I
f, I l, T piv, Cmp
cmp) GPUnoexcept()
133 while (
cmp(*
f, piv)) {
137 while (
cmp(piv, *l)) {
149template <
typename I,
typename Cmp>
150GPUdi()
void GPUCommonAlgorithm::QuickSort(I
f, I l, Cmp
cmp) GPUnoexcept()
152 if (l -
f <= 0xFFFF) {
153 QuickSortImpl<uint16_t>(
f, l,
cmp);
155 QuickSortImpl<uint32_t>(
f, l,
cmp);
159template <
typename IndexType,
typename I,
typename Cmp>
160GPUdi()
void GPUCommonAlgorithm::QuickSortImpl(I
f, I l, Cmp
cmp) GPUnoexcept()
172 pair
data[
sizeof(IndexType) * 8 - 4];
187 const auto it0 =
f +
s.top().first;
188 const auto it1 =
f +
s.top().second;
191 const auto piv = *MedianOf3Select(it0, it1,
cmp);
192 const auto pp = UnguardedPartition(it0, it1, piv,
cmp);
194 constexpr auto cutoff = 50u;
195 const auto lsz = pp - it0;
196 const auto rsz = it1 - pp;
199 s.emplace(pp -
f, it1 -
f);
202 s.emplace(it0 -
f, pp -
f);
206 s.emplace(it0 -
f, pp -
f);
209 s.emplace(pp -
f, it1 -
f);
213 InsertionSort(
f, l,
cmp);
217GPUdi()
void GPUCommonAlgorithm::QuickSort(I
f, I l) GPUnoexcept()
219 QuickSort(
f, l, [](
auto&&
x,
auto&&
y) {
return x <
y; });
227#if (((defined(__CUDACC__) && !defined(__clang__)) || defined(__HIPCC__))) && !defined(GPUCA_GPUCODE_HOSTONLY)
237GPUdi()
void GPUCommonAlgorithm::sortDeviceDynamic(T* begin, T*
end)
240 GPUCommonAlgorithm::sort(begin,
end);
242 GPUCommonAlgorithm::sortDeviceDynamic(begin,
end, [](
auto&&
x,
auto&&
y) {
return x <
y; });
246template <
class T,
class S>
247GPUdi()
void GPUCommonAlgorithm::sortDeviceDynamic(T* begin, T*
end, const
S& comp)
249 GPUCommonAlgorithm::sort(begin,
end, comp);
263#ifdef GPUCA_ALGORITHM_STD
264 std::sort(begin,
end);
266 QuickSort(begin,
end, [](
auto&&
x,
auto&&
y) {
return x <
y; });
270template <
class T,
class S>
271GPUdi()
void GPUCommonAlgorithm::sort(T* begin, T*
end, const
S& comp)
273#ifdef GPUCA_ALGORITHM_STD
274 std::sort(begin,
end, comp);
276 QuickSort(begin,
end, comp);
284 GPUCommonAlgorithm::sort(begin,
end);
290template <
class T,
class S>
293#if !defined(GPUCA_GPUCODE) || defined(GPUCA_DEVICE_SINGLE_THREAD)
294 GPUCommonAlgorithm::sort(begin,
end, comp);
295#elif defined(GPUCA_DETERMINISTIC_MODE)
297 GPUCommonAlgorithm::sort(begin,
end, comp);
302 for (int32_t
i = 0;
i <
n;
i++) {
305 int32_t curPos = 2 * tIdx +
offset;
306 int32_t nextPos = curPos + 1;
309 if (!comp(begin[curPos], begin[nextPos])) {
310 IterSwap(&begin[curPos], &begin[nextPos]);
337template <
class I,
class P>
359#pragma OPENCL EXTENSION cl_khr_subgroups : enable
362GPUdi() T warp_scan_inclusive_add_FUNC(T
v)
364 return sub_group_scan_inclusive_add(
v);
367GPUdi() uint8_t warp_scan_inclusive_add_FUNC<uint8_t>(uint8_t
v)
369 return sub_group_scan_inclusive_add((uint32_t)
v);
372GPUdi() T warp_broadcast_FUNC(T
v, int32_t
i)
374 return sub_group_broadcast(
v,
i);
377GPUdi() uint8_t warp_broadcast_FUNC<uint8_t>(uint8_t
v, int32_t
i)
379 return sub_group_broadcast((uint32_t)
v,
i);
382#define warp_scan_inclusive_add(v) warp_scan_inclusive_add_FUNC(v)
383#define warp_broadcast(v, i) warp_broadcast_FUNC(v, i)
385[[nodiscard]]
GPUdi() int32_t work_group_count(
bool pred)
387 return work_group_reduce_add((int32_t)pred);
390#elif (defined(__CUDACC__) || defined(__HIPCC__))
393#if !defined(GPUCA_GPUCODE_COMPILEKERNELS) && !defined(GPUCA_GPUCODE_HOSTONLY)
394#if defined(__CUDACC__)
395#include <cub/cub.cuh>
396#elif defined(__HIPCC__)
397#include <hipcub/hipcub.hpp>
401#define work_group_scan_inclusive_add(v) work_group_scan_inclusive_add_FUNC(v, smem)
402template <
class T,
class S>
403GPUdi() T work_group_scan_inclusive_add_FUNC(T
v,
S& smem)
405 typename S::BlockScan(smem.cubTmpMem).InclusiveSum(
v,
v);
410#define work_group_broadcast(v, i) work_group_broadcast_FUNC(v, i, smem)
411template <
class T,
class S>
412GPUdi() T work_group_broadcast_FUNC(T
v, int32_t
i,
S& smem)
414 if ((int32_t)threadIdx.x ==
i) {
415 smem.tmpBroadcast =
v;
423#define work_group_reduce_add(v) work_group_reduce_add_FUNC(v, smem)
424template <
class T,
class S>
425GPUdi() T work_group_reduce_add_FUNC(T
v,
S& smem)
427 v =
typename S::BlockReduce(smem.cubReduceTmpMem).Sum(
v);
429 v = work_group_broadcast(
v, 0);
433#define warp_scan_inclusive_add(v) warp_scan_inclusive_add_FUNC(v, smem)
434template <
class T,
class S>
435GPUdi() T warp_scan_inclusive_add_FUNC(T
v,
S& smem)
437 typename S::WarpScan(smem.cubWarpTmpMem).InclusiveSum(
v,
v);
441#define warp_broadcast(v, i) warp_broadcast_FUNC(v, i)
443GPUdi() T warp_broadcast_FUNC(T
v, int32_t
i)
446 return __shfl_sync(0xFFFFFFFF,
v,
i);
453GPUdi() T warp_shuffle_xor(T
v, int32_t laneMask)
456 return __shfl_xor_sync(0xFFFFFFFF,
v, laneMask);
458 return __shfl_xor(
v, laneMask);
464template <
int32_t W
idth,
class T>
465GPUdi() T warp_reduce_add(T
v)
467 for (int32_t
m = Width / 2;
m > 0;
m >>= 1) {
468 v += warp_shuffle_xor(
v,
m);
473template <
int32_t W
idth,
class T>
474GPUdi() T warp_reduce_min(T
v)
476 for (int32_t
m = Width / 2;
m > 0;
m >>= 1) {
477 const T o = warp_shuffle_xor(
v,
m);
483template <
int32_t W
idth,
class T>
484GPUdi() T warp_reduce_max(T
v)
486 for (int32_t
m = Width / 2;
m > 0;
m >>= 1) {
487 const T o = warp_shuffle_xor(
v,
m);
493[[nodiscard]]
GPUdi() bool work_group_any(
bool pred)
495 return __syncthreads_or(pred);
498[[nodiscard]]
GPUdi() uint32_t work_group_count(
bool pred)
500 return __syncthreads_count(pred);
507GPUdi() T work_group_scan_inclusive_add(T
v)
513GPUdi() T work_group_reduce_add(T
v)
525GPUdi() T warp_scan_inclusive_add(T
v)
531GPUdi() T warp_broadcast(T
v, int32_t
i)
536template <
int32_t W
idth,
class T>
542template <
int32_t W
idth,
class T>
543GPUdi() T warp_reduce_min(T
v)
548template <
int32_t W
idth,
class T>
549GPUdi() T warp_reduce_max(T
v)
554[[nodiscard]]
GPUdi() bool work_group_any(
bool pred)
559[[nodiscard]]
GPUdi() uint32_t work_group_count(
bool pred)
566#ifdef GPUCA_ALGORITHM_STD
567#undef GPUCA_ALGORITHM_STD
#define get_local_size(dim)
#define get_local_id(dim)
#define GPUCA_THREAD_INFO_PROVIDE
#define GPUCA_THREAD_INFO_DECL
T *end GPUCA_THREAD_INFO_DECL
GPUd() static void sort(T *begin
GPUhd() static I partitionPoint(I first
GLdouble GLdouble GLdouble GLdouble top
GLboolean GLboolean GLboolean b
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean GLboolean GLboolean a
uint8_t itsSharedClusterMap uint8_t
GPUCommonAlgorithm CAAlgo
Enum< T >::Iterator begin(Enum< T >)
char const *restrict const cmp