1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use core::fmt::Debug;
use core::ops::*;
mod io;
mod iters;
pub use iters::*;
mod transmute;
pub use transmute::*;
mod specializations;
pub use specializations::*;
pub use io::SimdBaseIo;
use crate::Simd;
pub trait SimdConsts: 'static + Copy + core::marker::Sync + core::marker::Send + Debug {
type Scalar: Copy + Debug + core::marker::Sync + core::marker::Send;
type HorizontalAddScalar: Copy + Debug + core::marker::Sync + core::marker::Send;
const WIDTH: usize;
/// The type of the transmuted array representation. This is to make indexing operations easier.
/// We are unable to use `&[Self::Scalar; Self::WIDTH]` because constants are not allowed.
type ArrayRepresentation: Index<usize, Output = Self::Scalar> + IndexMut<usize> + Clone;
/// The underlying intrinsic SIMD type.
type UnderlyingType: Copy + Debug + core::marker::Sync + core::marker::Send;
type Engine: Simd;
}
/// Operations shared by all SIMD types
pub trait SimdBaseOps:
SimdConsts
+ SimdBaseIo
+ IndexMut<usize>
+ Index<usize, Output = <Self as SimdConsts>::Scalar>
+ Add<Self, Output = Self>
+ Add<<Self as SimdConsts>::Scalar, Output = Self>
+ AddAssign<Self>
+ AddAssign<<Self as SimdConsts>::Scalar>
+ Neg<Output = Self>
+ Sub<Self, Output = Self>
+ Sub<<Self as SimdConsts>::Scalar, Output = Self>
+ SubAssign<Self>
+ SubAssign<<Self as SimdConsts>::Scalar>
+ Mul<Self, Output = Self>
+ Mul<<Self as SimdConsts>::Scalar, Output = Self>
+ MulAssign<Self>
+ MulAssign<<Self as SimdConsts>::Scalar>
+ BitAnd<Self, Output = Self>
+ BitAnd<<Self as SimdConsts>::Scalar, Output = Self>
+ BitAndAssign<Self>
+ BitAndAssign<<Self as SimdConsts>::Scalar>
+ BitOr<Self, Output = Self>
+ BitOr<<Self as SimdConsts>::Scalar, Output = Self>
+ BitOrAssign<Self>
+ BitOrAssign<<Self as SimdConsts>::Scalar>
+ BitXor<Self, Output = Self>
+ BitXor<<Self as SimdConsts>::Scalar, Output = Self>
+ BitXorAssign<Self>
+ BitXorAssign<<Self as SimdConsts>::Scalar>
+ Not<Output = Self>
{
/// Element-wise add between two vectors
fn add(self, rhs: Self) -> Self;
/// Element-wise subtract between two vectors
fn sub(self, rhs: Self) -> Self;
/// Element-wise multiply between two vectors
fn mul(self, rhs: Self) -> Self;
/// Element-wise negative of all elements
fn neg(self) -> Self {
Self::zeroes() - self
}
/// Binary and between two vectors
fn bit_and(self, rhs: Self) -> Self;
/// Binary or between two vectors
fn bit_or(self, rhs: Self) -> Self;
/// Binary xor between two vectors
fn bit_xor(self, rhs: Self) -> Self;
/// Binary not operation for a vector
fn bit_not(self) -> Self;
/// Element-wise absolute value.
///
/// For signed integer vectors this uses wrapping semantics, matching SIMD hardware
/// behavior: `abs(MIN)` returns `MIN`.
fn abs(self) -> Self;
/// Binary and not between two vectors `self & (!rhs)`
fn and_not(self, rhs: Self) -> Self;
/// Element-wise "blend" between two vectors. A is selected if the mask value
/// is zero, and B is selected if the mask value is all 1's. undefined behavior if
/// it's anything in between. See note below.
///
/// Note: SSE2 will select B only when all bits are 1, while SSE41 and AVX2 only
/// check the high bit. To maintain portability ensure all bits are 1 when using
/// blend. Results of comparison operations adhere to this.
fn blendv(self, a: Self, b: Self) -> Self;
/// Element-wise equality between two vectors. If two elements are equal, it returns all 1's
/// in the corresponding element of the result, otherwise it returns all 0's.
fn cmp_eq(self, rhs: Self) -> Self;
/// Element-wise inequality between two vectors. If two elements are not equal, it returns all 1's
/// in the corresponding element of the result, otherwise it returns all 0's.
fn cmp_neq(self, rhs: Self) -> Self;
/// Element-wise less than between two vectors. If the first element is less than the second element,
/// it returns all 1's in the corresponding element of the result, otherwise it returns all 0's.
fn cmp_lt(self, rhs: Self) -> Self;
/// Element-wise less than or equal to between two vectors. If the first element is less than or equal to the second element,
/// it returns all 1's in the corresponding element of the result, otherwise it returns all 0's.
fn cmp_lte(self, rhs: Self) -> Self;
/// Element-wise greater than between two vectors. If the first element is greater than the second element,
/// it returns all 1's in the corresponding element of the result, otherwise it returns all 0's.
fn cmp_gt(self, rhs: Self) -> Self;
/// Element-wise greater than or equal to between two vectors. If the first element is greater than or equal to the second element,
/// it returns all 1's in the corresponding element of the result, otherwise it returns all 0's.
fn cmp_gte(self, rhs: Self) -> Self;
/// Element-wise maximum between two vectors.
///
/// For floating-point vectors this follows backend SIMD `max` instruction behavior,
/// not Rust's scalar `f32::max`/`f64::max` contract.
///
/// - ordered, non-equal inputs: returns the mathematically larger lane
/// - unordered (`NaN`) or equal-tie (`+0.0` vs `-0.0`) inputs: backend dependent
/// (e.g. x86-style backends select `rhs`, while others may propagate `NaN`)
fn max(self, rhs: Self) -> Self;
/// Element-wise minimum between two vectors.
///
/// For floating-point vectors this follows backend SIMD `min` instruction behavior,
/// not Rust's scalar `f32::min`/`f64::min` contract.
///
/// - ordered, non-equal inputs: returns the mathematically smaller lane
/// - unordered (`NaN`) or equal-tie (`+0.0` vs `-0.0`) inputs: backend dependent
/// (e.g. x86-style backends select `rhs`, while others may propagate `NaN`)
fn min(self, rhs: Self) -> Self;
/// Add every number in the vector together
fn horizontal_add(self) -> Self::HorizontalAddScalar;
}
pub trait SimdBase: SimdBaseOps + SimdBaseIo + SimdIter {}
impl<T: SimdBaseOps + SimdBaseIo + SimdIter> SimdBase for T {}