Skip to main content

angle_sc/
simd.rs

1// Copyright (c) 2026 Ken Barker
2
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation the
6// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7// sell copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21//! The `simd` module contains functions for performing simd vector
22//! calculations on the `x86` and `x86_64` processor architectures.
23
24#[cfg(target_arch = "x86")]
25use core::arch::x86::{__m128d, _mm_cvtsd_f64, _mm_dp_pd, _mm_set_pd};
26#[cfg(target_arch = "x86_64")]
27use core::arch::x86_64::{__m128d, _mm_cvtsd_f64, _mm_dp_pd, _mm_set_pd};
28
29/// 2D vector double dot product function: a . b.
30///
31/// * `a`, `b` the __m128d double vectors.
32///
33/// * returns the 2D dot product of the vector double values.
34///
35/// # Safety
36///
37/// Requires SIMD Extensions SSE4.2 on the target processor.
38#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
39#[target_feature(enable = "sse4.2")]
40#[inline]
41#[must_use]
42pub unsafe fn dot2d(a: __m128d, b: __m128d) -> f64 {
43    let c = _mm_dp_pd(a, b, 0x33);
44    _mm_cvtsd_f64(c)
45}
46
47/// 2D vector double dot product function: a . b.
48///
49/// * `a_0`, `a_1` the first vector values.
50/// * `b_0`, `b_1` the second vector values.
51///
52/// * returns the 2D dot product of the vector double values.
53///
54/// # Safety
55///
56/// Requires SIMD Extensions SSE4.2 on the target processor.
57#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
58#[target_feature(enable = "sse4.2")]
59#[inline]
60#[must_use]
61pub unsafe fn dot_product(a_0: f64, a_1: f64, b_0: f64, b_1: f64) -> f64 {
62    unsafe { dot2d(_mm_set_pd(a_1, a_0), _mm_set_pd(b_1, b_0)) }
63}
64
65/// 2D vector double perp product function: a x b.
66///
67/// * `a_0`, `a_1` the first vector values.
68/// * `b_0`, `b_1` the second vector values.
69///
70/// * returns the 2D perp product of the vector double values.
71///
72/// # Safety
73///
74/// Requires SIMD Extensions SSE4.2 on the target processor.
75#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
76#[target_feature(enable = "sse4.2")]
77#[inline]
78#[must_use]
79pub unsafe fn perp_product(a_0: f64, a_1: f64, b_0: f64, b_1: f64) -> f64 {
80    unsafe { dot2d(_mm_set_pd(a_1, a_0), _mm_set_pd(-b_0, b_1)) }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_dot_product() {
89        unsafe {
90            assert_eq!(1.0, dot_product(1.0, 0.0, 1.0, 0.0));
91            assert_eq!(0.0, dot_product(1.0, 0.0, 0.0, 1.0));
92            assert_eq!(0.0, dot_product(0.0, 1.0, 1.0, 0.0));
93        }
94    }
95
96    #[test]
97    fn test_perp_product() {
98        unsafe {
99            assert_eq!(0.0, perp_product(1.0, 0.0, 1.0, 0.0));
100            assert_eq!(1.0, perp_product(1.0, 0.0, 0.0, 1.0));
101            assert_eq!(-1.0, perp_product(0.0, 1.0, 1.0, 0.0));
102        }
103    }
104}