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>

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

#define WARP 32
#define BLOCK 256

// SYCL device function [[clang::always_inline]] 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; offset > 0; offset /= 2) {
        v += sycl::sub_group::shuffle(0xFFFFFFFFu, v, item.get_sub_group().get_local_id()() - offset);
    }
    return v;
}

// TODO(decuda): rewrite as SYCL kernel lambda
 void reduce_block(const int* in, int* partial, int n) {
    __shared__ int shared[BLOCK / WARP];
    int tid = item.get_local_id();
    int gid = item.get_group(0) * item.get_local_range() + tid;

    // Grid-stride load + per-thread sum.
    int v = 0;
    for (int i = gid; i < n; i += item.get_global_range() / item.get_local_range() * item.get_local_range()) {
        v += in[i];
    }

    // In-warp reduction via shuffles.
    v = warp_reduce(v);
    item.barrier(sycl::access::fence_space::global_space);

    // First lane of each warp writes to shared memory.
    int lane = tid % WARP;
    int warp = tid / WARP;
    if (lane == 0) {
        shared[warp] = v;
    }
    item.barrier(sycl::access::fence_space::global_space);

    // 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);
        }
    }
}

// TODO(decuda): rewrite as SYCL kernel lambda
 void reduce_final(int* partial) {
    // Single-thread kernel to read back the final sum.
    if (item.get_local_id() == 0 && item.get_group(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);
    { /* decuda SYCL launch: queue.submit([&](sycl::handler& h) { h.parallel_for(sycl::range<3>{grid}, [=](sycl::item<3> it) { /* kernel `reduce_block` body with thread indices from it.get_*() */ }); }); smem=none stream=default args=d_in, d_partial, N */ };
    { /* decuda SYCL launch: queue.submit([&](sycl::handler& h) { h.parallel_for(sycl::range<3>{1}, [=](sycl::item<3> it) { /* kernel `reduce_final` body with thread indices from it.get_*() */ }); }); smem=none stream=default args=d_partial */ };

    int result = 0;
    cudaMemcpy(&result, d_partial, sizeof(int), cudaMemcpyDeviceToHost);

    cudaFree(d_in);
    cudaFree(d_partial);
    return 0;
}