Skip to content

Commit 8101074

Browse files
committed
Add various integer ops
1 parent 490b5cf commit 8101074

File tree

6 files changed

+220
-6
lines changed

6 files changed

+220
-6
lines changed

crates/core_simd/src/elements/int.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,29 @@ pub trait SimdInt: Copy + Sealed {
191191

192192
/// Returns the cumulative bitwise "xor" across the lanes of the vector.
193193
fn reduce_xor(self) -> Self::Scalar;
194+
195+
/// Reverses the byte order of each element.
196+
fn swap_bytes(self) -> Self;
197+
198+
/// Reverses the order of bits in each elemnent.
199+
/// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
200+
fn reverse_bits(self) -> Self;
201+
202+
/// Returns the number of leading zeros in the binary representation of each element.
203+
fn leading_zeros(self) -> Self;
204+
205+
/// Returns the number of trailing zeros in the binary representation of each element.
206+
fn trailing_zeros(self) -> Self;
207+
208+
/// Returns the number of leading ones in the binary representation of each element.
209+
fn leading_ones(self) -> Self;
210+
211+
/// Returns the number of trailing ones in the binary representation of each element.
212+
fn trailing_ones(self) -> Self;
194213
}
195214

196215
macro_rules! impl_trait {
197-
{ $($ty:ty),* } => {
216+
{ $($ty:ident ($unsigned:ident)),* } => {
198217
$(
199218
impl<const LANES: usize> Sealed for Simd<$ty, LANES>
200219
where
@@ -307,9 +326,45 @@ macro_rules! impl_trait {
307326
// Safety: `self` is an integer vector
308327
unsafe { intrinsics::simd_reduce_xor(self) }
309328
}
329+
330+
#[inline]
331+
fn swap_bytes(self) -> Self {
332+
// Safety: `self` is an integer vector
333+
unsafe { intrinsics::simd_bswap(self) }
334+
}
335+
336+
#[inline]
337+
fn reverse_bits(self) -> Self {
338+
// Safety: `self` is an integer vector
339+
unsafe { intrinsics::simd_bitreverse(self) }
340+
}
341+
342+
#[inline]
343+
fn leading_zeros(self) -> Self {
344+
// Safety: `self` is an integer vector
345+
unsafe { intrinsics::simd_ctlz(self) }
346+
}
347+
348+
#[inline]
349+
fn trailing_zeros(self) -> Self {
350+
// Safety: `self` is an integer vector
351+
unsafe { intrinsics::simd_cttz(self) }
352+
}
353+
354+
#[inline]
355+
fn leading_ones(self) -> Self {
356+
use crate::simd::SimdUint;
357+
self.cast::<$unsigned>().leading_ones().cast()
358+
}
359+
360+
#[inline]
361+
fn trailing_ones(self) -> Self {
362+
use crate::simd::SimdUint;
363+
self.cast::<$unsigned>().trailing_ones().cast()
364+
}
310365
}
311366
)*
312367
}
313368
}
314369

315-
impl_trait! { i8, i16, i32, i64, isize }
370+
impl_trait! { i8 (u8), i16 (u16), i32 (u32), i64 (u64), isize (usize) }

crates/core_simd/src/elements/uint.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,25 @@ pub trait SimdUint: Copy + Sealed {
7171

7272
/// Returns the cumulative bitwise "xor" across the lanes of the vector.
7373
fn reduce_xor(self) -> Self::Scalar;
74+
75+
/// Reverses the byte order of each element.
76+
fn swap_bytes(self) -> Self;
77+
78+
/// Reverses the order of bits in each elemnent.
79+
/// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
80+
fn reverse_bits(self) -> Self;
81+
82+
/// Returns the number of leading zeros in the binary representation of each element.
83+
fn leading_zeros(self) -> Self;
84+
85+
/// Returns the number of trailing zeros in the binary representation of each element.
86+
fn trailing_zeros(self) -> Self;
87+
88+
/// Returns the number of leading ones in the binary representation of each element.
89+
fn leading_ones(self) -> Self;
90+
91+
/// Returns the number of trailing ones in the binary representation of each element.
92+
fn trailing_ones(self) -> Self;
7493
}
7594

7695
macro_rules! impl_trait {
@@ -148,6 +167,40 @@ macro_rules! impl_trait {
148167
// Safety: `self` is an integer vector
149168
unsafe { intrinsics::simd_reduce_xor(self) }
150169
}
170+
171+
#[inline]
172+
fn swap_bytes(self) -> Self {
173+
// Safety: `self` is an integer vector
174+
unsafe { intrinsics::simd_bswap(self) }
175+
}
176+
177+
#[inline]
178+
fn reverse_bits(self) -> Self {
179+
// Safety: `self` is an integer vector
180+
unsafe { intrinsics::simd_bitreverse(self) }
181+
}
182+
183+
#[inline]
184+
fn leading_zeros(self) -> Self {
185+
// Safety: `self` is an integer vector
186+
unsafe { intrinsics::simd_ctlz(self) }
187+
}
188+
189+
#[inline]
190+
fn trailing_zeros(self) -> Self {
191+
// Safety: `self` is an integer vector
192+
unsafe { intrinsics::simd_cttz(self) }
193+
}
194+
195+
#[inline]
196+
fn leading_ones(self) -> Self {
197+
(!self).leading_zeros()
198+
}
199+
200+
#[inline]
201+
fn trailing_ones(self) -> Self {
202+
(!self).trailing_zeros()
203+
}
151204
}
152205
)*
153206
}

crates/core_simd/src/intrinsics.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,10 @@ extern "platform-intrinsic" {
160160

161161
/// convert an exposed address back to a pointer
162162
pub(crate) fn simd_from_exposed_addr<T, U>(addr: T) -> U;
163+
164+
// Integer operations
165+
pub(crate) fn simd_bswap<T>(x: T) -> T;
166+
pub(crate) fn simd_bitreverse<T>(x: T) -> T;
167+
pub(crate) fn simd_ctlz<T>(x: T) -> T;
168+
pub(crate) fn simd_cttz<T>(x: T) -> T;
163169
}

crates/core_simd/src/to_bytes.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::simd::SimdUint;
2+
13
macro_rules! impl_to_bytes {
24
{ $ty:ty, $size:literal } => {
35
impl<const LANES: usize> crate::simd::Simd<$ty, LANES>
@@ -12,12 +14,54 @@ macro_rules! impl_to_bytes {
1214
unsafe { core::mem::transmute_copy(&self) }
1315
}
1416

17+
/// Return the memory representation of this integer as a byte array in big-endian
18+
/// (network) byte order.
19+
pub fn to_be_bytes(self) -> crate::simd::Simd<u8, {{ $size * LANES }}> {
20+
let bytes = self.to_ne_bytes();
21+
if cfg!(target_endian = "big") {
22+
bytes
23+
} else {
24+
bytes.swap_bytes()
25+
}
26+
}
27+
28+
/// Return the memory representation of this integer as a byte array in little-endian
29+
/// byte order.
30+
pub fn to_le_bytes(self) -> crate::simd::Simd<u8, {{ $size * LANES }}> {
31+
let bytes = self.to_ne_bytes();
32+
if cfg!(target_endian = "little") {
33+
bytes
34+
} else {
35+
bytes.swap_bytes()
36+
}
37+
}
38+
1539
/// Create a native endian integer value from its memory representation as a byte array
1640
/// in native endianness.
1741
pub fn from_ne_bytes(bytes: crate::simd::Simd<u8, {{ $size * LANES }}>) -> Self {
1842
// Safety: transmuting between vectors is safe
1943
unsafe { core::mem::transmute_copy(&bytes) }
2044
}
45+
46+
/// Create an integer value from its representation as a byte array in big endian.
47+
pub fn from_be_bytes(bytes: crate::simd::Simd<u8, {{ $size * LANES }}>) -> Self {
48+
let bytes = if cfg!(target_endian = "big") {
49+
bytes
50+
} else {
51+
bytes.swap_bytes()
52+
};
53+
Self::from_ne_bytes(bytes)
54+
}
55+
56+
/// Create an integer value from its representation as a byte array in little endian.
57+
pub fn from_le_bytes(bytes: crate::simd::Simd<u8, {{ $size * LANES }}>) -> Self {
58+
let bytes = if cfg!(target_endian = "little") {
59+
bytes
60+
} else {
61+
bytes.swap_bytes()
62+
};
63+
Self::from_ne_bytes(bytes)
64+
}
2165
}
2266
}
2367
}

crates/core_simd/tests/ops_macros.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,54 @@ macro_rules! impl_common_integer_tests {
193193
Ok(())
194194
});
195195
}
196+
197+
fn swap_bytes<const LANES: usize>() {
198+
test_helpers::test_unary_elementwise(
199+
&$vector::<LANES>::swap_bytes,
200+
&$scalar::swap_bytes,
201+
&|_| true,
202+
)
203+
}
204+
205+
fn reverse_bits<const LANES: usize>() {
206+
test_helpers::test_unary_elementwise(
207+
&$vector::<LANES>::reverse_bits,
208+
&$scalar::reverse_bits,
209+
&|_| true,
210+
)
211+
}
212+
213+
fn leading_zeros<const LANES: usize>() {
214+
test_helpers::test_unary_elementwise(
215+
&$vector::<LANES>::leading_zeros,
216+
&|x| x.leading_zeros() as $scalar,
217+
&|_| true,
218+
)
219+
}
220+
221+
fn trailing_zeros<const LANES: usize>() {
222+
test_helpers::test_unary_elementwise(
223+
&$vector::<LANES>::leading_zeros,
224+
&|x| x.trailing_zeros() as $scalar,
225+
&|_| true,
226+
)
227+
}
228+
229+
fn leading_ones<const LANES: usize>() {
230+
test_helpers::test_unary_elementwise(
231+
&$vector::<LANES>::leading_ones,
232+
&|x| x.leading_ones() as $scalar,
233+
&|_| true,
234+
)
235+
}
236+
237+
fn trailing_ones<const LANES: usize>() {
238+
test_helpers::test_unary_elementwise(
239+
&$vector::<LANES>::leading_ones,
240+
&|x| x.trailing_ones() as $scalar,
241+
&|_| true,
242+
)
243+
}
196244
}
197245
}
198246
}

crates/core_simd/tests/to_bytes.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@ use core_simd::simd::Simd;
77
#[test]
88
fn byte_convert() {
99
let int = Simd::<u32, 2>::from_array([0xdeadbeef, 0x8badf00d]);
10-
let bytes = int.to_ne_bytes();
11-
assert_eq!(int[0].to_ne_bytes(), bytes[..4]);
12-
assert_eq!(int[1].to_ne_bytes(), bytes[4..]);
13-
assert_eq!(Simd::<u32, 2>::from_ne_bytes(bytes), int);
10+
let ne_bytes = int.to_ne_bytes();
11+
let be_bytes = int.to_be_bytes();
12+
let le_bytes = int.to_le_bytes();
13+
assert_eq!(int[0].to_ne_bytes(), ne_bytes[..4]);
14+
assert_eq!(int[1].to_ne_bytes(), ne_bytes[4..]);
15+
assert_eq!(int[0].to_be_bytes(), be_bytes[..4]);
16+
assert_eq!(int[1].to_be_bytes(), be_bytes[4..]);
17+
assert_eq!(int[0].to_le_bytes(), le_bytes[..4]);
18+
assert_eq!(int[1].to_le_bytes(), le_bytes[4..]);
19+
assert_eq!(Simd::<u32, 2>::from_ne_bytes(ne_bytes), int);
20+
assert_eq!(Simd::<u32, 2>::from_be_bytes(be_bytes), int);
21+
assert_eq!(Simd::<u32, 2>::from_le_bytes(le_bytes), int);
1422
}

0 commit comments

Comments
 (0)