## Coverage Report

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

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

    /home/noah/src/trueno/src/backends/sse2/mod.rs

    Line
    Count
    Source
    1
    //! SSE2 backend implementation (x86_64 baseline SIMD)
    2
    //!
    3
    //! This backend uses SSE2 intrinsics for 128-bit SIMD operations.
    4
    //! SSE2 is available on all x86_64 CPUs as a baseline requirement.
    5
    //!
    6
    //! # Performance
    7
    //!
    8
    //! Expected speedup: 4x for operations on aligned f32 vectors (4 elements per register)
    9
    //!
    10
    //! # Safety
    11
    //!
    12
    //! All SSE2 intrinsics are marked `unsafe` by Rust. This module carefully isolates
    13
    //! all unsafe code and verifies correctness through comprehensive testing.
    14
    15
    mod ops;
    16
    17
    #[cfg(target_arch = "x86_64")]
    18
    use std::arch::x86_64::*;
    19
    20
    use super::VectorBackend;
    21
    22
    /// SSE2 backend (128-bit SIMD for x86_64)
    23
    pub struct Sse2Backend;
    24
    25
    impl VectorBackend for Sse2Backend {
    26
        #[inline]
    27
        #[target_feature(enable = "sse2")]
    28
    0
        unsafe fn add(a: &[f32], b: &[f32], result: &mut [f32]) {
    29
    0
            ops::arithmetic::add(a, b, result);
    30
    0
        }
    31
    32
        #[inline]
    33
        #[target_feature(enable = "sse2")]
    34
    0
        unsafe fn sub(a: &[f32], b: &[f32], result: &mut [f32]) {
    35
    0
            ops::arithmetic::sub(a, b, result);
    36
    0
        }
    37
    38
        #[inline]
    39
        #[target_feature(enable = "sse2")]
    40
    0
        unsafe fn mul(a: &[f32], b: &[f32], result: &mut [f32]) {
    41
    0
            ops::arithmetic::mul(a, b, result);
    42
    0
        }
    43
    44
        #[inline]
    45
        #[target_feature(enable = "sse2")]
    46
    0
        unsafe fn div(a: &[f32], b: &[f32], result: &mut [f32]) {
    47
    0
            ops::arithmetic::div(a, b, result);
    48
    0
        }
    49
    50
        #[inline]
    51
        #[target_feature(enable = "sse2")]
    52
    0
        unsafe fn dot(a: &[f32], b: &[f32]) -> f32 {
    53
    0
            ops::reductions::dot(a, b)
    54
    0
        }
    55
    56
        #[inline]
    57
        #[target_feature(enable = "sse2")]
    58
    0
        unsafe fn sum(a: &[f32]) -> f32 {
    59
    0
            ops::reductions::sum(a)
    60
    0
        }
    61
    62
        #[inline]
    63
        #[target_feature(enable = "sse2")]
    64
    0
        unsafe fn max(a: &[f32]) -> f32 {
    65
    0
            ops::reductions::max(a)
    66
    0
        }
    67
    68
        #[inline]
    69
        #[target_feature(enable = "sse2")]
    70
    0
        unsafe fn min(a: &[f32]) -> f32 {
    71
    0
            ops::reductions::min(a)
    72
    0
        }
    73
    74
        #[inline]
    75
        #[target_feature(enable = "sse2")]
    76
    0
        unsafe fn argmax(a: &[f32]) -> usize {
    77
    0
            ops::reductions::argmax(a)
    78
    0
        }
    79
    80
        #[inline]
    81
        #[target_feature(enable = "sse2")]
    82
    0
        unsafe fn argmin(a: &[f32]) -> usize {
    83
    0
            ops::reductions::argmin(a)
    84
    0
        }
    85
    86
        #[inline]
    87
        #[target_feature(enable = "sse2")]
    88
    0
        unsafe fn sum_kahan(a: &[f32]) -> f32 {
    89
    0
            ops::reductions::sum_kahan(a)
    90
    0
        }
    91
    92
        #[inline]
    93
        #[target_feature(enable = "sse2")]
    94
    0
        unsafe fn norm_l2(a: &[f32]) -> f32 {
    95
    0
            if a.is_empty() { return 0.0; }
    96
    0
            Self::dot(a, a).sqrt()
    97
    0
        }
    98
    99
        #[inline]
    100
        #[target_feature(enable = "sse2")]
    101
    0
        unsafe fn norm_l1(a: &[f32]) -> f32 {
    102
    0
            if a.is_empty() { return 0.0; }
    103
    0
            let len = a.len();
    104
    0
            let mut i = 0;
    105
    0
            let mut acc = _mm_setzero_ps();
    106
    0
            let sign_mask = _mm_set1_ps(f32::from_bits(0x7FFF_FFFF));
    107
    0
            while i + 4 <= len {
    108
    0
                acc = _mm_add_ps(acc, _mm_and_ps(_mm_loadu_ps(a.as_ptr().add(i)), sign_mask));
    109
    0
                i += 4;
    110
    0
            }
    111
    0
            let mut result = {
    112
    0
                let temp = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
    113
    0
                let temp = _mm_add_ss(temp, _mm_shuffle_ps(temp, temp, 1));
    114
    0
                _mm_cvtss_f32(temp)
    115
            };
    116
    0
            for &val in &a[i..] { result += val.abs(); }
    117
    0
            result
    118
    0
        }
    119
    120
        #[inline]
    121
        #[target_feature(enable = "sse2")]
    122
    0
        unsafe fn norm_linf(a: &[f32]) -> f32 {
    123
    0
            if a.is_empty() { return 0.0; }
    124
    0
            let len = a.len();
    125
    0
            let mut i = 0;
    126
    0
            let mut max_vec = _mm_setzero_ps();
    127
    0
            let sign_mask = _mm_set1_ps(f32::from_bits(0x7FFF_FFFF));
    128
    0
            while i + 4 <= len {
    129
    0
                let va = _mm_loadu_ps(a.as_ptr().add(i));
    130
    0
                max_vec = _mm_max_ps(max_vec, _mm_and_ps(va, sign_mask));
    131
    0
                i += 4;
    132
    0
            }
    133
    0
            let mut result = {
    134
    0
                let temp = _mm_max_ps(max_vec, _mm_movehl_ps(max_vec, max_vec));
    135
    0
                let temp = _mm_max_ss(temp, _mm_shuffle_ps(temp, temp, 1));
    136
    0
                _mm_cvtss_f32(temp)
    137
            };
    138
    0
            for &val in &a[i..] { let abs_val = val.abs(); if abs_val > result { result = abs_val; } }
    139
    0
            result
    140
    0
        }
    141
    142
        #[inline]
    143
        #[target_feature(enable = "sse2")]
    144
    0
        unsafe fn scale(a: &[f32], scalar: f32, result: &mut [f32]) {
    145
    0
            let len = a.len();
    146
    0
            let mut i = 0;
    147
    0
            let scalar_vec = _mm_set1_ps(scalar);
    148
    0
            while i + 4 <= len {
    149
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_mul_ps(_mm_loadu_ps(a.as_ptr().add(i)), scalar_vec));
    150
    0
                i += 4;
    151
    0
            }
    152
    0
            for j in i..len { result[j] = a[j] * scalar; }
    153
    0
        }
    154
    155
        #[inline]
    156
        #[target_feature(enable = "sse2")]
    157
    0
        unsafe fn abs(a: &[f32], result: &mut [f32]) {
    158
    0
            let len = a.len();
    159
    0
            let mut i = 0;
    160
    0
            let sign_mask = _mm_set1_ps(f32::from_bits(0x7FFF_FFFF));
    161
    0
            while i + 4 <= len {
    162
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_and_ps(_mm_loadu_ps(a.as_ptr().add(i)), sign_mask));
    163
    0
                i += 4;
    164
    0
            }
    165
    0
            for j in i..len { result[j] = a[j].abs(); }
    166
    0
        }
    167
    168
        #[inline]
    169
        #[target_feature(enable = "sse2")]
    170
    0
        unsafe fn clamp(a: &[f32], min_val: f32, max_val: f32, result: &mut [f32]) {
    171
    0
            let len = a.len();
    172
    0
            let mut i = 0;
    173
    0
            let min_vec = _mm_set1_ps(min_val);
    174
    0
            let max_vec = _mm_set1_ps(max_val);
    175
    0
            while i + 4 <= len {
    176
    0
                let va = _mm_loadu_ps(a.as_ptr().add(i));
    177
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_min_ps(_mm_max_ps(va, min_vec), max_vec));
    178
    0
                i += 4;
    179
    0
            }
    180
    0
            for j in i..len { result[j] = a[j].max(min_val).min(max_val); }
    181
    0
        }
    182
    183
        #[inline]
    184
        #[target_feature(enable = "sse2")]
    185
    0
        unsafe fn lerp(a: &[f32], b: &[f32], t: f32, result: &mut [f32]) {
    186
    0
            let len = a.len();
    187
    0
            let mut i = 0;
    188
    0
            let t_vec = _mm_set1_ps(t);
    189
    0
            while i + 4 <= len {
    190
    0
                let va = _mm_loadu_ps(a.as_ptr().add(i));
    191
    0
                let vb = _mm_loadu_ps(b.as_ptr().add(i));
    192
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_add_ps(va, _mm_mul_ps(t_vec, _mm_sub_ps(vb, va))));
    193
    0
                i += 4;
    194
    0
            }
    195
    0
            for j in i..len { result[j] = a[j] + t * (b[j] - a[j]); }
    196
    0
        }
    197
    198
        #[inline]
    199
        #[target_feature(enable = "sse2")]
    200
    0
        unsafe fn fma(a: &[f32], b: &[f32], c: &[f32], result: &mut [f32]) {
    201
    0
            let len = a.len();
    202
    0
            let mut i = 0;
    203
    0
            while i + 4 <= len {
    204
    0
                let va = _mm_loadu_ps(a.as_ptr().add(i));
    205
    0
                let vb = _mm_loadu_ps(b.as_ptr().add(i));
    206
    0
                let vc = _mm_loadu_ps(c.as_ptr().add(i));
    207
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_add_ps(_mm_mul_ps(va, vb), vc));
    208
    0
                i += 4;
    209
    0
            }
    210
    0
            for j in i..len { result[j] = a[j] * b[j] + c[j]; }
    211
    0
        }
    212
    213
        #[inline]
    214
        #[target_feature(enable = "sse2")]
    215
    0
        unsafe fn relu(a: &[f32], result: &mut [f32]) {
    216
    0
            let len = a.len();
    217
    0
            let mut i = 0;
    218
    0
            let zero = _mm_setzero_ps();
    219
    0
            while i + 4 <= len {
    220
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_max_ps(_mm_loadu_ps(a.as_ptr().add(i)), zero));
    221
    0
                i += 4;
    222
    0
            }
    223
    0
            for j in i..len { result[j] = a[j].max(0.0); }
    224
    0
        }
    225
    226
        #[inline]
    227
        #[target_feature(enable = "sse2")]
    228
    0
        unsafe fn exp(a: &[f32], result: &mut [f32]) {
    229
            // Polynomial approximation for exp - range reduction + polynomial
    230
    0
            let len = a.len();
    231
    0
            let mut i = 0;
    232
    0
            let ln2 = _mm_set1_ps(std::f32::consts::LN_2);
    233
    0
            let inv_ln2 = _mm_set1_ps(1.0 / std::f32::consts::LN_2);
    234
    0
            let c1 = _mm_set1_ps(1.0);
    235
    0
            let c2 = _mm_set1_ps(0.5);
    236
    0
            let c3 = _mm_set1_ps(0.166_666_67);
    237
    0
            let c4 = _mm_set1_ps(0.041_666_668);
    238
    0
            let c5 = _mm_set1_ps(0.008_333_334);
    239
    0
            while i + 4 <= len {
    240
    0
                let x = _mm_loadu_ps(a.as_ptr().add(i));
    241
    0
                let k = _mm_cvtps_epi32(_mm_mul_ps(x, inv_ln2));
    242
    0
                let kf = _mm_cvtepi32_ps(k);
    243
    0
                let r = _mm_sub_ps(x, _mm_mul_ps(kf, ln2));
    244
    0
                let mut poly = _mm_add_ps(c1, _mm_mul_ps(r, c5));
    245
    0
                poly = _mm_add_ps(c1, _mm_mul_ps(r, _mm_add_ps(c4, _mm_mul_ps(r, poly))));
    246
    0
                poly = _mm_add_ps(c1, _mm_mul_ps(r, _mm_add_ps(c3, _mm_mul_ps(r, poly))));
    247
    0
                poly = _mm_add_ps(c1, _mm_mul_ps(r, _mm_add_ps(c2, _mm_mul_ps(r, poly))));
    248
    0
                poly = _mm_add_ps(c1, _mm_mul_ps(r, poly));
    249
    0
                let exp_k = _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(k, _mm_set1_epi32(127)), 23));
    250
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_mul_ps(poly, exp_k));
    251
    0
                i += 4;
    252
    0
            }
    253
    0
            for j in i..len { result[j] = a[j].exp(); }
    254
    0
        }
    255
    256
        #[inline]
    257
        #[target_feature(enable = "sse2")]
    258
    0
        unsafe fn sigmoid(a: &[f32], result: &mut [f32]) {
    259
            // sigmoid(x) = 1 / (1 + exp(-x))
    260
    0
            let len = a.len();
    261
    0
            let mut i = 0;
    262
    0
            let one = _mm_set1_ps(1.0);
    263
    0
            let neg_one = _mm_set1_ps(-1.0);
    264
    0
            let ln2 = _mm_set1_ps(std::f32::consts::LN_2);
    265
    0
            let inv_ln2 = _mm_set1_ps(1.0 / std::f32::consts::LN_2);
    266
    0
            let c2 = _mm_set1_ps(0.5);
    267
    0
            let c3 = _mm_set1_ps(0.166_666_67);
    268
    0
            let c4 = _mm_set1_ps(0.041_666_668);
    269
    0
            let c5 = _mm_set1_ps(0.008_333_334);
    270
    0
            while i + 4 <= len {
    271
    0
                let x = _mm_loadu_ps(a.as_ptr().add(i));
    272
    0
                let neg_x = _mm_mul_ps(x, neg_one);
    273
    0
                let k = _mm_cvtps_epi32(_mm_mul_ps(neg_x, inv_ln2));
    274
    0
                let kf = _mm_cvtepi32_ps(k);
    275
    0
                let r = _mm_sub_ps(neg_x, _mm_mul_ps(kf, ln2));
    276
    0
                let mut poly = _mm_add_ps(one, _mm_mul_ps(r, c5));
    277
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c4, _mm_mul_ps(r, poly))));
    278
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c3, _mm_mul_ps(r, poly))));
    279
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c2, _mm_mul_ps(r, poly))));
    280
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, poly));
    281
    0
                let exp_k = _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(k, _mm_set1_epi32(127)), 23));
    282
    0
                let exp_neg_x = _mm_mul_ps(poly, exp_k);
    283
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_div_ps(one, _mm_add_ps(one, exp_neg_x)));
    284
    0
                i += 4;
    285
    0
            }
    286
    0
            for j in i..len { result[j] = 1.0 / (1.0 + (-a[j]).exp()); }
    287
    0
        }
    288
    289
        #[inline]
    290
        #[target_feature(enable = "sse2")]
    291
    0
        unsafe fn gelu(a: &[f32], result: &mut [f32]) {
    292
            // GELU(x) = 0.5 * x * (1 + tanh(sqrt(2/pi) * (x + 0.044715 * x^3)))
    293
    0
            let len = a.len();
    294
    0
            let mut i = 0;
    295
    0
            let half = _mm_set1_ps(0.5);
    296
    0
            let one = _mm_set1_ps(1.0);
    297
    0
            let sqrt_2_pi = _mm_set1_ps(0.797_884_56);
    298
    0
            let coeff = _mm_set1_ps(0.044_715);
    299
    0
            while i + 4 <= len {
    300
    0
                let x = _mm_loadu_ps(a.as_ptr().add(i));
    301
    0
                let x3 = _mm_mul_ps(_mm_mul_ps(x, x), x);
    302
    0
                let inner = _mm_mul_ps(sqrt_2_pi, _mm_add_ps(x, _mm_mul_ps(coeff, x3)));
    303
    0
                // tanh approximation: (e^2x - 1) / (e^2x + 1)
    304
    0
                let two_inner = _mm_add_ps(inner, inner);
    305
    0
                let exp_2x = Self::exp_approx_sse2(two_inner);
    306
    0
                let tanh_val = _mm_div_ps(_mm_sub_ps(exp_2x, one), _mm_add_ps(exp_2x, one));
    307
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_mul_ps(half, _mm_mul_ps(x, _mm_add_ps(one, tanh_val))));
    308
    0
                i += 4;
    309
    0
            }
    310
    0
            for j in i..len {
    311
    0
                let x = a[j];
    312
    0
                result[j] = 0.5 * x * (1.0 + ((0.797_884_56 * (x + 0.044_715 * x * x * x)) as f64).tanh() as f32);
    313
    0
            }
    314
    0
        }
    315
    316
        #[inline]
    317
        #[target_feature(enable = "sse2")]
    318
    0
        unsafe fn swish(a: &[f32], result: &mut [f32]) {
    319
            // swish(x) = x * sigmoid(x)
    320
    0
            let len = a.len();
    321
    0
            let mut i = 0;
    322
    0
            let one = _mm_set1_ps(1.0);
    323
    0
            let neg_one = _mm_set1_ps(-1.0);
    324
    0
            let ln2 = _mm_set1_ps(std::f32::consts::LN_2);
    325
    0
            let inv_ln2 = _mm_set1_ps(1.0 / std::f32::consts::LN_2);
    326
    0
            let c2 = _mm_set1_ps(0.5);
    327
    0
            let c3 = _mm_set1_ps(0.166_666_67);
    328
    0
            let c4 = _mm_set1_ps(0.041_666_668);
    329
    0
            let c5 = _mm_set1_ps(0.008_333_334);
    330
    0
            while i + 4 <= len {
    331
    0
                let x = _mm_loadu_ps(a.as_ptr().add(i));
    332
    0
                let neg_x = _mm_mul_ps(x, neg_one);
    333
    0
                let k = _mm_cvtps_epi32(_mm_mul_ps(neg_x, inv_ln2));
    334
    0
                let kf = _mm_cvtepi32_ps(k);
    335
    0
                let r = _mm_sub_ps(neg_x, _mm_mul_ps(kf, ln2));
    336
    0
                let mut poly = _mm_add_ps(one, _mm_mul_ps(r, c5));
    337
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c4, _mm_mul_ps(r, poly))));
    338
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c3, _mm_mul_ps(r, poly))));
    339
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c2, _mm_mul_ps(r, poly))));
    340
    0
                poly = _mm_add_ps(one, _mm_mul_ps(r, poly));
    341
    0
                let exp_k = _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(k, _mm_set1_epi32(127)), 23));
    342
    0
                let exp_neg_x = _mm_mul_ps(poly, exp_k);
    343
    0
                let sigmoid = _mm_div_ps(one, _mm_add_ps(one, exp_neg_x));
    344
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_mul_ps(x, sigmoid));
    345
    0
                i += 4;
    346
    0
            }
    347
    0
            for j in i..len { result[j] = a[j] / (1.0 + (-a[j]).exp()); }
    348
    0
        }
    349
    350
        #[inline]
    351
        #[target_feature(enable = "sse2")]
    352
    0
        unsafe fn tanh(a: &[f32], result: &mut [f32]) {
    353
            // tanh(x) = (e^2x - 1) / (e^2x + 1)
    354
    0
            let len = a.len();
    355
    0
            let mut i = 0;
    356
    0
            let one = _mm_set1_ps(1.0);
    357
    0
            let two = _mm_set1_ps(2.0);
    358
    0
            while i + 4 <= len {
    359
    0
                let x = _mm_loadu_ps(a.as_ptr().add(i));
    360
    0
                let exp_2x = Self::exp_approx_sse2(_mm_mul_ps(two, x));
    361
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_div_ps(_mm_sub_ps(exp_2x, one), _mm_add_ps(exp_2x, one)));
    362
    0
                i += 4;
    363
    0
            }
    364
    0
            for j in i..len {
    365
    0
                let exp_2x = (2.0 * a[j]).exp();
    366
    0
                result[j] = (exp_2x - 1.0) / (exp_2x + 1.0);
    367
    0
            }
    368
    0
        }
    369
    370
        #[inline]
    371
        #[target_feature(enable = "sse2")]
    372
    0
        unsafe fn sqrt(a: &[f32], result: &mut [f32]) {
    373
    0
            let len = a.len();
    374
    0
            let mut i = 0;
    375
    0
            while i + 4 <= len {
    376
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_sqrt_ps(_mm_loadu_ps(a.as_ptr().add(i))));
    377
    0
                i += 4;
    378
    0
            }
    379
    0
            for j in i..len { result[j] = a[j].sqrt(); }
    380
    0
        }
    381
    382
        #[inline]
    383
        #[target_feature(enable = "sse2")]
    384
    0
        unsafe fn recip(a: &[f32], result: &mut [f32]) {
    385
    0
            let len = a.len();
    386
    0
            let mut i = 0;
    387
    0
            let one = _mm_set1_ps(1.0);
    388
    0
            while i + 4 <= len {
    389
    0
                _mm_storeu_ps(result.as_mut_ptr().add(i), _mm_div_ps(one, _mm_loadu_ps(a.as_ptr().add(i))));
    390
    0
                i += 4;
    391
    0
            }
    392
    0
            for j in i..len { result[j] = a[j].recip(); }
    393
    0
        }
    394
    395
    0
        unsafe fn ln(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::ln(a, result); }
    396
    0
        unsafe fn log2(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::log2(a, result); }
    397
    0
        unsafe fn log10(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::log10(a, result); }
    398
    0
        unsafe fn sin(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::sin(a, result); }
    399
    0
        unsafe fn cos(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::cos(a, result); }
    400
    0
        unsafe fn tan(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::tan(a, result); }
    401
    0
        unsafe fn floor(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::floor(a, result); }
    402
    0
        unsafe fn ceil(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::ceil(a, result); }
    403
    0
        unsafe fn round(a: &[f32], result: &mut [f32]) { super::scalar::ScalarBackend::round(a, result); }
    404
    }
    405
    406
    impl Sse2Backend {
    407
        /// SSE2 exp approximation helper
    408
        #[inline]
    409
        #[target_feature(enable = "sse2")]
    410
    0
        unsafe fn exp_approx_sse2(x: __m128) -> __m128 {
    411
    0
            let ln2 = _mm_set1_ps(std::f32::consts::LN_2);
    412
    0
            let inv_ln2 = _mm_set1_ps(1.0 / std::f32::consts::LN_2);
    413
    0
            let one = _mm_set1_ps(1.0);
    414
    0
            let c2 = _mm_set1_ps(0.5);
    415
    0
            let c3 = _mm_set1_ps(0.166_666_67);
    416
    0
            let c4 = _mm_set1_ps(0.041_666_668);
    417
    0
            let c5 = _mm_set1_ps(0.008_333_334);
    418
    0
            let k = _mm_cvtps_epi32(_mm_mul_ps(x, inv_ln2));
    419
    0
            let kf = _mm_cvtepi32_ps(k);
    420
    0
            let r = _mm_sub_ps(x, _mm_mul_ps(kf, ln2));
    421
    0
            let mut poly = _mm_add_ps(one, _mm_mul_ps(r, c5));
    422
    0
            poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c4, _mm_mul_ps(r, poly))));
    423
    0
            poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c3, _mm_mul_ps(r, poly))));
    424
    0
            poly = _mm_add_ps(one, _mm_mul_ps(r, _mm_add_ps(c2, _mm_mul_ps(r, poly))));
    425
    0
            poly = _mm_add_ps(one, _mm_mul_ps(r, poly));
    426
    0
            let exp_k = _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(k, _mm_set1_epi32(127)), 23));
    427
    0
            _mm_mul_ps(poly, exp_k)
    428
    0
        }
    429
    }
    430
    431
    #[cfg(test)]
    432
    mod tests {
    433
        use super::*;
    434
    435
        #[test]
    436
        fn test_sse2_add() {
    437
            let a = [1.0, 2.0, 3.0, 4.0, 5.0];
    438
            let b = [10.0, 20.0, 30.0, 40.0, 50.0];
    439
            let mut result = [0.0f32; 5];
    440
            unsafe { Sse2Backend::add(&a, &b, &mut result); }
    441
            assert_eq!(result, [11.0, 22.0, 33.0, 44.0, 55.0]);
    442
        }
    443
    444
        #[test]
    445
        fn test_sse2_sub() {
    446
            let a = [10.0, 20.0, 30.0, 40.0, 50.0];
    447
            let b = [1.0, 2.0, 3.0, 4.0, 5.0];
    448
            let mut result = [0.0f32; 5];
    449
            unsafe { Sse2Backend::sub(&a, &b, &mut result); }
    450
            assert_eq!(result, [9.0, 18.0, 27.0, 36.0, 45.0]);
    451
        }
    452
    453
        #[test]
    454
        fn test_sse2_mul() {
    455
            let a = [1.0, 2.0, 3.0, 4.0, 5.0];
    456
            let b = [2.0, 3.0, 4.0, 5.0, 6.0];
    457
            let mut result = [0.0f32; 5];
    458
            unsafe { Sse2Backend::mul(&a, &b, &mut result); }
    459
            assert_eq!(result, [2.0, 6.0, 12.0, 20.0, 30.0]);
    460
        }
    461
    462
        #[test]
    463
        fn test_sse2_div() {
    464
            let a = [10.0, 20.0, 30.0, 40.0, 50.0];
    465
            let b = [2.0, 4.0, 5.0, 8.0, 10.0];
    466
            let mut result = [0.0f32; 5];
    467
            unsafe { Sse2Backend::div(&a, &b, &mut result); }
    468
            assert_eq!(result, [5.0, 5.0, 6.0, 5.0, 5.0]);
    469
        }
    470
    471
        #[test]
    472
        fn test_sse2_dot() {
    473
            let a = [1.0, 2.0, 3.0, 4.0, 5.0];
    474
            let b = [2.0, 3.0, 4.0, 5.0, 6.0];
    475
            let result = unsafe { Sse2Backend::dot(&a, &b) };
    476
            assert!((result - 70.0).abs() < 1e-6);
    477
        }
    478
    479
        #[test]
    480
        fn test_sse2_sum() {
    481
            let a = [1.0, 2.0, 3.0, 4.0, 5.0];
    482
            let result = unsafe { Sse2Backend::sum(&a) };
    483
            assert!((result - 15.0).abs() < 1e-6);
    484
        }
    485
    486
        #[test]
    487
        fn test_sse2_max() {
    488
            let a = [1.0, 5.0, 3.0, 2.0, 4.0];
    489
            let result = unsafe { Sse2Backend::max(&a) };
    490
            assert!((result - 5.0).abs() < 1e-6);
    491
        }
    492
    493
        #[test]
    494
        fn test_sse2_min() {
    495
            let a = [5.0, 1.0, 3.0, 2.0, 4.0];
    496
            let result = unsafe { Sse2Backend::min(&a) };
    497
            assert!((result - 1.0).abs() < 1e-6);
    498
        }
    499
    500
        #[test]
    501
        fn test_sse2_argmax() {
    502
            let a = [1.0, 5.0, 3.0, 2.0, 4.0];
    503
            let result = unsafe { Sse2Backend::argmax(&a) };
    504
            assert_eq!(result, 1);
    505
        }
    506
    507
        #[test]
    508
        fn test_sse2_argmin() {
    509
            let a = [5.0, 1.0, 3.0, 2.0, 4.0];
    510
            let result = unsafe { Sse2Backend::argmin(&a) };
    511
            assert_eq!(result, 1);
    512
        }
    513
    514
        #[test]
    515
        fn test_sse2_norm_linf() {
    516
            let a = [-5.0, 1.0, 3.0, 2.0, -4.0];
    517
            let result = unsafe { Sse2Backend::norm_linf(&a) };
    518
            assert!((result - 5.0).abs() < 1e-6);
    519
        }
    520
    521
        #[test]
    522
        fn test_sse2_scale() {
    523
            let a = [1.0, 2.0, 3.0, 4.0, 5.0];
    524
            let mut result = [0.0f32; 5];
    525
            unsafe { Sse2Backend::scale(&a, 2.0, &mut result); }
    526
            assert_eq!(result, [2.0, 4.0, 6.0, 8.0, 10.0]);
    527
        }
    528
    529
        #[test]
    530
        fn test_sse2_abs() {
    531
            let a = [-1.0, 2.0, -3.0, 4.0, -5.0];
    532
            let mut result = [0.0f32; 5];
    533
            unsafe { Sse2Backend::abs(&a, &mut result); }
    534
            assert_eq!(result, [1.0, 2.0, 3.0, 4.0, 5.0]);
    535
        }
    536
    537
        #[test]
    538
        fn test_sse2_clamp() {
    539
            let a = [-1.0, 0.5, 1.5, 2.0, 3.0];
    540
            let mut result = [0.0f32; 5];
    541
            unsafe { Sse2Backend::clamp(&a, 0.0, 1.0, &mut result); }
    542
            assert_eq!(result, [0.0, 0.5, 1.0, 1.0, 1.0]);
    543
        }
    544
    545
        #[test]
    546
        fn test_sse2_relu() {
    547
            let a = [-1.0, 0.0, 1.0, -2.0, 3.0];
    548
            let mut result = [0.0f32; 5];
    549
            unsafe { Sse2Backend::relu(&a, &mut result); }
    550
            assert_eq!(result, [0.0, 0.0, 1.0, 0.0, 3.0]);
    551
        }
    552
    553
        #[test]
    554
        fn test_sse2_exp() {
    555
            let a = [0.0, 1.0, -1.0, 2.0];
    556
            let mut result = [0.0f32; 4];
    557
            unsafe { Sse2Backend::exp(&a, &mut result); }
    558
            assert!((result[0] - 1.0).abs() < 0.05);
    559
            assert!((result[1] - std::f32::consts::E).abs() < 0.1);
    560
        }
    561
    562
        #[test]
    563
        fn test_sse2_sigmoid() {
    564
            let a = [0.0, 1.0, -1.0, 10.0];
    565
            let mut result = [0.0f32; 4];
    566
            unsafe { Sse2Backend::sigmoid(&a, &mut result); }
    567
            assert!((result[0] - 0.5).abs() < 0.01);
    568
            assert!(result[1] > 0.5);
    569
            assert!(result[2] < 0.5);
    570
        }
    571
    572
        #[test]
    573
        fn test_sse2_sqrt() {
    574
            let a = [1.0, 4.0, 9.0, 16.0, 25.0];
    575
            let mut result = [0.0f32; 5];
    576
            unsafe { Sse2Backend::sqrt(&a, &mut result); }
    577
            assert_eq!(result, [1.0, 2.0, 3.0, 4.0, 5.0]);
    578
        }
    579
    580
        #[test]
    581
        fn test_sse2_sum_kahan() {
    582
            let a: Vec<f32> = (1..=16).map(|i| i as f32).collect();
    583
            let result = unsafe { Sse2Backend::sum_kahan(&a) };
    584
            assert!((result - 136.0).abs() < 1e-3);
    585
        }
    586
    587
        #[test]
    588
        fn test_sse2_norm_l2() {
    589
            let a = vec![3.0, 4.0];
    590
            let result = unsafe { Sse2Backend::norm_l2(&a) };
    591
            assert!((result - 5.0).abs() < 1e-5);
    592
        }
    593
    594
        #[test]
    595
        fn test_sse2_norm_l1() {
    596
            let a = vec![-1.0, 2.0, -3.0, 4.0];
    597
            let result = unsafe { Sse2Backend::norm_l1(&a) };
    598
            assert!((result - 10.0).abs() < 1e-5);
    599
        }
    600
    601
        #[test]
    602
        fn test_sse2_lerp() {
    603
            let a = vec![0.0; 16];
    604
            let b = vec![10.0; 16];
    605
            let mut result = vec![0.0; 16];
    606
            unsafe { Sse2Backend::lerp(&a, &b, 0.5, &mut result); }
    607
            assert!(result.iter().all(|&x| (x - 5.0).abs() < 1e-5));
    608
        }
    609
    610
        #[test]
    611
        fn test_sse2_fma() {
    612
            let a = vec![2.0; 16];
    613
            let b = vec![3.0; 16];
    614
            let c = vec![1.0; 16];
    615
            let mut result = vec![0.0; 16];
    616
            unsafe { Sse2Backend::fma(&a, &b, &c, &mut result); }
    617
            assert!(result.iter().all(|&x| (x - 7.0).abs() < 1e-5));
    618
        }
    619
    620
        #[test]
    621
        fn test_sse2_gelu() {
    622
            let a = vec![0.0, 1.0];
    623
            let mut result = vec![0.0; 2];
    624
            unsafe { Sse2Backend::gelu(&a, &mut result); }
    625
            assert!((result[0]).abs() < 1e-5);
    626
            assert!((result[1] - 0.841_192).abs() < 1e-2);
    627
        }
    628
    629
        #[test]
    630
        fn test_sse2_swish() {
    631
            let a = vec![0.0, 1.0];
    632
            let mut result = vec![0.0; 2];
    633
            unsafe { Sse2Backend::swish(&a, &mut result); }
    634
            assert!((result[0]).abs() < 1e-5);
    635
            assert!((result[1] - 0.731_059).abs() < 1e-2);
    636
        }
    637
    638
        #[test]
    639
        fn test_sse2_tanh() {
    640
            let a = vec![0.0, 1.0];
    641
            let mut result = vec![0.0; 2];
    642
            unsafe { Sse2Backend::tanh(&a, &mut result); }
    643
            assert!((result[0]).abs() < 1e-5);
    644
            assert!((result[1] - 0.761_594_2).abs() < 1e-2);
    645
        }
    646
    647
        #[test]
    648
        fn test_sse2_recip() {
    649
            let a = vec![2.0, 4.0, 5.0];
    650
            let mut result = vec![0.0; 3];
    651
            unsafe { Sse2Backend::recip(&a, &mut result); }
    652
            assert!((result[0] - 0.5).abs() < 1e-5);
    653
            assert!((result[1] - 0.25).abs() < 1e-5);
    654
            assert!((result[2] - 0.2).abs() < 1e-5);
    655
        }
    656
    657
        #[test]
    658
        fn test_sse2_transcendental() {
    659
            let a = vec![1.0, std::f32::consts::E, 10.0];
    660
            let mut ln_result = vec![0.0; 3];
    661
            let mut log10_result = vec![0.0; 3];
    662
            unsafe {
    663
                Sse2Backend::ln(&a, &mut ln_result);
    664
                Sse2Backend::log10(&a, &mut log10_result);
    665
            }
    666
            assert!((ln_result[0]).abs() < 1e-5);
    667
            assert!((ln_result[1] - 1.0).abs() < 1e-4);
    668
            assert!((log10_result[2] - 1.0).abs() < 1e-5);
    669
        }
    670
    671
        #[test]
    672
        fn test_sse2_trig() {
    673
            let a = vec![0.0, std::f32::consts::FRAC_PI_2];
    674
            let mut sin_result = vec![0.0; 2];
    675
            let mut cos_result = vec![0.0; 2];
    676
            unsafe {
    677
                Sse2Backend::sin(&a, &mut sin_result);
    678
                Sse2Backend::cos(&a, &mut cos_result);
    679
            }
    680
            assert!((sin_result[0]).abs() < 1e-5);
    681
            assert!((sin_result[1] - 1.0).abs() < 1e-5);
    682
            assert!((cos_result[0] - 1.0).abs() < 1e-5);
    683
        }
    684
    685
        #[test]
    686
        fn test_sse2_rounding() {
    687
            let a = vec![1.3, 1.5, 1.7, -1.3, -1.5, -1.7];
    688
            let mut floor_result = vec![0.0; 6];
    689
            let mut ceil_result = vec![0.0; 6];
    690
            unsafe {
    691
                Sse2Backend::floor(&a, &mut floor_result);
    692
                Sse2Backend::ceil(&a, &mut ceil_result);
    693
            }
    694
            assert_eq!(floor_result, vec![1.0, 1.0, 1.0, -2.0, -2.0, -2.0]);
    695
            assert_eq!(ceil_result, vec![2.0, 2.0, 2.0, -1.0, -1.0, -1.0]);
    696
        }
    697
    }