Skip to content

Commit

Permalink
Add assume into NonZeroIntX::get
Browse files Browse the repository at this point in the history
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 #119422
Related to llvm/llvm-project#76628
Related to #49572
  • Loading branch information
AngelicosPhosphoros committed Dec 30, 2023
1 parent 3a539c0 commit b895a3e
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 1 deletion.
17 changes: 16 additions & 1 deletion library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,22 @@ macro_rules! nonzero_integers {
#[inline]
#[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")]
pub const fn get(self) -> $Int {
self.0
// FIXME: Remove this after LLVM supports `!range` metadata for function
// arguments https://github.com/llvm/llvm-project/issues/76628
//
// Rustc can set range metadata only if it loads `self` from
// memory somewhere. If the value of `self` was from by-value argument
// of some not-inlined function, LLVM don't have range metadata
// to understand that the value cannot be zero.
if self.0 == 0 {
// SAFETY: It is an invariant of this type.
unsafe {
crate::hint::unreachable_unchecked()
}
}
else {
self.0
}
}

}
Expand Down
73 changes: 73 additions & 0 deletions tests/codegen/issues/issue-119422.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! This test checks that compiler don't generate useless compares to zeros
//! for NonZero integer types.

// compile-flags: -O --edition=2021 -Zmerge-functions=disabled
// only-64bit (because the LLVM type of i64 for usize shows up)

#![crate_type = "lib"]

use core::num::*;
use core::ptr::NonNull;

// CHECK-LABEL: @check_non_null
#[no_mangle]
pub fn check_non_null(x: NonNull<u8>) -> bool {
// CHECK: ret i1 false
x.as_ptr().is_null()
}

// CHECK-LABEL: @equals_zero_is_false_u8
#[no_mangle]
pub fn equals_zero_is_false_u8(x: NonZeroU8) -> bool {
// CHECK-NOT: br
// CHECK: ret i1 false
// CHECK-NOT: br
x.get() == 0
}

// CHECK-LABEL: @not_equals_zero_is_true_u8
#[no_mangle]
pub fn not_equals_zero_is_true_u8(x: NonZeroU8) -> bool {
// CHECK-NOT: br
// CHECK: ret i1 true
// CHECK-NOT: br
x.get() != 0
}

// CHECK-LABEL: @equals_zero_is_false_i8
#[no_mangle]
pub fn equals_zero_is_false_i8(x: NonZeroI8) -> bool {
// CHECK-NOT: br
// CHECK: ret i1 false
// CHECK-NOT: br
x.get() == 0
}

// CHECK-LABEL: @not_equals_zero_is_true_i8
#[no_mangle]
pub fn not_equals_zero_is_true_i8(x: NonZeroI8) -> bool {
// CHECK-NOT: br
// CHECK: ret i1 true
// CHECK-NOT: br
x.get() != 0
}

// CHECK-LABEL: @usize_try_from_u32
#[no_mangle]
pub fn usize_try_from_u32(x: NonZeroU32) -> NonZeroUsize {
// CHECK-NOT: br
// CHECK: zext i32 %{{.*}} to i64
// CHECK-NOT: br
// CHECK: ret i64
x.try_into().unwrap()
}

// CHECK-LABEL: @isize_try_from_i32
#[no_mangle]
pub fn isize_try_from_i32(x: NonZeroI32) -> NonZeroIsize {
// CHECK-NOT: br
// CHECK: sext i32 %{{.*}} to i64
// CHECK-NOT: br
// CHECK: ret i64
x.try_into().unwrap()
}

0 comments on commit b895a3e

Please sign in to comment.