about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-01-08 09:23:40 +0100
committerRalf Jung <post@ralfj.de>2025-01-08 09:23:40 +0100
commit2d180714e14b34e36bf883bdf706ebaf5fa96754 (patch)
tree36b4829675d832d323283fc37457f6509f8a519c /tests/codegen
parentfc4a52f598f6259a98964aa3290e9e74e396c1e3 (diff)
parent67f49010adf4ec3238564ec072b3652179813dd1 (diff)
downloadrust-2d180714e14b34e36bf883bdf706ebaf5fa96754.tar.gz
rust-2d180714e14b34e36bf883bdf706ebaf5fa96754.zip
Merge from rustc
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/bool-select-unpredictable.rs35
-rw-r--r--tests/codegen/emscripten-catch-unwind-js-eh.rs (renamed from tests/codegen/emcripten-catch-unwind.rs)0
-rw-r--r--tests/codegen/emscripten-catch-unwind-wasm-eh.rs65
-rw-r--r--tests/codegen/intrinsics/select_unpredictable.rs39
-rw-r--r--tests/codegen/min-function-alignment.rs43
-rw-r--r--tests/codegen/naked-fn/min-function-alignment.rs44
-rw-r--r--tests/codegen/slice-init.rs26
-rw-r--r--tests/codegen/target-feature-overrides.rs8
-rw-r--r--tests/codegen/tied-features-strength.rs5
-rw-r--r--tests/codegen/vec-in-place.rs54
-rw-r--r--tests/codegen/vec_pop_push_noop.rs3
11 files changed, 265 insertions, 57 deletions
diff --git a/tests/codegen/bool-select-unpredictable.rs b/tests/codegen/bool-select-unpredictable.rs
deleted file mode 100644
index 1562b177542..00000000000
--- a/tests/codegen/bool-select-unpredictable.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-//@ compile-flags: -O
-
-#![feature(select_unpredictable)]
-#![crate_type = "lib"]
-
-#[no_mangle]
-pub fn test_int(p: bool, a: u64, b: u64) -> u64 {
-    // CHECK-LABEL: define{{.*}} @test_int
-    // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
-    p.select_unpredictable(a, b)
-}
-
-#[no_mangle]
-pub fn test_pair(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
-    // CHECK-LABEL: define{{.*}} @test_pair
-    // CHECK: select i1 %p, {{.*}}, !unpredictable
-    p.select_unpredictable(a, b)
-}
-
-struct Large {
-    e: [u64; 100],
-}
-
-#[no_mangle]
-pub fn test_struct(p: bool, a: Large, b: Large) -> Large {
-    // CHECK-LABEL: define{{.*}} @test_struct
-    // CHECK: select i1 %p, {{.*}}, !unpredictable
-    p.select_unpredictable(a, b)
-}
-
-#[no_mangle]
-pub fn test_zst(p: bool, a: (), b: ()) -> () {
-    // CHECK-LABEL: define{{.*}} @test_zst
-    p.select_unpredictable(a, b)
-}
diff --git a/tests/codegen/emcripten-catch-unwind.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs
index b15fb40b68f..b15fb40b68f 100644
--- a/tests/codegen/emcripten-catch-unwind.rs
+++ b/tests/codegen/emscripten-catch-unwind-js-eh.rs
diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
new file mode 100644
index 00000000000..72395f432d5
--- /dev/null
+++ b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
@@ -0,0 +1,65 @@
+//@ compile-flags: -O --target wasm32-unknown-emscripten -Z emscripten-wasm-eh
+//@ needs-llvm-components: webassembly
+
+// Emscripten catch_unwind using wasm exceptions
+
+#![feature(no_core, lang_items, intrinsics, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "freeze"]
+trait Freeze {}
+#[lang = "copy"]
+trait Copy {}
+
+impl<T> Copy for *mut T {}
+
+#[rustc_intrinsic]
+fn size_of<T>() -> usize {
+    loop {}
+}
+
+extern "rust-intrinsic" {
+    fn catch_unwind(
+        try_fn: fn(_: *mut u8),
+        data: *mut u8,
+        catch_fn: fn(_: *mut u8, _: *mut u8),
+    ) -> i32;
+}
+
+// CHECK-LABEL: @ptr_size
+#[no_mangle]
+pub fn ptr_size() -> usize {
+    // CHECK: ret [[PTR_SIZE:.*]]
+    size_of::<*mut u8>()
+}
+
+// CHECK-LABEL: @test_catch_unwind
+#[no_mangle]
+pub unsafe fn test_catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32 {
+    // CHECK: start:
+    // CHECK: invoke void %try_fn(ptr %data)
+    // CHECK:         to label %__rust_try.exit unwind label %catchswitch.i
+    // CHECK:   catchswitch.i:                                    ; preds = %start
+    // CHECK:   %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller
+
+    // CHECK: catchpad.i:                                       ; preds = %catchswitch.i
+    // CHECK:   %catchpad2.i = catchpad within %catchswitch1.i [ptr null]
+    // CHECK:   %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i)
+    // CHECK:   %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i)
+    // CHECK:   call void %catch_fn(ptr %data, ptr %0) [ "funclet"(token %catchpad2.i) ]
+    // CHECK:   catchret from %catchpad2.i to label %__rust_try.exit
+
+    // CHECK: __rust_try.exit:                                  ; preds = %start, %catchpad.i
+    // CHECK:   %common.ret.op.i = phi i32 [ 0, %start ], [ 1, %catchpad.i ]
+    // CHECK:   ret i32 %common.ret.op.i
+
+    catch_unwind(try_fn, data, catch_fn)
+}
diff --git a/tests/codegen/intrinsics/select_unpredictable.rs b/tests/codegen/intrinsics/select_unpredictable.rs
index 2054838dd79..ea6127a48bf 100644
--- a/tests/codegen/intrinsics/select_unpredictable.rs
+++ b/tests/codegen/intrinsics/select_unpredictable.rs
@@ -1,8 +1,11 @@
-//@ compile-flags: -O
+//@ compile-flags: -O -Zmerge-functions=disabled
 
 #![feature(core_intrinsics)]
+#![feature(select_unpredictable)]
 #![crate_type = "lib"]
 
+/* Test the intrinsic */
+
 #[no_mangle]
 pub fn test_int(p: bool, a: u64, b: u64) -> u64 {
     // CHECK-LABEL: define{{.*}} @test_int
@@ -28,8 +31,42 @@ pub fn test_struct(p: bool, a: Large, b: Large) -> Large {
     core::intrinsics::select_unpredictable(p, a, b)
 }
 
+// ZSTs should not need a `select` expression.
 #[no_mangle]
 pub fn test_zst(p: bool, a: (), b: ()) -> () {
     // CHECK-LABEL: define{{.*}} @test_zst
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret void
     core::intrinsics::select_unpredictable(p, a, b)
 }
+
+/* Test the user-facing version */
+
+#[no_mangle]
+pub fn test_int2(p: bool, a: u64, b: u64) -> u64 {
+    // CHECK-LABEL: define{{.*}} @test_int2
+    // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
+    p.select_unpredictable(a, b)
+}
+
+#[no_mangle]
+pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
+    // CHECK-LABEL: define{{.*}} @test_pair2
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    p.select_unpredictable(a, b)
+}
+
+#[no_mangle]
+pub fn test_struct2(p: bool, a: Large, b: Large) -> Large {
+    // CHECK-LABEL: define{{.*}} @test_struct2
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    p.select_unpredictable(a, b)
+}
+
+#[no_mangle]
+pub fn test_zst2(p: bool, a: (), b: ()) -> () {
+    // CHECK-LABEL: define{{.*}} @test_zst2
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: ret void
+    p.select_unpredictable(a, b)
+}
diff --git a/tests/codegen/min-function-alignment.rs b/tests/codegen/min-function-alignment.rs
new file mode 100644
index 00000000000..7c0ad12402a
--- /dev/null
+++ b/tests/codegen/min-function-alignment.rs
@@ -0,0 +1,43 @@
+//@ revisions: align16 align1024
+//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+//@ [align16] compile-flags: -Zmin-function-alignment=16
+//@ [align1024] compile-flags: -Zmin-function-alignment=1024
+
+#![crate_type = "lib"]
+#![feature(fn_align)]
+
+// functions without explicit alignment use the global minimum
+//
+// CHECK-LABEL: @no_explicit_align
+// align16: align 16
+// align1024: align 1024
+#[no_mangle]
+pub fn no_explicit_align() {}
+
+// CHECK-LABEL: @lower_align
+// align16: align 16
+// align1024: align 1024
+#[no_mangle]
+#[repr(align(8))]
+pub fn lower_align() {}
+
+// the higher value of min-function-alignment and repr(align) wins out
+//
+// CHECK-LABEL: @higher_align
+// align16: align 32
+// align1024: align 1024
+#[no_mangle]
+#[repr(align(32))]
+pub fn higher_align() {}
+
+// cold functions follow the same rules as other functions
+//
+// in GCC, the `-falign-functions` does not apply to cold functions, but
+// `-Zmin-function-alignment` applies to all functions.
+//
+// CHECK-LABEL: @no_explicit_align_cold
+// align16: align 16
+// align1024: align 1024
+#[no_mangle]
+#[cold]
+pub fn no_explicit_align_cold() {}
diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs
new file mode 100644
index 00000000000..1330d796d39
--- /dev/null
+++ b/tests/codegen/naked-fn/min-function-alignment.rs
@@ -0,0 +1,44 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16
+//@ needs-asm-support
+//@ ignore-arm no "ret" mnemonic
+
+#![feature(naked_functions, fn_align)]
+#![crate_type = "lib"]
+
+// functions without explicit alignment use the global minimum
+//
+// CHECK: .balign 16
+#[no_mangle]
+#[naked]
+pub unsafe extern "C" fn naked_no_explicit_align() {
+    core::arch::naked_asm!("ret")
+}
+
+// CHECK: .balign 16
+#[no_mangle]
+#[repr(align(8))]
+#[naked]
+pub unsafe extern "C" fn naked_lower_align() {
+    core::arch::naked_asm!("ret")
+}
+
+// CHECK: .balign 32
+#[no_mangle]
+#[repr(align(32))]
+#[naked]
+pub unsafe extern "C" fn naked_higher_align() {
+    core::arch::naked_asm!("ret")
+}
+
+// cold functions follow the same rules as other functions
+//
+// in GCC, the `-falign-functions` does not apply to cold functions, but
+// `-Zmin-function-alignment` applies to all functions.
+//
+// CHECK: .balign 16
+#[no_mangle]
+#[cold]
+#[naked]
+pub unsafe extern "C" fn no_explicit_align_cold() {
+    core::arch::naked_asm!("ret")
+}
diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs
index 8126bf84618..1c2dd3e8875 100644
--- a/tests/codegen/slice-init.rs
+++ b/tests/codegen/slice-init.rs
@@ -63,6 +63,32 @@ pub fn nonzero_integer_array() {
     opaque(&x);
 }
 
+const N: usize = 100;
+
+// CHECK-LABEL: @u16_init_one_bytes
+#[no_mangle]
+pub fn u16_init_one_bytes() -> [u16; N] {
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: call void @llvm.memset.p0
+    [const { u16::from_be_bytes([1, 1]) }; N]
+}
+
+// FIXME: undef bytes can just be initialized with the same value as the
+// defined bytes, if the defines bytes are all the same.
+// CHECK-LABEL: @option_none_init
+#[no_mangle]
+pub fn option_none_init() -> [Option<u8>; N] {
+    // CHECK-NOT: select
+    // CHECK: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: switch
+    // CHECK: icmp
+    // CHECK-NOT: call void @llvm.memset.p0
+    [None; N]
+}
+
 // Use an opaque function to prevent rustc from removing useless drops.
 #[inline(never)]
 pub fn opaque(_: impl Sized) {}
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
index f38a1ae72de..e7f70a1e24a 100644
--- a/tests/codegen/target-feature-overrides.rs
+++ b/tests/codegen/target-feature-overrides.rs
@@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
 }
 
 // CHECK: attributes [[APPLEATTRS]]
-// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
+// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx,+avx,{{.*}}"
 // CHECK: attributes [[BANANAATTRS]]
-// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx"
+// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx"
diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs
index 1b2b63c3d1a..6daa5cd7d5e 100644
--- a/tests/codegen/tied-features-strength.rs
+++ b/tests/codegen/tied-features-strength.rs
@@ -11,10 +11,11 @@
 // ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
 
 //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
-// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?))*}}" }
+// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
 
 //@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
-// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-fp-armv8,?)|(-neon,?))*}}" }
+// `neon` and `fp-armv8` get enabled as target base features, but then disabled again at the end of the list.
+// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}},-neon,-fp-armv8{{(,\+fpmr)?}}" }
 
 //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+fp-armv8,?)|(\+neon,?))*}}" }
diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs
index 33de0913f77..e835a7ef69b 100644
--- a/tests/codegen/vec-in-place.rs
+++ b/tests/codegen/vec-in-place.rs
@@ -37,8 +37,11 @@ pub struct Baz {
 #[no_mangle]
 pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| e as u8).collect()
@@ -48,8 +51,11 @@ pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
 #[no_mangle]
 pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| Wrapper(e)).collect()
@@ -76,8 +82,11 @@ pub fn vec_iterator_cast_signed_nested(vec: Vec<Vec<i32>>) -> Vec<Vec<u32>> {
 #[no_mangle]
 pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| e.0).collect()
@@ -87,8 +96,11 @@ pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
 #[no_mangle]
 pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
@@ -98,8 +110,11 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
 #[no_mangle]
 pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
 
@@ -114,8 +129,11 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
 #[no_mangle]
 pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
 
@@ -138,6 +156,12 @@ pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
     // CHECK-NOT: call
     // CHECK-NOT: %{{.*}} = mul
     // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: call
+    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
 
     vec.into_iter().map(|Wrapper(e)| e).collect()
 }
@@ -154,6 +178,12 @@ pub fn vec_iterator_cast_wrap_drop(vec: Vec<String>) -> Vec<Wrapper<String>> {
     // CHECK-NOT: call
     // CHECK-NOT: %{{.*}} = mul
     // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: call
+    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
     // CHECK: ret void
 
     vec.into_iter().map(Wrapper).collect()
diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs
index a8ad5b6f1a3..4821e840884 100644
--- a/tests/codegen/vec_pop_push_noop.rs
+++ b/tests/codegen/vec_pop_push_noop.rs
@@ -12,9 +12,6 @@ pub fn noop(v: &mut Vec<u8>) {
     // CHECK-NOT: call
     // CHECK: tail call void @llvm.assume
     // CHECK-NOT: grow_one
-    // llvm-pre-19: call
-    // llvm-pre-19-same: void @llvm.assume
-    // llvm-pre-19-NOT: grow_one
     // CHECK-NOT: call
     // CHECK: {{ret|[}]}}
     if let Some(x) = v.pop() {