// 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.
// Complex fixture: shared-memory histogram with atomic updates, grid-stride
// loops, warp-level reduction, and constant-memory lookup table.
//
// Exercises:
// - __global__ / __device__ / __shared__ / __constant__ qualifiers
// - atomicAdd, atomicMin, atomicMax
// - __syncthreads, __syncwarp
// - threadIdx/blockIdx/blockDim/gridDim with .x field access
// - warpSize, __laneid
// - cudaMalloc / cudaFree / cudaMemcpy / cudaMemset
// - cuda_runtime.h header
#include <CL/cl.h> /* was: cuda_runtime.h */
#define NBINS 256
__constant int c_binMax[1]
__device int clamp_bin(int v) {
if (v < 0) return 0 if (v > c_binMax[0]) return c_binMax[0] return v}
__kernel void histogram(const int* data, int n, int* bins) {
__local int local_bins[NBINS] int tid = get_local_id(0) int bid = get_group_id(0) * get_local_size(0) + tid
// Initialize shared bins.
for (int i = tid local_bins[i] = 0 }
barrier(CLK_LOCAL_MEM_FENCE)
// Grid-stride loop: each thread atomically updates its local bin.
for (int i = bid int b = clamp_bin(data[i]) atomicAdd(&local_bins[b], 1) }
barrier(CLK_LOCAL_MEM_FENCE)
// Reduce shared bins into global bins with atomic ops.
for (int i = tid if (local_bins[i] > 0) {
atomicAdd(&bins[i], local_bins[i]) atomicMin(&bins[i], c_binMax[0]) atomicMax(&bins[i], 0) }
}
}
__kernel void warp_reduce(const int* in, int* out) {
int lane = get_sub_group_id() * get_sub_group_size() + get_sub_group_local_id()() int v = in[get_local_id(0)] // Naive warp shuffle reduction (preserved verbatim by decuda).
for (int offset = warpSize /* CL_DEVICE_WARP_SIZE_NV */ / 2 int t = sub_group_shuffle(0xFFFFFFFFu, v, lane - offset) v += t }
barrier(CLK_LOCAL_MEM_FENCE) /* approx */ if (lane == 0) {
out[get_group_id(0)] = v }
}
int main(void) {
const int N = 1 << 20 int* d_data = nullptr int* d_bins = nullptr int* d_out = nullptr
cudaMalloc((void**)&d_data, N * sizeof(int)) cudaMalloc((void**)&d_bins, NBINS * sizeof(int)) cudaMalloc((void**)&d_out, 1024 * sizeof(int))
cudaMemset(d_bins, 0, NBINS * sizeof(int)) cudaMemcpy(d_data, d_data, N * sizeof(int), cudaMemcpyDeviceToDevice)
int maxbin = NBINS - 1 cudaMemcpyToSymbol(c_binMax, &maxbin, sizeof(int))
dim3 grid(N / 256) dim3 block(256) clEnqueueNDRangeKernel(queue, histogram_kernel, 1, NULL, (size_t[1]){grid}, (size_t[1]){block}, 0, NULL, NULL) /* args: d_data, N, d_bins */ clEnqueueNDRangeKernel(queue, warp_reduce_kernel, 1, NULL, (size_t[1]){N / 32}, (size_t[1]){32}, 0, NULL, NULL) /* args: d_data, d_out */
cudaDeviceSynchronize() cudaFree(d_data) cudaFree(d_bins) cudaFree(d_out) return 0}