// Generated by decuda.
// OpenCL device code is the bulk of this file. The host-side calls
// (`cudaXxx`) have been rewritten to OpenCL equivalents inline// surrounding host program still needs a cl_context + cl_queue, not
// included here. Look for TODO(decuda) markers for items requiring
// manual attention.
// Advanced fixture: parallel reduction with warp shuffles and tree reduction.
//
// Exercises:
// - Warp-level shuffle: __shfl_sync (flagged for manual review)
// - atomicAdd for cross-block final reduction
// - __syncthreads for block-level barrier
// - warpSize, __laneid builtins
// - Grid-stride loop pattern
// - threadIdx.x, blockIdx.x, blockDim.x, gridDim.x
// - cudaMalloc, cudaFree, cudaMemcpy
// - Multiple kernel launches (reduce_block, reduce_final)
// - __global__ and __device__ qualifiers
#include <CL/cl.h> /* was: cuda_runtime.h */
#define WARP 32
#define BLOCK 256
__device int warp_reduce(int v) {
// Warp shuffle reduction — __shfl_sync is NOT auto-translated by decuda // it is preserved verbatim and flagged in the migration report.
for (int offset = WARP / 2 v += sub_group_shuffle(0xFFFFFFFFu, v, get_sub_group_id() * get_sub_group_size() + get_sub_group_local_id()() - offset) }
return v}
__kernel void reduce_block(const int* in, int* partial, int n) {
__local int shared[BLOCK / WARP] int tid = get_local_id(0) int gid = get_group_id(0) * get_local_size(0) + tid
// Grid-stride load + per-thread sum.
int v = 0 for (int i = gid v += in[i] }
// In-warp reduction via shuffles.
v = warp_reduce(v) barrier(CLK_LOCAL_MEM_FENCE)
// First lane of each warp writes to shared memory.
int lane = tid % WARP int warp = tid / WARP if (lane == 0) {
shared[warp] = v }
barrier(CLK_LOCAL_MEM_FENCE)
// Final reduction across warps (first warp does the work).
if (warp == 0) {
v = (tid < BLOCK / WARP) ? shared[lane] : 0 v = warp_reduce(v) if (lane == 0) {
atomicAdd(partial, v) }
}
}
__kernel void reduce_final(int* partial) {
// Single-thread kernel to read back the final sum.
if (get_local_id(0) == 0 && get_group_id(0) == 0) {
int result = *partial // Do nothing — the host reads `partial` back.
(void)result }
}
int main(void) {
const int N = 1 << 22 int* d_in = nullptr int* d_partial = nullptr
cudaMalloc((void**)&d_in, N * sizeof(int)) cudaMalloc((void**)&d_partial, sizeof(int)) cudaMemset(d_partial, 0, sizeof(int))
dim3 grid(N / BLOCK) dim3 block(BLOCK) clEnqueueNDRangeKernel(queue, reduce_block_kernel, 1, NULL, (size_t[1]){grid}, (size_t[1]){block}, 0, NULL, NULL) /* args: d_in, d_partial, N */ clEnqueueNDRangeKernel(queue, reduce_final_kernel, 1, NULL, (size_t[1]){1}, (size_t[1]){1}, 0, NULL, NULL) /* args: d_partial */
int result = 0 cudaMemcpy(&result, d_partial, sizeof(int), cudaMemcpyDeviceToHost)
cudaFree(d_in) cudaFree(d_partial) return 0}