未验证 提交 b35c60e9 编写于 作者: M Mark Simulacrum 提交者: GitHub

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.
......@@ -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)]
......
......@@ -267,6 +267,16 @@ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
```
"),
#[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 @@ pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
", $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 @@ pub fn count_zeros(self) -> u32 {
$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 @@ pub fn leading_zeros(self) -> u32 {
$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 @@ pub fn rotate_right(self, n: u32) -> Self {
/// 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 @@ pub fn reverse_bits(self) -> Self {
$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 @@ pub fn from_be(x: Self) -> Self {
$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 @@ pub fn from_le(x: Self) -> Self {
$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 @@ pub fn to_be(self) -> Self { // or not to be?
$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 @@ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
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 @@ pub fn count_ones(self) -> u32 {
", $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 @@ pub fn count_zeros(self) -> u32 {
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 @@ pub fn leading_zeros(self) -> u32 {
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 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
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 {
unsafe { uint_cttz_call!(self, $BITS) as u32 }
}
}
......@@ -2167,6 +2347,16 @@ pub fn rotate_right(self, n: u32) -> Self {
/// 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 @@ pub fn reverse_bits(self) -> Self {
}", $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 @@ pub fn from_be(x: Self) -> Self {
}", $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 @@ pub fn from_le(x: Self) -> Self {
}", $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 @@ pub fn to_be(self) -> Self { // or not to be?
}", $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() }
......
// 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());
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册