mirror of
https://github.com/rust-lang/rust.git
synced 2025-10-08 13:20:11 +00:00

Set the dead_on_return attribute (added in LLVM 21) for arguments that are passed indirectly, but not byval. This indicates that the value of the argument on return does not matter, enabling additional dead store elimination.
279 lines
8.6 KiB
Rust
279 lines
8.6 KiB
Rust
//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
|
|
#![crate_type = "lib"]
|
|
#![feature(rustc_attrs)]
|
|
#![feature(allocator_api)]
|
|
|
|
use std::marker::PhantomPinned;
|
|
use std::mem::MaybeUninit;
|
|
use std::num::NonZero;
|
|
use std::ptr::NonNull;
|
|
|
|
pub struct S {
|
|
_field: [i32; 8],
|
|
}
|
|
|
|
pub struct UnsafeInner {
|
|
_field: std::cell::UnsafeCell<i16>,
|
|
}
|
|
|
|
pub struct NotUnpin {
|
|
_field: i32,
|
|
_marker: PhantomPinned,
|
|
}
|
|
|
|
pub enum MyBool {
|
|
True,
|
|
False,
|
|
}
|
|
|
|
// CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x)
|
|
#[no_mangle]
|
|
pub fn boolean(x: bool) -> bool {
|
|
x
|
|
}
|
|
|
|
// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x)
|
|
#[no_mangle]
|
|
pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
|
|
x
|
|
}
|
|
|
|
// CHECK: noundef zeroext i1 @enum_bool(i1 noundef zeroext %x)
|
|
#[no_mangle]
|
|
pub fn enum_bool(x: MyBool) -> MyBool {
|
|
x
|
|
}
|
|
|
|
// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x)
|
|
#[no_mangle]
|
|
pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
|
|
x
|
|
}
|
|
|
|
// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x)
|
|
#[no_mangle]
|
|
pub fn char(x: char) -> char {
|
|
x
|
|
}
|
|
|
|
// CHECK: i32 @maybeuninit_char(i32{{.*}} %x)
|
|
#[no_mangle]
|
|
pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
|
|
x
|
|
}
|
|
|
|
// CHECK: noundef i64 @int(i64 noundef %x)
|
|
#[no_mangle]
|
|
pub fn int(x: u64) -> u64 {
|
|
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
|
|
}
|
|
|
|
// CHECK: noundef i64 @option_nonzero_int(i64 noundef %x)
|
|
#[no_mangle]
|
|
pub fn option_nonzero_int(x: Option<NonZero<u64>>) -> Option<NonZero<u64>> {
|
|
x
|
|
}
|
|
|
|
// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
|
|
// FIXME #25759 This should also have `nocapture`
|
|
#[no_mangle]
|
|
pub fn readonly_borrow(_: &i32) {}
|
|
|
|
// CHECK: noundef align 4 dereferenceable(4) ptr @readonly_borrow_ret()
|
|
#[no_mangle]
|
|
pub fn readonly_borrow_ret() -> &'static i32 {
|
|
loop {}
|
|
}
|
|
|
|
// CHECK: @static_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
|
|
// static borrow may be captured
|
|
#[no_mangle]
|
|
pub fn static_borrow(_: &'static i32) {}
|
|
|
|
// CHECK: @named_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
|
|
// borrow with named lifetime may be captured
|
|
#[no_mangle]
|
|
pub fn named_borrow<'r>(_: &'r i32) {}
|
|
|
|
// CHECK: @unsafe_borrow(ptr noundef nonnull align 2 %_1)
|
|
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
|
#[no_mangle]
|
|
pub fn unsafe_borrow(_: &UnsafeInner) {}
|
|
|
|
// CHECK: @mutable_unsafe_borrow(ptr noalias noundef align 2 dereferenceable(2) %_1)
|
|
// ... unless this is a mutable borrow, those never alias
|
|
#[no_mangle]
|
|
pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {}
|
|
|
|
// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1)
|
|
// FIXME #25759 This should also have `nocapture`
|
|
#[no_mangle]
|
|
pub fn mutable_borrow(_: &mut i32) {}
|
|
|
|
// CHECK: noundef align 4 dereferenceable(4) ptr @mutable_borrow_ret()
|
|
#[no_mangle]
|
|
pub fn mutable_borrow_ret() -> &'static mut i32 {
|
|
loop {}
|
|
}
|
|
|
|
#[no_mangle]
|
|
// CHECK: @mutable_notunpin_borrow(ptr noundef nonnull align 4 %_1)
|
|
// This one is *not* `noalias` because it might be self-referential.
|
|
// It is also not `dereferenceable` due to
|
|
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
|
|
pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
|
|
|
|
// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
|
|
// But `&NotUnpin` behaves perfectly normal.
|
|
#[no_mangle]
|
|
pub fn notunpin_borrow(_: &NotUnpin) {}
|
|
|
|
// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
|
|
#[no_mangle]
|
|
pub fn indirect_struct(_: S) {}
|
|
|
|
// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4 dereferenceable(32) %_1)
|
|
// FIXME #25759 This should also have `nocapture`
|
|
#[no_mangle]
|
|
pub fn borrowed_struct(_: &S) {}
|
|
|
|
// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %_x)
|
|
#[no_mangle]
|
|
pub fn option_borrow(_x: Option<&i32>) {}
|
|
|
|
// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x)
|
|
#[no_mangle]
|
|
pub fn option_borrow_mut(_x: Option<&mut i32>) {}
|
|
|
|
// Function that must NOT have `dereferenceable` or `align`.
|
|
#[rustc_layout_scalar_valid_range_start(16)]
|
|
pub struct RestrictedAddress(&'static i16);
|
|
enum E {
|
|
A(RestrictedAddress),
|
|
B,
|
|
C,
|
|
}
|
|
// If the `nonnull` ever goes missing, you might have to tweak the
|
|
// scalar_valid_range on `RestrictedAddress` to get it back. You
|
|
// might even have to add a `rustc_layout_scalar_valid_range_end`.
|
|
// CHECK: @nonnull_and_nondereferenceable(ptr noundef nonnull %_x)
|
|
#[no_mangle]
|
|
pub fn nonnull_and_nondereferenceable(_x: E) {}
|
|
|
|
// CHECK: @raw_struct(ptr noundef %_1)
|
|
#[no_mangle]
|
|
pub fn raw_struct(_: *const S) {}
|
|
|
|
// CHECK: @raw_option_nonnull_struct(ptr noundef %_1)
|
|
#[no_mangle]
|
|
pub fn raw_option_nonnull_struct(_: Option<NonNull<S>>) {}
|
|
|
|
// `Box` can get deallocated during execution of the function, so it should
|
|
// not get `dereferenceable`.
|
|
// CHECK: noundef nonnull align 4 ptr @_box(ptr noalias noundef nonnull align 4 %x)
|
|
#[no_mangle]
|
|
pub fn _box(x: Box<i32>) -> Box<i32> {
|
|
x
|
|
}
|
|
|
|
// With a custom allocator, it should *not* have `noalias`. (See
|
|
// <https://github.com/rust-lang/miri/issues/3341> for why.) The second argument is the allocator,
|
|
// which is a reference here that still carries `noalias` as usual.
|
|
// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1)
|
|
#[no_mangle]
|
|
pub fn _box_custom(x: Box<i32, &std::alloc::Global>) {
|
|
drop(x)
|
|
}
|
|
|
|
// CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x)
|
|
#[no_mangle]
|
|
pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
|
|
x
|
|
}
|
|
|
|
// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}})
|
|
#[no_mangle]
|
|
pub fn struct_return() -> S {
|
|
S { _field: [0, 0, 0, 0, 0, 0, 0, 0] }
|
|
}
|
|
|
|
// Hack to get the correct size for the length part in slices
|
|
// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1)
|
|
#[no_mangle]
|
|
pub fn helper(_: usize) {}
|
|
|
|
// CHECK: @slice(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
|
|
// FIXME #25759 This should also have `nocapture`
|
|
#[no_mangle]
|
|
pub fn slice(_: &[u8]) {}
|
|
|
|
// CHECK: @mutable_slice(ptr noalias noundef nonnull align 1 %_1.0, [[USIZE]] noundef %_1.1)
|
|
// FIXME #25759 This should also have `nocapture`
|
|
#[no_mangle]
|
|
pub fn mutable_slice(_: &mut [u8]) {}
|
|
|
|
// CHECK: @unsafe_slice(ptr noundef nonnull align 2 %_1.0, [[USIZE]] noundef %_1.1)
|
|
// unsafe interior means this isn't actually readonly and there may be aliases ...
|
|
#[no_mangle]
|
|
pub fn unsafe_slice(_: &[UnsafeInner]) {}
|
|
|
|
// CHECK: @raw_slice(ptr noundef %_1.0, [[USIZE]] noundef %_1.1)
|
|
#[no_mangle]
|
|
pub fn raw_slice(_: *const [u8]) {}
|
|
|
|
// CHECK: @str(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
|
|
// FIXME #25759 This should also have `nocapture`
|
|
#[no_mangle]
|
|
pub fn str(_: &[u8]) {}
|
|
|
|
// CHECK: @trait_borrow(ptr noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
|
|
// FIXME #25759 This should also have `nocapture`
|
|
#[no_mangle]
|
|
pub fn trait_borrow(_: &dyn Drop) {}
|
|
|
|
// CHECK: @option_trait_borrow(ptr noundef align 1 %x.0, ptr %x.1)
|
|
#[no_mangle]
|
|
pub fn option_trait_borrow(x: Option<&dyn Drop>) {}
|
|
|
|
// CHECK: @option_trait_borrow_mut(ptr noundef align 1 %x.0, ptr %x.1)
|
|
#[no_mangle]
|
|
pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {}
|
|
|
|
// CHECK: @trait_raw(ptr noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
|
|
#[no_mangle]
|
|
pub fn trait_raw(_: *const dyn Drop) {}
|
|
|
|
// CHECK: @trait_box(ptr noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
|
|
#[no_mangle]
|
|
pub fn trait_box(_: Box<dyn Drop + Unpin>) {}
|
|
|
|
// CHECK: { ptr, ptr } @trait_option(ptr noalias noundef align 1 %x.0, ptr %x.1)
|
|
#[no_mangle]
|
|
pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + Unpin>> {
|
|
x
|
|
}
|
|
|
|
// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1)
|
|
#[no_mangle]
|
|
pub fn return_slice(x: &[u16]) -> &[u16] {
|
|
x
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// CHECK: { i1, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1)
|
|
#[no_mangle]
|
|
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
|
|
x
|
|
}
|