now that we have CGT around, we can start using preferred types
for return values too.  Instead of compiling something like:

struct foo {
  int *X;
  float *Y;
};

struct foo test(struct foo *P) { return *P; }

to:

%1 = type { i64, i64 }

define %1 @test(%struct.foo* %P) nounwind {
entry:
  %retval = alloca %struct.foo, align 8           ; <%struct.foo*> [#uses=2]
  %P.addr = alloca %struct.foo*, align 8          ; <%struct.foo**> [#uses=2]
  store %struct.foo* %P, %struct.foo** %P.addr
  %tmp = load %struct.foo** %P.addr               ; <%struct.foo*> [#uses=1]
  %tmp1 = bitcast %struct.foo* %retval to i8*     ; <i8*> [#uses=1]
  %tmp2 = bitcast %struct.foo* %tmp to i8*        ; <i8*> [#uses=1]
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp1, i8* %tmp2, i64 16, i32 8, i1 false)
  %0 = bitcast %struct.foo* %retval to %1*        ; <%1*> [#uses=1]
  %1 = load %1* %0, align 1                       ; <%1> [#uses=1]
  ret %1 %1
}

We now get the result more type safe, with:

define %struct.foo @test(%struct.foo* %P) nounwind {
entry:
  %retval = alloca %struct.foo, align 8           ; <%struct.foo*> [#uses=2]
  %P.addr = alloca %struct.foo*, align 8          ; <%struct.foo**> [#uses=2]
  store %struct.foo* %P, %struct.foo** %P.addr
  %tmp = load %struct.foo** %P.addr               ; <%struct.foo*> [#uses=1]
  %tmp1 = bitcast %struct.foo* %retval to i8*     ; <i8*> [#uses=1]
  %tmp2 = bitcast %struct.foo* %tmp to i8*        ; <i8*> [#uses=1]
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp1, i8* %tmp2, i64 16, i32 8, i1 false)
  %0 = load %struct.foo* %retval                  ; <%struct.foo> [#uses=1]
  ret %struct.foo %0
}

That memcpy is completely terrible, but I don't know how to fix it.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109729 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 1e94dbd..fc9dcfd 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -1243,6 +1243,7 @@
   assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
   assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
 
+  const llvm::Type *IRType = 0;
   const llvm::Type *ResType = 0;
   switch (Lo) {
   case NoClass:
@@ -1260,7 +1261,10 @@
     // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
     // available register of the sequence %rax, %rdx is used.
   case Integer:
-    ResType = Get8ByteTypeAtOffset(0, 0, RetTy, 0);
+    if (IRType == 0)
+      IRType = CGT.ConvertTypeRecursive(RetTy);
+      
+    ResType = Get8ByteTypeAtOffset(IRType, 0, RetTy, 0);
     break;
 
     // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
@@ -1299,7 +1303,10 @@
     break;
 
   case Integer: {
-    const llvm::Type *HiType =  Get8ByteTypeAtOffset(0, 8, RetTy, 8);
+    if (IRType == 0)
+      IRType = CGT.ConvertTypeRecursive(RetTy);
+
+    const llvm::Type *HiType =  Get8ByteTypeAtOffset(IRType, 8, RetTy, 8);
     ResType = llvm::StructType::get(getVMContext(), ResType, HiType, NULL);
     break;
   }
@@ -1456,7 +1463,6 @@
 
 void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
   
-  // Pass preferred type into classifyReturnType.
   FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
 
   // Keep track of the number of assigned registers.
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index b4500d6..7bff700 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -159,4 +159,12 @@
   return X+X;
 }
 
+struct foo26 {
+  int *X;
+  float *Y;
+};
 
+struct foo26 f26(struct foo26 *P) {
+  // CHECK: define %struct.foo26 @f26(%struct.foo26* %P)
+  return *P;
+}
diff --git a/test/CodeGenObjC/x86_64-struct-return-gc.m b/test/CodeGenObjC/x86_64-struct-return-gc.m
index c62a33f..8022d59 100644
--- a/test/CodeGenObjC/x86_64-struct-return-gc.m
+++ b/test/CodeGenObjC/x86_64-struct-return-gc.m
@@ -9,7 +9,7 @@
 void Coerce_test(void) {
   struct Coerce c;
   
-  // CHECK: call i64 @coerce_func
+  // CHECK: call i8* @coerce_func
   // CHECK: call i8* @objc_memmove_collectable(
   c = coerce_func();
 }