From 3695af697efa26b0ea3b67739ade3ecc3929154e Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov@redhat.com>
Date: Mon, 19 Feb 2024 15:02:49 +0100
Subject: [PATCH 1/3] Set writable and dead_on_unwind attributes for sret
 arguments

---
 compiler/rustc_codegen_llvm/src/abi.rs              | 13 +++++++++++++
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs         |  2 ++
 compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h      |  2 ++
 compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp    | 10 ++++++++++
 tests/codegen/function-arguments.rs                 |  2 +-
 .../codegen/loongarch-abi/loongarch64-lp64d-abi.rs  |  2 +-
 tests/codegen/maybeuninit-rvo.rs                    |  3 ++-
 7 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index f918facc86db1..94d67859f2f30 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -2,6 +2,7 @@ use crate::attributes;
 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;
@@ -420,6 +421,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     cx.type_array(cx.type_i8(), self.ret.layout.size.bytes()),
                 );
                 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
+                if cx.sess().opts.optimize != config::OptLevel::No
+                    && llvm_util::get_version() >= (18, 0, 0)
+                {
+                    attributes::apply_to_llfn(
+                        llfn,
+                        llvm::AttributePlace::Argument(i),
+                        &[
+                            llvm::AttributeKind::Writable.create_attr(cx.llcx),
+                            llvm::AttributeKind::DeadOnUnwind.create_attr(cx.llcx),
+                        ],
+                    );
+                }
             }
             PassMode::Cast { cast, pad_i32: _ } => {
                 cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 5509baaa3e94c..96265043a1cc2 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -200,6 +200,8 @@ pub enum AttributeKind {
     AllocAlign = 39,
     SanitizeSafeStack = 40,
     FnRetThunkExtern = 41,
+    Writable = 42,
+    DeadOnUnwind = 43,
 }
 
 /// LLVMIntPredicate
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 6d578c97f3fe1..a493abbbc7e5a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -91,6 +91,8 @@ enum LLVMRustAttribute {
   AllocAlign = 39,
   SanitizeSafeStack = 40,
   FnRetThunkExtern = 41,
+  Writable = 42,
+  DeadOnUnwind = 43,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 37c2da4c23a1a..fb5a56155fddf 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -312,6 +312,16 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::SafeStack;
   case FnRetThunkExtern:
     return Attribute::FnRetThunkExtern;
+#if LLVM_VERSION_GE(18, 0)
+  case Writable:
+    return Attribute::Writable;
+  case DeadOnUnwind:
+    return Attribute::DeadOnUnwind;
+#else
+  case Writable:
+  case DeadOnUnwind:
+    report_fatal_error("Not supported on this LLVM version");
+#endif
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index 468ec0a77533b..570d32f78faa4 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -198,7 +198,7 @@ pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
   x
 }
 
-// CHECK: @struct_return(ptr noalias nocapture noundef sret([32 x i8]) align 4 dereferenceable(32){{( %_0)?}})
+// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([32 x i8]) align 4 dereferenceable(32){{( %_0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
   S {
diff --git a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs
index c9be4f6d383a9..d978f2d252541 100644
--- a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs
+++ b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs
@@ -260,7 +260,7 @@ pub struct IntDoubleInt {
 #[no_mangle]
 pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}
 
-// CHECK: define void @f_ret_int_double_int_s(ptr noalias nocapture noundef sret([24 x i8]) align 8 dereferenceable(24) %_0)
+// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([24 x i8]) align 8 dereferenceable(24) %_0)
 #[no_mangle]
 pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt {
     IntDoubleInt { a: 1, b: 2., c: 3 }
diff --git a/tests/codegen/maybeuninit-rvo.rs b/tests/codegen/maybeuninit-rvo.rs
index 954514c736bd4..d6b9ee8d11d8b 100644
--- a/tests/codegen/maybeuninit-rvo.rs
+++ b/tests/codegen/maybeuninit-rvo.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: -O
+//@ min-llvm-version: 18
 #![feature(c_unwind)]
 #![crate_type = "lib"]
 
@@ -24,7 +25,7 @@ extern "C-unwind" {
 
 pub fn new_from_uninit_unwind() -> Foo {
     // CHECK-LABEL: new_from_uninit
-    // CHECK: call void @llvm.memcpy.
+    // CHECK-NOT: call void @llvm.memcpy.
     let mut x = std::mem::MaybeUninit::uninit();
     unsafe {
         init_unwind(x.as_mut_ptr());

From 137775dd631769bd83c90ec8f12bb17db9e6d411 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov@redhat.com>
Date: Tue, 9 Apr 2024 10:05:26 +0900
Subject: [PATCH 2/3] Fix incorrect CHECK-LABEL

---
 tests/codegen/maybeuninit-rvo.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/codegen/maybeuninit-rvo.rs b/tests/codegen/maybeuninit-rvo.rs
index d6b9ee8d11d8b..d21e878c818be 100644
--- a/tests/codegen/maybeuninit-rvo.rs
+++ b/tests/codegen/maybeuninit-rvo.rs
@@ -24,7 +24,7 @@ extern "C-unwind" {
 }
 
 pub fn new_from_uninit_unwind() -> Foo {
-    // CHECK-LABEL: new_from_uninit
+    // CHECK-LABEL: new_from_uninit_unwind
     // CHECK-NOT: call void @llvm.memcpy.
     let mut x = std::mem::MaybeUninit::uninit();
     unsafe {

From 976267b5141ef9a72ba3cb9edf01ca3bc53ec81e Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov@redhat.com>
Date: Thu, 25 Apr 2024 11:44:32 +0900
Subject: [PATCH 3/3] Add needs-unwind to codegen test

When compiled with -C panic=abort we'd generate an extra
panic_cannot_unwind shim in the variant calling C-unwind.
---
 tests/codegen/maybeuninit-rvo.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/codegen/maybeuninit-rvo.rs b/tests/codegen/maybeuninit-rvo.rs
index d21e878c818be..cc5da39a9cac8 100644
--- a/tests/codegen/maybeuninit-rvo.rs
+++ b/tests/codegen/maybeuninit-rvo.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: -O
+//@ needs-unwind
 //@ min-llvm-version: 18
 #![feature(c_unwind)]
 #![crate_type = "lib"]