diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 03bcf9caeea0c..a8e7b214c77a6 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -584,6 +584,10 @@ extern "rust-intrinsic" { /// Reverses the bytes in an integer type `T`. pub fn bswap(x: T) -> T; + /// Reverses the bits in an integer type `T`. + #[cfg(not(stage0))] + pub fn bitreverse(x: T) -> T; + /// Performs checked integer addition. pub fn add_with_overflow(x: T, y: T) -> (T, bool); diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 229a864d712c5..44e4018bdb5e9 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -224,6 +224,24 @@ macro_rules! int_impl { (self as $UnsignedT).trailing_zeros() } + /// Reverses the bit pattern of the integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let n = 0b10101000u8; + /// + /// assert_eq!(n.reverse_bits(), 0b00010101u8); + /// ``` + #[cfg(not(stage0))] + #[unstable(feature = "reverse_bits", issue = "0", reason = "recently added")] + #[inline] + pub fn reverse_bits(self) -> Self { + (self as $UnsignedT).reverse_bits() as Self + } + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// @@ -1290,6 +1308,24 @@ macro_rules! uint_impl { } } + /// Reverses the bit pattern of the integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let n = 0b10101000u8; + /// + /// assert_eq!(n.reverse_bits(), 0b00010101u8); + /// ``` + #[cfg(not(stage0))] + #[unstable(feature = "reverse_bits", issue = "0", reason = "recently added")] + #[inline] + pub fn reverse_bits(self) -> Self { + unsafe { intrinsics::bitreverse(self) } + } + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 9bbc72eba36ef..229a5001db021 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -1001,6 +1001,11 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option { ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); + ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); + ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); + ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); + ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5924ae1ad84c5..13ad43089ecb8 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -607,7 +607,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_nil(ccx) }, - (_, "ctlz") | (_, "cttz") | (_, "ctpop") | (_, "bswap") | + (_, "ctlz") | (_, "cttz") | (_, "ctpop") | (_, "bswap") | (_, "bitreverse") | (_, "add_with_overflow") | (_, "sub_with_overflow") | (_, "mul_with_overflow") | (_, "overflowing_add") | (_, "overflowing_sub") | (_, "overflowing_mul") | (_, "unchecked_div") | (_, "unchecked_rem") => { @@ -629,6 +629,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, &llargs, call_debug_location) } } + "bitreverse" => Call(bcx, ccx.get_intrinsic(&format!("llvm.bitreverse.i{}", + width)), + &llargs, call_debug_location), "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { let intrinsic = format!("llvm.{}{}.with.overflow.i{}", if signed { 's' } else { 'u' }, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index eae0cfb0f2267..09ea0763be866 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -265,7 +265,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { "volatile_store" => (1, vec!( tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ), tcx.mk_nil()), - "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec!(param(ccx, 0)), param(ccx, 0)), + "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" => + (1, vec!(param(ccx, 0)), param(ccx, 0)), "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => (1, vec!(param(ccx, 0), param(ccx, 0)), diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 759dc515456de..79ee2b12fd4a9 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -16,6 +16,7 @@ mod rusti { pub fn ctlz(x: T) -> T; pub fn cttz(x: T) -> T; pub fn bswap(x: T) -> T; + pub fn bitreverse(x: T) -> T; } } @@ -101,5 +102,14 @@ pub fn main() { assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A); assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); + + assert_eq!(bitreverse(0x0Au8), 0x50); + assert_eq!(bitreverse(0x0Ai8), 0x50); + assert_eq!(bitreverse(0x0A0Cu16), 0x3050); + assert_eq!(bitreverse(0x0A0Ci16), 0x3050); + assert_eq!(bitreverse(0x0ABBCC0Eu32), 0x7033DD50); + assert_eq!(bitreverse(0x0ABBCC0Ei32), 0x7033DD50); + assert_eq!(bitreverse(0x0122334455667708u64), 0x10EE66AA22CC4480); + assert_eq!(bitreverse(0x0122334455667708i64), 0x10EE66AA22CC4480); } }