Skip to content

Have offset_from_unsigned assume the isize::MAX restriction #123598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
use super::FunctionCx;
use crate::common::IntPredicate;
use crate::errors;
use crate::errors::InvalidMonomorphization;
use crate::meth;
Expand Down Expand Up @@ -499,6 +500,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// The `_unsigned` version knows the relative ordering of the pointers,
// so can use `sub nuw` and `udiv exact` instead of dealing in signed.
let d = bx.unchecked_usub(a, b);
if let OptLevel::Default | OptLevel::Aggressive = bx.sess().opts.optimize {
// Despite dealing in `usize`, it's still not allowed for the
// pointers to be more than `isize::MAX` apart.
let inrange = bx.icmp(IntPredicate::IntSGE, d, bx.const_usize(0));
bx.assume(inrange);
}
bx.exactudiv(d, pointee_size)
}
}
Expand Down
16 changes: 11 additions & 5 deletions tests/codegen/intrinsics/offset_from.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//@ compile-flags: -C opt-level=1
//@ revisions: OPT1 OPT2
//@ [OPT1] compile-flags: -Copt-level=1
//@ [OPT2] compile-flags: -Copt-level=2
//@ only-64bit (because we're using [ui]size)

#![crate_type = "lib"]
Expand All @@ -17,8 +19,9 @@ pub unsafe fn offset_from_odd_size(a: *const RGB, b: *const RGB) -> isize {
// CHECK: start
// CHECK-NEXT: ptrtoint
// CHECK-NEXT: ptrtoint
// CHECK-NEXT: sub i64
// CHECK-NEXT: sdiv exact i64 %{{[0-9]+}}, 3
// CHECK-NEXT: %[[D:.+]] = sub i64
// CHECK-NOT: assume
// CHECK-NEXT: sdiv exact i64 %[[D]], 3
// CHECK-NEXT: ret i64
ptr_offset_from(a, b)
}
Expand All @@ -29,8 +32,11 @@ pub unsafe fn offset_from_unsigned_odd_size(a: *const RGB, b: *const RGB) -> usi
// CHECK: start
// CHECK-NEXT: ptrtoint
// CHECK-NEXT: ptrtoint
// CHECK-NEXT: sub nuw i64
// CHECK-NEXT: udiv exact i64 %{{[0-9]+}}, 3
// CHECK-NEXT: %[[D:.+]] = sub nuw i64
// OPT1-NOT: assume
// OPT2-NEXT: %[[POS:.+]] = icmp sgt i64 %[[D]], -1
// OPT2-NEXT: tail call void @llvm.assume(i1 %[[POS]])
// CHECK-NEXT: udiv exact i64 %[[D]], 3
// CHECK-NEXT: ret i64
ptr_offset_from_unsigned(a, b)
}
15 changes: 13 additions & 2 deletions tests/codegen/slice-iter-len-eq-zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@
type Demo = [u8; 3];

// CHECK-LABEL: @slice_iter_len_eq_zero
// CHECK-SAME: ptr noundef nonnull %0
// CHECK-SAME: ptr noundef %1
#[no_mangle]
pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool {
// CHECK-NOT: sub
// CHECK: %[[RET:.+]] = icmp eq ptr {{%1|%0}}, {{%1|%0}}
// There's no `nonnull` in the signature, so we end up with an assume.
// CHECK: %[[NNULL:.+]] = icmp ne ptr %1, null
// CHECK: tail call void @llvm.assume(i1 %[[NNULL]])

// CHECK-DAG: %[[E:.+]] = ptrtoint ptr %1 to i
// CHECK-DAG: %[[B:.+]] = ptrtoint ptr %0 to i
// CHECK: %[[D:.+]] = sub nuw {{.+}} %[[E]], %[[B]]
// CHECK: %[[NNEG:.+]] = icmp sgt {{.+}} %[[D]], -1
// CHECK: tail call void @llvm.assume(i1 %[[NNEG]])

// CHECK: %[[RET:.+]] = icmp eq ptr {{%1, %0|%0, %1}}
// CHECK: ret i1 %[[RET]]
y.len() == 0
}
Expand Down
27 changes: 27 additions & 0 deletions tests/codegen/vec-in-place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ pub struct Baz {
pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
// CHECK-NOT: loop
// CHECK-NOT: call

// CHECK: %[[LEN_IN_ISIZE:.+]] = icmp sgt i{{.+}}, -1
// CHECK-NEXT: call void @llvm.assume(i1 %[[LEN_IN_ISIZE]])

// CHECK-NOT: loop
// CHECK-NOT: call

vec.into_iter().map(|e| e as u8).collect()
}

Expand All @@ -46,6 +53,13 @@ pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
// CHECK-NOT: loop
// CHECK-NOT: call

// CHECK: %[[LEN_IN_ISIZE:.+]] = icmp sgt i{{.+}}, -1
// CHECK-NEXT: call void @llvm.assume(i1 %[[LEN_IN_ISIZE]])

// CHECK-NOT: loop
// CHECK-NOT: call

vec.into_iter().map(|e| Wrapper(e)).collect()
}

Expand All @@ -54,6 +68,13 @@ pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
// CHECK-NOT: loop
// CHECK-NOT: call

// CHECK: %[[LEN_IN_ISIZE:.+]] = icmp sgt i{{.+}}, -1
// CHECK-NEXT: call void @llvm.assume(i1 %[[LEN_IN_ISIZE]])

// CHECK-NOT: loop
// CHECK-NOT: call

vec.into_iter().map(|e| e.0).collect()
}

Expand Down Expand Up @@ -90,3 +111,9 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
// correct.
vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
}

// Make sure that the `NOT`s above don't trigger on the `nocallback` attribute further down.

// CHECK-LABEL: @last_definition
#[no_mangle]
pub fn last_definition() {}
Loading