Skip to content

Commit fe77f5d

Browse files
authored
Rollup merge of rust-lang#48573 - Amanieu:bitreverse2, r=sfackler
Add functions for reversing the bit pattern in an integer I'm reviving PR rust-lang#32798 now that the LLVM issues have been resolved. > This adds the bitreverse intrinsic and adds a reverse_bits function to all integer types.
2 parents e3451f8 + 88aec91 commit fe77f5d

File tree

8 files changed

+120
-4
lines changed

8 files changed

+120
-4
lines changed

src/libcore/intrinsics.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,10 @@ extern "rust-intrinsic" {
12921292
/// Reverses the bytes in an integer type `T`.
12931293
pub fn bswap<T>(x: T) -> T;
12941294

1295+
/// Reverses the bits in an integer type `T`.
1296+
#[cfg(not(stage0))]
1297+
pub fn bitreverse<T>(x: T) -> T;
1298+
12951299
/// Performs checked integer addition.
12961300
/// The stabilized versions of this intrinsic are available on the integer
12971301
/// primitives via the `overflowing_add` method. For example,

src/libcore/num/mod.rs

+54
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,33 @@ $EndFeature, "
321321
(self as $UnsignedT).swap_bytes() as Self
322322
}
323323

324+
/// Reverses the bit pattern of the integer.
325+
///
326+
/// # Examples
327+
///
328+
/// Please note that this example is shared between integer types.
329+
/// Which explains why `i16` is used here.
330+
///
331+
/// Basic usage:
332+
///
333+
/// ```
334+
/// #![feature(reverse_bits)]
335+
///
336+
/// let n: i16 = 0b0000000_01010101;
337+
/// assert_eq!(n, 85);
338+
///
339+
/// let m = n.reverse_bits();
340+
///
341+
/// assert_eq!(m as u16, 0b10101010_00000000);
342+
/// assert_eq!(m, -22016);
343+
/// ```
344+
#[unstable(feature = "reverse_bits", issue = "48763")]
345+
#[cfg(not(stage0))]
346+
#[inline]
347+
pub fn reverse_bits(self) -> Self {
348+
(self as $UnsignedT).reverse_bits() as Self
349+
}
350+
324351
doc_comment! {
325352
concat!("Converts an integer from big endian to the target's endianness.
326353
@@ -1773,6 +1800,33 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
17731800
unsafe { intrinsics::bswap(self as $ActualT) as Self }
17741801
}
17751802

1803+
/// Reverses the bit pattern of the integer.
1804+
///
1805+
/// # Examples
1806+
///
1807+
/// Basic usage:
1808+
///
1809+
/// Please note that this example is shared between integer types.
1810+
/// Which explains why `u16` is used here.
1811+
///
1812+
/// ```
1813+
/// #![feature(reverse_bits)]
1814+
///
1815+
/// let n: u16 = 0b0000000_01010101;
1816+
/// assert_eq!(n, 85);
1817+
///
1818+
/// let m = n.reverse_bits();
1819+
///
1820+
/// assert_eq!(m, 0b10101010_00000000);
1821+
/// assert_eq!(m, 43520);
1822+
/// ```
1823+
#[unstable(feature = "reverse_bits", issue = "48763")]
1824+
#[cfg(not(stage0))]
1825+
#[inline]
1826+
pub fn reverse_bits(self) -> Self {
1827+
unsafe { intrinsics::bitreverse(self as $ActualT) as Self }
1828+
}
1829+
17761830
doc_comment! {
17771831
concat!("Converts an integer from big endian to the target's endianness.
17781832

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#![feature(try_trait)]
4747
#![feature(exact_chunks)]
4848
#![feature(atomic_nand)]
49+
#![feature(reverse_bits)]
4950

5051
extern crate core;
5152
extern crate test;

src/libcore/tests/num/uint_macros.rs

+11
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ mod tests {
9797
assert_eq!(_1.swap_bytes(), _1);
9898
}
9999

100+
#[test]
101+
fn test_reverse_bits() {
102+
assert_eq!(A.reverse_bits().reverse_bits(), A);
103+
assert_eq!(B.reverse_bits().reverse_bits(), B);
104+
assert_eq!(C.reverse_bits().reverse_bits(), C);
105+
106+
// Swapping these should make no difference
107+
assert_eq!(_0.reverse_bits(), _0);
108+
assert_eq!(_1.reverse_bits(), _1);
109+
}
110+
100111
#[test]
101112
fn test_le() {
102113
assert_eq!($T::from_le(A.to_le()), A);

src/librustc_trans/context.rs

+6
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,12 @@ fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option<ValueRef> {
597597
ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64);
598598
ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128);
599599

600+
ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8);
601+
ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16);
602+
ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32);
603+
ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64);
604+
ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128);
605+
600606
ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
601607
ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
602608
ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});

src/librustc_trans/intrinsic.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
287287
], None)
288288
},
289289
"ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
290-
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
291-
"overflowing_add" | "overflowing_sub" | "overflowing_mul" |
290+
"bitreverse" | "add_with_overflow" | "sub_with_overflow" |
291+
"mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
292292
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => {
293293
let ty = arg_tys[0];
294294
match int_type_width_signed(ty, cx) {
@@ -315,6 +315,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
315315
&[args[0].immediate()], None)
316316
}
317317
}
318+
"bitreverse" => {
319+
bx.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)),
320+
&[args[0].immediate()], None)
321+
}
318322
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
319323
let intrinsic = format!("llvm.{}{}.with.overflow.i{}",
320324
if signed { 's' } else { 'u' },

src/librustc_typeck/check/intrinsic.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
275275
"volatile_store" =>
276276
(1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()),
277277

278-
"ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap" =>
278+
"ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" |
279+
"bswap" | "bitreverse" =>
279280
(1, vec![param(0)], param(0)),
280281

281282
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" =>

src/test/run-pass/intrinsics-integer.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(intrinsics)]
11+
#![feature(intrinsics, i128_type)]
1212

1313
mod rusti {
1414
extern "rust-intrinsic" {
@@ -18,6 +18,7 @@ mod rusti {
1818
pub fn cttz<T>(x: T) -> T;
1919
pub fn cttz_nonzero<T>(x: T) -> T;
2020
pub fn bswap<T>(x: T) -> T;
21+
pub fn bitreverse<T>(x: T) -> T;
2122
}
2223
}
2324

@@ -29,106 +30,127 @@ pub fn main() {
2930
assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0);
3031
assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0);
3132
assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0);
33+
assert_eq!(ctpop(0u128), 0); assert_eq!(ctpop(0i128), 0);
3234

3335
assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1);
3436
assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1);
3537
assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1);
3638
assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1);
39+
assert_eq!(ctpop(1u128), 1); assert_eq!(ctpop(1i128), 1);
3740

3841
assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2);
3942
assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2);
4043
assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2);
4144
assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2);
45+
assert_eq!(ctpop(10u128), 2); assert_eq!(ctpop(10i128), 2);
4246

4347
assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3);
4448
assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3);
4549
assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3);
4650
assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3);
51+
assert_eq!(ctpop(100u128), 3); assert_eq!(ctpop(100i128), 3);
4752

4853
assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8);
4954
assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16);
5055
assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32);
5156
assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64);
57+
assert_eq!(ctpop(-1i128 as u128), 128); assert_eq!(ctpop(-1i128), 128);
5258

5359
assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8);
5460
assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16);
5561
assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32);
5662
assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64);
63+
assert_eq!(ctlz(0u128), 128); assert_eq!(ctlz(0i128), 128);
5764

5865
assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7);
5966
assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15);
6067
assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31);
6168
assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63);
69+
assert_eq!(ctlz(1u128), 127); assert_eq!(ctlz(1i128), 127);
6270

6371
assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4);
6472
assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12);
6573
assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28);
6674
assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60);
75+
assert_eq!(ctlz(10u128), 124); assert_eq!(ctlz(10i128), 124);
6776

6877
assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1);
6978
assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9);
7079
assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25);
7180
assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57);
81+
assert_eq!(ctlz(100u128), 121); assert_eq!(ctlz(100i128), 121);
7282

7383
assert_eq!(ctlz_nonzero(1u8), 7); assert_eq!(ctlz_nonzero(1i8), 7);
7484
assert_eq!(ctlz_nonzero(1u16), 15); assert_eq!(ctlz_nonzero(1i16), 15);
7585
assert_eq!(ctlz_nonzero(1u32), 31); assert_eq!(ctlz_nonzero(1i32), 31);
7686
assert_eq!(ctlz_nonzero(1u64), 63); assert_eq!(ctlz_nonzero(1i64), 63);
87+
assert_eq!(ctlz_nonzero(1u128), 127); assert_eq!(ctlz_nonzero(1i128), 127);
7788

7889
assert_eq!(ctlz_nonzero(10u8), 4); assert_eq!(ctlz_nonzero(10i8), 4);
7990
assert_eq!(ctlz_nonzero(10u16), 12); assert_eq!(ctlz_nonzero(10i16), 12);
8091
assert_eq!(ctlz_nonzero(10u32), 28); assert_eq!(ctlz_nonzero(10i32), 28);
8192
assert_eq!(ctlz_nonzero(10u64), 60); assert_eq!(ctlz_nonzero(10i64), 60);
93+
assert_eq!(ctlz_nonzero(10u128), 124); assert_eq!(ctlz_nonzero(10i128), 124);
8294

8395
assert_eq!(ctlz_nonzero(100u8), 1); assert_eq!(ctlz_nonzero(100i8), 1);
8496
assert_eq!(ctlz_nonzero(100u16), 9); assert_eq!(ctlz_nonzero(100i16), 9);
8597
assert_eq!(ctlz_nonzero(100u32), 25); assert_eq!(ctlz_nonzero(100i32), 25);
8698
assert_eq!(ctlz_nonzero(100u64), 57); assert_eq!(ctlz_nonzero(100i64), 57);
99+
assert_eq!(ctlz_nonzero(100u128), 121); assert_eq!(ctlz_nonzero(100i128), 121);
87100

88101
assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0);
89102
assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0);
90103
assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0);
91104
assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0);
105+
assert_eq!(cttz(-1i128 as u128), 0); assert_eq!(cttz(-1i128), 0);
92106

93107
assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8);
94108
assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16);
95109
assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32);
96110
assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64);
111+
assert_eq!(cttz(0u128), 128); assert_eq!(cttz(0i128), 128);
97112

98113
assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0);
99114
assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0);
100115
assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0);
101116
assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0);
117+
assert_eq!(cttz(1u128), 0); assert_eq!(cttz(1i128), 0);
102118

103119
assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1);
104120
assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1);
105121
assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1);
106122
assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1);
123+
assert_eq!(cttz(10u128), 1); assert_eq!(cttz(10i128), 1);
107124

108125
assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2);
109126
assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2);
110127
assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2);
111128
assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2);
129+
assert_eq!(cttz(100u128), 2); assert_eq!(cttz(100i128), 2);
112130

113131
assert_eq!(cttz_nonzero(-1i8 as u8), 0); assert_eq!(cttz_nonzero(-1i8), 0);
114132
assert_eq!(cttz_nonzero(-1i16 as u16), 0); assert_eq!(cttz_nonzero(-1i16), 0);
115133
assert_eq!(cttz_nonzero(-1i32 as u32), 0); assert_eq!(cttz_nonzero(-1i32), 0);
116134
assert_eq!(cttz_nonzero(-1i64 as u64), 0); assert_eq!(cttz_nonzero(-1i64), 0);
135+
assert_eq!(cttz_nonzero(-1i128 as u128), 0); assert_eq!(cttz_nonzero(-1i128), 0);
117136

118137
assert_eq!(cttz_nonzero(1u8), 0); assert_eq!(cttz_nonzero(1i8), 0);
119138
assert_eq!(cttz_nonzero(1u16), 0); assert_eq!(cttz_nonzero(1i16), 0);
120139
assert_eq!(cttz_nonzero(1u32), 0); assert_eq!(cttz_nonzero(1i32), 0);
121140
assert_eq!(cttz_nonzero(1u64), 0); assert_eq!(cttz_nonzero(1i64), 0);
141+
assert_eq!(cttz_nonzero(1u128), 0); assert_eq!(cttz_nonzero(1i128), 0);
122142

123143
assert_eq!(cttz_nonzero(10u8), 1); assert_eq!(cttz_nonzero(10i8), 1);
124144
assert_eq!(cttz_nonzero(10u16), 1); assert_eq!(cttz_nonzero(10i16), 1);
125145
assert_eq!(cttz_nonzero(10u32), 1); assert_eq!(cttz_nonzero(10i32), 1);
126146
assert_eq!(cttz_nonzero(10u64), 1); assert_eq!(cttz_nonzero(10i64), 1);
147+
assert_eq!(cttz_nonzero(10u128), 1); assert_eq!(cttz_nonzero(10i128), 1);
127148

128149
assert_eq!(cttz_nonzero(100u8), 2); assert_eq!(cttz_nonzero(100i8), 2);
129150
assert_eq!(cttz_nonzero(100u16), 2); assert_eq!(cttz_nonzero(100i16), 2);
130151
assert_eq!(cttz_nonzero(100u32), 2); assert_eq!(cttz_nonzero(100i32), 2);
131152
assert_eq!(cttz_nonzero(100u64), 2); assert_eq!(cttz_nonzero(100i64), 2);
153+
assert_eq!(cttz_nonzero(100u128), 2); assert_eq!(cttz_nonzero(100i128), 2);
132154

133155
assert_eq!(bswap(0x0Au8), 0x0A); // no-op
134156
assert_eq!(bswap(0x0Ai8), 0x0A); // no-op
@@ -138,5 +160,18 @@ pub fn main() {
138160
assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A);
139161
assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201);
140162
assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201);
163+
assert_eq!(bswap(0x0122334455667708u128), 0x08776655443322010000000000000000);
164+
assert_eq!(bswap(0x0122334455667708i128), 0x08776655443322010000000000000000);
165+
166+
assert_eq!(bitreverse(0x0Au8), 0x50);
167+
assert_eq!(bitreverse(0x0Ai8), 0x50);
168+
assert_eq!(bitreverse(0x0A0Cu16), 0x3050);
169+
assert_eq!(bitreverse(0x0A0Ci16), 0x3050);
170+
assert_eq!(bitreverse(0x0ABBCC0Eu32), 0x7033DD50);
171+
assert_eq!(bitreverse(0x0ABBCC0Ei32), 0x7033DD50);
172+
assert_eq!(bitreverse(0x0122334455667708u64), 0x10EE66AA22CC4480);
173+
assert_eq!(bitreverse(0x0122334455667708i64), 0x10EE66AA22CC4480);
174+
assert_eq!(bitreverse(0x0122334455667708u128), 0x10EE66AA22CC44800000000000000000);
175+
assert_eq!(bitreverse(0x0122334455667708i128), 0x10EE66AA22CC44800000000000000000);
141176
}
142177
}

0 commit comments

Comments
 (0)