## Coverage Report

#### Created: 2026-01-25 15:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/noah/src/realizar/src/gpu/simd_ops.rs

    Line
    Count
    Source
    1
    //! GPU SIMD Operations Module (PMAT-802)
    2
    //!
    3
    //! Extracted from gpu/mod.rs - SIMD-accelerated compute primitives.
    4
    //!
    5
    //! ## Contents
    6
    //! - `scalar_softmax`, `simd_softmax` - Softmax implementations (IMP-038)
    7
    //! - `scalar_rope`, `simd_rope` - RoPE implementations (IMP-041)
    8
    9
    // ============================================================================
    10
    // SIMD-accelerated operations (M18 - IMP-038)
    11
    // ============================================================================
    12
    13
    /// Scalar softmax implementation (baseline for comparison)
    14
    ///
    15
    /// Computes softmax using standard scalar operations.
    16
    #[must_use]
    17
    127
    pub fn scalar_softmax(input: &[f32]) -> Vec<f32> {
    18
    127
        if input.is_empty() {
    19
    4
            return Vec::new();
    20
    123
        }
    21
    22
        // Find max for numerical stability
    23
    123
        let max_val = input.iter().copied().fold(f32::NEG_INFINITY, f32::max);
    24
    25
        // Compute exp(x - max) and sum
    26
    112k
        let exp_vals123: Vec<f32>123 = input123.iter123().map123(|&x| (x - max_val).exp()).collect123();
    27
    123
        let sum: f32 = exp_vals.iter().sum();
    28
    29
        // Normalize
    30
    112k
        exp_vals.iter()123.map123(|&e| e / sum).collect123()
    31
    127
    }
    32
    33
    /// SIMD-accelerated softmax implementation (M18 - IMP-038)
    34
    ///
    35
    /// Uses Trueno's SIMD operations for vectorized computation.
    36
    /// Falls back to scalar for unsupported sizes.
    37
    #[must_use]
    38
    122
    pub fn simd_softmax(input: &[f32]) -> Vec<f32> {
    39
    122
        if input.is_empty() {
    40
    4
            return Vec::new();
    41
    118
        }
    42
    43
        // Find max using SIMD via trueno
    44
    118
        let max_val = input.iter().copied().fold(f32::NEG_INFINITY, f32::max);
    45
    46
        // Compute exp(x - max) - exp is not SIMD accelerated
    47
    112k
        let exp_vals118: Vec<f32>118 = input118.iter118().map118(|&x| (x - max_val).exp()).collect118();
    48
    49
        // Sum using trueno's SIMD sum
    50
    118
        let exp_vec = trueno::Vector::from_slice(&exp_vals);
    51
    118
        let sum = exp_vec.sum().unwrap_or_else(|_| exp_vals.iter()0.sum0());
    52
    53
        // Normalize
    54
    112k
        exp_vals.iter()118.map118(|&e| e / sum).collect118()
    55
    122
    }
    56
    57
    // ============================================================================
    58
    // Scalar and SIMD RoPE implementations (M19 - IMP-041)
    59
    // ============================================================================
    60
    61
    /// Scalar RoPE (Rotary Position Embedding) implementation
    62
    ///
    63
    /// Standard scalar implementation of rotary position embeddings.
    64
    /// Input shape: [seq_len * hidden_dim] flattened
    65
    #[must_use]
    66
    21
    pub fn scalar_rope(input: &[f32], seq_len: usize, head_dim: usize, theta: f32) -> Vec<f32> {
    67
    21
        if input.is_empty() || seq_len == 017 || head_dim == 014 {
    68
    11
            return Vec::new();
    69
    10
        }
    70
    71
    10
        let hidden_dim = input.len() / seq_len;
    72
    10
        let num_heads = hidden_dim / head_dim;
    73
    10
        let mut output = vec![0.0f32; input.len()];
    74
    75
        // Compute RoPE for each position
    76
    20
        for pos in 0..seq_len10 {
    77
    22
            for head in 0..num_heads20 {
    78
    22
                let head_start = pos * hidden_dim + head * head_dim;
    79
    80
                // Apply rotary embedding to pairs of elements
    81
    134
                for i in 0..head_dim / 222 {
    82
    134
                    let freq = 1.0 / theta.powf((2.0 * i as f32) / head_dim as f32);
    83
    134
                    let angle = pos as f32 * freq;
    84
    134
                    let cos_val = angle.cos();
    85
    134
                    let sin_val = angle.sin();
    86
    87
    134
                    let idx0 = head_start + i;
    88
    134
                    let idx1 = head_start + i + head_dim / 2;
    89
    90
    134
                    if idx1 < input.len() {
    91
    134
                        let x0 = input[idx0];
    92
    134
                        let x1 = input[idx1];
    93
    134
                        output[idx0] = x0 * cos_val - x1 * sin_val;
    94
    134
                        output[idx1] = x0 * sin_val + x1 * cos_val;
    95
    134
                    }0
    96
                }
    97
            }
    98
        }
    99
    100
    10
        output
    101
    21
    }
    102
    103
    /// SIMD-accelerated RoPE implementation (M19 - IMP-041)
    104
    ///
    105
    /// Uses Trueno's SIMD operations for vectorized position encoding.
    106
    #[must_use]
    107
    14
    pub fn simd_rope(input: &[f32], seq_len: usize, head_dim: usize, theta: f32) -> Vec<f32> {
    108
    14
        if input.is_empty() || seq_len == 010 || head_dim == 08 {
    109
    8
            return Vec::new();
    110
    6
        }
    111
    112
    6
        let hidden_dim = input.len() / seq_len;
    113
    6
        let num_heads = hidden_dim / head_dim;
    114
    6
        let half_head = head_dim / 2;
    115
    116
        // Pre-compute frequency table (cache-friendly)
    117
    6
        let mut freqs: Vec<f32> = Vec::with_capacity(half_head);
    118
    36
        for i in 0..half_head6 {
    119
    36
            freqs.push(1.0 / theta.powf((2.0 * i as f32) / head_dim as f32));
    120
    36
        }
    121
    122
    6
        let mut output = vec![0.0f32; input.len()];
    123
    124
        // Process each position using SIMD operations
    125
    13
        for pos in 0..seq_len6 {
    126
            // Pre-compute angles for this position
    127
    80
            let angles13: Vec<f32>13 = freqs.iter()13.map13(|&f| pos as f32 * f).collect13();
    128
    80
            let cos_vals13: Vec<f32>13 = angles.iter()13.map13(|&a| a.cos()).collect13();
    129
    80
            let sin_vals13: Vec<f32>13 = angles.iter()13.map13(|&a| a.sin()).collect13();
    130
    131
            // Use trueno vectors for batch operations
    132
    13
            let cos_vec = trueno::Vector::from_slice(&cos_vals);
    133
    13
            let sin_vec = trueno::Vector::from_slice(&sin_vals);
    134
    135
    15
            for head in 0..num_heads13 {
    136
    15
                let head_start = pos * hidden_dim + head * head_dim;
    137
    138
                // Extract x0 and x1 halves
    139
    15
                let x0_slice = &input[head_start..head_start + half_head];
    140
    15
                let x1_slice = &input[head_start + half_head..head_start + head_dim];
    141
    142
    15
                let x0_vec = trueno::Vector::from_slice(x0_slice);
    143
    15
                let x1_vec = trueno::Vector::from_slice(x1_slice);
    144
    145
                // Compute: out0 = x0 * cos - x1 * sin
    146
                //          out1 = x0 * sin + x1 * cos
    147
    15
                let x0_cos = x0_vec.mul(&cos_vec).unwrap_or_else(|_| x0_vec0.clone0());
    148
    15
                let x1_sin = x1_vec.mul(&sin_vec).unwrap_or_else(|_| x1_vec0.clone0());
    149
    15
                let x0_sin = x0_vec.mul(&sin_vec).unwrap_or_else(|_| x0_vec0.clone0());
    150
    15
                let x1_cos = x1_vec.mul(&cos_vec).unwrap_or_else(|_| x1_vec0.clone0());
    151
    152
    15
                let out0 = x0_cos
    153
    15
                    .sub(&x1_sin)
    154
    15
                    .unwrap_or_else(|_| trueno::Vector::from_slice0(x0_slice0));
    155
    15
                let out1 = x0_sin
    156
    15
                    .add(&x1_cos)
    157
    15
                    .unwrap_or_else(|_| trueno::Vector::from_slice0(x1_slice0));
    158
    159
                // Copy results to output
    160
    15
                output[head_start..head_start + half_head].copy_from_slice(out0.as_slice());
    161
    15
                output[head_start + half_head..head_start + head_dim].copy_from_slice(out1.as_slice());
    162
            }
    163
        }
    164
    165
    6
        output
    166
    14
    }