From eb338220911fbcf0661e4f8802b23d0bd4e5d077 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Sat, 6 Jul 2019 21:52:25 +0200
Subject: [PATCH] Pass type to byval attributes

Part of: Prepare for LLVM 9 update
https://github.com/rust-lang/rust/pull/62474
---
 src/librustc_codegen_llvm/abi.rs      | 64 +++++++++++++++------------
 src/librustc_codegen_llvm/declare.rs  |  2 +-
 src/librustc_codegen_llvm/llvm/ffi.rs |  2 +
 src/rustllvm/RustWrapper.cpp          | 22 +++++++++
 4 files changed, 60 insertions(+), 30 deletions(-)

diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 38d4b7e3f9d8..ff87afe0c444 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -34,17 +34,17 @@ trait ArgAttributeExt {
 impl ArgAttributeExt for ArgAttribute {
     fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
         for_each_kind!(self, f,
-                       ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
+                       NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
     }
 }
 
 pub trait ArgAttributesExt {
-    fn apply_llfn(&self, idx: AttributePlace, llfn: &Value);
-    fn apply_callsite(&self, idx: AttributePlace, callsite: &Value);
+    fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>);
+    fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>);
 }
 
 impl ArgAttributesExt for ArgAttributes {
-    fn apply_llfn(&self, idx: AttributePlace, llfn: &Value) {
+    fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) {
         let mut regular = self.regular;
         unsafe {
             let deref = self.pointee_size.bytes();
@@ -65,11 +65,14 @@ impl ArgAttributesExt for ArgAttributes {
                                                idx.as_uint(),
                                                align.bytes() as u32);
             }
+            if regular.contains(ArgAttribute::ByVal) {
+                llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap());
+            }
             regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
         }
     }
 
-    fn apply_callsite(&self, idx: AttributePlace, callsite: &Value) {
+    fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) {
         let mut regular = self.regular;
         unsafe {
             let deref = self.pointee_size.bytes();
@@ -90,6 +93,9 @@ impl ArgAttributesExt for ArgAttributes {
                                                        idx.as_uint(),
                                                        align.bytes() as u32);
             }
+            if regular.contains(ArgAttribute::ByVal) {
+                llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap());
+            }
             regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
         }
     }
@@ -298,7 +304,7 @@ pub trait FnTypeLlvmExt<'tcx> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
-    fn apply_attrs_llfn(&self, llfn: &'ll Value);
+    fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
 }
 
@@ -384,51 +390,51 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
         }
     }
 
-    fn apply_attrs_llfn(&self, llfn: &'ll Value) {
+    fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
         let mut i = 0;
-        let mut apply = |attrs: &ArgAttributes| {
-            attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
+        let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
+            attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
             i += 1;
         };
         match self.ret.mode {
             PassMode::Direct(ref attrs) => {
-                attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
+                attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None);
             }
-            PassMode::Indirect(ref attrs, _) => apply(attrs),
+            PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))),
             _ => {}
         }
         for arg in &self.args {
             if arg.pad.is_some() {
-                apply(&ArgAttributes::new());
+                apply(&ArgAttributes::new(), None);
             }
             match arg.mode {
                 PassMode::Ignore(_) => {}
                 PassMode::Direct(ref attrs) |
-                PassMode::Indirect(ref attrs, None) => apply(attrs),
+                PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(cx))),
                 PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
-                    apply(attrs);
-                    apply(extra_attrs);
+                    apply(attrs, None);
+                    apply(extra_attrs, None);
                 }
                 PassMode::Pair(ref a, ref b) => {
-                    apply(a);
-                    apply(b);
+                    apply(a, None);
+                    apply(b, None);
                 }
-                PassMode::Cast(_) => apply(&ArgAttributes::new()),
+                PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
             }
         }
     }
 
     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
         let mut i = 0;
-        let mut apply = |attrs: &ArgAttributes| {
-            attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
+        let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
+            attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty);
             i += 1;
         };
         match self.ret.mode {
             PassMode::Direct(ref attrs) => {
-                attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite);
+                attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None);
             }
-            PassMode::Indirect(ref attrs, _) => apply(attrs),
+            PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))),
             _ => {}
         }
         if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi {
@@ -446,21 +452,21 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
         }
         for arg in &self.args {
             if arg.pad.is_some() {
-                apply(&ArgAttributes::new());
+                apply(&ArgAttributes::new(), None);
             }
             match arg.mode {
                 PassMode::Ignore(_) => {}
                 PassMode::Direct(ref attrs) |
-                PassMode::Indirect(ref attrs, None) => apply(attrs),
+                PassMode::Indirect(ref attrs, None) => apply(attrs, Some(arg.layout.llvm_type(bx))),
                 PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
-                    apply(attrs);
-                    apply(extra_attrs);
+                    apply(attrs, None);
+                    apply(extra_attrs, None);
                 }
                 PassMode::Pair(ref a, ref b) => {
-                    apply(a);
-                    apply(b);
+                    apply(a, None);
+                    apply(b, None);
                 }
-                PassMode::Cast(_) => apply(&ArgAttributes::new()),
+                PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
             }
         }
 
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index bcb14b8899ec..62eab0f3d4e6 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -107,7 +107,7 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
         }
 
-        fty.apply_attrs_llfn(llfn);
+        fty.apply_attrs_llfn(self, llfn);
 
         llfn
     }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index a5c295cd4525..75f639ec3eca 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -794,6 +794,7 @@ extern "C" {
     pub fn LLVMRustAddAlignmentAttr(Fn: &Value, index: c_uint, bytes: u32);
     pub fn LLVMRustAddDereferenceableAttr(Fn: &Value, index: c_uint, bytes: u64);
     pub fn LLVMRustAddDereferenceableOrNullAttr(Fn: &Value, index: c_uint, bytes: u64);
+    pub fn LLVMRustAddByValAttr(Fn: &Value, index: c_uint, ty: &Type);
     pub fn LLVMRustAddFunctionAttribute(Fn: &Value, index: c_uint, attr: Attribute);
     pub fn LLVMRustAddFunctionAttrStringValue(Fn: &Value,
                                               index: c_uint,
@@ -824,6 +825,7 @@ extern "C" {
     pub fn LLVMRustAddDereferenceableOrNullCallSiteAttr(Instr: &Value,
                                                         index: c_uint,
                                                         bytes: u64);
+    pub fn LLVMRustAddByValCallSiteAttr(Instr: &Value, index: c_uint, ty: &Type);
 
     // Operations on load/store instructions (only)
     pub fn LLVMSetVolatile(MemoryAccessInst: &Value, volatile: Bool);
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 66453c08a66e..16d08ee534ed 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -237,6 +237,17 @@ extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr,
       Call->getContext(), Index, B));
 }
 
+extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index,
+                                             LLVMTypeRef Ty) {
+  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+#if LLVM_VERSION_GE(9, 0)
+  Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty));
+#else
+  Attribute Attr = Attribute::get(Call->getContext(), Attribute::ByVal);
+#endif
+  Call.addAttribute(Index, Attr);
+}
+
 extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
                                              LLVMRustAttribute RustAttr) {
   Function *A = unwrap<Function>(Fn);
@@ -271,6 +282,17 @@ extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn,
   A->addAttributes(Index, B);
 }
 
+extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index,
+                                     LLVMTypeRef Ty) {
+  Function *F = unwrap<Function>(Fn);
+#if LLVM_VERSION_GE(9, 0)
+  Attribute Attr = Attribute::getWithByValType(F->getContext(), unwrap(Ty));
+#else
+  Attribute Attr = Attribute::get(F->getContext(), Attribute::ByVal);
+#endif
+  F->addAttribute(Index, Attr);
+}
+
 extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
                                                    unsigned Index,
                                                    const char *Name,
