about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark Simulacrum <mark.simulacrum@gmail.com>2018-06-03 18:18:03 -0600
committerGitHub <noreply@github.com>2018-06-03 18:18:03 -0600
commitb35c60e95e99a02fdc3ce57121aad558164b0f76 (patch)
tree1b0849d28039a5fb9b2a62c50261030c9a8a6253
parentdf137907560e43b21bb598116ccd1adb073b2b4c (diff)
parent8b5f962762b500a1428e9d6937d964922a233fa1 (diff)
downloadrust-b35c60e95e99a02fdc3ce57121aad558164b0f76.tar.gz
rust-b35c60e95e99a02fdc3ce57121aad558164b0f76.zip
Rollup merge of #51299 - faern:const-int-ops, r=oli-obk
const fn integer operations

A follow up to #51171
Fixes #51267

Makes a lot of the integer methods (`swap_bytes`, `count_ones` etc) `const fn`s. See #51267 for a discussion about why this is wanted and the solution used.
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/num/mod.rs294
-rw-r--r--src/test/run-pass/const-endianess.rs32
3 files changed, 313 insertions, 14 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index e6ab64a3312..b27552651a0 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 ea652ad811e..26dd08b10b9 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 00000000000..fa34b49210a
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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());
+    }
+}