Skip to content

Commit 5a3a8b4

Browse files
committed
Auto merge of rust-lang#119452 - AngelicosPhosphoros:make_nonzeroint_get_assume_nonzero, r=<try>
Add assume into `NonZeroIntX::get` LLVM currently don't support range metadata for function arguments so it fails to optimize non zero integers using their invariant if they are provided using by-value function arguments. Related to rust-lang#119422 Related to llvm/llvm-project#76628 Related to rust-lang#49572
2 parents 5a345b3 + b895a3e commit 5a3a8b4

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

library/core/src/num/nonzero.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,22 @@ macro_rules! nonzero_integers {
104104
#[inline]
105105
#[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")]
106106
pub const fn get(self) -> $Int {
107-
self.0
107+
// FIXME: Remove this after LLVM supports `!range` metadata for function
108+
// arguments https://github.com/llvm/llvm-project/issues/76628
109+
//
110+
// Rustc can set range metadata only if it loads `self` from
111+
// memory somewhere. If the value of `self` was from by-value argument
112+
// of some not-inlined function, LLVM don't have range metadata
113+
// to understand that the value cannot be zero.
114+
if self.0 == 0 {
115+
// SAFETY: It is an invariant of this type.
116+
unsafe {
117+
crate::hint::unreachable_unchecked()
118+
}
119+
}
120+
else {
121+
self.0
122+
}
108123
}
109124

110125
}

tests/codegen/issues/issue-119422.rs

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//! This test checks that compiler don't generate useless compares to zeros
2+
//! for NonZero integer types.
3+
4+
// compile-flags: -O --edition=2021 -Zmerge-functions=disabled
5+
// only-64bit (because the LLVM type of i64 for usize shows up)
6+
7+
#![crate_type = "lib"]
8+
9+
use core::num::*;
10+
use core::ptr::NonNull;
11+
12+
// CHECK-LABEL: @check_non_null
13+
#[no_mangle]
14+
pub fn check_non_null(x: NonNull<u8>) -> bool {
15+
// CHECK: ret i1 false
16+
x.as_ptr().is_null()
17+
}
18+
19+
// CHECK-LABEL: @equals_zero_is_false_u8
20+
#[no_mangle]
21+
pub fn equals_zero_is_false_u8(x: NonZeroU8) -> bool {
22+
// CHECK-NOT: br
23+
// CHECK: ret i1 false
24+
// CHECK-NOT: br
25+
x.get() == 0
26+
}
27+
28+
// CHECK-LABEL: @not_equals_zero_is_true_u8
29+
#[no_mangle]
30+
pub fn not_equals_zero_is_true_u8(x: NonZeroU8) -> bool {
31+
// CHECK-NOT: br
32+
// CHECK: ret i1 true
33+
// CHECK-NOT: br
34+
x.get() != 0
35+
}
36+
37+
// CHECK-LABEL: @equals_zero_is_false_i8
38+
#[no_mangle]
39+
pub fn equals_zero_is_false_i8(x: NonZeroI8) -> bool {
40+
// CHECK-NOT: br
41+
// CHECK: ret i1 false
42+
// CHECK-NOT: br
43+
x.get() == 0
44+
}
45+
46+
// CHECK-LABEL: @not_equals_zero_is_true_i8
47+
#[no_mangle]
48+
pub fn not_equals_zero_is_true_i8(x: NonZeroI8) -> bool {
49+
// CHECK-NOT: br
50+
// CHECK: ret i1 true
51+
// CHECK-NOT: br
52+
x.get() != 0
53+
}
54+
55+
// CHECK-LABEL: @usize_try_from_u32
56+
#[no_mangle]
57+
pub fn usize_try_from_u32(x: NonZeroU32) -> NonZeroUsize {
58+
// CHECK-NOT: br
59+
// CHECK: zext i32 %{{.*}} to i64
60+
// CHECK-NOT: br
61+
// CHECK: ret i64
62+
x.try_into().unwrap()
63+
}
64+
65+
// CHECK-LABEL: @isize_try_from_i32
66+
#[no_mangle]
67+
pub fn isize_try_from_i32(x: NonZeroI32) -> NonZeroIsize {
68+
// CHECK-NOT: br
69+
// CHECK: sext i32 %{{.*}} to i64
70+
// CHECK-NOT: br
71+
// CHECK: ret i64
72+
x.try_into().unwrap()
73+
}

0 commit comments

Comments
 (0)