tenflowers-core 0.1.1

Core tensor operations and execution engine for TenfloweRS
Documentation
/*
 * reduction_kernels.hip
 * ROCm/HIP kernels for optimized reduction operations
 * Optimized for AMD wavefront execution and memory hierarchy
 */

#include <hip/hip_runtime.h>

// Hierarchical sum reduction using shared memory and wavefront intrinsics
__global__ void rocm_hierarchical_sum(float* input, float* output, int count) {
    __shared__ float shared_memory[256];
    
    int tid = threadIdx.x;
    int gid = blockIdx.x * blockDim.x + threadIdx.x;
    int wavefront_id = tid / 64;  // AMD wavefront size is 64
    int lane_id = tid % 64;
    
    // Load data into shared memory with coalesced access
    float local_sum = 0.0f;
    
    // Grid-stride loop for better memory utilization
    for (int i = gid; i < count; i += gridDim.x * blockDim.x) {
        local_sum += input[i];
    }
    
    shared_memory[tid] = local_sum;
    __syncthreads();
    
    // Wavefront-level reduction using shuffle operations
    // AMD GPUs have 64-thread wavefronts
    if (tid < 64) {
        float wavefront_sum = shared_memory[tid];
        
        // Use wave reduction primitives (simplified representation)
        for (int offset = 32; offset > 0; offset >>= 1) {
            wavefront_sum += shared_memory[tid + offset];
        }
        
        if (lane_id == 0) {
            shared_memory[wavefront_id] = wavefront_sum;
        }
    }
    
    __syncthreads();
    
    // Final reduction across wavefronts
    if (tid < 4) {  // Assuming max 4 wavefronts per block (256 threads / 64)
        float final_sum = (tid < (blockDim.x + 63) / 64) ? shared_memory[tid] : 0.0f;
        
        for (int offset = 2; offset > 0; offset >>= 1) {
            if (tid < offset) {
                final_sum += shared_memory[tid + offset];
            }
        }
        
        if (tid == 0) {
            atomicAdd(output, final_sum);
        }
    }
}

// Optimized mean calculation with single-pass algorithm
__global__ void rocm_optimized_mean(float* input, float* output, int count) {
    __shared__ float shared_sum[256];
    
    int tid = threadIdx.x;
    int gid = blockIdx.x * blockDim.x + threadIdx.x;
    
    // Calculate local sum
    float local_sum = 0.0f;
    int local_count = 0;
    
    for (int i = gid; i < count; i += gridDim.x * blockDim.x) {
        local_sum += input[i];
        local_count++;
    }
    
    shared_sum[tid] = local_sum;
    __syncthreads();
    
    // Tree reduction for sum
    for (int stride = blockDim.x / 2; stride > 0; stride >>= 1) {
        if (tid < stride) {
            shared_sum[tid] += shared_sum[tid + stride];
        }
        __syncthreads();
    }
    
    // Calculate final mean
    if (tid == 0) {
        float total_sum = shared_sum[0];
        atomicAdd(output, total_sum / count);
    }
}

// Optimized max reduction with early termination for RDNA/CDNA
__global__ void rocm_optimized_max(float* input, float* output, int count) {
    __shared__ float shared_max[256];
    
    int tid = threadIdx.x;
    int gid = blockIdx.x * blockDim.x + threadIdx.x;
    
    float local_max = -FLT_MAX;
    
    for (int i = gid; i < count; i += gridDim.x * blockDim.x) {
        local_max = fmaxf(local_max, input[i]);
    }
    
    shared_max[tid] = local_max;
    __syncthreads();
    
    // Tree reduction for max
    for (int stride = blockDim.x / 2; stride > 0; stride >>= 1) {
        if (tid < stride) {
            shared_max[tid] = fmaxf(shared_max[tid], shared_max[tid + stride]);
        }
        __syncthreads();
    }
    
    if (tid == 0) {
        // Use atomic max operation (simplified for this example)
        float current_max = *output;
        while (shared_max[0] > current_max) {
            float old_max = atomicCAS((int*)output, *(int*)&current_max, *(int*)&shared_max[0]);
            if (old_max == *(int*)&current_max) break;
            current_max = *(float*)&old_max;
        }
    }
}

// Optimized min reduction with early termination for RDNA/CDNA
__global__ void rocm_optimized_min(float* input, float* output, int count) {
    __shared__ float shared_min[256];
    
    int tid = threadIdx.x;
    int gid = blockIdx.x * blockDim.x + threadIdx.x;
    
    float local_min = FLT_MAX;
    
    for (int i = gid; i < count; i += gridDim.x * blockDim.x) {
        local_min = fminf(local_min, input[i]);
    }
    
    shared_min[tid] = local_min;
    __syncthreads();
    
    // Tree reduction for min
    for (int stride = blockDim.x / 2; stride > 0; stride >>= 1) {
        if (tid < stride) {
            shared_min[tid] = fminf(shared_min[tid], shared_min[tid + stride]);
        }
        __syncthreads();
    }
    
    if (tid == 0) {
        // Use atomic min operation (simplified for this example)
        float current_min = *output;
        while (shared_min[0] < current_min) {
            float old_min = atomicCAS((int*)output, *(int*)&current_min, *(int*)&shared_min[0]);
            if (old_min == *(int*)&current_min) break;
            current_min = *(float*)&old_min;
        }
    }
}

// CDNA-specific optimized reduction using LDS (Local Data Share)
__global__ void rocm_cdna_optimized_sum(float* input, float* output, int count) {
    __shared__ float lds_memory[1024];  // CDNA has larger LDS capacity
    
    int tid = threadIdx.x;
    int gid = blockIdx.x * blockDim.x + threadIdx.x;
    
    // Load more data per thread on CDNA due to higher compute capacity
    float local_sum = 0.0f;
    const int elements_per_thread = 8;
    
    for (int i = 0; i < elements_per_thread; i++) {
        int idx = gid * elements_per_thread + i;
        if (idx < count) {
            local_sum += input[idx];
        }
    }
    
    lds_memory[tid] = local_sum;
    __syncthreads();
    
    // Use larger reduction tree for CDNA's wider execution units
    for (int stride = blockDim.x / 2; stride > 0; stride >>= 1) {
        if (tid < stride) {
            lds_memory[tid] += lds_memory[tid + stride];
        }
        __syncthreads();
    }
    
    if (tid == 0) {
        atomicAdd(output, lds_memory[0]);
    }
}