Skip to content

Set dead_on_return attribute for indirect arguments #145093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::attributes::{self, llfn_attrs_from_instance};
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm::{self, Attribute, AttributePlace};
use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
Expand Down Expand Up @@ -500,7 +501,16 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
}
}
PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
apply(attrs);
let i = apply(attrs);
if cx.sess().opts.optimize != config::OptLevel::No
&& llvm_util::get_version() >= (21, 0, 0)
{
attributes::apply_to_llfn(
llfn,
llvm::AttributePlace::Argument(i),
&[llvm::AttributeKind::DeadOnReturn.create_attr(cx.llcx)],
);
}
}
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
assert!(!on_stack);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ pub(crate) enum AttributeKind {
FnRetThunkExtern = 41,
Writable = 42,
DeadOnUnwind = 43,
DeadOnReturn = 44,
}

/// LLVMIntPredicate
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ enum class LLVMRustAttributeKind {
FnRetThunkExtern = 41,
Writable = 42,
DeadOnUnwind = 43,
DeadOnReturn = 44,
};

static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
Expand Down Expand Up @@ -369,6 +370,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
return Attribute::Writable;
case LLVMRustAttributeKind::DeadOnUnwind:
return Attribute::DeadOnUnwind;
case LLVMRustAttributeKind::DeadOnReturn:
#if LLVM_VERSION_GE(21, 0)
return Attribute::DeadOnReturn;
#else
report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later");
#endif
}
report_fatal_error("bad LLVMRustAttributeKind");
}
Expand Down
6 changes: 3 additions & 3 deletions tests/codegen-llvm/addr-of-mutate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Test for the absence of `readonly` on the argument when it is mutated via `&raw const`.
// See <https://github.com/rust-lang/rust/issues/111502>.

// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x)
// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x)
#[no_mangle]
pub fn foo(x: [u8; 128]) -> u8 {
let ptr = core::ptr::addr_of!(x).cast_mut();
Expand All @@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 {
x[0]
}

// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
#[no_mangle]
pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut();
Expand All @@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
}

// If going through a deref (and there are no other mutating accesses), then `readonly` is fine.
// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
#[no_mangle]
pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut();
Expand Down
31 changes: 31 additions & 0 deletions tests/codegen-llvm/dead_on_return.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//@ compile-flags: -C opt-level=3
//@ min-llvm-version: 21

#![crate_type = "lib"]
#![allow(unused_assignments, unused_variables)]

// Check that the old string is deallocated, but a new one is not initialized.
#[unsafe(no_mangle)]
pub fn test_str_new(mut s: String) {
// CHECK-LABEL: @test_str_new
// CHECK: __rust_dealloc
// CHECK-NOT: store
s = String::new();
}

#[unsafe(no_mangle)]
pub fn test_str_take(mut x: String) -> String {
// CHECK-LABEL: @test_str_take
// CHECK-NEXT: {{.*}}:
// CHECK-NEXT: call void @llvm.memcpy
// CHECK-NEXT: ret
core::mem::take(&mut x)
}

#[unsafe(no_mangle)]
pub fn test_array_store(mut x: [u32; 100]) {
// CHECK-LABEL: @test_array_store
// CHECK-NEXT: {{.*}}:
// CHECK-NEXT: ret
x[0] = 1;
}
2 changes: 1 addition & 1 deletion tests/codegen-llvm/function-arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
#[no_mangle]
pub fn notunpin_borrow(_: &NotUnpin) {}

// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
// 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) {}

Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ pub struct IntDoubleInt {
c: i32,
}

// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a)
// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a)
#[no_mangle]
pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}

Expand Down
Loading