diff options
Diffstat (limited to 'tests/codegen')
53 files changed, 1016 insertions, 206 deletions
diff --git a/tests/codegen/abi-x86-interrupt.rs b/tests/codegen/abi-x86-interrupt.rs index 255ccba2c11..9a1ded2c9e3 100644 --- a/tests/codegen/abi-x86-interrupt.rs +++ b/tests/codegen/abi-x86-interrupt.rs @@ -13,8 +13,6 @@ extern crate minicore; use minicore::*; -// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi +// CHECK: define x86_intrcc void @has_x86_interrupt_abi #[no_mangle] -pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 { - a -} +pub extern "x86-interrupt" fn has_x86_interrupt_abi() {} diff --git a/tests/codegen/abi-x86-sse.rs b/tests/codegen/abi-x86-sse.rs index 837bf6134b0..68d2acfb527 100644 --- a/tests/codegen/abi-x86-sse.rs +++ b/tests/codegen/abi-x86-sse.rs @@ -17,7 +17,13 @@ #![crate_type = "lib"] #[lang = "sized"] -trait Sized {} +trait Sized: MetaSized {} + +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} + +#[lang = "pointee_sized"] +trait PointeeSized {} #[lang = "copy"] trait Copy {} @@ -27,8 +33,9 @@ trait Copy {} #[repr(simd)] pub struct Sse([f32; 4]); -// x86-64: <4 x float> @sse_id(<4 x float> {{[^,]*}}) -// x86-32: <4 x float> @sse_id(<4 x float> {{[^,]*}}) +// FIXME: due to #139029 we are passing them all indirectly. +// x86-64: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) +// x86-32: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) // x86-32-nosse: void @sse_id(ptr{{( [^,]*)?}} sret([16 x i8]){{( .*)?}}, ptr{{( [^,]*)?}}) #[no_mangle] pub fn sse_id(x: Sse) -> Sse { diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs index 660d8cd2bbf..fd572910c28 100644 --- a/tests/codegen/align-fn.rs +++ b/tests/codegen/align-fn.rs @@ -1,68 +1,141 @@ -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code +//@ edition: 2024 +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) #![crate_type = "lib"] #![feature(fn_align)] // CHECK: align 16 -#[no_mangle] -#[repr(align(16))] +#[unsafe(no_mangle)] +#[align(16)] pub fn fn_align() {} pub struct A; impl A { // CHECK: align 16 - #[no_mangle] - #[repr(align(16))] + #[unsafe(no_mangle)] + #[align(16)] pub fn method_align(self) {} // CHECK: align 16 - #[no_mangle] - #[repr(align(16))] + #[unsafe(no_mangle)] + #[align(16)] pub fn associated_fn() {} } trait T: Sized { fn trait_fn() {} - // CHECK: align 32 - #[repr(align(32))] fn trait_method(self) {} + + #[align(8)] + fn trait_method_inherit_low(self); + + #[align(32)] + fn trait_method_inherit_high(self); + + #[align(32)] + fn trait_method_inherit_default(self) {} + + #[align(4)] + #[align(128)] + #[align(8)] + fn inherit_highest(self) {} } impl T for A { - // CHECK: align 16 - #[no_mangle] - #[repr(align(16))] + // CHECK-LABEL: trait_fn + // CHECK-SAME: align 16 + #[unsafe(no_mangle)] + #[align(16)] fn trait_fn() {} - // CHECK: align 16 - #[no_mangle] - #[repr(align(16))] + // CHECK-LABEL: trait_method + // CHECK-SAME: align 16 + #[unsafe(no_mangle)] + #[align(16)] fn trait_method(self) {} -} -impl T for () {} + // The prototype's align is ignored because the align here is higher. + // CHECK-LABEL: trait_method_inherit_low + // CHECK-SAME: align 16 + #[unsafe(no_mangle)] + #[align(16)] + fn trait_method_inherit_low(self) {} + + // The prototype's align is used because it is higher. + // CHECK-LABEL: trait_method_inherit_high + // CHECK-SAME: align 32 + #[unsafe(no_mangle)] + #[align(16)] + fn trait_method_inherit_high(self) {} + + // The prototype's align inherited. + // CHECK-LABEL: trait_method_inherit_default + // CHECK-SAME: align 32 + #[unsafe(no_mangle)] + fn trait_method_inherit_default(self) {} -pub fn foo() { - ().trait_method(); + // The prototype's highest align inherited. + // CHECK-LABEL: inherit_highest + // CHECK-SAME: align 128 + #[unsafe(no_mangle)] + #[align(32)] + #[align(64)] + fn inherit_highest(self) {} } +trait HasDefaultImpl: Sized { + // CHECK-LABEL: inherit_from_default_method + // CHECK-LABEL: inherit_from_default_method + // CHECK-SAME: align 32 + #[align(32)] + fn inherit_from_default_method(self) {} +} + +pub struct InstantiateDefaultMethods; + +impl HasDefaultImpl for InstantiateDefaultMethods {} + // CHECK-LABEL: align_specified_twice_1 // CHECK-SAME: align 64 -#[no_mangle] -#[repr(align(32), align(64))] +#[unsafe(no_mangle)] +#[align(32)] +#[align(64)] pub fn align_specified_twice_1() {} // CHECK-LABEL: align_specified_twice_2 // CHECK-SAME: align 128 -#[no_mangle] -#[repr(align(128), align(32))] +#[unsafe(no_mangle)] +#[align(128)] +#[align(32)] pub fn align_specified_twice_2() {} // CHECK-LABEL: align_specified_twice_3 // CHECK-SAME: align 256 -#[no_mangle] -#[repr(align(32))] -#[repr(align(256))] +#[unsafe(no_mangle)] +#[align(32)] +#[align(256)] pub fn align_specified_twice_3() {} + +const _: () = { + // CHECK-LABEL: align_unmangled + // CHECK-SAME: align 256 + #[unsafe(no_mangle)] + #[align(32)] + #[align(256)] + extern "C" fn align_unmangled() {} +}; + +unsafe extern "C" { + #[align(256)] + fn align_unmangled(); +} + +// FIXME also check `gen` et al +// CHECK-LABEL: async_align +// CHECK-SAME: align 64 +#[unsafe(no_mangle)] +#[align(64)] +pub async fn async_align() {} diff --git a/tests/codegen/align-struct.rs b/tests/codegen/align-struct.rs index 402a184d4c0..d4cc65e9158 100644 --- a/tests/codegen/align-struct.rs +++ b/tests/codegen/align-struct.rs @@ -15,9 +15,11 @@ pub struct Nested64 { d: i8, } +// This has the extra field in B to ensure it's not ScalarPair, +// and thus that the test actually emits it via memory, not `insertvalue`. pub enum Enum4 { A(i32), - B(i32), + B(i32, i32), } pub enum Enum64 { @@ -54,7 +56,7 @@ pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 { // CHECK-LABEL: @enum4 #[no_mangle] pub fn enum4(a: i32) -> Enum4 { - // CHECK: %e4 = alloca [8 x i8], align 4 + // CHECK: %e4 = alloca [12 x i8], align 4 let e4 = Enum4::A(a); e4 } diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs index 19f14647c1d..3735860d510 100644 --- a/tests/codegen/alloc-optimisation.rs +++ b/tests/codegen/alloc-optimisation.rs @@ -5,7 +5,8 @@ pub fn alloc_test(data: u32) { // CHECK-LABEL: @alloc_test // CHECK-NEXT: start: - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret void let x = Box::new(data); drop(x); diff --git a/tests/codegen/asm/critical.rs b/tests/codegen/asm/critical.rs index 8c039900cab..0f29d7c69b4 100644 --- a/tests/codegen/asm/critical.rs +++ b/tests/codegen/asm/critical.rs @@ -1,6 +1,5 @@ //@ only-x86_64 //@ compile-flags: -C no-prepopulate-passes -#![feature(asm_goto)] #![feature(asm_goto_with_outputs)] #![crate_type = "lib"] use std::arch::asm; diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs new file mode 100644 index 00000000000..c354228acc5 --- /dev/null +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Copt-level=2 + +#![crate_type = "lib"] +#![no_std] + +// This test is paired with the arch-specific -opt3.rs test. + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs index c1dab2bc295..203d12005de 100644 --- a/tests/codegen/dont-shuffle-bswaps.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs @@ -1,29 +1,27 @@ -//@ revisions: OPT2 OPT3 OPT3_S390X -//@[OPT2] compile-flags: -Copt-level=2 -//@[OPT3] compile-flags: -C opt-level=3 -// some targets don't do the opt we are looking for -//@[OPT3] only-64bit -//@[OPT3] ignore-s390x -//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13 -//@[OPT3_S390X] only-s390x +//@ revisions: AARCH64 X86_64 Z13 +//@ compile-flags: -Copt-level=3 +//@[AARCH64] only-aarch64 +//@[X86_64] only-x86_64 +//@[Z13] only-s390x +//@[Z13] compile-flags: -Ctarget-cpu=z13 #![crate_type = "lib"] #![no_std] +// This test is paired with the arch-neutral -opt2.rs test + // The code is from https://github.com/rust-lang/rust/issues/122805. // Ensure we do not generate the shufflevector instruction // to avoid complicating the code. + // CHECK-LABEL: define{{.*}}void @convert( // CHECK-NOT: shufflevector + // On higher opt levels, this should just be a bswap: -// OPT3: load <8 x i16> -// OPT3-NEXT: call <8 x i16> @llvm.bswap -// OPT3-NEXT: store <8 x i16> -// OPT3-NEXT: ret void -// OPT3_S390X: load <8 x i16> -// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap -// OPT3_S390X-NEXT: store <8 x i16> -// OPT3_S390X-NEXT: ret void +// CHECK: load <8 x i16> +// CHECK-NEXT: call <8 x i16> @llvm.bswap +// CHECK-NEXT: store <8 x i16> +// CHECK-NEXT: ret void #[no_mangle] pub fn convert(value: [u16; 8]) -> [u8; 16] { #[cfg(target_endian = "little")] diff --git a/tests/codegen/common_prim_int_ptr.rs b/tests/codegen/common_prim_int_ptr.rs index a1d7a125f32..53716adccbf 100644 --- a/tests/codegen/common_prim_int_ptr.rs +++ b/tests/codegen/common_prim_int_ptr.rs @@ -11,9 +11,9 @@ #[no_mangle] pub fn insert_int(x: usize) -> Result<usize, Box<()>> { // CHECK: start: - // CHECK-NEXT: inttoptr i{{[0-9]+}} %x to ptr - // CHECK-NEXT: insertvalue - // CHECK-NEXT: ret { i{{[0-9]+}}, ptr } + // CHECK-NEXT: %[[WO_PROV:.+]] = getelementptr i8, ptr null, [[USIZE:i[0-9]+]] %x + // CHECK-NEXT: %[[R:.+]] = insertvalue { [[USIZE]], ptr } { [[USIZE]] 0, ptr poison }, ptr %[[WO_PROV]], 1 + // CHECK-NEXT: ret { [[USIZE]], ptr } %[[R]] Ok(x) } diff --git a/tests/codegen/deduced-param-attrs.rs b/tests/codegen/deduced-param-attrs.rs index 22db090d4d8..34504c80fad 100644 --- a/tests/codegen/deduced-param-attrs.rs +++ b/tests/codegen/deduced-param-attrs.rs @@ -1,8 +1,8 @@ //@ compile-flags: -Copt-level=3 #![crate_type = "lib"] -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![allow(internal_features)] +#![feature(unsized_fn_params)] use std::cell::Cell; use std::hint; diff --git a/tests/codegen/dst-offset.rs b/tests/codegen/dst-offset.rs index 7177a960432..2cf5fa9fac6 100644 --- a/tests/codegen/dst-offset.rs +++ b/tests/codegen/dst-offset.rs @@ -3,8 +3,9 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 #![crate_type = "lib"] -#![feature(extern_types)] +#![feature(extern_types, sized_hierarchy)] +use std::marker::PointeeSized; use std::ptr::addr_of; // Hack to get the correct type for usize @@ -12,7 +13,7 @@ use std::ptr::addr_of; #[no_mangle] pub fn helper(_: usize) {} -struct Dst<T: ?Sized> { +struct Dst<T: PointeeSized> { x: u32, y: u8, z: T, diff --git a/tests/codegen/emscripten-catch-unwind-js-eh.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs index 3ab4b5c9c63..f43869cf218 100644 --- a/tests/codegen/emscripten-catch-unwind-js-eh.rs +++ b/tests/codegen/emscripten-catch-unwind-js-eh.rs @@ -9,8 +9,14 @@ #![no_std] #![no_core] +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} #[lang = "freeze"] trait Freeze {} #[lang = "copy"] diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs index d0571e4df08..b0750d52268 100644 --- a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs +++ b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs @@ -8,8 +8,14 @@ #![no_std] #![no_core] +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} #[lang = "freeze"] trait Freeze {} #[lang = "copy"] diff --git a/tests/codegen/enum/enum-aggregate.rs b/tests/codegen/enum/enum-aggregate.rs new file mode 100644 index 00000000000..0161e5f3fa1 --- /dev/null +++ b/tests/codegen/enum/enum-aggregate.rs @@ -0,0 +1,126 @@ +//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes +//@ min-llvm-version: 19 +//@ only-64bit + +#![crate_type = "lib"] + +use std::cmp::Ordering; +use std::num::NonZero; +use std::ptr::NonNull; + +#[no_mangle] +fn make_some_bool(x: bool) -> Option<bool> { + // CHECK-LABEL: i8 @make_some_bool(i1 zeroext %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8 + // CHECK-NEXT: ret i8 %[[WIDER]] + Some(x) +} + +#[no_mangle] +fn make_none_bool() -> Option<bool> { + // CHECK-LABEL: i8 @make_none_bool() + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 2 + None +} + +#[no_mangle] +fn make_some_ordering(x: Ordering) -> Option<Ordering> { + // CHECK-LABEL: i8 @make_some_ordering(i8 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 %x + Some(x) +} + +#[no_mangle] +fn make_some_u16(x: u16) -> Option<u16> { + // CHECK-LABEL: { i16, i16 } @make_some_u16(i16 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i16, i16 } { i16 1, i16 poison }, i16 %x, 1 + // CHECK-NEXT: ret { i16, i16 } %0 + Some(x) +} + +#[no_mangle] +fn make_none_u16() -> Option<u16> { + // CHECK-LABEL: { i16, i16 } @make_none_u16() + // CHECK-NEXT: start: + // CHECK-NEXT: ret { i16, i16 } { i16 0, i16 undef } + None +} + +#[no_mangle] +fn make_some_nzu32(x: NonZero<u32>) -> Option<NonZero<u32>> { + // CHECK-LABEL: i32 @make_some_nzu32(i32 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret i32 %x + Some(x) +} + +#[no_mangle] +fn make_ok_ptr(x: NonNull<u16>) -> Result<NonNull<u16>, usize> { + // CHECK-LABEL: { i64, ptr } @make_ok_ptr(ptr %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %x, 1 + // CHECK-NEXT: ret { i64, ptr } %0 + Ok(x) +} + +#[no_mangle] +fn make_ok_int(x: usize) -> Result<usize, NonNull<u16>> { + // CHECK-LABEL: { i64, ptr } @make_ok_int(i64 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[NOPROV:.+]] = getelementptr i8, ptr null, i64 %x + // CHECK-NEXT: %[[R:.+]] = insertvalue { i64, ptr } { i64 0, ptr poison }, ptr %[[NOPROV]], 1 + // CHECK-NEXT: ret { i64, ptr } %[[R]] + Ok(x) +} + +#[no_mangle] +fn make_some_ref(x: &u16) -> Option<&u16> { + // CHECK-LABEL: ptr @make_some_ref(ptr align 2 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr %x + Some(x) +} + +#[no_mangle] +fn make_none_ref<'a>() -> Option<&'a u16> { + // CHECK-LABEL: ptr @make_none_ref() + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr null + None +} + +#[inline(never)] +fn make_err_generic<E>(e: E) -> Result<u32, E> { + // CHECK-LABEL: define{{.+}}make_err_generic + // CHECK-NEXT: start: + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: ret i32 poison + Err(e) +} + +#[no_mangle] +fn make_uninhabited_err_indirectly(n: Never) -> Result<u32, Never> { + // CHECK-LABEL: i32 @make_uninhabited_err_indirectly() + // CHECK-NEXT: start: + // CHECK-NEXT: call{{.+}}make_err_generic + make_err_generic(n) +} + +#[no_mangle] +fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> { + // Actually reaching this would be UB, so we don't actually build a result. + + // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v) + // CHECK-NEXT: start: + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: call void @llvm.trap() + // CHECK-NEXT: unreachable + Ok((v, n)) +} + +enum Never {} diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index 6da6ad1f078..98635008d06 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -98,7 +98,7 @@ pub enum Enum2 { E, } -// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0) +// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, -?[0-9]+\))?}} i8 @match2(i8{{.+}}%0) // CHECK-NEXT: start: // CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 diff --git a/tests/codegen/error-provide.rs b/tests/codegen/error-provide.rs index 25a66078fd4..7f091e34359 100644 --- a/tests/codegen/error-provide.rs +++ b/tests/codegen/error-provide.rs @@ -37,9 +37,9 @@ impl std::error::Error for MyError { // and eliminate redundant ones, rather than compare one-by-one. // CHECK-NEXT: start: - // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i64, ptr - // CHECK-NEXT: switch i64 %[[SCRUTINEE]], label %{{.*}} [ - // CHECK-COUNT-3: i64 {{.*}}, label %{{.*}} + // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr + // CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [ + // CHECK-COUNT-3: i128 {{.*}}, label %{{.*}} // CHECK-NEXT: ] request .provide_ref::<MyBacktrace1>(&self.backtrace1) diff --git a/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs new file mode 100644 index 00000000000..2097567f322 --- /dev/null +++ b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs @@ -0,0 +1,22 @@ +//! Make sure that line debuginfo of function parameters are correct even if +//! they are not on the same line. Regression test for +// <https://github.com/rust-lang/rust/issues/45010>. + +//@ compile-flags: -g -Copt-level=0 + +#[rustfmt::skip] // Having parameters on different lines is crucial for this test. +pub fn foo( + x_parameter_not_in_std: i32, + y_parameter_not_in_std: i32, +) -> i32 { + x_parameter_not_in_std + y_parameter_not_in_std +} + +fn main() { + foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`) +} + +// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1, +// CHECK-SAME: line: 9 +// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2, +// CHECK-SAME: line: 10 diff --git a/tests/codegen/frame-pointer-cli-control.rs b/tests/codegen/frame-pointer-cli-control.rs new file mode 100644 index 00000000000..a65dd132763 --- /dev/null +++ b/tests/codegen/frame-pointer-cli-control.rs @@ -0,0 +1,61 @@ +//@ add-core-stubs +//@ compile-flags: --crate-type=rlib -Copt-level=0 +//@ revisions: force-on aarch64-apple aarch64-apple-on aarch64-apple-off +//@ [force-on] compile-flags: -Cforce-frame-pointers=on +//@ [aarch64-apple] needs-llvm-components: aarch64 +//@ [aarch64-apple] compile-flags: --target=aarch64-apple-darwin +//@ [aarch64-apple-on] needs-llvm-components: aarch64 +//@ [aarch64-apple-on] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=on +//@ [aarch64-apple-off] needs-llvm-components: aarch64 +//@ [aarch64-apple-off] compile-flags: --target=aarch64-apple-darwin -Cforce-frame-pointers=off +/*! + +Tests the extent to which frame pointers can be controlled by the CLI. +The behavior of our frame pointer options, at present, is an irreversible ratchet, where +a "weaker" option that allows omitting frame pointers may be overridden by the target demanding +that all code (or all non-leaf code, more often) must be compiled with frame pointers. +This was discussed on 2025-05-22 in the T-compiler meeting and accepted as an intentional change, +ratifying the prior decisions by compiler contributors and reviewers as correct, +though it was also acknowledged that the flag allows somewhat confusing inputs. + +We find aarch64-apple-darwin useful because of its icy-clear policy regarding frame pointers, +e.g. <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms> says: + +* The frame pointer register (x29) must always address a valid frame record. Some functions — + such as leaf functions or tail calls — may opt not to create an entry in this list. + As a result, stack traces are always meaningful, even without debug information. + +Many Rust fn, if externally visible, may be expected to follow target ABI by tools or asm code! +This can make it a problem to generate ABI-incorrect code, which may mean "with frame pointers". +For this and other reasons, `-Cforce-frame-pointers=off` cannot override the target definition. +This can cause some confusion because it is "reverse polarity" relative to C compilers, which have +commands like `-fomit-frame-pointer`, `-fomit-leaf-frame-pointer`, or `-fno-omit-frame-pointer`! + +Specific cases where platforms or tools rely on frame pointers for sound or correct unwinding: +- illumos: <https://smartos.org/bugview/OS-7515> +- aarch64-windows: <https://github.com/rust-lang/rust/issues/123686> +- aarch64-linux: <https://github.com/rust-lang/rust/issues/123733> +- dtrace (freebsd and openbsd): <https://github.com/rust-lang/rust/issues/97723> +- openbsd: <https://github.com/rust-lang/rust/issues/43575> +- i686-msvc <https://github.com/rust-lang/backtrace-rs/pull/584#issuecomment-1966177530> +- i686-mingw: <https://github.com/rust-lang/rust/commit/3f1d3948d6d434b34dd47f132c126a6cb6b8a4ab> +*/ +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; + +// CHECK: i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] { +#[no_mangle] +pub fn peach(x: u32) -> u32 { + x +} + +// CHECK: attributes [[PEACH_ATTRS]] = { +// force-on-SAME: {{.*}}"frame-pointer"="all" +// aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf" +// aarch64-apple-on-SAME: {{.*}}"frame-pointer"="all" +// +// yes, we are testing this doesn't do anything: +// aarch64-apple-off-SAME: {{.*}}"frame-pointer"="non-leaf" +// CHECK-SAME: } diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index f0708a7a109..c8cd8526ae5 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -1,7 +1,6 @@ //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes #![crate_type = "lib"] #![feature(rustc_attrs)] -#![feature(dyn_star)] #![feature(allocator_api)] use std::marker::PhantomPinned; @@ -277,11 +276,3 @@ pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> { pub fn enum_id_2(x: Option<u8>) -> Option<u8> { x } - -// CHECK: { ptr, {{.+}} } @dyn_star(ptr noundef %x.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %x.1) -// Expect an ABI something like `{ {}*, [3 x i64]* }`, but that's hard to match on generically, -// so do like the `trait_box` test and just match on `{{.+}}` for the vtable. -#[no_mangle] -pub fn dyn_star(x: dyn* Drop) -> dyn* Drop { - x -} diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs index be45e4db90f..8c9480ab091 100644 --- a/tests/codegen/intrinsics/transmute-x64.rs +++ b/tests/codegen/intrinsics/transmute-x64.rs @@ -9,17 +9,20 @@ use std::mem::transmute; // CHECK-LABEL: @check_sse_pair_to_avx( #[no_mangle] pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { + // CHECK: start: // CHECK-NOT: alloca - // CHECK: %0 = load <4 x i64>, ptr %x, align 16 - // CHECK: store <4 x i64> %0, ptr %_0, align 32 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 32 %_0, ptr align 16 %x, i64 32, i1 false) + // CHECK-NEXT: ret void transmute(x) } // CHECK-LABEL: @check_sse_pair_from_avx( #[no_mangle] pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) { + // CHECK: start: // CHECK-NOT: alloca - // CHECK: %0 = load <4 x i64>, ptr %x, align 32 - // CHECK: store <4 x i64> %0, ptr %_0, align 16 + // CHECK-NEXT: %[[TEMP:.+]] = load <4 x i64>, ptr %x, align 32 + // CHECK-NEXT: store <4 x i64> %[[TEMP]], ptr %_0, align 16 + // CHECK-NEXT: ret void transmute(x) } diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 560ebcccdd0..c9a1cd58af3 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -29,28 +29,28 @@ pub struct Aggregate8(u8); // CHECK-LABEL: @check_bigger_size( #[no_mangle] pub unsafe fn check_bigger_size(x: u16) -> u32 { - // CHECK: call void @llvm.trap + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_size( #[no_mangle] pub unsafe fn check_smaller_size(x: u32) -> u16 { - // CHECK: call void @llvm.trap + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_array( #[no_mangle] pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { - // CHECK: call void @llvm.trap + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_bigger_array( #[no_mangle] pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { - // CHECK: call void @llvm.trap + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } @@ -58,9 +58,9 @@ pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { { RET = CastTransmute(x); @@ -73,9 +73,9 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { { RET = CastTransmute(x); @@ -88,9 +88,9 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_uninhabited(x: u16) { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { let temp: BigNever; { @@ -104,7 +104,9 @@ pub unsafe fn check_to_uninhabited(x: u16) { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { - // CHECK: ret i16 poison + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret i16 poison mir! { { RET = CastTransmute(x); @@ -401,9 +403,9 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { pub unsafe fn check_unit_to_never(x: ()) { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { let temp: ZstNever; { @@ -420,6 +422,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 // CHECK-NEXT: ret void mir! { { diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs index 3bb942d11d5..28173530324 100644 --- a/tests/codegen/iter-repeat-n-trivial-drop.rs +++ b/tests/codegen/iter-repeat-n-trivial-drop.rs @@ -1,5 +1,6 @@ //@ compile-flags: -C opt-level=3 //@ only-x86_64 +//@ needs-deterministic-layouts #![crate_type = "lib"] #![feature(iter_repeat_n)] @@ -25,10 +26,10 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCop // CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]] // CHECK: [[NOT_EMPTY]]: - // CHECK-NEXT: %[[DEC:.+]] = add i64 %[[COUNT]], -1 - // CHECK-NEXT: store i64 %[[DEC]] // CHECK-NOT: br - // CHECK: %[[VAL:.+]] = load i16 + // CHECK: %[[DEC:.+]] = add i64 %[[COUNT]], -1 + // CHECK-NEXT: %[[VAL:.+]] = load i16 + // CHECK-NEXT: store i64 %[[DEC]] // CHECK-NEXT: br label %[[EMPTY]] // CHECK: [[EMPTY]]: diff --git a/tests/codegen/min-function-alignment.rs b/tests/codegen/min-function-alignment.rs index 7c0ad12402a..6a3843b0f4f 100644 --- a/tests/codegen/min-function-alignment.rs +++ b/tests/codegen/min-function-alignment.rs @@ -1,33 +1,36 @@ //@ revisions: align16 align1024 -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code //@ [align16] compile-flags: -Zmin-function-alignment=16 //@ [align1024] compile-flags: -Zmin-function-alignment=1024 +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) #![crate_type = "lib"] #![feature(fn_align)] -// functions without explicit alignment use the global minimum +// Functions without explicit alignment use the global minimum. // -// CHECK-LABEL: @no_explicit_align +// NOTE: this function deliberately has zero (0) attributes! That is to make sure that +// `-Zmin-function-alignment` is applied regardless of whether attributes are used. +// +// 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))] +#[align(8)] pub fn lower_align() {} -// the higher value of min-function-alignment and repr(align) wins out +// the higher value of min-function-alignment and the align attribute wins out // // CHECK-LABEL: @higher_align // align16: align 32 // align1024: align 1024 #[no_mangle] -#[repr(align(32))] +#[align(32)] pub fn higher_align() {} // cold functions follow the same rules as other functions diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs index 223c41b15bb..46218cf79d6 100644 --- a/tests/codegen/naked-asan.rs +++ b/tests/codegen/naked-asan.rs @@ -1,22 +1,28 @@ -// Make sure we do not request sanitizers for naked functions. +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu -Zsanitizer=address -Ctarget-feature=-crt-static -//@ only-x86_64 -//@ needs-sanitizer-address -//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static +// Make sure we do not request sanitizers for naked functions. #![crate_type = "lib"] +#![feature(no_core)] #![no_std] +#![no_core] #![feature(abi_x86_interrupt)] +extern crate minicore; +use minicore::*; + +#[no_mangle] pub fn caller() { - page_fault_handler(1, 2); + unsafe { asm!("call {}", sym page_fault_handler) } } -// CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]] +// CHECK: declare x86_intrcc void @page_fault_handler(){{.*}}#[[ATTRS:[0-9]+]] #[unsafe(naked)] #[no_mangle] -pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { - core::arch::naked_asm!("ud2") +pub extern "x86-interrupt" fn page_fault_handler() { + naked_asm!("ud2") } // CHECK: #[[ATTRS]] = diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index 47ef779f1b2..2648b0213ca 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -1,6 +1,7 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 //@ needs-asm-support //@ ignore-arm no "ret" mnemonic +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) #![crate_type = "lib"] #![feature(fn_align)] @@ -8,7 +9,7 @@ use std::arch::naked_asm; // CHECK: .balign 16 // CHECK-LABEL: naked_empty: -#[repr(align(16))] +#[align(16)] #[no_mangle] #[unsafe(naked)] pub extern "C" fn naked_empty() { diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs index 1d778be8c90..4ebaacd3eff 100644 --- a/tests/codegen/naked-fn/min-function-alignment.rs +++ b/tests/codegen/naked-fn/min-function-alignment.rs @@ -1,6 +1,7 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16 //@ needs-asm-support //@ ignore-arm no "ret" mnemonic +//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) #![feature(fn_align)] #![crate_type = "lib"] @@ -16,7 +17,7 @@ pub extern "C" fn naked_no_explicit_align() { // CHECK: .balign 16 #[no_mangle] -#[repr(align(8))] +#[align(8)] #[unsafe(naked)] pub extern "C" fn naked_lower_align() { core::arch::naked_asm!("ret") @@ -24,7 +25,7 @@ pub extern "C" fn naked_lower_align() { // CHECK: .balign 32 #[no_mangle] -#[repr(align(32))] +#[align(32)] #[unsafe(naked)] pub extern "C" fn naked_higher_align() { core::arch::naked_asm!("ret") diff --git a/tests/codegen/pie-relocation-model.rs b/tests/codegen/pie-relocation-model.rs index b10af693452..cb8de91ccd7 100644 --- a/tests/codegen/pie-relocation-model.rs +++ b/tests/codegen/pie-relocation-model.rs @@ -13,7 +13,7 @@ pub fn call_foreign_fn() -> u8 { // External functions are still marked as non-dso_local, since we don't know if the symbol // is defined in the binary or in the shared library. -// CHECK: declare zeroext i8 @foreign_fn() +// CHECK: declare i8 @foreign_fn() extern "C" { fn foreign_fn() -> u8; } diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs new file mode 100644 index 00000000000..915c2c3d797 --- /dev/null +++ b/tests/codegen/retpoline.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +// Test that the +// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls` +// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set. + +//@ add-core-stubs +//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [enabled_retpoline] compile-flags: -Zretpoline +//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] +extern crate minicore; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} } + + // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } + // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } +} diff --git a/tests/codegen/riscv-abi/cast-local-large-enough.rs b/tests/codegen/riscv-abi/cast-local-large-enough.rs new file mode 100644 index 00000000000..9d21d73b459 --- /dev/null +++ b/tests/codegen/riscv-abi/cast-local-large-enough.rs @@ -0,0 +1,44 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(C, align(64))] +struct Aligned(f64); + +#[repr(C, align(64))] +struct AlignedPair(f32, f64); + +impl Copy for Aligned {} +impl Copy for AlignedPair {} + +// CHECK-LABEL: define double @read_aligned +#[unsafe(no_mangle)] +pub extern "C" fn read_aligned(x: &Aligned) -> Aligned { + // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) + // CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64 + // CHECK-NEXT: ret double %[[RES]] + *x +} + +// CHECK-LABEL: define { float, double } @read_aligned_pair +#[unsafe(no_mangle)] +pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair { + // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false) + // CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64 + // CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8 + // CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8 + // CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0 + // CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1 + // CHECK-NEXT: ret { float, double } %[[RES2]] + *x +} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs index 2a7eca6fc19..8fec275fd06 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs @@ -1,5 +1,9 @@ // Verifies that type metadata identifiers for drop functions are emitted correctly. // +// Non needs_drop drop glue isn't codegen'd at all, so we don't try to check the IDs there. But we +// do check it's not emitted which should help catch bugs if we do start generating it again in the +// future. +// //@ needs-sanitizer-cfi //@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static @@ -10,18 +14,18 @@ // CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE") struct EmptyDrop; -// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK-NOT: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -struct NonEmptyDrop; +struct PresentDrop; -impl Drop for NonEmptyDrop { +impl Drop for PresentDrop { fn drop(&mut self) {} - // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}NonEmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}PresentDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} } pub fn foo() { let _ = Box::new(EmptyDrop) as Box<dyn Send>; - let _ = Box::new(NonEmptyDrop) as Box<dyn Send>; + let _ = Box::new(PresentDrop) as Box<dyn Send>; } // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"} diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs new file mode 100644 index 00000000000..2c8cdc919b8 --- /dev/null +++ b/tests/codegen/sanitizer/kcfi/naked-function.rs @@ -0,0 +1,47 @@ +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Thing; +trait MyTrait { + #[unsafe(naked)] + extern "C" fn my_naked_function() { + // the real function is defined + // CHECK: .globl + // CHECK-SAME: my_naked_function + naked_asm!("ret") + } +} +impl MyTrait for Thing {} + +// the shim calls the real function +// CHECK-LABEL: define +// CHECK-SAME: my_naked_function +// CHECK-SAME: reify.shim.fnptr + +// CHECK-LABEL: main +#[unsafe(no_mangle)] +pub fn main() { + // Trick the compiler into generating an indirect call. + const F: extern "C" fn() = Thing::my_naked_function; + + // main calls the shim function + // CHECK: call void + // CHECK-SAME: my_naked_function + // CHECK-SAME: reify.shim.fnptr + (F)(); +} + +// CHECK: declare !kcfi_type +// CHECK-SAME: my_naked_function diff --git a/tests/codegen/set-discriminant-invalid.rs b/tests/codegen/set-discriminant-invalid.rs index 0b7cb14880c..dd584ef1c14 100644 --- a/tests/codegen/set-discriminant-invalid.rs +++ b/tests/codegen/set-discriminant-invalid.rs @@ -16,10 +16,9 @@ impl IntoError<Error> for Api { type Source = ApiError; // CHECK-LABEL: @into_error // CHECK: llvm.trap() - // Also check the next two instructions to make sure we do not match against `trap` + // Also check the next instruction to make sure we do not match against `trap` // elsewhere in the code. - // CHECK-NEXT: load - // CHECK-NEXT: ret + // CHECK-NEXT: ret i8 poison #[no_mangle] fn into_error(self, error: Self::Source) -> Error { Error::Api { source: error } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index d3853361de9..301f06c2d74 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -1,14 +1,8 @@ // //@ compile-flags: -C no-prepopulate-passes -// LLVM IR isn't very portable and the one tested here depends on the ABI -// which is different between x86 (where we use SSE registers) and others. -// `x86-64` and `x86-32-sse2` are identical, but compiletest does not support -// taking the union of multiple `only` annotations. -//@ revisions: x86-64 x86-32-sse2 other -//@[x86-64] only-x86_64 -//@[x86-32-sse2] only-rustc_abi-x86-sse2 -//@[other] ignore-rustc_abi-x86-sse2 -//@[other] ignore-x86_64 +// 32bit MSVC does not align things properly so we suppress high alignment annotations (#112480) +//@ ignore-i686-pc-windows-msvc +//@ ignore-i686-pc-windows-gnu #![crate_type = "lib"] #![allow(non_camel_case_types)] @@ -46,10 +40,7 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> { // CHECK-LABEL: @build_array_transmute_s #[no_mangle] pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { - // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // x86-32: ret <4 x float> %[[VAL:.+]] - // x86-64: ret <4 x float> %[[VAL:.+]] - // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) unsafe { std::mem::transmute(x) } } @@ -63,9 +54,6 @@ pub fn build_array_t(x: [f32; 4]) -> T { // CHECK-LABEL: @build_array_transmute_t #[no_mangle] pub fn build_array_transmute_t(x: [f32; 4]) -> T { - // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // x86-32: ret <4 x float> %[[VAL:.+]] - // x86-64: ret <4 x float> %[[VAL:.+]] - // other: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) unsafe { std::mem::transmute(x) } } diff --git a/tests/codegen/simd/aggregate-simd.rs b/tests/codegen/simd/aggregate-simd.rs new file mode 100644 index 00000000000..065e429a4c7 --- /dev/null +++ b/tests/codegen/simd/aggregate-simd.rs @@ -0,0 +1,106 @@ +//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes +//@ only-64bit + +#![feature(core_intrinsics, repr_simd)] +#![no_std] +#![crate_type = "lib"] + +use core::intrinsics::simd::{simd_add, simd_extract}; + +#[repr(simd)] +#[derive(Clone, Copy)] +pub struct Simd<T, const N: usize>([T; N]); + +#[repr(simd, packed)] +#[derive(Clone, Copy)] +pub struct PackedSimd<T, const N: usize>([T; N]); + +#[repr(transparent)] +pub struct Transparent<T>(T); + +// These tests don't actually care about the add/extract, but it ensures the +// aggregated temporaries are only used in potentially-SSA ways. + +#[no_mangle] +pub fn simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { + // CHECK-LABEL: simd_aggregate_pot + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %b = load <4 x i32>, ptr %y, align 4 + // CHECK: add <4 x i32> %a, %b + + unsafe { + let a = Simd(x); + let b = Simd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { + // CHECK-LABEL: simd_aggregate_npot + // CHECK: %a = load <7 x i32>, ptr %x, align 4 + // CHECK: %b = load <7 x i32>, ptr %y, align 4 + // CHECK: add <7 x i32> %a, %b + + unsafe { + let a = Simd(x); + let b = Simd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn packed_simd_aggregate_pot(x: [u32; 4], y: [u32; 4]) -> u32 { + // CHECK-LABEL: packed_simd_aggregate_pot + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %b = load <4 x i32>, ptr %y, align 4 + // CHECK: add <4 x i32> %a, %b + + unsafe { + let a = PackedSimd(x); + let b = PackedSimd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn packed_simd_aggregate_npot(x: [u32; 7], y: [u32; 7]) -> u32 { + // CHECK-LABEL: packed_simd_aggregate_npot + // CHECK: %b = alloca [28 x i8], align 4 + // CHECK: %a = alloca [28 x i8], align 4 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %x, i64 28, i1 false) + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b, ptr align 4 %y, i64 28, i1 false) + // CHECK: %[[TEMPA:.+]] = load <7 x i32>, ptr %a, align 4 + // CHECK: %[[TEMPB:.+]] = load <7 x i32>, ptr %b, align 4 + // CHECK: add <7 x i32> %[[TEMPA]], %[[TEMPB]] + + unsafe { + let a = PackedSimd(x); + let b = PackedSimd(y); + let c = simd_add(a, b); + simd_extract(c, 1) + } +} + +#[no_mangle] +pub fn transparent_simd_aggregate(x: [u32; 4]) -> u32 { + // The transparent wrapper can just use the same SSA value as its field. + // No extra processing or spilling needed. + + // CHECK-LABEL: transparent_simd_aggregate + // CHECK-NOT: alloca + // CHECK: %[[RET:.+]] = alloca [4 x i8] + // CHECK-NOT: alloca + // CHECK: %a = load <4 x i32>, ptr %x, align 4 + // CHECK: %[[TEMP:.+]] = extractelement <4 x i32> %a, i32 1 + // CHECK: store i32 %[[TEMP]], ptr %[[RET]] + + unsafe { + let a = Simd(x); + let b = Transparent(a); + simd_extract(b.0, 1) + } +} diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs index a27d5e3af45..73e0d29d7d6 100644 --- a/tests/codegen/simd/packed-simd.rs +++ b/tests/codegen/simd/packed-simd.rs @@ -30,16 +30,18 @@ fn load<T, const N: usize>(v: PackedSimd<T, N>) -> FullSimd<T, N> { } } -// CHECK-LABEL: define <3 x float> @square_packed_full(ptr{{[a-z_ ]*}} align 4 {{[^,]*}}) +// CHECK-LABEL: square_packed_full +// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] +// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 #[no_mangle] pub fn square_packed_full(x: PackedSimd<f32, 3>) -> FullSimd<f32, 3> { - // The unoptimized version of this is not very interesting to check - // since `load` does not get inlined. - // opt3-NEXT: start: - // opt3-NEXT: load <3 x float> + // CHECK-NEXT: start + // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]] + // CHECK: load <3 x float> let x = load(x); - // opt3-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> - // opt3-NEXT: ret <3 x float> [[VREG:%[a-z0-9_]+]] + // CHECK: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> + // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] + // CHECK-NEXT: ret void unsafe { intrinsics::simd_mul(x, x) } } diff --git a/tests/codegen/target-feature-negative-implication.rs b/tests/codegen/target-feature-negative-implication.rs new file mode 100644 index 00000000000..36cd82dd8cf --- /dev/null +++ b/tests/codegen/target-feature-negative-implication.rs @@ -0,0 +1,20 @@ +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: --target=x86_64-unknown-linux-gnu +//@ compile-flags: -Ctarget-feature=-avx2 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub unsafe fn banana() { + // CHECK-LABEL: @banana() + // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { +} + +// CHECK: attributes [[BANANAATTRS]] +// CHECK-SAME: -avx512 diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs index 0fc1e0136b3..eb19b0de2fa 100644 --- a/tests/codegen/target-feature-overrides.rs +++ b/tests/codegen/target-feature-overrides.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength //@ add-core-stubs //@ revisions: COMPAT INCOMPAT //@ needs-llvm-components: x86 @@ -39,7 +40,7 @@ pub unsafe fn banana() -> u32 { // CHECK: attributes [[APPLEATTRS]] // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}" +// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}" // CHECK: attributes [[BANANAATTRS]] // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx" +// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}" diff --git a/tests/codegen/terminating-catchpad.rs b/tests/codegen/terminating-catchpad.rs index 17d88796300..a2ec19871d1 100644 --- a/tests/codegen/terminating-catchpad.rs +++ b/tests/codegen/terminating-catchpad.rs @@ -15,8 +15,14 @@ #![no_std] #![no_core] +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} unsafe extern "C-unwind" { safe fn unwinds(); diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs index 6be0e21e0ef..81499c070d1 100644 --- a/tests/codegen/tied-features-strength.rs +++ b/tests/codegen/tied-features-strength.rs @@ -4,14 +4,23 @@ //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 +// Rust made SVE require neon. //@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0 -// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" } +// ENABLE_SVE: attributes #0 +// ENABLE_SVE-SAME: +neon +// ENABLE_SVE-SAME: +sve +// However, disabling SVE does not disable neon. //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0 -// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-sve,?)|(\+neon,?))*}}" } +// DISABLE_SVE: attributes #0 +// DISABLE_SVE-NOT: -neon +// DISABLE_SVE-SAME: -sve +// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way. //@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0 -// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-fp-armv8,?)|(-neon,?))*}}" } +// DISABLE_NEON: attributes #0 +// DISABLE_NEON-SAME: -neon +// DISABLE_NEON-SAME: -fp-armv8 //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" } diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index c080259a917..ce1b0558b2e 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -1,6 +1,12 @@ +//@ add-core-stubs //@ compile-flags: -C opt-level=0 -C no-prepopulate-passes #![crate_type = "lib"] +#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)] +#![no_core] +extern crate minicore; + +use minicore::*; // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, // without needing to pointercast, and SRoA will turn that into a `bitcast`. @@ -14,7 +20,7 @@ // CHECK-NEXT: ret i32 %_0 #[no_mangle] pub fn f32_to_bits(x: f32) -> u32 { - unsafe { std::mem::transmute(x) } + unsafe { mem::transmute(x) } } // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b) @@ -22,7 +28,7 @@ pub fn f32_to_bits(x: f32) -> u32 { // CHECK-NEXT: ret i8 %_0 #[no_mangle] pub fn bool_to_byte(b: bool) -> u8 { - unsafe { std::mem::transmute(b) } + unsafe { mem::transmute(b) } } // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte) @@ -30,14 +36,14 @@ pub fn bool_to_byte(b: bool) -> u8 { // CHECK-NEXT: ret i1 %_0 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { - std::mem::transmute(byte) + mem::transmute(byte) } // CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p) // CHECK: ret ptr %p #[no_mangle] pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { - unsafe { std::mem::transmute(p) } + unsafe { mem::transmute(p) } } // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p) @@ -45,7 +51,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { // CHECK-NEXT: ret [[USIZE]] %_0 #[no_mangle] pub fn ptr_to_int(p: *mut u16) -> usize { - unsafe { std::mem::transmute(p) } + unsafe { mem::transmute(p) } } // CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i) @@ -53,5 +59,85 @@ pub fn ptr_to_int(p: *mut u16) -> usize { // CHECK-NEXT: ret ptr %_0 #[no_mangle] pub fn int_to_ptr(i: usize) -> *mut u16 { - unsafe { std::mem::transmute(i) } + unsafe { mem::transmute(i) } +} + +// This is the one case where signedness matters to transmuting: +// the LLVM type is `i8` here because of `repr(i8)`, +// whereas below with the `repr(u8)` it's `i1` in LLVM instead. +#[repr(i8)] +pub enum FakeBoolSigned { + False = 0, + True = 1, +} + +// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1 zeroext %b) +// CHECK: %_0 = zext i1 %b to i8 +// CHECK-NEXT: ret i8 %_0 +#[no_mangle] +pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b) +// CHECK: %_0 = trunc nuw i8 %b to i1 +// CHECK-NEXT: ret i1 %_0 +#[no_mangle] +pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool { + unsafe { mem::transmute(b) } +} + +#[repr(u8)] +pub enum FakeBoolUnsigned { + False = 0, + True = 1, +} + +// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1 zeroext %b) +// CHECK: ret i1 %b +#[no_mangle] +pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b) +// CHECK: ret i1 %b +#[no_mangle] +pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { + unsafe { mem::transmute(b) } +} + +#[repr(simd)] +struct S([i64; 1]); + +// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store <1 x i64> %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load i64, ptr %[[RET]] +// CHECK-NEXT: ret i64 %[[TEMP]] +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 { + unsafe { mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store i64 %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load <1 x i64>, ptr %[[RET]] +// CHECK-NEXT: ret <1 x i64> %[[TEMP]] +#[no_mangle] +#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] +#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] +#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] +#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S { + unsafe { mem::transmute(b) } } diff --git a/tests/codegen/union-aggregate.rs b/tests/codegen/union-aggregate.rs new file mode 100644 index 00000000000..aac66c5dcdd --- /dev/null +++ b/tests/codegen/union-aggregate.rs @@ -0,0 +1,108 @@ +//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes +//@ min-llvm-version: 19 +//@ only-64bit + +#![crate_type = "lib"] +#![feature(transparent_unions)] +#![feature(repr_simd)] + +#[repr(transparent)] +union MU<T: Copy> { + uninit: (), + value: T, +} + +use std::cmp::Ordering; +use std::num::NonZero; +use std::ptr::NonNull; + +#[no_mangle] +fn make_mu_bool(x: bool) -> MU<bool> { + // CHECK-LABEL: i8 @make_mu_bool(i1 zeroext %x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8 + // CHECK-NEXT: ret i8 %[[WIDER]] + MU { value: x } +} + +#[no_mangle] +fn make_mu_bool_uninit() -> MU<bool> { + // CHECK-LABEL: i8 @make_mu_bool_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret i8 undef + MU { uninit: () } +} + +#[no_mangle] +fn make_mu_ref(x: &u16) -> MU<&u16> { + // CHECK-LABEL: ptr @make_mu_ref(ptr align 2 %x) + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr %x + MU { value: x } +} + +#[no_mangle] +fn make_mu_ref_uninit<'a>() -> MU<&'a u16> { + // CHECK-LABEL: ptr @make_mu_ref_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret ptr undef + MU { uninit: () } +} + +#[no_mangle] +fn make_mu_str(x: &str) -> MU<&str> { + // CHECK-LABEL: { ptr, i64 } @make_mu_str(ptr align 1 %x.0, i64 %x.1) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { ptr, i64 } poison, ptr %x.0, 0 + // CHECK-NEXT: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1 + // CHECK-NEXT: ret { ptr, i64 } %1 + MU { value: x } +} + +#[no_mangle] +fn make_mu_str_uninit<'a>() -> MU<&'a str> { + // CHECK-LABEL: { ptr, i64 } @make_mu_str_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret { ptr, i64 } undef + MU { uninit: () } +} + +#[no_mangle] +fn make_mu_pair(x: (u8, u32)) -> MU<(u8, u32)> { + // CHECK-LABEL: { i8, i32 } @make_mu_pair(i8 %x.0, i32 %x.1) + // CHECK-NEXT: start: + // CHECK-NEXT: %0 = insertvalue { i8, i32 } poison, i8 %x.0, 0 + // CHECK-NEXT: %1 = insertvalue { i8, i32 } %0, i32 %x.1, 1 + // CHECK-NEXT: ret { i8, i32 } %1 + MU { value: x } +} + +#[no_mangle] +fn make_mu_pair_uninit() -> MU<(u8, u32)> { + // CHECK-LABEL: { i8, i32 } @make_mu_pair_uninit() + // CHECK-NEXT: start: + // CHECK-NEXT: ret { i8, i32 } undef + MU { uninit: () } +} + +#[repr(simd)] +#[derive(Copy, Clone)] +struct I32X32([i32; 32]); + +#[no_mangle] +fn make_mu_simd(x: I32X32) -> MU<I32X32> { + // CHECK-LABEL: void @make_mu_simd(ptr{{.+}}%_0, ptr{{.+}}%x) + // CHECK-NEXT: start: + // CHECK-NEXT: %[[TEMP:.+]] = load <32 x i32>, ptr %x, + // CHECK-NEXT: store <32 x i32> %[[TEMP]], ptr %_0, + // CHECK-NEXT: ret void + MU { value: x } +} + +#[no_mangle] +fn make_mu_simd_uninit() -> MU<I32X32> { + // CHECK-LABEL: void @make_mu_simd_uninit(ptr{{.+}}%_0) + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + MU { uninit: () } +} diff --git a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs index 0d9c7757883..ecace722e0d 100644 --- a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs +++ b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs @@ -2,8 +2,15 @@ //@ compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes #![no_core] #![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} // Test that `nounwind` attributes are correctly applied to exported `aapcs` and // `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We diff --git a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs index 4c7b2856e2e..7df46813ed1 100644 --- a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs @@ -2,8 +2,15 @@ //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] #![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} // Test that `nounwind` attributes are correctly applied to exported `fastcall` and // `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We diff --git a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs index ffc11d1faef..cc06ee12549 100644 --- a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs @@ -2,8 +2,15 @@ //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] #![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} // Test that `nounwind` attributes are correctly applied to exported `stdcall` and `stdcall-unwind` // extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable diff --git a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs index c869ca7e2b8..69bfaf80b4b 100644 --- a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs +++ b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs @@ -2,8 +2,15 @@ //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes #![no_core] #![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} // Test that `nounwind` attributes are correctly applied to exported `sysv64` and // `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We diff --git a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs index 19b23ee47ba..05f6b8b70e1 100644 --- a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs @@ -2,8 +2,15 @@ //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] #![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} // Test that `nounwind` attributes are correctly applied to exported `thiscall` and // `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We diff --git a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs index b420f67ca9b..d001a16b32a 100644 --- a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs @@ -2,8 +2,15 @@ //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] #![feature(no_core, lang_items, abi_vectorcall)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} // Test that `nounwind` attributes are correctly applied to exported `vectorcall` and // `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute. diff --git a/tests/codegen/unwind-abis/win64-unwind-abi.rs b/tests/codegen/unwind-abis/win64-unwind-abi.rs index 2697d3cbcd6..257f00b54e4 100644 --- a/tests/codegen/unwind-abis/win64-unwind-abi.rs +++ b/tests/codegen/unwind-abis/win64-unwind-abi.rs @@ -2,8 +2,15 @@ //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes #![no_core] #![feature(no_core, lang_items)] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -trait Sized {} +pub trait Sized: MetaSized {} // Test that `nounwind` attributes are correctly applied to exported `win64` and // `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We diff --git a/tests/codegen/unwind-landingpad-inline.rs b/tests/codegen/unwind-landingpad-inline.rs index 920774b3402..1cf606279e6 100644 --- a/tests/codegen/unwind-landingpad-inline.rs +++ b/tests/codegen/unwind-landingpad-inline.rs @@ -10,8 +10,10 @@ // See https://github.com/rust-lang/rust/issues/46515 // CHECK-LABEL: @check_no_escape_in_landingpad // CHECK: start: -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable -// CHECK-NEXT: __rust_no_alloc_shim_is_unstable +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM:_R.+__rust_no_alloc_shim_is_unstable_v2]]() +// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 +// CHECK-NEXT: tail call void @[[NO_ALLOC_SHIM]]() // CHECK-NEXT: ret void #[no_mangle] pub fn check_no_escape_in_landingpad(f: fn()) { diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index 1f6836f6dfa..a5ef8653b99 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -41,9 +41,6 @@ pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> { // 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() } @@ -55,9 +52,6 @@ pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> { // 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() } @@ -86,9 +80,6 @@ pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> { // 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() } @@ -100,9 +91,6 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> { // 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() } @@ -114,9 +102,6 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. // This currently is not guaranteed for repr(Rust) types, but it happens to work here and @@ -133,9 +118,6 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. // This currently is not guaranteed for repr(Rust) types, but it happens to work here and @@ -156,12 +138,7 @@ 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 + // CHECK: ret void vec.into_iter().map(|Wrapper(e)| e).collect() } @@ -178,12 +155,6 @@ 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-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs index a88573522d4..807548ef883 100644 --- a/tests/codegen/vec-iter-collect-len.rs +++ b/tests/codegen/vec-iter-collect-len.rs @@ -4,7 +4,9 @@ #[no_mangle] pub fn get_len() -> usize { // CHECK-LABEL: @get_len - // CHECK-NOT: call - // CHECK-NOT: invoke + // CHECK-NEXT: start: + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() + // CHECK-NEXT: ret i{{[0-9]+}} 3 [1, 2, 3].iter().collect::<Vec<_>>().len() } diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs index f6ed2898bda..93b55454b10 100644 --- a/tests/codegen/vec-optimizes-away.rs +++ b/tests/codegen/vec-optimizes-away.rs @@ -5,7 +5,8 @@ pub fn sum_me() -> i32 { // CHECK-LABEL: @sum_me // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1 + // CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 + // CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2() // CHECK-NEXT: ret i32 6 vec![1, 2, 3].iter().sum::<i32>() } diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs index d2d0c4b78ab..26604478c11 100644 --- a/tests/codegen/virtual-function-elimination.rs +++ b/tests/codegen/virtual-function-elimination.rs @@ -6,8 +6,6 @@ // CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]] #![crate_type = "lib"] -#![allow(incomplete_features)] -#![feature(unsized_locals)] use std::rc::Rc; |
