Skip to content

Commit 81ce43b

Browse files
committed
Implement __bswap[sdt]i2 intrinsics
These can be emitted by gcc, at least if requested specifically via __builtin_bswap{32,64,128}.
1 parent 0ccc1bf commit 81ce43b

File tree

5 files changed

+80
-0
lines changed

5 files changed

+80
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ rely on CI.
154154
- [ ] arm/unordsf2vfp.S
155155
- [x] ashldi3.c
156156
- [x] ashrdi3.c
157+
- [x] bswapdi2.c
158+
- [x] bswapsi2.c
159+
- [x] bswapti2.c
157160
- [x] comparedf2.c
158161
- [x] comparesf2.c
159162
- [x] divdf3.c

build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ fn configure_check_cfg() {
161161
"__ashlsi3",
162162
"__ashrdi3",
163163
"__ashrsi3",
164+
"__bswapsi2",
165+
"__bswapdi2",
166+
"__bswapti2",
164167
"__clzsi2",
165168
"__divdi3",
166169
"__divsi3",

src/int/bswap.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use crate::int::Int;
2+
3+
fn bswap<I: Int + From<u8>>(x: I) -> I {
4+
let mut ret = I::ZERO;
5+
for (i, byte) in x.to_be_bytes().into_iter().enumerate() {
6+
ret |= I::from(byte) << (i as u32 * 8);
7+
}
8+
ret
9+
}
10+
11+
intrinsics! {
12+
#[maybe_use_optimized_c_shim]
13+
/// Swaps bytes in 32-bit number
14+
pub extern "C" fn __bswapsi2(x: u32) -> u32 {
15+
bswap(x)
16+
}
17+
18+
#[maybe_use_optimized_c_shim]
19+
/// Swaps bytes in 64-bit number
20+
pub extern "C" fn __bswapdi2(x: u64) -> u64 {
21+
bswap(x)
22+
}
23+
24+
#[maybe_use_optimized_c_shim]
25+
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
26+
/// Swaps bytes in 128-bit number
27+
pub extern "C" fn __bswapti2(x: u128) -> u128 {
28+
bswap(x)
29+
}
30+
}

src/int/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod specialized_div_rem;
44

55
pub mod addsub;
66
mod big;
7+
pub mod bswap;
78
pub mod leading_zeros;
89
pub mod mul;
910
pub mod sdiv;
@@ -62,6 +63,8 @@ pub(crate) trait Int: MinInt
6263
+ ops::BitXor<Output = Self>
6364
+ ops::BitAnd<Output = Self>
6465
{
66+
type Bytes: IntoIterator<Item = u8>;
67+
6568
/// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing
6669
/// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111,
6770
/// 112,119,120,125,126,127].
@@ -103,6 +106,8 @@ pub(crate) trait Int: MinInt
103106
fn overflowing_add(self, other: Self) -> (Self, bool);
104107
fn leading_zeros(self) -> u32;
105108
fn ilog2(self) -> u32;
109+
110+
fn to_be_bytes(self) -> Self::Bytes;
106111
}
107112
}
108113

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

155160
macro_rules! int_impl_common {
156161
($ty:ty) => {
162+
type Bytes = [u8; Self::BITS as usize / 8];
163+
157164
fn from_bool(b: bool) -> Self {
158165
b as $ty
159166
}
@@ -205,6 +212,10 @@ macro_rules! int_impl_common {
205212
fn ilog2(self) -> u32 {
206213
<Self>::ilog2(self)
207214
}
215+
216+
fn to_be_bytes(self) -> Self::Bytes {
217+
self.to_be_bytes()
218+
}
208219
};
209220
}
210221

testcrate/tests/misc.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,39 @@ fn leading_zeros() {
9292
})
9393
}
9494

95+
#[test]
96+
fn bswap() {
97+
use compiler_builtins::int::bswap::{__bswapdi2, __bswapsi2};
98+
fuzz(N, |x: u32| {
99+
assert_eq!(x.swap_bytes(), __bswapsi2(x));
100+
});
101+
fuzz(N, |x: u64| {
102+
assert_eq!(x.swap_bytes(), __bswapdi2(x));
103+
});
104+
105+
assert_eq!(__bswapsi2(0x12345678u32), 0x78563412u32);
106+
assert_eq!(__bswapsi2(0x00000001u32), 0x01000000u32);
107+
assert_eq!(__bswapdi2(0x123456789ABCDEF0u64), 0xF0DEBC9A78563412u64);
108+
assert_eq!(__bswapdi2(0x0200000001000000u64), 0x0000000100000002u64);
109+
110+
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
111+
{
112+
use compiler_builtins::int::bswap::__bswapti2;
113+
fuzz(N, |x: u128| {
114+
assert_eq!(x.swap_bytes(), __bswapti2(x));
115+
});
116+
117+
assert_eq!(
118+
__bswapti2(0x123456789ABCDEF013579BDF02468ACEu128),
119+
0xCE8A4602DF9B5713F0DEBC9A78563412u128
120+
);
121+
assert_eq!(
122+
__bswapti2(0x04000000030000000200000001000000u128),
123+
0x00000001000000020000000300000004u128
124+
);
125+
}
126+
}
127+
95128
// This is approximate because of issues related to
96129
// https://github.com/rust-lang/rust/issues/73920.
97130
// TODO how do we resolve this indeterminacy?

0 commit comments

Comments
 (0)