Skip to content

Commit 1b9ab89

Browse files
committed
Make most integer operations const fns
1 parent 2954cb5 commit 1b9ab89

File tree

2 files changed

+115
-40
lines changed

2 files changed

+115
-40
lines changed

src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#![feature(cfg_target_has_atomic)]
8282
#![feature(concat_idents)]
8383
#![feature(const_fn)]
84+
#![feature(const_int_ops)]
8485
#![feature(core_float)]
8586
#![feature(custom_attribute)]
8687
#![feature(doc_cfg)]

src/libcore/num/mod.rs

+114-40
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,9 @@ $EndFeature, "
267267
```
268268
"),
269269
#[stable(feature = "rust1", since = "1.0.0")]
270+
#[rustc_const_unstable(feature = "const_int_ops")]
270271
#[inline]
271-
pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
272+
pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
272273
}
273274

274275
doc_comment! {
@@ -282,8 +283,9 @@ Basic usage:
282283
", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, "
283284
```"),
284285
#[stable(feature = "rust1", since = "1.0.0")]
286+
#[rustc_const_unstable(feature = "const_int_ops")]
285287
#[inline]
286-
pub fn count_zeros(self) -> u32 {
288+
pub const fn count_zeros(self) -> u32 {
287289
(!self).count_ones()
288290
}
289291
}
@@ -302,8 +304,9 @@ assert_eq!(n.leading_zeros(), 0);",
302304
$EndFeature, "
303305
```"),
304306
#[stable(feature = "rust1", since = "1.0.0")]
307+
#[rustc_const_unstable(feature = "const_int_ops")]
305308
#[inline]
306-
pub fn leading_zeros(self) -> u32 {
309+
pub const fn leading_zeros(self) -> u32 {
307310
(self as $UnsignedT).leading_zeros()
308311
}
309312
}
@@ -322,8 +325,9 @@ assert_eq!(n.trailing_zeros(), 2);",
322325
$EndFeature, "
323326
```"),
324327
#[stable(feature = "rust1", since = "1.0.0")]
328+
#[rustc_const_unstable(feature = "const_int_ops")]
325329
#[inline]
326-
pub fn trailing_zeros(self) -> u32 {
330+
pub const fn trailing_zeros(self) -> u32 {
327331
(self as $UnsignedT).trailing_zeros()
328332
}
329333
}
@@ -396,8 +400,9 @@ $EndFeature, "
396400
/// assert_eq!(m, 21760);
397401
/// ```
398402
#[stable(feature = "rust1", since = "1.0.0")]
403+
#[rustc_const_unstable(feature = "const_int_ops")]
399404
#[inline]
400-
pub fn swap_bytes(self) -> Self {
405+
pub const fn swap_bytes(self) -> Self {
401406
(self as $UnsignedT).swap_bytes() as Self
402407
}
403408

@@ -447,9 +452,17 @@ if cfg!(target_endian = \"big\") {
447452
$EndFeature, "
448453
```"),
449454
#[stable(feature = "rust1", since = "1.0.0")]
455+
#[rustc_const_unstable(feature = "const_int_ops")]
450456
#[inline]
451-
pub fn from_be(x: Self) -> Self {
452-
if cfg!(target_endian = "big") { x } else { x.swap_bytes() }
457+
pub const fn from_be(x: Self) -> Self {
458+
#[cfg(target_endian = "big")]
459+
{
460+
x
461+
}
462+
#[cfg(not(target_endian = "big"))]
463+
{
464+
x.swap_bytes()
465+
}
453466
}
454467
}
455468

@@ -473,9 +486,17 @@ if cfg!(target_endian = \"little\") {
473486
$EndFeature, "
474487
```"),
475488
#[stable(feature = "rust1", since = "1.0.0")]
489+
#[rustc_const_unstable(feature = "const_int_ops")]
476490
#[inline]
477-
pub fn from_le(x: Self) -> Self {
478-
if cfg!(target_endian = "little") { x } else { x.swap_bytes() }
491+
pub const fn from_le(x: Self) -> Self {
492+
#[cfg(target_endian = "little")]
493+
{
494+
x
495+
}
496+
#[cfg(not(target_endian = "little"))]
497+
{
498+
x.swap_bytes()
499+
}
479500
}
480501
}
481502

@@ -499,9 +520,17 @@ if cfg!(target_endian = \"big\") {
499520
$EndFeature, "
500521
```"),
501522
#[stable(feature = "rust1", since = "1.0.0")]
523+
#[rustc_const_unstable(feature = "const_int_ops")]
502524
#[inline]
503-
pub fn to_be(self) -> Self { // or not to be?
504-
if cfg!(target_endian = "big") { self } else { self.swap_bytes() }
525+
pub const fn to_be(self) -> Self { // or not to be?
526+
#[cfg(target_endian = "big")]
527+
{
528+
self
529+
}
530+
#[cfg(not(target_endian = "big"))]
531+
{
532+
self.swap_bytes()
533+
}
505534
}
506535
}
507536

@@ -525,9 +554,17 @@ if cfg!(target_endian = \"little\") {
525554
$EndFeature, "
526555
```"),
527556
#[stable(feature = "rust1", since = "1.0.0")]
557+
#[rustc_const_unstable(feature = "const_int_ops")]
528558
#[inline]
529-
pub fn to_le(self) -> Self {
530-
if cfg!(target_endian = "little") { self } else { self.swap_bytes() }
559+
pub const fn to_le(self) -> Self {
560+
#[cfg(target_endian = "little")]
561+
{
562+
self
563+
}
564+
#[cfg(not(target_endian = "little"))]
565+
{
566+
self.swap_bytes()
567+
}
531568
}
532569
}
533570

@@ -1943,6 +1980,19 @@ impl isize {
19431980
int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "" }
19441981
}
19451982

1983+
// Emits the correct `cttz` call, depending on the size of the type.
1984+
macro_rules! uint_cttz_call {
1985+
// As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic
1986+
// emits two conditional moves on x86_64. By promoting the value to
1987+
// u16 and setting bit 8, we get better code without any conditional
1988+
// operations.
1989+
// FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284)
1990+
// pending, remove this workaround once LLVM generates better code
1991+
// for cttz8.
1992+
($value:expr, 8) => { intrinsics::cttz($value as u16 | 0x100) };
1993+
($value:expr, $_BITS:expr) => { intrinsics::cttz($value) }
1994+
}
1995+
19461996
// `Int` + `UnsignedInt` implemented for unsigned integers
19471997
macro_rules! uint_impl {
19481998
($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr) => {
@@ -2020,8 +2070,9 @@ Basic usage:
20202070
assert_eq!(n.count_ones(), 3);", $EndFeature, "
20212071
```"),
20222072
#[stable(feature = "rust1", since = "1.0.0")]
2073+
#[rustc_const_unstable(feature = "const_int_ops")]
20232074
#[inline]
2024-
pub fn count_ones(self) -> u32 {
2075+
pub const fn count_ones(self) -> u32 {
20252076
unsafe { intrinsics::ctpop(self as $ActualT) as u32 }
20262077
}
20272078
}
@@ -2037,8 +2088,9 @@ Basic usage:
20372088
", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, "
20382089
```"),
20392090
#[stable(feature = "rust1", since = "1.0.0")]
2091+
#[rustc_const_unstable(feature = "const_int_ops")]
20402092
#[inline]
2041-
pub fn count_zeros(self) -> u32 {
2093+
pub const fn count_zeros(self) -> u32 {
20422094
(!self).count_ones()
20432095
}
20442096
}
@@ -2056,8 +2108,9 @@ Basic usage:
20562108
assert_eq!(n.leading_zeros(), 2);", $EndFeature, "
20572109
```"),
20582110
#[stable(feature = "rust1", since = "1.0.0")]
2111+
#[rustc_const_unstable(feature = "const_int_ops")]
20592112
#[inline]
2060-
pub fn leading_zeros(self) -> u32 {
2113+
pub const fn leading_zeros(self) -> u32 {
20612114
unsafe { intrinsics::ctlz(self as $ActualT) as u32 }
20622115
}
20632116
}
@@ -2076,22 +2129,10 @@ Basic usage:
20762129
assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
20772130
```"),
20782131
#[stable(feature = "rust1", since = "1.0.0")]
2132+
#[rustc_const_unstable(feature = "const_int_ops")]
20792133
#[inline]
2080-
pub fn trailing_zeros(self) -> u32 {
2081-
// As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic
2082-
// emits two conditional moves on x86_64. By promoting the value to
2083-
// u16 and setting bit 8, we get better code without any conditional
2084-
// operations.
2085-
// FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284)
2086-
// pending, remove this workaround once LLVM generates better code
2087-
// for cttz8.
2088-
unsafe {
2089-
if $BITS == 8 {
2090-
intrinsics::cttz(self as u16 | 0x100) as u32
2091-
} else {
2092-
intrinsics::cttz(self) as u32
2093-
}
2094-
}
2134+
pub const fn trailing_zeros(self) -> u32 {
2135+
unsafe { uint_cttz_call!(self, $BITS) as u32 }
20952136
}
20962137
}
20972138

@@ -2167,8 +2208,9 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
21672208
/// assert_eq!(m, 21760);
21682209
/// ```
21692210
#[stable(feature = "rust1", since = "1.0.0")]
2211+
#[rustc_const_unstable(feature = "const_int_ops")]
21702212
#[inline]
2171-
pub fn swap_bytes(self) -> Self {
2213+
pub const fn swap_bytes(self) -> Self {
21722214
unsafe { intrinsics::bswap(self as $ActualT) as Self }
21732215
}
21742216

@@ -2218,9 +2260,17 @@ if cfg!(target_endian = \"big\") {
22182260
}", $EndFeature, "
22192261
```"),
22202262
#[stable(feature = "rust1", since = "1.0.0")]
2263+
#[rustc_const_unstable(feature = "const_int_ops")]
22212264
#[inline]
2222-
pub fn from_be(x: Self) -> Self {
2223-
if cfg!(target_endian = "big") { x } else { x.swap_bytes() }
2265+
pub const fn from_be(x: Self) -> Self {
2266+
#[cfg(target_endian = "big")]
2267+
{
2268+
x
2269+
}
2270+
#[cfg(not(target_endian = "big"))]
2271+
{
2272+
x.swap_bytes()
2273+
}
22242274
}
22252275
}
22262276

@@ -2244,9 +2294,17 @@ if cfg!(target_endian = \"little\") {
22442294
}", $EndFeature, "
22452295
```"),
22462296
#[stable(feature = "rust1", since = "1.0.0")]
2297+
#[rustc_const_unstable(feature = "const_int_ops")]
22472298
#[inline]
2248-
pub fn from_le(x: Self) -> Self {
2249-
if cfg!(target_endian = "little") { x } else { x.swap_bytes() }
2299+
pub const fn from_le(x: Self) -> Self {
2300+
#[cfg(target_endian = "little")]
2301+
{
2302+
x
2303+
}
2304+
#[cfg(not(target_endian = "little"))]
2305+
{
2306+
x.swap_bytes()
2307+
}
22502308
}
22512309
}
22522310

@@ -2270,9 +2328,17 @@ if cfg!(target_endian = \"big\") {
22702328
}", $EndFeature, "
22712329
```"),
22722330
#[stable(feature = "rust1", since = "1.0.0")]
2331+
#[rustc_const_unstable(feature = "const_int_ops")]
22732332
#[inline]
2274-
pub fn to_be(self) -> Self { // or not to be?
2275-
if cfg!(target_endian = "big") { self } else { self.swap_bytes() }
2333+
pub const fn to_be(self) -> Self { // or not to be?
2334+
#[cfg(target_endian = "big")]
2335+
{
2336+
self
2337+
}
2338+
#[cfg(not(target_endian = "big"))]
2339+
{
2340+
self.swap_bytes()
2341+
}
22762342
}
22772343
}
22782344

@@ -2296,9 +2362,17 @@ if cfg!(target_endian = \"little\") {
22962362
}", $EndFeature, "
22972363
```"),
22982364
#[stable(feature = "rust1", since = "1.0.0")]
2365+
#[rustc_const_unstable(feature = "const_int_ops")]
22992366
#[inline]
2300-
pub fn to_le(self) -> Self {
2301-
if cfg!(target_endian = "little") { self } else { self.swap_bytes() }
2367+
pub const fn to_le(self) -> Self {
2368+
#[cfg(target_endian = "little")]
2369+
{
2370+
self
2371+
}
2372+
#[cfg(not(target_endian = "little"))]
2373+
{
2374+
self.swap_bytes()
2375+
}
23022376
}
23032377
}
23042378

0 commit comments

Comments
 (0)