about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/array-from_fn.rs13
-rw-r--r--tests/codegen/call-metadata.rs1
-rw-r--r--tests/codegen/cast-optimized.rs2
-rw-r--r--tests/codegen/common_prim_int_ptr.rs4
-rw-r--r--tests/codegen/const-vector.rs107
-rw-r--r--tests/codegen/enum/enum-match.rs2
-rw-r--r--tests/codegen/function-arguments.rs6
-rw-r--r--tests/codegen/intrinsics/nontemporal.rs30
-rw-r--r--tests/codegen/issues/issue-107681-unwrap_unchecked.rs20
-rw-r--r--tests/codegen/issues/issue-118306.rs23
-rw-r--r--tests/codegen/issues/issue-126585.rs24
-rw-r--r--tests/codegen/issues/issue-68667-unwrap-combinators.rs2
-rw-r--r--tests/codegen/issues/str-to-string-128690.rs36
-rw-r--r--tests/codegen/range-attribute.rs68
-rw-r--r--tests/codegen/repr/transparent.rs2
15 files changed, 327 insertions, 13 deletions
diff --git a/tests/codegen/array-from_fn.rs b/tests/codegen/array-from_fn.rs
new file mode 100644
index 00000000000..7202d0c67e6
--- /dev/null
+++ b/tests/codegen/array-from_fn.rs
@@ -0,0 +1,13 @@
+//@ revisions: NORMAL OPT
+//@ [NORMAL] compile-flags: -C opt-level=0 -C debuginfo=2
+//@ [OPT] compile-flags: -C opt-level=s -C debuginfo=0
+
+#![crate_type = "lib"]
+#![feature(array_from_fn)]
+
+#[no_mangle]
+pub fn iota() -> [u8; 16] {
+    // OPT-NOT: core..array..Guard
+    // NORMAL: core..array..Guard
+    std::array::from_fn(|i| i as _)
+}
diff --git a/tests/codegen/call-metadata.rs b/tests/codegen/call-metadata.rs
index b2168990ff8..73c4b33e2cf 100644
--- a/tests/codegen/call-metadata.rs
+++ b/tests/codegen/call-metadata.rs
@@ -2,6 +2,7 @@
 // scalar value.
 
 //@ compile-flags: -O -C no-prepopulate-passes
+//@ ignore-llvm-version: 19 - 99
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/cast-optimized.rs b/tests/codegen/cast-optimized.rs
index 313b2b4f0d6..59cf40935cd 100644
--- a/tests/codegen/cast-optimized.rs
+++ b/tests/codegen/cast-optimized.rs
@@ -20,8 +20,6 @@ pub fn u32_index(c: u32) -> [bool; 22] {
 // CHECK-LABEL: @char_as_u32_index
 #[no_mangle]
 pub fn char_as_u32_index(c: char) -> [bool; 22] {
-    // CHECK: %[[B:.+]] = icmp ult i32 %c, 1114112
-    // CHECK: call void @llvm.assume(i1 %[[B]])
     let c = c as u32;
 
     let mut array = [false; 22];
diff --git a/tests/codegen/common_prim_int_ptr.rs b/tests/codegen/common_prim_int_ptr.rs
index 87fa89abb86..aa7ebb4c911 100644
--- a/tests/codegen/common_prim_int_ptr.rs
+++ b/tests/codegen/common_prim_int_ptr.rs
@@ -28,7 +28,7 @@ pub fn insert_box(x: Box<()>) -> Result<usize, Box<()>> {
 
 // CHECK-LABEL: @extract_int
 // CHECK-NOT: nonnull
-// CHECK-SAME: (i{{[0-9]+}} {{[^,]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
+// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
 #[no_mangle]
 pub unsafe fn extract_int(x: Result<usize, Box<()>>) -> usize {
     // CHECK: [[TEMP:%.+]] = ptrtoint ptr [[PAYLOAD]] to [[USIZE:i[0-9]+]]
@@ -40,7 +40,7 @@ pub unsafe fn extract_int(x: Result<usize, Box<()>>) -> usize {
 }
 
 // CHECK-LABEL: @extract_box
-// CHECK-SAME: (i{{[0-9]+}} {{[^,]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
+// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
 #[no_mangle]
 pub unsafe fn extract_box(x: Result<usize, Box<i32>>) -> Box<i32> {
     // CHECK: ret ptr [[PAYLOAD]]
diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs
new file mode 100644
index 00000000000..d368838201e
--- /dev/null
+++ b/tests/codegen/const-vector.rs
@@ -0,0 +1,107 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+// This test checks that constants of SIMD type are passed as immediate vectors.
+// We ensure that both vector representations (struct with fields and struct wrapping array) work.
+#![crate_type = "lib"]
+#![feature(abi_unadjusted)]
+#![feature(const_trait_impl)]
+#![feature(repr_simd)]
+#![feature(rustc_attrs)]
+#![feature(simd_ffi)]
+#![allow(non_camel_case_types)]
+
+// Setting up structs that can be used as const vectors
+#[repr(simd)]
+#[derive(Clone)]
+pub struct i8x2(i8, i8);
+
+#[repr(simd)]
+#[derive(Clone)]
+pub struct i8x2_arr([i8; 2]);
+
+#[repr(simd)]
+#[derive(Clone)]
+pub struct f32x2(f32, f32);
+
+#[repr(simd)]
+#[derive(Clone)]
+pub struct f32x2_arr([f32; 2]);
+
+#[repr(simd, packed)]
+#[derive(Copy, Clone)]
+pub struct Simd<T, const N: usize>([T; N]);
+
+// The following functions are required for the tests to ensure
+// that they are called with a const vector
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2(a: i8x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2_two_args(a: i8x2, b: i8x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2_mixed_args(a: i8x2, c: i32, b: i8x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2_arr(a: i8x2_arr);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_f32x2(a: f32x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_f32x2_arr(a: f32x2_arr);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_simd(a: Simd<i32, 4>);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_simd_unaligned(a: Simd<i32, 3>);
+}
+
+// Ensure the packed variant of the simd struct does not become a const vector
+// if the size is not a power of 2
+// CHECK: %"Simd<i32, 3>" = type { [3 x i32] }
+
+pub fn do_call() {
+    unsafe {
+        // CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64>
+        test_i8x2(const { i8x2(32, 64) });
+
+        // CHECK: call void @test_i8x2_two_args(<2 x i8> <i8 32, i8 64>, <2 x i8> <i8 8, i8 16>
+        test_i8x2_two_args(const { i8x2(32, 64) }, const { i8x2(8, 16) });
+
+        // CHECK: call void @test_i8x2_mixed_args(<2 x i8> <i8 32, i8 64>, i32 43, <2 x i8> <i8 8, i8 16>
+        test_i8x2_mixed_args(const { i8x2(32, 64) }, 43, const { i8x2(8, 16) });
+
+        // CHECK: call void @test_i8x2_arr(<2 x i8> <i8 32, i8 64>
+        test_i8x2_arr(const { i8x2_arr([32, 64]) });
+
+        // CHECK: call void @test_f32x2(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
+        test_f32x2(const { f32x2(0.32, 0.64) });
+
+        // CHECK: void @test_f32x2_arr(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
+        test_f32x2_arr(const { f32x2_arr([0.32, 0.64]) });
+
+        // CHECK: call void @test_simd(<4 x i32> <i32 2, i32 4, i32 6, i32 8>
+        test_simd(const { Simd::<i32, 4>([2, 4, 6, 8]) });
+
+        // CHECK: call void @test_simd_unaligned(%"Simd<i32, 3>" %1
+        test_simd_unaligned(const { Simd::<i32, 3>([2, 4, 6]) });
+    }
+}
diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs
index 8da5de63e67..a24b98050d2 100644
--- a/tests/codegen/enum/enum-match.rs
+++ b/tests/codegen/enum/enum-match.rs
@@ -34,7 +34,7 @@ pub enum Enum1 {
 
 // CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1{{.*}}
 // CHECK-NEXT: start:
-// CHECK-NEXT: %1 = add i8 %0, -2
+// CHECK-NEXT: %1 = add{{( nsw)?}} i8 %0, -2
 // CHECK-NEXT: %2 = zext i8 %1 to i64
 // CHECK-NEXT: %3 = icmp ult i8 %1, 2
 // CHECK-NEXT: %4 = add nuw nsw i64 %2, 1
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index 56504df4034..bf9f405192b 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -50,7 +50,7 @@ pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
     x
 }
 
-// CHECK: noundef i32 @char(i32 noundef %x)
+// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32 noundef{{( range\(i32 0, 1114112\))?}} %x)
 #[no_mangle]
 pub fn char(x: char) -> char {
     x
@@ -68,7 +68,7 @@ pub fn int(x: u64) -> u64 {
     x
 }
 
-// CHECK: noundef i64 @nonzero_int(i64 noundef %x)
+// CHECK: noundef{{( range\(i64 1, 0\))?}} i64 @nonzero_int(i64 noundef{{( range\(i64 1, 0\))?}} %x)
 #[no_mangle]
 pub fn nonzero_int(x: NonZero<u64>) -> NonZero<u64> {
     x
@@ -250,7 +250,7 @@ pub fn return_slice(x: &[u16]) -> &[u16] {
     x
 }
 
-// CHECK: { i16, i16 } @enum_id_1(i16 noundef %x.0, i16 %x.1)
+// CHECK: { i16, i16 } @enum_id_1(i16 noundef{{( range\(i16 0, 3\))?}} %x.0, i16 %x.1)
 #[no_mangle]
 pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
     x
diff --git a/tests/codegen/intrinsics/nontemporal.rs b/tests/codegen/intrinsics/nontemporal.rs
index 076d6d6d9da..ff2d6296066 100644
--- a/tests/codegen/intrinsics/nontemporal.rs
+++ b/tests/codegen/intrinsics/nontemporal.rs
@@ -1,13 +1,37 @@
 //@ compile-flags: -O
+//@revisions: with_nontemporal without_nontemporal
+//@[with_nontemporal] compile-flags: --target aarch64-unknown-linux-gnu
+//@[with_nontemporal] needs-llvm-components: aarch64
+//@[without_nontemporal] compile-flags: --target x86_64-unknown-linux-gnu
+//@[without_nontemporal] needs-llvm-components: x86
 
-#![feature(core_intrinsics)]
+// Ensure that we *do* emit the `!nontemporal` flag on architectures where it
+// is well-behaved, but do *not* emit it on architectures where it is ill-behaved.
+// For more context, see <https://github.com/rust-lang/rust/issues/114582> and
+// <https://github.com/llvm/llvm-project/issues/64521>.
+
+#![feature(no_core, lang_items, intrinsics)]
+#![no_core]
 #![crate_type = "lib"]
 
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+impl Copy for u32 {}
+impl<T> Copy for *mut T {}
+
+extern "rust-intrinsic" {
+    pub fn nontemporal_store<T>(ptr: *mut T, val: T);
+}
+
 #[no_mangle]
 pub fn a(a: &mut u32, b: u32) {
     // CHECK-LABEL: define{{.*}}void @a
-    // CHECK: store i32 %b, ptr %a, align 4, !nontemporal
+    // with_nontemporal: store i32 %b, ptr %a, align 4, !nontemporal
+    // without_nontemporal-NOT: nontemporal
     unsafe {
-        std::intrinsics::nontemporal_store(a, b);
+        nontemporal_store(a, b);
     }
 }
diff --git a/tests/codegen/issues/issue-107681-unwrap_unchecked.rs b/tests/codegen/issues/issue-107681-unwrap_unchecked.rs
new file mode 100644
index 00000000000..7d9679d2322
--- /dev/null
+++ b/tests/codegen/issues/issue-107681-unwrap_unchecked.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -O
+//@ min-llvm-version: 19
+
+// Test for #107681.
+// Make sure we don't create `br` or `select` instructions.
+
+#![crate_type = "lib"]
+
+use std::iter::Copied;
+use std::slice::Iter;
+
+#[no_mangle]
+pub unsafe fn foo(x: &mut Copied<Iter<'_, u32>>) -> u32 {
+    // CHECK-LABEL: @foo(
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    // CHECK: [[RET:%.*]] = load i32, ptr
+    // CHECK-NEXT: ret i32 [[RET]]
+    x.next().unwrap_unchecked()
+}
diff --git a/tests/codegen/issues/issue-118306.rs b/tests/codegen/issues/issue-118306.rs
new file mode 100644
index 00000000000..8af1c6a971c
--- /dev/null
+++ b/tests/codegen/issues/issue-118306.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -O
+//@ min-llvm-version: 19
+//@ only-x86_64
+
+// Test for #118306.
+// Make sure we don't create `br` or `select` instructions.
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn branchy(input: u64) -> u64 {
+    // CHECK-LABEL: @branchy(
+    // CHECK-NEXT:  start:
+    // CHECK-NEXT:    [[_2:%.*]] = and i64 [[INPUT:%.*]], 3
+    // CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i64], ptr @switch.table.branchy, i64 0, i64 [[_2]]
+    // CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]]
+    // CHECK-NEXT:    ret i64 [[SWITCH_LOAD]]
+    match input % 4 {
+        1 | 2 => 1,
+        3 => 2,
+        _ => 0,
+    }
+}
diff --git a/tests/codegen/issues/issue-126585.rs b/tests/codegen/issues/issue-126585.rs
new file mode 100644
index 00000000000..a468efd728d
--- /dev/null
+++ b/tests/codegen/issues/issue-126585.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -Copt-level=s
+//@ min-llvm-version: 19
+//@ only-x86_64
+
+// Test for #126585.
+// Ensure that this IR doesn't have extra undef phi input, which also guarantees that this asm
+// doesn't have subsequent labels and unnecessary `jmp` instructions.
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+fn checked_div_round(a: u64, b: u64) -> Option<u64> {
+    // CHECK-LABEL: @checked_div_round
+    // CHECK: phi
+    // CHECK-NOT: undef
+    // CHECK: phi
+    // CHECK-NOT: undef
+    match b {
+        0 => None,
+        1 => Some(a),
+        // `a / b` is computable and `(a % b) * 2` can not overflow since `b >= 2`.
+        b => Some(a / b + if (a % b) * 2 >= b { 1 } else { 0 }),
+    }
+}
diff --git a/tests/codegen/issues/issue-68667-unwrap-combinators.rs b/tests/codegen/issues/issue-68667-unwrap-combinators.rs
index 6bd4c566a0c..21a5a5bf4ee 100644
--- a/tests/codegen/issues/issue-68667-unwrap-combinators.rs
+++ b/tests/codegen/issues/issue-68667-unwrap-combinators.rs
@@ -5,7 +5,7 @@
 // MIR inlining now optimizes this code.
 
 // CHECK-LABEL: @unwrap_combinators
-// CHECK: icmp
+// CHECK: {{icmp|trunc}}
 // CHECK-NEXT: icmp
 // CHECK-NEXT: select i1
 // CHECK-NEXT: ret i1
diff --git a/tests/codegen/issues/str-to-string-128690.rs b/tests/codegen/issues/str-to-string-128690.rs
new file mode 100644
index 00000000000..8b416306ba6
--- /dev/null
+++ b/tests/codegen/issues/str-to-string-128690.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
+#![crate_type = "lib"]
+
+//! Make sure str::to_string is specialized not to use fmt machinery.
+
+// CHECK-LABEL: define {{(dso_local )?}}void @one_ref
+#[no_mangle]
+pub fn one_ref(input: &str) -> String {
+    // CHECK-NOT: {{(call|invoke).*}}fmt
+    input.to_string()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}void @two_ref
+#[no_mangle]
+pub fn two_ref(input: &&str) -> String {
+    // CHECK-NOT: {{(call|invoke).*}}fmt
+    input.to_string()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref
+#[no_mangle]
+pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
+    // CHECK-NOT: {{(call|invoke).*}}fmt
+    input.to_string()
+}
+
+// This is a known performance cliff because of the macro-generated
+// specialized impl. If this test suddenly starts failing,
+// consider removing the `to_string_str!` macro in `alloc/str/string.rs`.
+//
+// CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref
+#[no_mangle]
+pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String {
+    // CHECK: {{(call|invoke).*}}fmt
+    input.to_string()
+}
diff --git a/tests/codegen/range-attribute.rs b/tests/codegen/range-attribute.rs
new file mode 100644
index 00000000000..bb19bec0fb9
--- /dev/null
+++ b/tests/codegen/range-attribute.rs
@@ -0,0 +1,68 @@
+// Checks that range metadata gets emitted on functions result and arguments
+// with scalar value.
+
+//@ compile-flags: -O -C no-prepopulate-passes
+//@ min-llvm-version: 19
+
+#![crate_type = "lib"]
+
+use std::num::NonZero;
+
+// Hack to get the correct size for usize
+// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// CHECK: noundef range(i128 1, 0) i128 @nonzero_int(i128 noundef range(i128 1, 0) %x)
+#[no_mangle]
+pub fn nonzero_int(x: NonZero<u128>) -> NonZero<u128> {
+    x
+}
+
+// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8 noundef range(i8 0, 3) %x)
+#[no_mangle]
+pub fn optional_bool(x: Option<bool>) -> Option<bool> {
+    x
+}
+
+pub enum Enum0 {
+    A(bool),
+    B,
+    C,
+}
+
+// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8 noundef range(i8 0, 4) %x)
+#[no_mangle]
+pub fn enum0_value(x: Enum0) -> Enum0 {
+    x
+}
+
+pub enum Enum1 {
+    A(u64),
+    B(u64),
+    C(u64),
+}
+
+// CHECK: { [[ENUM1_TYP:i[0-9]+]], i64 } @enum1_value([[ENUM1_TYP]] noundef range([[ENUM1_TYP]] 0, 3) %x.0, i64 noundef %x.1)
+#[no_mangle]
+pub fn enum1_value(x: Enum1) -> Enum1 {
+    x
+}
+
+pub enum Enum2 {
+    A(Enum0),
+    B(Enum0),
+    C(Enum0),
+}
+
+// CHECK: { i8, i8 } @enum2_value(i8 noundef range(i8 0, 3) %x.0, i8 noundef %x.1)
+#[no_mangle]
+pub fn enum2_value(x: Enum2) -> Enum2 {
+    x
+}
+
+// CHECK: noundef [[USIZE]] @takes_slice(ptr noalias noundef nonnull readonly align 4 %x.0, [[USIZE]] noundef %x.1)
+#[no_mangle]
+pub fn takes_slice(x: &[i32]) -> usize {
+    x.len()
+}
diff --git a/tests/codegen/repr/transparent.rs b/tests/codegen/repr/transparent.rs
index 4b41332db45..9140b8542ec 100644
--- a/tests/codegen/repr/transparent.rs
+++ b/tests/codegen/repr/transparent.rs
@@ -74,7 +74,7 @@ pub enum Bool {
     FileNotFound,
 }
 
-// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?}} i8 @test_Gpz(i8 noundef{{( zeroext)?}} %_1)
+// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?( range\(i8 0, 3\))?}} i8 @test_Gpz(i8 noundef{{( zeroext)?( range\(i8 0, 3\))?}} %_1)
 #[no_mangle]
 pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> {
     loop {}