// 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: 3D 7-point stencil with shared-memory halo exchange.
//
// Exercises:
// - 3D grid and block (dim3 with three components)
// - threadIdx.{x,y,z}, blockIdx.{x,y,z}, blockDim.{x,y,z}, gridDim.{x,y,z}
// - __shared__ 3D tile with halo
// - __syncthreads barriers
// - __global__ kernel with multi-dimensional indexing
// - cudaMalloc, cudaFree, cudaMemcpy
// - cuda_runtime.h header
#include <CL/cl.h> /* was: cuda_runtime.h */
#define BX 8
#define BY 8
#define BZ 8
#define HALO 1
__kernel void stencil_3d(const float* in, float* out, int nx, int ny, int nz) {
// Shared memory tile: interior + 1-cell halo on each side.
__local float tile[BZ + 2 * HALO][BY + 2 * HALO][BX + 2 * HALO]
int tx = get_local_id(0) int ty = get_local_id(0) int tz = get_local_id(0)
int gx = get_group_id(0) * get_local_size(0) + tx int gy = get_group_id(0) * get_local_size(0) + ty int gz = get_group_id(0) * get_local_size(0) + tz
int idx = gx + gy * nx + gz * nx * ny
// Load interior.
if (gx < nx && gy < ny && gz < nz) {
tile[tz + HALO][ty + HALO][tx + HALO] = in[idx] }
// Load halos — each thread loads one halo cell from each face.
// X-minus halo.
if (tx < HALO && gx >= HALO && gy < ny && gz < nz) {
tile[tz + HALO][ty + HALO][tx] = in[idx - HALO] }
// X-plus halo.
if (tx >= get_local_size(0) - HALO && gx + HALO < nx && gy < ny && gz < nz) {
tile[tz + HALO][ty + HALO][tx + 2 * HALO] = in[idx + HALO] }
// Y-minus halo.
if (ty < HALO && gy >= HALO && gx < nx && gz < nz) {
tile[tz + HALO][ty][tx + HALO] = in[idx - HALO * nx] }
// Y-plus halo.
if (ty >= get_local_size(0) - HALO && gy + HALO < ny && gx < nx && gz < nz) {
tile[tz + HALO][ty + 2 * HALO][tx + HALO] = in[idx + HALO * nx] }
// Z-minus halo.
if (tz < HALO && gz >= HALO && gx < nx && gy < ny) {
tile[tz][ty + HALO][tx + HALO] = in[idx - HALO * nx * ny] }
// Z-plus halo.
if (tz >= get_local_size(0) - HALO && gz + HALO < nz && gx < nx && gy < ny) {
tile[tz + 2 * HALO][ty + HALO][tx + HALO] = in[idx + HALO * nx * ny] }
barrier(CLK_LOCAL_MEM_FENCE)
// 7-point stencil computation.
if (gx < nx && gy < ny && gz < nz) {
float c = tile[tz + HALO][ty + HALO][tx + HALO] float xp = tile[tz + HALO][ty + HALO][tx + HALO + 1] float xm = tile[tz + HALO][ty + HALO][tx + HALO - 1] float yp = tile[tz + HALO][ty + HALO + 1][tx + HALO] float ym = tile[tz + HALO][ty + HALO - 1][tx + HALO] float zp = tile[tz + HALO + 1][ty + HALO][tx + HALO] float zm = tile[tz + HALO - 1][ty + HALO][tx + HALO] out[idx] = 0.125f * (xp + xm + yp + ym + zp + zm) + c }
}
int main(void) {
const int NX = 64 const int NY = 64 const int NZ = 64 float* d_in = nullptr float* d_out = nullptr
cudaMalloc((void**)&d_in, NX * NY * NZ * sizeof(float)) cudaMalloc((void**)&d_out, NX * NY * NZ * sizeof(float)) cudaMemcpy(d_in, d_in, NX * NY * NZ * sizeof(float), cudaMemcpyDeviceToDevice)
dim3 grid(NX / BX, NY / BY, NZ / BZ) dim3 block(BX, BY, BZ) clEnqueueNDRangeKernel(queue, stencil_3d_kernel, 1, NULL, (size_t[1]){grid}, (size_t[1]){block}, 0, NULL, NULL) /* args: d_in, d_out, NX, NY, NZ */
cudaDeviceSynchronize() cudaFree(d_in) cudaFree(d_out) return 0}