[llvm-commits] [dragonegg] r92690 - /dragonegg/trunk/llvm-convert.cpp

Duncan Sands baldrick at free.fr
Mon Jan 4 22:13:37 PST 2010


Author: baldrick
Date: Tue Jan  5 00:13:37 2010
New Revision: 92690

URL: http://llvm.org/viewvc/llvm-project?rev=92690&view=rev
Log:
Port commit 90914 (stuart) from llvm-gcc:
If a callee returns a structure in registers, but the stored image of
those registers is bigger than the destination, store the registers
into a temporary, and copy the desired (smaller) part to the
destination.  <rdar://problem/7437022>
The original testcase returned an array of three 32-bit floats,
wrapped in a struct; the value was returned as two doubles in xmm0/1,
and stored as a 128-bit value.

Modified:
    dragonegg/trunk/llvm-convert.cpp

Modified: dragonegg/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-convert.cpp?rev=92690&r1=92689&r2=92690&view=diff

==============================================================================
--- dragonegg/trunk/llvm-convert.cpp (original)
+++ dragonegg/trunk/llvm-convert.cpp Tue Jan  5 00:13:37 2010
@@ -3070,9 +3070,27 @@
     return 0;
 
   if (Client.isAggrReturn()) {
-    Value *Dest = Builder.CreateBitCast(DestLoc->Ptr,
-                                       PointerType::getUnqual(Call->getType()));
-    LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Call,Dest,DestLoc->Volatile,Builder);
+    if (TD.getTypeAllocSize(Call->getType()) <= TD.getTypeAllocSize(DestLoc->Ptr->getType())) {
+      Value *Dest = Builder.CreateBitCast(DestLoc->Ptr,
+                                          Call->getType()->getPointerTo());
+      LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Call,Dest,DestLoc->Volatile,Builder);
+    } else {
+      // The call will return an aggregate value in registers, but
+      // those registers are bigger than DestLoc.  Allocate a
+      // temporary to match the registers, store the registers there,
+      // cast the temporary into the correct (smaller) type, and using
+      // the correct type, copy the value into DestLoc.  Assume the
+      // optimizer will delete the temporary and clean this up.
+      AllocaInst *biggerTmp = CreateTemporary(Call->getType());
+      LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Call,biggerTmp,/*Volatile=*/false,
+                                       Builder);
+      EmitAggregateCopy(*DestLoc,
+                        MemRef(Builder.CreateBitCast(biggerTmp,Call->getType()->
+                                                     getPointerTo()),
+                               DestLoc->getAlignment(),
+                               DestLoc->Volatile),
+                        gimple_call_return_type(stmt));
+    }
     return 0;
   }
 





More information about the llvm-commits mailing list