diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 32cf31231c301..71a727f4c017b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -81,6 +81,7 @@ #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] +#![feature(const_int_ops)] #![feature(core_float)] #![feature(custom_attribute)] #![feature(doc_cfg)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ea652ad811e3c..26dd08b10b9b8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -267,6 +267,16 @@ $EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } @@ -282,6 +292,18 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentatio"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn count_zeros(self) -> u32 { (!self).count_ones() @@ -302,6 +324,18 @@ assert_eq!(n.leading_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + (self as $UnsignedT).leading_zeros() + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn leading_zeros(self) -> u32 { (self as $UnsignedT).leading_zeros() @@ -322,6 +356,18 @@ assert_eq!(n.trailing_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + (self as $UnsignedT).trailing_zeros() + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn trailing_zeros(self) -> u32 { (self as $UnsignedT).trailing_zeros() @@ -396,6 +442,16 @@ $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn swap_bytes(self) -> Self { + (self as $UnsignedT).swap_bytes() as Self + } + + /// Dummy docs. See !stage0 documentation. + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self @@ -447,6 +503,25 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn from_be(x: Self) -> Self { if cfg!(target_endian = "big") { x } else { x.swap_bytes() } @@ -473,6 +548,25 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn from_le(x: Self) -> Self { if cfg!(target_endian = "little") { x } else { x.swap_bytes() } @@ -499,6 +593,25 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn to_be(self) -> Self { // or not to be? if cfg!(target_endian = "big") { self } else { self.swap_bytes() } @@ -525,6 +638,25 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn to_le(self) -> Self { if cfg!(target_endian = "little") { self } else { self.swap_bytes() } @@ -1943,6 +2075,19 @@ impl isize { int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "" } } +// Emits the correct `cttz` call, depending on the size of the type. +macro_rules! uint_cttz_call { + // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic + // emits two conditional moves on x86_64. By promoting the value to + // u16 and setting bit 8, we get better code without any conditional + // operations. + // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) + // pending, remove this workaround once LLVM generates better code + // for cttz8. + ($value:expr, 8) => { intrinsics::cttz($value as u16 | 0x100) }; + ($value:expr, $_BITS:expr) => { intrinsics::cttz($value) } +} + // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr) => { @@ -2020,6 +2165,18 @@ Basic usage: assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn count_ones(self) -> u32 { + unsafe { intrinsics::ctpop(self as $ActualT) as u32 } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn count_ones(self) -> u32 { unsafe { intrinsics::ctpop(self as $ActualT) as u32 } @@ -2037,6 +2194,18 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn count_zeros(self) -> u32 { (!self).count_ones() @@ -2056,6 +2225,18 @@ Basic usage: assert_eq!(n.leading_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + unsafe { intrinsics::ctlz(self as $ActualT) as u32 } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn leading_zeros(self) -> u32 { unsafe { intrinsics::ctlz(self as $ActualT) as u32 } @@ -2076,22 +2257,21 @@ Basic usage: assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + unsafe { uint_cttz_call!(self, $BITS) as u32 } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn trailing_zeros(self) -> u32 { - // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic - // emits two conditional moves on x86_64. By promoting the value to - // u16 and setting bit 8, we get better code without any conditional - // operations. - // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) - // pending, remove this workaround once LLVM generates better code - // for cttz8. - unsafe { - if $BITS == 8 { - intrinsics::cttz(self as u16 | 0x100) as u32 - } else { - intrinsics::cttz(self) as u32 - } - } + unsafe { uint_cttz_call!(self, $BITS) as u32 } } } @@ -2167,6 +2347,16 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn swap_bytes(self) -> Self { + unsafe { intrinsics::bswap(self as $ActualT) as Self } + } + + /// Dummy docs. See !stage0 documentation. + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn swap_bytes(self) -> Self { unsafe { intrinsics::bswap(self as $ActualT) as Self } @@ -2218,6 +2408,25 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn from_be(x: Self) -> Self { if cfg!(target_endian = "big") { x } else { x.swap_bytes() } @@ -2244,6 +2453,25 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn from_le(x: Self) -> Self { if cfg!(target_endian = "little") { x } else { x.swap_bytes() } @@ -2270,6 +2498,25 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn to_be(self) -> Self { // or not to be? if cfg!(target_endian = "big") { self } else { self.swap_bytes() } @@ -2296,6 +2543,25 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] + #[rustc_const_unstable(feature = "const_int_ops")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] #[inline] pub fn to_le(self) -> Self { if cfg!(target_endian = "little") { self } else { self.swap_bytes() } diff --git a/src/test/run-pass/const-endianess.rs b/src/test/run-pass/const-endianess.rs new file mode 100644 index 0000000000000..fa34b49210a6a --- /dev/null +++ b/src/test/run-pass/const-endianess.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_int_ops)] +#![feature(test)] + +extern crate test; +use test::black_box as b; + +const BE_U32: u32 = 55u32.to_be(); +const LE_U32: u32 = 55u32.to_le(); + + +fn main() { + assert_eq!(BE_U32, b(55u32).to_be()); + assert_eq!(LE_U32, b(55u32).to_le()); + + #[cfg(not(target_arch = "asmjs"))] + { + const BE_U128: u128 = 999999u128.to_be(); + const LE_I128: i128 = -999999i128.to_le(); + assert_eq!(BE_U128, b(999999u128).to_be()); + assert_eq!(LE_I128, b(-999999i128).to_le()); + } +}