Add LLVM range attributes to slice length parameters
This commit is contained in:
parent
3be68033b6
commit
0ba7bcfc44
7 changed files with 100 additions and 18 deletions
|
|
@ -522,6 +522,28 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
let ii = apply(b);
|
||||
if let BackendRepr::ScalarPair(scalar_a, scalar_b) = arg.layout.backend_repr {
|
||||
apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a);
|
||||
let primitive_b = scalar_b.primitive();
|
||||
let scalar_b = if let rustc_abi::Primitive::Int(int, false) = primitive_b
|
||||
&& let ty::Ref(_, pointee_ty, _) = *arg.layout.ty.kind()
|
||||
&& let ty::Slice(element_ty) = *pointee_ty.kind()
|
||||
&& let elem_size = cx.layout_of(element_ty).size
|
||||
&& elem_size != rustc_abi::Size::ZERO
|
||||
{
|
||||
// Ideally the layout calculations would have set the range,
|
||||
// but that's complicated due to cycles, so in the mean time
|
||||
// we calculate and apply it here.
|
||||
debug_assert!(scalar_b.is_always_valid(cx));
|
||||
let isize_max = int.signed_max() as u64;
|
||||
rustc_abi::Scalar::Initialized {
|
||||
value: primitive_b,
|
||||
valid_range: rustc_abi::WrappingRange {
|
||||
start: 0,
|
||||
end: u128::from(isize_max / elem_size.bytes()),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
scalar_b
|
||||
};
|
||||
apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,17 +208,23 @@ pub fn struct_return() -> S {
|
|||
#[no_mangle]
|
||||
pub fn helper(_: usize) {}
|
||||
|
||||
// CHECK: @slice(ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, [[USIZE]] noundef %_1.1)
|
||||
// CHECK: @slice(
|
||||
// CHECK-SAME: ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0,
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1)
|
||||
// FIXME #25759 This should also have `nocapture`
|
||||
#[no_mangle]
|
||||
pub fn slice(_: &[u8]) {}
|
||||
|
||||
// CHECK: @mutable_slice(ptr noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1)
|
||||
// CHECK: @mutable_slice(
|
||||
// CHECK-SAME: ptr noalias noundef nonnull align 1 %_1.0,
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1)
|
||||
// FIXME #25759 This should also have `nocapture`
|
||||
#[no_mangle]
|
||||
pub fn mutable_slice(_: &mut [u8]) {}
|
||||
|
||||
// CHECK: @unsafe_slice(ptr noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1)
|
||||
// CHECK: @unsafe_slice(
|
||||
// CHECK-SAME: ptr noundef nonnull align 2 %_1.0,
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, 1073741824|i64 0, 4611686018427387904}}) %_1.1)
|
||||
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
||||
#[no_mangle]
|
||||
pub fn unsafe_slice(_: &[UnsafeInner]) {}
|
||||
|
|
@ -227,7 +233,9 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {}
|
|||
#[no_mangle]
|
||||
pub fn raw_slice(_: *const [u8]) {}
|
||||
|
||||
// CHECK: @str(ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, [[USIZE]] noundef %_1.1)
|
||||
// CHECK: @str(
|
||||
// CHECK-SAME: ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0,
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1)
|
||||
// FIXME #25759 This should also have `nocapture`
|
||||
#[no_mangle]
|
||||
pub fn str(_: &[u8]) {}
|
||||
|
|
@ -259,7 +267,9 @@ pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + U
|
|||
x
|
||||
}
|
||||
|
||||
// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2{{( captures\(address, read_provenance\))?}} %x.0, [[USIZE]] noundef %x.1)
|
||||
// CHECK: { ptr, [[USIZE]] } @return_slice(
|
||||
// CHECK-SAME: ptr noalias noundef nonnull readonly align 2{{( captures\(address, read_provenance\))?}} %x.0,
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, 1073741824|i64 0, 4611686018427387904}}) %x.1)
|
||||
#[no_mangle]
|
||||
pub fn return_slice(x: &[u16]) -> &[u16] {
|
||||
x
|
||||
|
|
|
|||
|
|
@ -67,8 +67,26 @@ pub fn enum2_value(x: Enum2) -> Enum2 {
|
|||
x
|
||||
}
|
||||
|
||||
// CHECK: noundef [[USIZE]] @takes_slice(ptr {{.*}} %x.0, [[USIZE]] noundef %x.1)
|
||||
// CHECK: noundef [[USIZE]] @takes_slice_4(ptr {{.*}} %x.0, [[USIZE]] noundef
|
||||
// bit32-SAME: range(i32 0, [[#0x20000000]])
|
||||
// bit64-SAME: range(i64 0, [[#0x2000000000000000]])
|
||||
// CHECK-SAME: %x.1)
|
||||
#[no_mangle]
|
||||
pub fn takes_slice(x: &[i32]) -> usize {
|
||||
pub fn takes_slice_4(x: &[i32]) -> usize {
|
||||
x.len()
|
||||
}
|
||||
|
||||
// CHECK: noundef [[USIZE]] @takes_slice_3(ptr {{.*}} %x.0, [[USIZE]] noundef
|
||||
// bit32-SAME: range(i32 0, [[#0x2AAAAAAB]])
|
||||
// bit64-SAME: range(i64 0, [[#0x2AAAAAAAAAAAAAAB]])
|
||||
// CHECK-SAME: %x.1)
|
||||
#[no_mangle]
|
||||
pub fn takes_slice_3(x: &[[u8; 3]]) -> usize {
|
||||
x.len()
|
||||
}
|
||||
|
||||
// CHECK: noundef [[USIZE]] @takes_zst_slice(ptr {{.*}} %x.0, [[USIZE]] noundef %x.1)
|
||||
#[no_mangle]
|
||||
pub fn takes_zst_slice(x: &[()]) -> usize {
|
||||
x.len()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub fn chunks4(x: &[u8]) -> &[[u8; 4]] {
|
|||
// CHECK-LABEL: @chunks4_with_remainder
|
||||
#[no_mangle]
|
||||
pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) {
|
||||
// CHECK-DAG: and i64 %x.1, -4
|
||||
// CHECK-DAG: and i64 %x.1, [[#0x7FFFFFFFFFFFFFFC]]
|
||||
// CHECK-DAG: and i64 %x.1, 3
|
||||
// CHECK-DAG: lshr
|
||||
// CHECK-NOT: mul
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'
|
|||
// attribute is there, and confirms adding the assume back doesn't do anything.
|
||||
|
||||
// CHECK-LABEL: @slice_iter_new
|
||||
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1)
|
||||
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1)
|
||||
#[no_mangle]
|
||||
pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> {
|
||||
// CHECK-NOT: slice
|
||||
|
|
@ -66,7 +66,7 @@ pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> {
|
|||
}
|
||||
|
||||
// CHECK-LABEL: @slice_iter_mut_new
|
||||
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1)
|
||||
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1)
|
||||
#[no_mangle]
|
||||
pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> {
|
||||
// CHECK-NOT: slice
|
||||
|
|
|
|||
32
tests/codegen-llvm/slice-len-math.rs
Normal file
32
tests/codegen-llvm/slice-len-math.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//@ compile-flags: -C opt-level=3
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[no_mangle]
|
||||
// CHECK-LABEL: @len_plus_ten_a
|
||||
pub fn len_plus_ten_a(s: &[u8]) -> usize {
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: add
|
||||
// CHECK: %[[R:.+]] = add nuw i{{.+}} %s.1, 10
|
||||
// CHECK-NEXT: ret {{.+}} %[[R]]
|
||||
s.len().wrapping_add(10)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
// CHECK-LABEL: @len_plus_ten_b
|
||||
pub fn len_plus_ten_b(s: &[u32]) -> usize {
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: add
|
||||
// CHECK: %[[R:.+]] = add nuw nsw i{{.+}} %s.1, 10
|
||||
// CHECK-NEXT: ret {{.+}} %[[R]]
|
||||
s.len().wrapping_add(10)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
// CHECK-LABEL: @len_plus_len
|
||||
pub fn len_plus_len(x: &[u8], y: &[u8]) -> usize {
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: add
|
||||
// CHECK: %[[R:.+]] = add nuw i{{.+}} {{%x.1, %y.1|%y.1, %x.1}}
|
||||
// CHECK-NEXT: ret {{.+}} %[[R]]
|
||||
usize::wrapping_add(x.len(), y.len())
|
||||
}
|
||||
|
|
@ -42,8 +42,8 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool {
|
|||
// equality for non-byte types also just emit a `bcmp`, not a loop.
|
||||
|
||||
// CHECK-LABEL: @eq_slice_of_nested_u8(
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef %y.1
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
|
||||
#[no_mangle]
|
||||
fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
|
||||
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
|
||||
|
|
@ -54,8 +54,8 @@ fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
|
|||
}
|
||||
|
||||
// CHECK-LABEL: @eq_slice_of_i32(
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef %y.1
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
|
||||
#[no_mangle]
|
||||
fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
|
||||
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
|
||||
|
|
@ -66,8 +66,8 @@ fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
|
|||
}
|
||||
|
||||
// CHECK-LABEL: @eq_slice_of_nonzero(
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef %y.1
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
|
||||
#[no_mangle]
|
||||
fn eq_slice_of_nonzero(x: &[NonZero<i32>], y: &[NonZero<i32>]) -> bool {
|
||||
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
|
||||
|
|
@ -78,8 +78,8 @@ fn eq_slice_of_nonzero(x: &[NonZero<i32>], y: &[NonZero<i32>]) -> bool {
|
|||
}
|
||||
|
||||
// CHECK-LABEL: @eq_slice_of_option_of_nonzero(
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef %y.1
|
||||
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
|
||||
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
|
||||
#[no_mangle]
|
||||
fn eq_slice_of_option_of_nonzero(x: &[Option<NonZero<i16>>], y: &[Option<NonZero<i16>>]) -> bool {
|
||||
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue