Skip to content

Commit ee8c62f

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 ee8c62f

File tree

5 files changed

+83
-0
lines changed

5 files changed

+83
-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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
#[avr_skip]
14+
/// Swaps bytes in 32-bit number
15+
pub extern "C" fn __bswapsi2(x: u32) -> u32 {
16+
bswap(x)
17+
}
18+
19+
#[maybe_use_optimized_c_shim]
20+
#[avr_skip]
21+
/// Swaps bytes in 64-bit number
22+
pub extern "C" fn __bswapdi2(x: u64) -> u64 {
23+
bswap(x)
24+
}
25+
26+
#[maybe_use_optimized_c_shim]
27+
#[avr_skip]
28+
/// Swaps bytes in 128-bit number
29+
pub extern "C" fn __bswapti2(x: u128) -> u128 {
30+
bswap(x)
31+
}
32+
}

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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,40 @@ fn leading_zeros() {
9292
})
9393
}
9494

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

0 commit comments

Comments
 (0)