decuda 0.1.1

CUDA to HIP, SYCL, OpenCL, and Rust GPU migration tool — automatic source-code translator for porting CUDA C++ kernels to AMD ROCm HIP, Intel oneAPI SYCL, Khronos OpenCL, and Rust GPU (cust / rust-gpu)
Documentation
// Generated by decuda.
// SYCL kernels replace CUDA kernels with parallel_for lambdas; this
// output is a *starting point* and almost always requires manual
// follow-up. Look for the `TODO(decuda)` markers in this file.

#include <sycl/sycl.hpp>

// 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 <sycl/sycl.hpp> /* was: cuda_runtime.h */

#define NBINS 256

/* constant -> SYCL constant_accessor */ int c_binMax[1];

// SYCL device function [[clang::always_inline]] int clamp_bin(int v) {
    if (v < 0) return 0;
    if (v > c_binMax[0]) return c_binMax[0];
    return v;
}

// TODO(decuda): rewrite as SYCL kernel lambda
 void histogram(const int* data, int n, int* bins) {
    __shared__ int local_bins[NBINS];
    int tid = item.get_local_id();
    int bid = item.get_group(0) * item.get_local_range() + tid;

    // Initialize shared bins.
    for (int i = tid; i < NBINS; i += item.get_local_range()) {
        local_bins[i] = 0;
    }
    item.barrier(sycl::access::fence_space::global_space);

    // Grid-stride loop: each thread atomically updates its local bin.
    for (int i = bid; i < n; i += item.get_global_range() / item.get_local_range() * item.get_local_range()) {
        int b = clamp_bin(data[i]);
        atomicAdd(&local_bins[b], 1);
    }
    item.barrier(sycl::access::fence_space::global_space);

    // Reduce shared bins into global bins with atomic ops.
    for (int i = tid; i < NBINS; i += item.get_local_range()) {
        if (local_bins[i] > 0) {
            atomicAdd(&bins[i], local_bins[i]);
            atomicMin(&bins[i], c_binMax[0]);
            atomicMax(&bins[i], 0);
        }
    }
}

// TODO(decuda): rewrite as SYCL kernel lambda
 void warp_reduce(const int* in, int* out) {
    int lane = item.get_sub_group().get_local_id()();
    int v = in[item.get_local_id()];
    // Naive warp shuffle reduction (preserved verbatim by decuda).
    for (int offset = 32 /* warpSize */ / 2; offset > 0; offset /= 2) {
        int t = sycl::sub_group::shuffle(0xFFFFFFFFu, v, lane - offset);
        v += t;
    }
    /* no native syncwarp on SYCL */ item.barrier() /* fallback */;
    if (lane == 0) {
        out[item.get_group(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);
    { /* decuda SYCL launch: queue.submit([&](sycl::handler& h) { h.parallel_for(sycl::range<3>{grid}, [=](sycl::item<3> it) { /* kernel `histogram` body with thread indices from it.get_*() */ }); }); smem=none stream=default args=d_data, N, d_bins */ };
    { /* decuda SYCL launch: queue.submit([&](sycl::handler& h) { h.parallel_for(sycl::range<3>{N / 32}, [=](sycl::item<3> it) { /* kernel `warp_reduce` body with thread indices from it.get_*() */ }); }); smem=none stream=default args=d_data, d_out */ };

    cudaDeviceSynchronize();
    cudaFree(d_data);
    cudaFree(d_bins);
    cudaFree(d_out);
    return 0;
}