Skip to content

Commit 376957a

Browse files
committed
Move integer functions to traits.
1 parent 9718639 commit 376957a

File tree

8 files changed

+413
-340
lines changed

8 files changed

+413
-340
lines changed

crates/core_simd/src/elements.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod int;
2+
mod uint;
3+
4+
pub use int::*;
5+
pub use uint::*;

crates/core_simd/src/elements/int.rs

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
use crate::simd::{
2+
intrinsics, LaneCount, Mask, Simd, SimdElement, SimdPartialOrd, SupportedLaneCount,
3+
};
4+
5+
/// Operations on SIMD vectors of signed integers.
6+
pub trait SimdInt: Sized {
7+
/// Mask type used for manipulating this SIMD vector type.
8+
type Mask;
9+
10+
/// Scalar type contained by this SIMD vector type.
11+
type Scalar;
12+
13+
/// Lanewise saturating add.
14+
///
15+
/// # Examples
16+
/// ```
17+
/// # #![feature(portable_simd)]
18+
/// # use core::simd::Simd;
19+
/// use core::i32::{MIN, MAX};
20+
/// let x = Simd::from_array([MIN, 0, 1, MAX]);
21+
/// let max = Simd::splat(MAX);
22+
/// let unsat = x + max;
23+
/// let sat = x.saturating_add(max);
24+
/// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
25+
/// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
26+
/// ```
27+
fn saturating_add(self, second: Self) -> Self;
28+
29+
/// Lanewise saturating subtract.
30+
///
31+
/// # Examples
32+
/// ```
33+
/// # #![feature(portable_simd)]
34+
/// # use core::simd::Simd;
35+
/// use core::i32::{MIN, MAX};
36+
/// let x = Simd::from_array([MIN, -2, -1, MAX]);
37+
/// let max = Simd::splat(MAX);
38+
/// let unsat = x - max;
39+
/// let sat = x.saturating_sub(max);
40+
/// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
41+
/// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
42+
fn saturating_sub(self, second: Self) -> Self;
43+
44+
/// Lanewise absolute value, implemented in Rust.
45+
/// Every lane becomes its absolute value.
46+
///
47+
/// # Examples
48+
/// ```
49+
/// # #![feature(portable_simd)]
50+
/// # use core::simd::Simd;
51+
/// use core::i32::{MIN, MAX};
52+
/// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
53+
/// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
54+
/// ```
55+
fn abs(self) -> Self;
56+
57+
/// Lanewise saturating absolute value, implemented in Rust.
58+
/// As abs(), except the MIN value becomes MAX instead of itself.
59+
///
60+
/// # Examples
61+
/// ```
62+
/// # #![feature(portable_simd)]
63+
/// # use core::simd::Simd;
64+
/// use core::i32::{MIN, MAX};
65+
/// let xs = Simd::from_array([MIN, -2, 0, 3]);
66+
/// let unsat = xs.abs();
67+
/// let sat = xs.saturating_abs();
68+
/// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
69+
/// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
70+
/// ```
71+
fn saturating_abs(self) -> Self;
72+
73+
/// Lanewise saturating negation, implemented in Rust.
74+
/// As neg(), except the MIN value becomes MAX instead of itself.
75+
///
76+
/// # Examples
77+
/// ```
78+
/// # #![feature(portable_simd)]
79+
/// # use core::simd::Simd;
80+
/// use core::i32::{MIN, MAX};
81+
/// let x = Simd::from_array([MIN, -2, 3, MAX]);
82+
/// let unsat = -x;
83+
/// let sat = x.saturating_neg();
84+
/// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
85+
/// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
86+
/// ```
87+
fn saturating_neg(self) -> Self;
88+
89+
/// Returns true for each positive lane and false if it is zero or negative.
90+
fn is_positive(self) -> Self::Mask;
91+
92+
/// Returns true for each negative lane and false if it is zero or positive.
93+
fn is_negative(self) -> Self::Mask;
94+
95+
/// Returns numbers representing the sign of each lane.
96+
/// * `0` if the number is zero
97+
/// * `1` if the number is positive
98+
/// * `-1` if the number is negative
99+
fn signum(self) -> Self;
100+
101+
/// Returns the sum of the lanes of the vector, with wrapping addition.
102+
///
103+
/// # Examples
104+
///
105+
/// ```
106+
/// # #![feature(portable_simd)]
107+
/// # use core::simd::i32x4;
108+
/// let v = i32x4::from_array([1, 2, 3, 4]);
109+
/// assert_eq!(v.reduce_sum(), 10);
110+
///
111+
/// // SIMD integer addition is always wrapping
112+
/// let v = i32x4::from_array([i32::MAX, 1, 0, 0]);
113+
/// assert_eq!(v.reduce_sum(), i32::MIN);
114+
/// ```
115+
fn reduce_sum(self) -> Self::Scalar;
116+
117+
/// Returns the product of the lanes of the vector, with wrapping multiplication.
118+
///
119+
/// # Examples
120+
///
121+
/// ```
122+
/// # #![feature(portable_simd)]
123+
/// # use core::simd::i32x4;
124+
/// let v = i32x4::from_array([1, 2, 3, 4]);
125+
/// assert_eq!(v.reduce_product(), 24);
126+
///
127+
/// // SIMD integer multiplication is always wrapping
128+
/// let v = i32x4::from_array([i32::MAX, 2, 1, 1]);
129+
/// assert!(v.reduce_product() < i32::MAX);
130+
/// ```
131+
fn reduce_product(self) -> Self::Scalar;
132+
133+
/// Returns the maximum lane in the vector.
134+
///
135+
/// # Examples
136+
///
137+
/// ```
138+
/// # #![feature(portable_simd)]
139+
/// # use core::simd::i32x4;
140+
/// let v = i32x4::from_array([1, 2, 3, 4]);
141+
/// assert_eq!(v.reduce_max(), 4);
142+
/// ```
143+
fn reduce_max(self) -> Self::Scalar;
144+
145+
/// Returns the minimum lane in the vector.
146+
///
147+
/// # Examples
148+
///
149+
/// ```
150+
/// # #![feature(portable_simd)]
151+
/// # use core::simd::i32x4;
152+
/// let v = i32x4::from_array([1, 2, 3, 4]);
153+
/// assert_eq!(v.reduce_min(), 1);
154+
/// ```
155+
fn reduce_min(self) -> Self::Scalar;
156+
157+
/// Returns the cumulative bitwise "and" across the lanes of the vector.
158+
fn reduce_and(self) -> Self::Scalar;
159+
160+
/// Returns the cumulative bitwise "or" across the lanes of the vector.
161+
fn reduce_or(self) -> Self::Scalar;
162+
163+
/// Returns the cumulative bitwise "xor" across the lanes of the vector.
164+
fn reduce_xor(self) -> Self::Scalar;
165+
}
166+
167+
macro_rules! impl_trait {
168+
{ $($ty:ty),* } => {
169+
$(
170+
impl<const LANES: usize> SimdInt for Simd<$ty, LANES>
171+
where
172+
LaneCount<LANES>: SupportedLaneCount,
173+
{
174+
type Mask = Mask<<$ty as SimdElement>::Mask, LANES>;
175+
type Scalar = $ty;
176+
177+
#[inline]
178+
fn saturating_add(self, second: Self) -> Self {
179+
// Safety: `self` is a vector
180+
unsafe { intrinsics::simd_saturating_add(self, second) }
181+
}
182+
183+
#[inline]
184+
fn saturating_sub(self, second: Self) -> Self {
185+
// Safety: `self` is a vector
186+
unsafe { intrinsics::simd_saturating_sub(self, second) }
187+
}
188+
189+
#[inline]
190+
fn abs(self) -> Self {
191+
const SHR: $ty = <$ty>::BITS as $ty - 1;
192+
let m = self >> Simd::splat(SHR);
193+
(self^m) - m
194+
}
195+
196+
#[inline]
197+
fn saturating_abs(self) -> Self {
198+
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement
199+
const SHR: $ty = <$ty>::BITS as $ty - 1;
200+
let m = self >> Simd::splat(SHR);
201+
(self^m).saturating_sub(m)
202+
}
203+
204+
#[inline]
205+
fn saturating_neg(self) -> Self {
206+
Self::splat(0).saturating_sub(self)
207+
}
208+
209+
#[inline]
210+
fn is_positive(self) -> Self::Mask {
211+
self.simd_gt(Self::splat(0))
212+
}
213+
214+
#[inline]
215+
fn is_negative(self) -> Self::Mask {
216+
self.simd_lt(Self::splat(0))
217+
}
218+
219+
#[inline]
220+
fn signum(self) -> Self {
221+
self.is_positive().select(
222+
Self::splat(1),
223+
self.is_negative().select(Self::splat(-1), Self::splat(0))
224+
)
225+
}
226+
227+
#[inline]
228+
fn reduce_sum(self) -> Self::Scalar {
229+
// Safety: `self` is an integer vector
230+
unsafe { intrinsics::simd_reduce_add_ordered(self, 0) }
231+
}
232+
233+
#[inline]
234+
fn reduce_product(self) -> Self::Scalar {
235+
// Safety: `self` is an integer vector
236+
unsafe { intrinsics::simd_reduce_mul_ordered(self, 1) }
237+
}
238+
239+
#[inline]
240+
fn reduce_max(self) -> Self::Scalar {
241+
// Safety: `self` is an integer vector
242+
unsafe { intrinsics::simd_reduce_max(self) }
243+
}
244+
245+
#[inline]
246+
fn reduce_min(self) -> Self::Scalar {
247+
// Safety: `self` is an integer vector
248+
unsafe { intrinsics::simd_reduce_min(self) }
249+
}
250+
251+
#[inline]
252+
fn reduce_and(self) -> Self::Scalar {
253+
// Safety: `self` is an integer vector
254+
unsafe { intrinsics::simd_reduce_and(self) }
255+
}
256+
257+
#[inline]
258+
fn reduce_or(self) -> Self::Scalar {
259+
// Safety: `self` is an integer vector
260+
unsafe { intrinsics::simd_reduce_or(self) }
261+
}
262+
263+
#[inline]
264+
fn reduce_xor(self) -> Self::Scalar {
265+
// Safety: `self` is an integer vector
266+
unsafe { intrinsics::simd_reduce_xor(self) }
267+
}
268+
}
269+
)*
270+
}
271+
}
272+
273+
impl_trait! { i8, i16, i32, i64, isize }

0 commit comments

Comments
 (0)