From 1ac37d50c0096f13604c7ca249517b76ff1f1802 Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Thu, 12 Sep 2013 23:23:44 -0400
Subject: [PATCH] set sret attribute as needed on call instructions

Since function pointers do not carry along the function attributes with
them in the type, this needs to be set on the call instruction itself.

Closes #9152
---
 src/librustc/middle/trans/build.rs   |  4 ++--
 src/librustc/middle/trans/builder.rs | 14 +++++++-------
 src/librustc/middle/trans/foreign.rs |  2 +-
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index acec33f7004..11458eda585 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -655,9 +655,9 @@ pub fn FastCall(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
 }
 
 pub fn CallWithConv(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
-                    Conv: CallConv) -> ValueRef {
+                    Conv: CallConv, sret: bool) -> ValueRef {
     if cx.unreachable { return _UndefReturn(cx, Fn); }
-    B(cx).call_with_conv(Fn, Args, Conv)
+    B(cx).call_with_conv(Fn, Args, Conv, sret)
 }
 
 pub fn AtomicFence(cx: @mut Block, order: AtomicOrdering) {
diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs
index 6a1acf68efa..349f14aefbc 100644
--- a/src/librustc/middle/trans/builder.rs
+++ b/src/librustc/middle/trans/builder.rs
@@ -13,6 +13,7 @@ use lib::llvm::llvm;
 use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
 use lib::llvm::{Opcode, IntPredicate, RealPredicate, False};
 use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
+use lib::llvm::{StructRetAttribute};
 use middle::trans::base;
 use middle::trans::common::*;
 use middle::trans::machine::llalign_of_min;
@@ -778,14 +779,9 @@ impl Builder {
 
     pub fn call(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
         self.count_insn("call");
-
-        debug!("Call(llfn=%s, args=%?)",
-               self.ccx.tn.val_to_str(llfn),
-               args.map(|arg| self.ccx.tn.val_to_str(*arg)));
-
         do args.as_imm_buf |ptr, len| {
             unsafe {
-            llvm::LLVMBuildCall(self.llbuilder, llfn, ptr, len as c_uint, noname())
+                llvm::LLVMBuildCall(self.llbuilder, llfn, ptr, len as c_uint, noname())
             }
         }
     }
@@ -801,12 +797,16 @@ impl Builder {
     }
 
     pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
-                        conv: CallConv) -> ValueRef {
+                         conv: CallConv, sret: bool) -> ValueRef {
         self.count_insn("callwithconv");
         unsafe {
             let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
                                         args.len() as c_uint, noname());
             lib::llvm::SetInstructionCallConv(v, conv);
+            if sret {
+                let return_slot = 1;
+                llvm::LLVMAddInstrAttribute(v, return_slot, StructRetAttribute as c_uint);
+            }
             v
         }
     }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 26968ce4881..681852b3bf2 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -266,7 +266,7 @@ pub fn trans_native_call(bcx: @mut Block,
         }
     };
 
-    let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc);
+    let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc, fn_type.sret);
 
     // If the function we just called does not use an outpointer,
     // store the result into the rust outpointer. Cast the outpointer