diff options
Diffstat (limited to 'tests/codegen')
| -rw-r--r-- | tests/codegen/array-equality.rs | 30 | ||||
| -rw-r--r-- | tests/codegen/comparison-operators-2-tuple.rs | 121 | ||||
| -rw-r--r-- | tests/codegen/consts.rs | 4 | ||||
| -rw-r--r-- | tests/codegen/option-as-slice.rs | 36 | ||||
| -rw-r--r-- | tests/codegen/remap_path_prefix/main.rs | 2 | ||||
| -rw-r--r-- | tests/codegen/slice-indexing.rs | 35 | ||||
| -rw-r--r-- | tests/codegen/slice-ref-equality.rs | 56 | ||||
| -rw-r--r-- | tests/codegen/thread-local.rs | 1 |
8 files changed, 280 insertions, 5 deletions
diff --git a/tests/codegen/array-equality.rs b/tests/codegen/array-equality.rs index cd5e82a9205..abfe295f8b6 100644 --- a/tests/codegen/array-equality.rs +++ b/tests/codegen/array-equality.rs @@ -1,4 +1,4 @@ -// compile-flags: -O +// compile-flags: -O -Z merge-functions=disabled // only-x86_64 #![crate_type = "lib"] @@ -43,6 +43,15 @@ pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool { a == b } +// CHECK-LABEL: @array_char_eq +#[no_mangle] +pub fn array_char_eq(a: [char; 2], b: [char; 2]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i64 %0, %1 + // CHECK-NEXT: ret i1 %[[EQ]] + a == b +} + // CHECK-LABEL: @array_eq_zero_short(i48 #[no_mangle] pub fn array_eq_zero_short(x: [u16; 3]) -> bool { @@ -52,6 +61,25 @@ pub fn array_eq_zero_short(x: [u16; 3]) -> bool { x == [0; 3] } +// CHECK-LABEL: @array_eq_none_short(i40 +#[no_mangle] +pub fn array_eq_none_short(x: [Option<std::num::NonZeroU8>; 5]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i40 %0, 0 + // CHECK-NEXT: ret i1 %[[EQ]] + x == [None; 5] +} + +// CHECK-LABEL: @array_eq_zero_nested( +#[no_mangle] +pub fn array_eq_zero_nested(x: [[u8; 3]; 3]) -> bool { + // CHECK: %[[VAL:.+]] = load i72 + // CHECK-SAME: align 1 + // CHECK: %[[EQ:.+]] = icmp eq i72 %[[VAL]], 0 + // CHECK: ret i1 %[[EQ]] + x == [[0; 3]; 3] +} + // CHECK-LABEL: @array_eq_zero_mid( #[no_mangle] pub fn array_eq_zero_mid(x: [u16; 8]) -> bool { diff --git a/tests/codegen/comparison-operators-2-tuple.rs b/tests/codegen/comparison-operators-2-tuple.rs new file mode 100644 index 00000000000..a9d25e3b53c --- /dev/null +++ b/tests/codegen/comparison-operators-2-tuple.rs @@ -0,0 +1,121 @@ +// compile-flags: -C opt-level=1 -Z merge-functions=disabled +// min-llvm-version: 15.0 +// only-x86_64 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +type TwoTuple = (i16, u16); + +// +// The operators are all overridden directly, so should optimize easily. +// +// Yes, the `s[lg]t` is correct for the `[lg]e` version because it's only used +// in the side of the select where we know the values are *not* equal. +// + +// CHECK-LABEL: @check_lt_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_lt_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a < b +} + +// CHECK-LABEL: @check_le_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_le_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a <= b +} + +// CHECK-LABEL: @check_gt_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_gt_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a > b +} + +// CHECK-LABEL: @check_ge_direct +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_ge_direct(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + a >= b +} + +// +// These ones are harder, since there are more intermediate values to remove. +// +// `<` seems to be getting lucky right now, so test that doesn't regress. +// +// The others, however, aren't managing to optimize away the extra `select`s yet. +// See <https://github.com/rust-lang/rust/issues/106107> for more about this. +// + +// CHECK-LABEL: @check_lt_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_lt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]] + // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]] + // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_lt() +} + +// CHECK-LABEL: @check_le_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_le_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sle i16 %[[A0]], %[[B0]] + // FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]] + // FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // FIXME-CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_le() +} + +// CHECK-LABEL: @check_gt_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_gt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]] + // FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]] + // FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // FIXME-CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_gt() +} + +// CHECK-LABEL: @check_ge_via_cmp +// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]]) +#[no_mangle] +pub fn check_ge_via_cmp(a: TwoTuple, b: TwoTuple) -> bool { + // FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]] + // FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sge i16 %[[A0]], %[[B0]] + // FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]] + // FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]] + // FIXME-CHECK: ret i1 %[[R]] + Ord::cmp(&a, &b).is_ge() +} diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs index d0418d11142..dd22fd0f7e8 100644 --- a/tests/codegen/consts.rs +++ b/tests/codegen/consts.rs @@ -9,11 +9,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @alloc12 = {{.*}}, align 2 +// CHECK: @alloc_76bfe2f13a3e3b01074971d122eac57e = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@alloc[0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs new file mode 100644 index 00000000000..d735d558374 --- /dev/null +++ b/tests/codegen/option-as-slice.rs @@ -0,0 +1,36 @@ +// compile-flags: -O -Z randomize-layout=no +// only-x86_64 + +#![crate_type = "lib"] +#![feature(option_as_slice)] + +extern crate core; + +use core::num::NonZeroU64; +use core::option::Option; + +// CHECK-LABEL: @u64_opt_as_slice +#[no_mangle] +pub fn u64_opt_as_slice(o: &Option<u64>) -> &[u64] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + o.as_slice() +} + +// CHECK-LABEL: @nonzero_u64_opt_as_slice +#[no_mangle] +pub fn nonzero_u64_opt_as_slice(o: &Option<NonZeroU64>) -> &[NonZeroU64] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0 + // CHECK-NEXT: zext i1 %[[NZ]] to i64 + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + o.as_slice() +} diff --git a/tests/codegen/remap_path_prefix/main.rs b/tests/codegen/remap_path_prefix/main.rs index 78ebbccfce1..6c0cd6997d0 100644 --- a/tests/codegen/remap_path_prefix/main.rs +++ b/tests/codegen/remap_path_prefix/main.rs @@ -12,7 +12,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: @alloc2 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }> +// CHECK: @alloc_92a59126a55aa3c0019b6c8a007fe001 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }> pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs new file mode 100644 index 00000000000..c40d59fb0cf --- /dev/null +++ b/tests/codegen/slice-indexing.rs @@ -0,0 +1,35 @@ +// compile-flags: -O +// only-64bit (because the LLVM type of i64 for usize shows up) +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::ops::Range; + +// CHECK-LABEL: @index_by_range( +#[no_mangle] +pub fn index_by_range(x: &[u16], r: Range<usize>) -> &[u16] { + // CHECK: sub nuw i64 + &x[r] +} + +// CHECK-LABEL: @get_unchecked_by_range( +#[no_mangle] +pub unsafe fn get_unchecked_by_range(x: &[u16], r: Range<usize>) -> &[u16] { + // CHECK: sub nuw i64 + x.get_unchecked(r) +} + +// CHECK-LABEL: @index_mut_by_range( +#[no_mangle] +pub fn index_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] { + // CHECK: sub nuw i64 + &mut x[r] +} + +// CHECK-LABEL: @get_unchecked_mut_by_range( +#[no_mangle] +pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] { + // CHECK: sub nuw i64 + x.get_unchecked_mut(r) +} diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs index 47fde12bf30..8f0adab35e7 100644 --- a/tests/codegen/slice-ref-equality.rs +++ b/tests/codegen/slice-ref-equality.rs @@ -1,7 +1,10 @@ -// compile-flags: -C opt-level=3 -Zmerge-functions=disabled +// compile-flags: -O -Zmerge-functions=disabled +// ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] +use std::num::{NonZeroI16, NonZeroU32}; + // #71602 reported a simple array comparison just generating a loop. // This was originally fixed by ensuring it generates a single bcmp, // but we now generate it as a load+icmp instead. `is_zero_slice` was @@ -36,3 +39,54 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool { // CHECK-NEXT: ret i1 %[[EQ]] *data == [0; 4] } + +// The following test the extra specializations to make sure that slice +// 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 %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %1, 3 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i8\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_i32( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_nonzero( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_option_of_nonzero( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_option_of_nonzero(x: &[Option<NonZeroI16>], y: &[Option<NonZeroI16>]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 1 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i16\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} diff --git a/tests/codegen/thread-local.rs b/tests/codegen/thread-local.rs index 0f1b29ca79b..aa7fab7fb17 100644 --- a/tests/codegen/thread-local.rs +++ b/tests/codegen/thread-local.rs @@ -4,6 +4,7 @@ // ignore-wasm globals are used instead of thread locals // ignore-emscripten globals are used instead of thread locals // ignore-android does not use #[thread_local] +// ignore-nto does not use #[thread_local] #![crate_type = "lib"] |
