blob: 8062419ed5c6eb1eafd5cbd8eee10a52d7d5eacb [file] [log] [blame] [edit]
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
//@ compile-flags: -Cpanic=abort -Csymbol-mangling-version=v0
//@ revisions: LLVM21 LLVM20
//@ [LLVM21] min-llvm-version: 21
//@ [LLVM20] max-llvm-major-version: 20
#![feature(custom_mir, core_intrinsics)]
#![crate_type = "lib"]
extern crate core;
use core::intrinsics::mir::*;
use std::cell::Cell;
use std::hint::black_box;
use std::mem::ManuallyDrop;
pub struct Big {
pub blah: [i32; 1024],
}
pub struct BigCell {
pub blah: [Cell<i32>; 1024],
}
pub struct BigDrop {
pub blah: [u8; 1024],
}
impl Drop for BigDrop {
#[inline(never)]
fn drop(&mut self) {}
}
// CHECK-LABEL: @mutate(
// CHECK-NOT: readonly
// CHECK-SAME: %b)
#[unsafe(no_mangle)]
pub fn mutate(mut b: Big) {
b.blah[987] = 654;
black_box(&b);
}
// LLVM21-LABEL: @deref_mut({{.*}}readonly {{.*}}captures(none) {{.*}}%c)
// LLVM20-LABEL: @deref_mut({{.*}}readonly {{.*}}%c)
#[unsafe(no_mangle)]
pub fn deref_mut(c: (BigCell, &mut usize)) {
*c.1 = 42;
}
// LLVM21-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}}captures(none){{.*}})
// LLVM20-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}})
#[unsafe(no_mangle)]
#[custom_mir(dialect = "runtime", phase = "optimized")]
pub fn call_copy_arg(a: Big) {
mir! {
{
Call(RET = call_copy_arg(a), ReturnTo(bb1), UnwindUnreachable())
}
bb1 = {
Return()
}
}
}
// CHECK-LABEL: @call_move_arg(
// CHECK-NOT: readonly
// LLVM21-SAME: captures(address)
// CHECK-SAME: )
#[unsafe(no_mangle)]
#[custom_mir(dialect = "runtime", phase = "optimized")]
pub fn call_move_arg(a: Big) {
mir! {
{
Call(RET = call_move_arg(Move(a)), ReturnTo(bb1), UnwindUnreachable())
}
bb1 = {
Return()
}
}
}
fn shared_borrow<T>(a: T) {
black_box(&a);
}
// Freeze parameter cannot be mutated through a shared borrow.
//
// CHECK-LABEL: ; deduced_param_attrs::shared_borrow::<deduced_param_attrs::Big>
// CHECK-NEXT: ;
// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(address) {{.*}}%a)
// LLVM20-NEXT: (ptr {{.*}}readonly {{.*}}%a)
pub static A0: fn(Big) = shared_borrow;
// !Freeze parameter can be mutated through a shared borrow.
//
// CHECK-LABEL: ; deduced_param_attrs::shared_borrow::<deduced_param_attrs::BigCell>
// CHECK-NEXT: ;
// CHECK-NOT: readonly
// CHECK-NEXT: %a)
pub static A1: fn(BigCell) = shared_borrow;
// The parameter can be mutated through a raw const borrow.
//
// CHECK-LABEL: ; deduced_param_attrs::raw_const_borrow
// CHECK-NOT: readonly
// CHECK-NEXT : %a)
#[inline(never)]
pub fn raw_const_borrow(a: Big) {
black_box(&raw const a);
}
fn consume<T>(_: T) {}
// The parameter doesn't need to be dropped.
//
// CHECK-LABEL: ; deduced_param_attrs::consume::<deduced_param_attrs::BigCell>
// CHECK-NEXT: ;
// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(none) {{.*}})
// LLVM20-NEXT: (ptr {{.*}}readonly {{.*}})
pub static B0: fn(BigCell) = consume;
// The parameter needs to be dropped.
//
// CHECK-LABEL: ; deduced_param_attrs::consume::<deduced_param_attrs::BigDrop>
// CHECK-NEXT: ;
// LLVM21-NEXT: (ptr {{.*}}captures(address) {{.*}})
// LLVM20-NEXT: (ptr {{.*}})
pub static B1: fn(BigDrop) = consume;
fn consume_parts<T>(t: (T, T)) {
let (_t0, ..) = t;
}
// In principle it would be possible to deduce readonly here.
//
// CHECK-LABEL: ; deduced_param_attrs::consume_parts::<[u8; 40]>
// CHECK-NEXT: ;
// CHECK-NOT: readonly
// CHECK-NEXT: %t)
pub static C1: fn(([u8; 40], [u8; 40])) = consume_parts;
// The inner field of ManuallyDrop<BigDrop> needs to be dropped.
//
// CHECK-LABEL: @manually_drop_field(
// CHECK-NOT: readonly
// CHECK-SAME: %b)
#[unsafe(no_mangle)]
pub fn manually_drop_field(a: fn() -> BigDrop, mut b: ManuallyDrop<BigDrop>) {
// FIXME(tmiasko) replace with custom MIR, instead of expecting MIR optimizations to turn this
// into: drop((_2.0: BigDrop))
*b = a();
unsafe { core::intrinsics::unreachable() }
}
// `readonly` is omitted from the return place, even when applicable.
//
// CHECK-LABEL: @never_returns(
// CHECK-NOT: readonly
// CHECK-SAME: %_0)
#[unsafe(no_mangle)]
pub fn never_returns() -> [u8; 80] {
loop {}
}
// LLVM21-LABEL: @not_captured_return_place(ptr{{.*}} captures(none) {{.*}}%_0)
#[unsafe(no_mangle)]
pub fn not_captured_return_place() -> [u8; 80] {
[0u8; 80]
}
// LLVM21-LABEL: @captured_return_place(ptr{{.*}} captures(address) {{.*}}%_0)
#[unsafe(no_mangle)]
pub fn captured_return_place() -> [u8; 80] {
black_box([0u8; 80])
}