[llvm-commits] [llvm-gcc-4.2] r50198 - in /llvm-gcc-4.2/trunk/gcc: config/i386/llvm-i386.cpp llvm-convert.cpp

Devang Patel dpatel at apple.com
Wed Apr 23 16:50:58 PDT 2008


Author: dpatel
Date: Wed Apr 23 18:50:58 2008
New Revision: 50198

URL: http://llvm.org/viewvc/llvm-project?rev=50198&view=rev
Log:
Use bitcast to connect aggreate return value with actual return registers.
Now struct bar { double f; int a; char b, c, d, e; }; is returned as { double, i64 }


Modified:
    llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp
    llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp

Modified: llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp?rev=50198&r1=50197&r2=50198&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp Wed Apr 23 18:50:58 2008
@@ -934,7 +934,6 @@
     return true;
 
   // llvm only accepts first class types for multiple values in ret instruction.
-  bool foundNonInt = false;
   bool foundInt = false;
   unsigned STyElements = STy->getNumElements();
   for (unsigned i = 0; i < STyElements; ++i) { 
@@ -943,22 +942,9 @@
       ETy = ATy->getElementType();
     if (!ETy->isFirstClassType() && ETy->getTypeID() != Type::X86_FP80TyID)
       return false;
-    if (!ETy->isInteger())
-      foundNonInt = true;
-    else
+    if (ETy->isInteger())
       foundInt = true;
   }
-  // FIXME. llvm x86-64 code generator does not handle all cases of
-  // multiple value return. Remove this when the code generator restriction 
-  // is removed.
-  if (!foundNonInt)
-    return false;
-
-  // FIXME: Fix code generator. Causes Benchmarks/McCat/09-vor/vor failures.
-  if (STyElements == 2
-      && STy->getElementType(0)->getTypeID() == Type::DoubleTyID
-      && STy->getElementType(1)->getTypeID() == Type::DoubleTyID)
-    return false;
 
   // Let gcc specific routine answer the question.
   enum x86_64_reg_class Class[MAX_CLASSES];
@@ -1003,6 +989,114 @@
   return NULL;
 }
 
+void
+llvm_x86_64_get_multiple_return_reg_classes(tree TreeType, const Type *Ty,
+                                            std::vector<const Type*> &Elts){
+  enum x86_64_reg_class Class[MAX_CLASSES];
+  enum machine_mode Mode = ix86_getNaturalModeForType(TreeType);
+  HOST_WIDE_INT Bytes =
+    (Mode == BLKmode) ? int_size_in_bytes(TreeType) : (int) GET_MODE_SIZE(Mode);
+  int NumClasses = ix86_ClassifyArgument(Mode, TreeType, Class, 0);
+  if (!NumClasses)
+     assert(0 && "This type does not need multiple return registers!");
+
+  if (NumClasses == 1 && Class[0] == X86_64_INTEGERSI_CLASS)
+    // This will fit in one i32 register.
+     assert(0 && "This type does not need multiple return registers!");
+
+  if (NumClasses == 1 && Class[0] == X86_64_INTEGER_CLASS)
+     assert(0 && "This type does not need multiple return registers!");
+
+
+  for (int i = 0; i < NumClasses; ++i) {
+    switch (Class[i]) {
+    case X86_64_INTEGER_CLASS:
+    case X86_64_INTEGERSI_CLASS:
+      Elts.push_back(Type::Int64Ty);
+      Bytes -= 8;
+      break;
+    case X86_64_SSE_CLASS:
+      // If it's a SSE class argument, then one of the followings are possible:
+      // 1. 1 x SSE, size is 8: 1 x Double.
+      // 2. 1 x SSE + 1 x SSEUP, size is 16: 1 x <4 x i32>, <4 x f32>,
+      //                                         <2 x i64>, or <2 x f64>.
+      // 3. 1 x SSE + 1 x SSESF, size is 12: 1 x Double, 1 x Float.
+      // 4. 2 x SSE, size is 16: 2 x Double.
+      if ((NumClasses-i) == 1) {
+        if (Bytes == 8) {
+          Elts.push_back(Type::DoubleTy);
+          Bytes -= 8;
+        } else
+          assert(0 && "Not yet handled!");
+      } else if ((NumClasses-i) == 2) {
+        if (Class[i+1] == X86_64_SSEUP_CLASS) {
+          const Type *Ty = ConvertType(TreeType);
+          if (const StructType *STy = dyn_cast<StructType>(Ty))
+            // Look pass the struct wrapper.
+            if (STy->getNumElements() == 1)
+              Ty = STy->getElementType(0);
+          if (const VectorType *VTy = dyn_cast<VectorType>(Ty)) {
+            if (VTy->getNumElements() == 2) {
+              if (VTy->getElementType()->isInteger())
+                Elts.push_back(VectorType::get(Type::Int64Ty, 2));
+              else
+                Elts.push_back(VectorType::get(Type::DoubleTy, 2));
+              Bytes -= 8;
+            } else {
+              assert(VTy->getNumElements() == 4);
+              if (VTy->getElementType()->isInteger())
+                Elts.push_back(VectorType::get(Type::Int32Ty, 4));
+              else
+                Elts.push_back(VectorType::get(Type::FloatTy, 4));
+              Bytes -= 4;
+            }
+          } else if (llvm_x86_is_all_integer_types(Ty)) {
+            Elts.push_back(VectorType::get(Type::Int32Ty, 4));
+            Bytes -= 4;
+          } else {
+            Elts.push_back(VectorType::get(Type::FloatTy, 4));
+            Bytes -= 4;
+          }
+        } else if (Class[i+1] == X86_64_SSESF_CLASS) {
+          assert(Bytes == 12 && "Not yet handled!");
+          Elts.push_back(Type::DoubleTy);
+          Elts.push_back(Type::FloatTy);
+          Bytes -= 12;
+        } else if (Class[i+1] == X86_64_SSE_CLASS) {
+          Elts.push_back(Type::DoubleTy);
+          Elts.push_back(Type::DoubleTy);
+          Bytes -= 16;
+        } else if (Class[i+1] == X86_64_SSEDF_CLASS && Bytes == 16) {
+          Elts.push_back(VectorType::get(Type::FloatTy, 2));
+          Elts.push_back(Type::DoubleTy);
+        } else if (Class[i+1] == X86_64_INTEGER_CLASS) {
+          Elts.push_back(VectorType::get(Type::FloatTy, 2));
+          Elts.push_back(Type::Int64Ty);
+        } else
+          assert(0 && "Not yet handled!");
+        ++i; // Already handled the next one.
+      } else
+        assert(0 && "Not yet handled!");
+      break;
+    case X86_64_SSESF_CLASS:
+      Elts.push_back(Type::FloatTy);
+      Bytes -= 4;
+      break;
+    case X86_64_SSEDF_CLASS:
+      Elts.push_back(Type::DoubleTy);
+      Bytes -= 8;
+      break;
+    case X86_64_X87_CLASS:
+    case X86_64_X87UP_CLASS:
+    case X86_64_COMPLEX_X87_CLASS:
+        assert(0 && "Not yet handled!");
+    case X86_64_NO_CLASS:
+        assert(0 && "Not yet handled!");
+    default: assert(0 && "Unexpected register class!");
+    }
+  }
+}
+
 // Return LLVM Type if TYPE can be returned as an aggregate, 
 // otherwise return NULL.
 const Type *llvm_x86_aggr_type_for_struct_return(tree type) {
@@ -1021,54 +1115,10 @@
     return StructType::get(ElementTypes, STy->isPacked());
   } 
 
-  if (NumElements == 3
-      && STy->getElementType(0)->getTypeID() == Type::FloatTyID
-      && STy->getElementType(1)->getTypeID() == Type::FloatTyID
-      && STy->getElementType(2)->getTypeID() == Type::FloatTyID) {
-    ElementTypes.push_back(VectorType::get(Type::FloatTy, 4));
-    ElementTypes.push_back(Type::FloatTy);
-    return StructType::get(ElementTypes, STy->isPacked());
-  }
+  std::vector<const Type*> GCCElts;
+  llvm_x86_64_get_multiple_return_reg_classes(type, Ty, GCCElts);
+  return StructType::get(GCCElts, STy->isPacked());
 
-  for (unsigned i = 0; i < NumElements; ++i) {
-    const Type *T = STy->getElementType(i);
-    
-    if (T->isFirstClassType()) {
-      ElementTypes.push_back(T);
-      continue;
-    }
-    
-    const ArrayType *ATy = dyn_cast<ArrayType>(T);
-    assert (ATy && "Unexpected struct element type!");
-    assert (ATy->getElementType()->isFirstClassType() 
-            && "Unexpected ArrayType element type!");
-    
-    unsigned size = ATy->getNumElements();
-    if (ATy->getElementType()->isFloatingPoint()) {
-      switch (size) {
-      case 2:
-        // use { <4 x float> } for struct { float[2]; }
-        ElementTypes.push_back(VectorType::get(ATy->getElementType(), 4));
-        break;
-      case 3:
-        // use { <4 x float>, float } for struct { float[3]; }
-        ElementTypes.push_back(VectorType::get(ATy->getElementType(), 4));
-        ElementTypes.push_back(ATy->getElementType());
-        break;
-      case 4:
-        // use { <4  x float>, <4 x float> } for struct { float[4]; }
-        ElementTypes.push_back(VectorType::get(ATy->getElementType(), 4));
-        ElementTypes.push_back(VectorType::get(ATy->getElementType(), 4));
-        break;
-      default:
-        assert (0 && "Unexpected floating point array size!");
-      }
-    } else {
-      for (unsigned j = 0; j < size; ++j)
-        ElementTypes.push_back(ATy->getElementType());
-    }
-  }
-  return StructType::get(ElementTypes, STy->isPacked());
 }
 
 // llvm_x86_build_multiple_return_value - Function FN returns multiple value
@@ -1082,6 +1132,17 @@
   const PointerType *PTy = cast<PointerType>(RetVal->getType());
   const StructType *RetSTy = cast<StructType>(PTy->getElementType());
 
+  llvm::Value *Idxs[3];
+  Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
+  Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, 0);
+  Idxs[2] = ConstantInt::get(llvm::Type::Int32Ty, 0);
+  Value *GEP = Builder.CreateGEP(RetVal, Idxs, Idxs+3, "mrv_gep");
+  Value *E = Builder.CreateLoad(GEP, "mrv");
+  Value *R = Builder.CreateBitCast(E, STy->getElementType(0), "tmp");
+
+
+
+
   // Walk RetSTy elements and populate RetVals vector. Note, STy and RetSTy
   // may not match. For example, when STy is { <2 x float> } the RetSTy is
   // { float[2]; }
@@ -1227,6 +1288,7 @@
 
   const PointerType *PTy = cast<PointerType>(Dest->getType());
   const StructType *DestTy = cast<StructType>(PTy->getElementType());
+
   unsigned SNO = 0;
   unsigned DNO = 0;
 

Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=50198&r1=50197&r2=50198&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Wed Apr 23 18:50:58 2008
@@ -760,8 +760,16 @@
     } else {
       Value *RetVal = DECL_LLVM(DECL_RESULT(FnDecl));
       if (const StructType *STy = dyn_cast<StructType>(Fn->getReturnType())) {
-        // Handle multiple return values
-        LLVM_BUILD_MULTIPLE_RETURN_VALUE(Fn,RetVal,RetVals,Builder);
+        Value *R1 = BitCastToType(RetVal, PointerType::getUnqual(STy));
+
+        llvm::Value *Idxs[2];
+        Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
+        for (unsigned ri = 0; ri < STy->getNumElements(); ++ri) {
+          Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, ri);
+          Value *GEP = Builder.CreateGEP(R1, Idxs, Idxs+2, "mrv_gep");
+          Value *E = Builder.CreateLoad(GEP, "mrv");
+          RetVals.push_back(E);
+        }
       } else {
         // Otherwise, this aggregate result must be something that is returned in
         // a scalar register for this target.  We must bit convert the aggregate
@@ -2641,7 +2649,9 @@
   Call->setName("tmp");
 
   if (Client.isAggrReturn()) {
-    LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Call,DestLoc->Ptr,DestLoc->Volatile,Builder);
+    Value *Dest = BitCastToType(DestLoc->Ptr,
+                                PointerType::getUnqual(Call->getType()));
+    LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Call,Dest,DestLoc->Volatile,Builder);
     return 0;
   }
 





More information about the llvm-commits mailing list