Skip to content

Commit 20383c9

Browse files
committed
Auto merge of rust-lang#148350 - scottmcm:slice-range-attributes, r=JonathanBrouwer,davidtwco
Add LLVM range attributes to slice length parameters It'll take a bunch more work to do this in layout -- because of cycles in `struct Foo<'a>(&'a Foo<'a>);` -- so until we figure out how to do that well, just look for slices specifically and add the proper range for the length.
2 parents 1f880d9 + 0ba7bcf commit 20383c9

File tree

7 files changed

+100
-18
lines changed

7 files changed

+100
-18
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,28 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
528528
let ii = apply(b);
529529
if let BackendRepr::ScalarPair(scalar_a, scalar_b) = arg.layout.backend_repr {
530530
apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a);
531+
let primitive_b = scalar_b.primitive();
532+
let scalar_b = if let rustc_abi::Primitive::Int(int, false) = primitive_b
533+
&& let ty::Ref(_, pointee_ty, _) = *arg.layout.ty.kind()
534+
&& let ty::Slice(element_ty) = *pointee_ty.kind()
535+
&& let elem_size = cx.layout_of(element_ty).size
536+
&& elem_size != rustc_abi::Size::ZERO
537+
{
538+
// Ideally the layout calculations would have set the range,
539+
// but that's complicated due to cycles, so in the mean time
540+
// we calculate and apply it here.
541+
debug_assert!(scalar_b.is_always_valid(cx));
542+
let isize_max = int.signed_max() as u64;
543+
rustc_abi::Scalar::Initialized {
544+
value: primitive_b,
545+
valid_range: rustc_abi::WrappingRange {
546+
start: 0,
547+
end: u128::from(isize_max / elem_size.bytes()),
548+
},
549+
}
550+
} else {
551+
scalar_b
552+
};
531553
apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b);
532554
}
533555
}

tests/codegen-llvm/function-arguments.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,17 +208,23 @@ pub fn struct_return() -> S {
208208
#[no_mangle]
209209
pub fn helper(_: usize) {}
210210

211-
// CHECK: @slice(ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, [[USIZE]] noundef %_1.1)
211+
// CHECK: @slice(
212+
// CHECK-SAME: ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0,
213+
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1)
212214
// FIXME #25759 This should also have `nocapture`
213215
#[no_mangle]
214216
pub fn slice(_: &[u8]) {}
215217

216-
// CHECK: @mutable_slice(ptr noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1)
218+
// CHECK: @mutable_slice(
219+
// CHECK-SAME: ptr noalias noundef nonnull align 1 %_1.0,
220+
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1)
217221
// FIXME #25759 This should also have `nocapture`
218222
#[no_mangle]
219223
pub fn mutable_slice(_: &mut [u8]) {}
220224

221-
// CHECK: @unsafe_slice(ptr noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1)
225+
// CHECK: @unsafe_slice(
226+
// CHECK-SAME: ptr noundef nonnull align 2 %_1.0,
227+
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, 1073741824|i64 0, 4611686018427387904}}) %_1.1)
222228
// unsafe interior means this isn't actually readonly and there may be aliases ...
223229
#[no_mangle]
224230
pub fn unsafe_slice(_: &[UnsafeInner]) {}
@@ -227,7 +233,9 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {}
227233
#[no_mangle]
228234
pub fn raw_slice(_: *const [u8]) {}
229235

230-
// CHECK: @str(ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, [[USIZE]] noundef %_1.1)
236+
// CHECK: @str(
237+
// CHECK-SAME: ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0,
238+
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1)
231239
// FIXME #25759 This should also have `nocapture`
232240
#[no_mangle]
233241
pub fn str(_: &[u8]) {}
@@ -259,7 +267,9 @@ pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + U
259267
x
260268
}
261269

262-
// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2{{( captures\(address, read_provenance\))?}} %x.0, [[USIZE]] noundef %x.1)
270+
// CHECK: { ptr, [[USIZE]] } @return_slice(
271+
// CHECK-SAME: ptr noalias noundef nonnull readonly align 2{{( captures\(address, read_provenance\))?}} %x.0,
272+
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, 1073741824|i64 0, 4611686018427387904}}) %x.1)
263273
#[no_mangle]
264274
pub fn return_slice(x: &[u16]) -> &[u16] {
265275
x

tests/codegen-llvm/range-attribute.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,26 @@ pub fn enum2_value(x: Enum2) -> Enum2 {
6767
x
6868
}
6969

70-
// CHECK: noundef [[USIZE]] @takes_slice(ptr {{.*}} %x.0, [[USIZE]] noundef %x.1)
70+
// CHECK: noundef [[USIZE]] @takes_slice_4(ptr {{.*}} %x.0, [[USIZE]] noundef
71+
// bit32-SAME: range(i32 0, [[#0x20000000]])
72+
// bit64-SAME: range(i64 0, [[#0x2000000000000000]])
73+
// CHECK-SAME: %x.1)
7174
#[no_mangle]
72-
pub fn takes_slice(x: &[i32]) -> usize {
75+
pub fn takes_slice_4(x: &[i32]) -> usize {
76+
x.len()
77+
}
78+
79+
// CHECK: noundef [[USIZE]] @takes_slice_3(ptr {{.*}} %x.0, [[USIZE]] noundef
80+
// bit32-SAME: range(i32 0, [[#0x2AAAAAAB]])
81+
// bit64-SAME: range(i64 0, [[#0x2AAAAAAAAAAAAAAB]])
82+
// CHECK-SAME: %x.1)
83+
#[no_mangle]
84+
pub fn takes_slice_3(x: &[[u8; 3]]) -> usize {
85+
x.len()
86+
}
87+
88+
// CHECK: noundef [[USIZE]] @takes_zst_slice(ptr {{.*}} %x.0, [[USIZE]] noundef %x.1)
89+
#[no_mangle]
90+
pub fn takes_zst_slice(x: &[()]) -> usize {
7391
x.len()
7492
}

tests/codegen-llvm/slice-as_chunks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn chunks4(x: &[u8]) -> &[[u8; 4]] {
1919
// CHECK-LABEL: @chunks4_with_remainder
2020
#[no_mangle]
2121
pub fn chunks4_with_remainder(x: &[u8]) -> (&[[u8; 4]], &[u8]) {
22-
// CHECK-DAG: and i64 %x.1, -4
22+
// CHECK-DAG: and i64 %x.1, [[#0x7FFFFFFFFFFFFFFC]]
2323
// CHECK-DAG: and i64 %x.1, 3
2424
// CHECK-DAG: lshr
2525
// CHECK-NOT: mul

tests/codegen-llvm/slice-iter-nonnull.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'
5151
// attribute is there, and confirms adding the assume back doesn't do anything.
5252

5353
// CHECK-LABEL: @slice_iter_new
54-
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1)
54+
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1)
5555
#[no_mangle]
5656
pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> {
5757
// CHECK-NOT: slice
@@ -66,7 +66,7 @@ pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> {
6666
}
6767

6868
// CHECK-LABEL: @slice_iter_mut_new
69-
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1)
69+
// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1)
7070
#[no_mangle]
7171
pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> {
7272
// CHECK-NOT: slice
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ compile-flags: -C opt-level=3
2+
#![crate_type = "lib"]
3+
4+
#[no_mangle]
5+
// CHECK-LABEL: @len_plus_ten_a
6+
pub fn len_plus_ten_a(s: &[u8]) -> usize {
7+
// CHECK: start:
8+
// CHECK-NOT: add
9+
// CHECK: %[[R:.+]] = add nuw i{{.+}} %s.1, 10
10+
// CHECK-NEXT: ret {{.+}} %[[R]]
11+
s.len().wrapping_add(10)
12+
}
13+
14+
#[no_mangle]
15+
// CHECK-LABEL: @len_plus_ten_b
16+
pub fn len_plus_ten_b(s: &[u32]) -> usize {
17+
// CHECK: start:
18+
// CHECK-NOT: add
19+
// CHECK: %[[R:.+]] = add nuw nsw i{{.+}} %s.1, 10
20+
// CHECK-NEXT: ret {{.+}} %[[R]]
21+
s.len().wrapping_add(10)
22+
}
23+
24+
#[no_mangle]
25+
// CHECK-LABEL: @len_plus_len
26+
pub fn len_plus_len(x: &[u8], y: &[u8]) -> usize {
27+
// CHECK: start:
28+
// CHECK-NOT: add
29+
// CHECK: %[[R:.+]] = add nuw i{{.+}} {{%x.1, %y.1|%y.1, %x.1}}
30+
// CHECK-NEXT: ret {{.+}} %[[R]]
31+
usize::wrapping_add(x.len(), y.len())
32+
}

tests/codegen-llvm/slice-ref-equality.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool {
4242
// equality for non-byte types also just emit a `bcmp`, not a loop.
4343

4444
// CHECK-LABEL: @eq_slice_of_nested_u8(
45-
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
46-
// CHECK-SAME: [[USIZE]] noundef %y.1
45+
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
46+
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
4747
#[no_mangle]
4848
fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
4949
// 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 {
5454
}
5555

5656
// CHECK-LABEL: @eq_slice_of_i32(
57-
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
58-
// CHECK-SAME: [[USIZE]] noundef %y.1
57+
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
58+
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
5959
#[no_mangle]
6060
fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
6161
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
@@ -66,8 +66,8 @@ fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
6666
}
6767

6868
// CHECK-LABEL: @eq_slice_of_nonzero(
69-
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
70-
// CHECK-SAME: [[USIZE]] noundef %y.1
69+
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
70+
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
7171
#[no_mangle]
7272
fn eq_slice_of_nonzero(x: &[NonZero<i32>], y: &[NonZero<i32>]) -> bool {
7373
// CHECK: icmp eq [[USIZE]] %x.1, %y.1
@@ -78,8 +78,8 @@ fn eq_slice_of_nonzero(x: &[NonZero<i32>], y: &[NonZero<i32>]) -> bool {
7878
}
7979

8080
// CHECK-LABEL: @eq_slice_of_option_of_nonzero(
81-
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
82-
// CHECK-SAME: [[USIZE]] noundef %y.1
81+
// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef range({{.+}}) %x.1
82+
// CHECK-SAME: [[USIZE]] noundef range({{.+}}) %y.1
8383
#[no_mangle]
8484
fn eq_slice_of_option_of_nonzero(x: &[Option<NonZero<i16>>], y: &[Option<NonZero<i16>>]) -> bool {
8585
// CHECK: icmp eq [[USIZE]] %x.1, %y.1

0 commit comments

Comments
 (0)