Skip to content

Commit

Permalink
Implement __bswap[sdt]i2 intrinsics
Browse files Browse the repository at this point in the history
These can be emitted by gcc, at least if requested specifically via __builtin_bswap{32,64,128}.
  • Loading branch information
tea committed Jun 25, 2024
1 parent 0ccc1bf commit 6ea6820
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ rely on CI.
- [ ] arm/unordsf2vfp.S
- [x] ashldi3.c
- [x] ashrdi3.c
- [x] bswapdi2.c
- [x] bswapsi2.c
- [x] bswapti2.c
- [x] comparedf2.c
- [x] comparesf2.c
- [x] divdf3.c
Expand Down
3 changes: 3 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ fn configure_check_cfg() {
"__ashlsi3",
"__ashrdi3",
"__ashrsi3",
"__bswapsi2",
"__bswapdi2",
"__bswapti2",
"__clzsi2",
"__divdi3",
"__divsi3",
Expand Down
32 changes: 32 additions & 0 deletions src/int/bswap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::int::Int;

fn bswap<I: Int + From<u8>>(x: I) -> I {
let mut ret = I::ZERO;
for (i, byte) in x.to_be_bytes().into_iter().enumerate() {
ret |= I::from(byte) << (i as u32 * 8);
}
ret
}

intrinsics! {
#[maybe_use_optimized_c_shim]
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
/// Swaps bytes in 32-bit number
pub extern "C" fn __bswapsi2(x: u32) -> u32 {
bswap(x)
}

#[maybe_use_optimized_c_shim]
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
/// Swaps bytes in 64-bit number
pub extern "C" fn __bswapdi2(x: u64) -> u64 {
bswap(x)
}

#[maybe_use_optimized_c_shim]
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
/// Swaps bytes in 128-bit number
pub extern "C" fn __bswapti2(x: u128) -> u128 {
bswap(x)
}
}
11 changes: 11 additions & 0 deletions src/int/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod specialized_div_rem;

pub mod addsub;
mod big;
pub mod bswap;
pub mod leading_zeros;
pub mod mul;
pub mod sdiv;
Expand Down Expand Up @@ -62,6 +63,8 @@ pub(crate) trait Int: MinInt
+ ops::BitXor<Output = Self>
+ ops::BitAnd<Output = Self>
{
type Bytes: IntoIterator<Item = u8>;

/// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing
/// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111,
/// 112,119,120,125,126,127].
Expand Down Expand Up @@ -103,6 +106,8 @@ pub(crate) trait Int: MinInt
fn overflowing_add(self, other: Self) -> (Self, bool);
fn leading_zeros(self) -> u32;
fn ilog2(self) -> u32;

fn to_be_bytes(self) -> Self::Bytes;
}
}

Expand Down Expand Up @@ -154,6 +159,8 @@ pub(crate) const fn make_fuzz_lengths(bits: u32) -> [u8; 20] {

macro_rules! int_impl_common {
($ty:ty) => {
type Bytes = [u8; Self::BITS as usize / 8];

fn from_bool(b: bool) -> Self {
b as $ty
}
Expand Down Expand Up @@ -205,6 +212,10 @@ macro_rules! int_impl_common {
fn ilog2(self) -> u32 {
<Self>::ilog2(self)
}

fn to_be_bytes(self) -> Self::Bytes {
self.to_be_bytes()
}
};
}

Expand Down
28 changes: 28 additions & 0 deletions testcrate/tests/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,34 @@ fn leading_zeros() {
})
}

#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
#[test]
fn bswap() {
use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2, __bswapti2};
fuzz(N, |x: u32| {
assert_eq!(x.swap_bytes(), __bswapsi2(x));
});
fuzz(N, |x: u64| {
assert_eq!(x.swap_bytes(), __bswapdi2(x));
});
fuzz(N, |x: u128| {
assert_eq!(x.swap_bytes(), __bswapti2(x));
});

assert_eq!(__bswapsi2(0x12345678u32), 0x78563412u32);
assert_eq!(__bswapsi2(0x00000001u32), 0x01000000u32);
assert_eq!(__bswapdi2(0x123456789ABCDEF0u64), 0xF0DEBC9A78563412u64);
assert_eq!(__bswapdi2(0x0200000001000000u64), 0x0000000100000002u64);
assert_eq!(
__bswapti2(0x123456789ABCDEF013579BDF02468ACEu128),
0xCE8A4602DF9B5713F0DEBC9A78563412u128
);
assert_eq!(
__bswapti2(0x04000000030000000200000001000000u128),
0x00000001000000020000000300000004u128
);
}

// This is approximate because of issues related to
// https://github.com/rust-lang/rust/issues/73920.
// TODO how do we resolve this indeterminacy?
Expand Down

0 comments on commit 6ea6820

Please sign in to comment.