| 132 | template <int BlockSize, int NumPerThread, typename Self, |
| 133 | typename Reducer, typename Index> |
| 134 | __global__ void FullReductionKernel(Reducer reducer, const Self input, Index num_coeffs, |
| 135 | typename Self::CoeffReturnType* output, unsigned int* semaphore) { |
| 136 | #if (defined(EIGEN_HIP_DEVICE_COMPILE) && defined(__HIP_ARCH_HAS_WARP_SHUFFLE__)) || (EIGEN_CUDA_ARCH >= 300) |
| 137 | // Initialize the output value |
| 138 | const Index first_index = blockIdx.x * BlockSize * NumPerThread + threadIdx.x; |
| 139 | if (gridDim.x == 1) { |
| 140 | if (first_index == 0) { |
| 141 | *output = reducer.initialize(); |
| 142 | } |
| 143 | } |
| 144 | else { |
| 145 | if (threadIdx.x == 0) { |
| 146 | unsigned int block = atomicCAS(semaphore, 0u, 1u); |
| 147 | if (block == 0) { |
| 148 | // We're the first block to run, initialize the output value |
| 149 | atomicExchCustom(output, reducer.initialize()); |
| 150 | __threadfence(); |
| 151 | atomicExch(semaphore, 2u); |
| 152 | } |
| 153 | else { |
| 154 | // Wait for the first block to initialize the output value. |
| 155 | // Use atomicCAS here to ensure that the reads aren't cached |
| 156 | unsigned int val; |
| 157 | do { |
| 158 | val = atomicCAS(semaphore, 2u, 2u); |
| 159 | } |
| 160 | while (val < 2u); |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | __syncthreads(); |
| 166 | |
| 167 | eigen_assert(gridDim.x == 1 || *semaphore >= 2u); |
| 168 | |
| 169 | typename Self::CoeffReturnType accum = reducer.initialize(); |
| 170 | Index max_iter = numext::mini<Index>(num_coeffs - first_index, NumPerThread*BlockSize); |
| 171 | for (Index i = 0; i < max_iter; i+=BlockSize) { |
| 172 | const Index index = first_index + i; |
| 173 | eigen_assert(index < num_coeffs); |
| 174 | typename Self::CoeffReturnType val = input.m_impl.coeff(index); |
| 175 | reducer.reduce(val, &accum); |
| 176 | } |
| 177 | |
| 178 | #pragma unroll |
| 179 | for (int offset = warpSize/2; offset > 0; offset /= 2) { |
| 180 | #if defined(EIGEN_HIPCC) |
| 181 | // use std::is_floating_point to determine the type of reduced_val |
| 182 | // This is needed because when Type == double, hipcc will give a "call to __shfl_down is ambguous" error |
| 183 | // and list the float and int versions of __shfl_down as the candidate functions. |
| 184 | if (std::is_floating_point<typename Self::CoeffReturnType>::value) { |
| 185 | reducer.reduce(__shfl_down(static_cast<float>(accum), offset, warpSize), &accum); |
| 186 | } else { |
| 187 | reducer.reduce(__shfl_down(static_cast<int>(accum), offset, warpSize), &accum); |
| 188 | } |
| 189 | #elif defined(EIGEN_CUDA_SDK_VER) && EIGEN_CUDA_SDK_VER < 90000 |
| 190 | reducer.reduce(__shfl_down(accum, offset, warpSize), &accum); |
| 191 | #else |
nothing calls this directly
no test coverage detected