[llvm-commits] [llvm-gcc-4.2] r52436 - in /llvm-gcc-4.2/trunk/gcc: config/i386/llvm-i386-target.h config/i386/llvm-i386.cpp llvm-abi.h llvm-convert.cpp llvm-internal.h llvm-types.cpp

Dale Johannesen dalej at apple.com
Tue Jun 17 16:39:43 PDT 2008


Author: johannes
Date: Tue Jun 17 18:39:43 2008
New Revision: 52436

URL: http://llvm.org/viewvc/llvm-project?rev=52436&view=rev
Log:
X86-64 ABI.  Handle returning structs like
{  struct {}x[4]; double y; }
where the 1st word is allocated but not returned.


Modified:
    llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h
    llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp
    llvm-gcc-4.2/trunk/gcc/llvm-abi.h
    llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
    llvm-gcc-4.2/trunk/gcc/llvm-internal.h
    llvm-gcc-4.2/trunk/gcc/llvm-types.cpp

Modified: llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h?rev=52436&r1=52435&r2=52436&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h (original)
+++ llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h Tue Jun 17 18:39:43 2008
@@ -116,10 +116,11 @@
 
 /* LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be 
    returned as a scalar, otherwise return NULL. */
-#define LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(X) \
-  llvm_x86_scalar_type_for_struct_return(X)
+#define LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(X, Y) \
+  llvm_x86_scalar_type_for_struct_return((X), (Y))
 
-extern const Type *llvm_x86_scalar_type_for_struct_return(tree type);
+extern const Type *llvm_x86_scalar_type_for_struct_return(tree type, 
+                                                          unsigned *Offset);
 
 /* LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be 
    returned as an aggregate, otherwise return NULL. */

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=52436&r1=52435&r2=52436&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 Tue Jun 17 18:39:43 2008
@@ -941,17 +941,6 @@
   if (llvm_x86_should_not_return_complex_in_memory(TreeType))
     return true;
 
-  // FIXME: llvm x86-64 code generator is not able to handle return {i8, float}
-  bool foundInt = false;
-  unsigned STyElements = STy->getNumElements();
-  for (unsigned i = 0; i < STyElements; ++i) { 
-    const Type *ETy = STy->getElementType(i);
-    if (const ArrayType *ATy = dyn_cast<ArrayType>(ETy))
-      ETy = ATy->getElementType();
-    if (ETy->isInteger())
-      foundInt = true;
-  }
-
   // Let gcc specific routine answer the question.
   enum x86_64_reg_class Class[MAX_CLASSES];
   enum machine_mode Mode = ix86_getNaturalModeForType(TreeType);
@@ -959,12 +948,15 @@
   if (NumClasses == 0)
     return false;
 
-  if (NumClasses == 1 && foundInt)
-    return false;
-
   if (NumClasses == 1 && 
       (Class[0] == X86_64_INTEGERSI_CLASS || Class[0] == X86_64_INTEGER_CLASS))
-    // This will fit in one i32 register.
+    // This will fit in one i64 register.
+    return false;
+
+  if (NumClasses == 2 &&
+      (Class[0] == X86_64_NO_CLASS || Class[1] == X86_64_NO_CLASS))
+    // One word is padding which is not passed at all; treat this as returning
+    // the scalar type of the other word.
     return false;
 
   // Otherwise, use of multiple value return is OK.
@@ -973,7 +965,8 @@
 
 // llvm_x86_scalar_type_for_struct_return - Return LLVM type if TYPE
 // can be returned as a scalar, otherwise return NULL.
-const Type *llvm_x86_scalar_type_for_struct_return(tree type) {
+const Type *llvm_x86_scalar_type_for_struct_return(tree type, unsigned *Offset) {
+  *Offset = 0;
   const Type *Ty = ConvertType(type);
   unsigned Size = getTargetData().getABITypeSize(Ty);
   if (Size == 0)
@@ -989,13 +982,67 @@
   if (llvm_suitable_multiple_ret_value_type(Ty, type))
     return NULL;
 
-  if (Size <= 8)
-    return Type::Int64Ty;
-  else if (Size <= 16)
-    return IntegerType::get(128);
-  else if (Size <= 32)
-    return IntegerType::get(256);
+  if (TARGET_64BIT) {
+    // This logic relies on llvm_suitable_multiple_ret_value_type to have
+    // removed anything not expected here.
+    enum x86_64_reg_class Class[MAX_CLASSES];
+    enum machine_mode Mode = ix86_getNaturalModeForType(type);
+    int NumClasses = ix86_ClassifyArgument(Mode, type, Class, 0);
+    if (NumClasses == 0)
+      return Type::Int64Ty;
 
+    if (NumClasses == 1) {
+      if (Class[0] == X86_64_INTEGERSI_CLASS ||
+          Class[0] == X86_64_INTEGER_CLASS) {
+        // one int register
+        HOST_WIDE_INT Bytes =
+          (Mode == BLKmode) ? int_size_in_bytes(type) : 
+                              (int) GET_MODE_SIZE(Mode);
+        if (Bytes>4)
+          return Type::Int64Ty;
+        else if (Bytes>2)
+          return Type::Int32Ty;
+        else if (Bytes>1)
+          return Type::Int16Ty;
+        else
+          return Type::Int8Ty;
+      }
+      assert(0 && "Unexpected type!"); 
+    }
+    if (NumClasses == 2) {
+      if (Class[1] == X86_64_NO_CLASS) {
+        if (Class[0] == X86_64_INTEGER_CLASS || 
+            Class[0] == X86_64_NO_CLASS ||
+            Class[0] == X86_64_INTEGERSI_CLASS)
+          return Type::Int64Ty;
+        else if (Class[0] == X86_64_SSE_CLASS || Class[0] == X86_64_SSEDF_CLASS)
+          return Type::DoubleTy;
+        else if (Class[0] == X86_64_SSESF_CLASS)
+          return Type::FloatTy;
+        assert(0 && "Unexpected type!");
+      }
+      if (Class[0] == X86_64_NO_CLASS) {
+        *Offset = 8;
+        if (Class[1] == X86_64_INTEGERSI_CLASS ||
+            Class[1] == X86_64_INTEGER_CLASS)
+          return Type::Int64Ty;
+        else if (Class[1] == X86_64_SSE_CLASS || Class[1] == X86_64_SSEDF_CLASS)
+          return Type::DoubleTy;
+        else if (Class[1] == X86_64_SSESF_CLASS)
+          return Type::FloatTy;
+        assert(0 && "Unexpected type!"); 
+      }
+      assert(0 && "Unexpected type!");
+    }
+    assert(0 && "Unexpected type!");
+  } else {
+    if (Size <= 8)
+      return Type::Int64Ty;
+    else if (Size <= 16)
+      return IntegerType::get(128);
+    else if (Size <= 32)
+      return IntegerType::get(256);
+  }
   return NULL;
 }
 

Modified: llvm-gcc-4.2/trunk/gcc/llvm-abi.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-abi.h?rev=52436&r1=52435&r2=52436&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi.h Tue Jun 17 18:39:43 2008
@@ -57,8 +57,10 @@
 
   /// HandleAggregateResultAsScalar - This callback is invoked if the function
   /// returns an aggregate value by bit converting it to the specified scalar
-  /// type and returning that.
-  void HandleAggregateResultAsScalar(const Type *ScalarTy) {}
+  /// type and returning that.  The bit conversion should start at byte Offset
+  /// within the struct, and ScalarTy is not necessarily big enough to cover
+  /// the entire struct.
+  void HandleAggregateResultAsScalar(const Type *ScalarTy, unsigned Offset=0) {}
 
   /// HandleAggregateResultAsAggregate - This callback is invoked if the function
   /// returns an aggregate value using multiple return values.
@@ -197,9 +199,10 @@
 // getLLVMScalarTypeForStructReturn - Return LLVM Type if TY can be 
 // returned as a scalar, otherwise return NULL. This is the default
 // target independent implementation.
-static const Type* getLLVMScalarTypeForStructReturn(tree type) {
+static const Type* getLLVMScalarTypeForStructReturn(tree type, unsigned *Offset) {
   const Type *Ty = ConvertType(type);
   unsigned Size = getTargetData().getABITypeSize(Ty);
+  *Offset = 0;
   if (Size == 0)
     return Type::VoidTy;
   else if (Size == 1)
@@ -309,8 +312,8 @@
 // LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be 
 // returned as a scalar, otherwise return NULL.
 #ifndef LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN
-#define LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(X) \
-  getLLVMScalarTypeForStructReturn(X)
+#define LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(X, Y) \
+  getLLVMScalarTypeForStructReturn((X), (Y))
 #endif
 
 // LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be 
@@ -351,6 +354,7 @@
   /// on the client that indicate how its pieces should be handled.  This
   /// handles things like returning structures via hidden parameters.
   void HandleReturnType(tree type, tree fn, bool isBuiltin) {
+    unsigned Offset = 0;
     const Type *Ty = ConvertType(type);
     if (Ty->getTypeID() == Type::VectorTyID) {
       // Vector handling is weird on x86.  In particular builtin and
@@ -378,8 +382,9 @@
         // aggregate.
         if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type))
           C.HandleAggregateResultAsAggregate(AggrTy);
-        else if (const Type* ScalarTy = LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(type))
-          C.HandleAggregateResultAsScalar(ScalarTy);
+        else if (const Type* ScalarTy = 
+                    LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(type, &Offset))
+          C.HandleAggregateResultAsScalar(ScalarTy, Offset);
         else {
           assert(0 && "Unable to determine how to return this aggregate!");
           abort();

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=52436&r1=52435&r2=52436&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Tue Jun 17 18:39:43 2008
@@ -350,6 +350,7 @@
   FnDecl = fndecl;
   Fn = 0;
   ReturnBB = UnwindBB = 0;
+  ReturnOffset = 0;
   
   if (TheDebugInfo) {
     expanded_location Location = expand_location(DECL_SOURCE_LOCATION (fndecl));
@@ -427,10 +428,11 @@
     IRBuilder Builder;
     std::vector<Value*> LocStack;
     std::vector<std::string> NameStack;
+    unsigned Offset;
     FunctionPrologArgumentConversion(tree FnDecl,
                                      Function::arg_iterator &ai,
                                      const IRBuilder &B)
-      : FunctionDecl(FnDecl), AI(ai), Builder(B) {}
+      : FunctionDecl(FnDecl), AI(ai), Builder(B), Offset(0) {}
     
     void setName(const std::string &Name) {
       NameStack.push_back(Name);
@@ -520,6 +522,10 @@
       abort();
     }
 
+    void HandleAggregateResultAsScalar(const Type *ScalarTy, unsigned Offset=0) {
+      this->Offset = Offset;
+    }
+
     void EnterField(unsigned FieldNo, const llvm::Type *StructTy) {
       NameStack.push_back(NameStack.back()+"."+utostr(FieldNo));
       
@@ -696,6 +702,8 @@
   // Handle the DECL_RESULT.
   ABIConverter.HandleReturnType(TREE_TYPE(TREE_TYPE(FnDecl)), FnDecl,
                                 DECL_BUILT_IN(FnDecl));
+  // Remember this for use by FinishFunctionBody.
+  TheTreeToLLVM->ReturnOffset = Client.Offset;
 
   // Prepend the static chain (if any) to the list of arguments.
   tree Args = static_chain ? static_chain : DECL_ARGUMENTS(FnDecl);
@@ -805,10 +813,16 @@
           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
-        // to the specified scalar type, which we do by casting the pointer and
-        // loading.
+        // Otherwise, this aggregate result must be something that is returned
+        // in a scalar register for this target.  We must bit convert the
+        // aggregate to the specified scalar type, which we do by casting the
+        // pointer and loading.  The load does not necessarily start at the 
+        // beginning of the aggregate (x86-64).
+        if (ReturnOffset) {
+          RetVal = BitCastToType(RetVal, PointerType::getUnqual(Type::Int8Ty));
+          RetVal = Builder.CreateGEP(RetVal, 
+                    ConstantInt::get(TD.getIntPtrType(), ReturnOffset), "tmp");
+        }
         RetVal = BitCastToType(RetVal,
                                PointerType::getUnqual(Fn->getReturnType()));
         RetVal = Builder.CreateLoad(RetVal, "retval");
@@ -2383,6 +2397,7 @@
     MemRef RetBuf;
     bool isShadowRet;
     bool isAggrRet;
+    unsigned Offset;
 
     FunctionCallArgumentConversion(SmallVector<Value*, 16> &ops,
                                    const FunctionType *FnTy,
@@ -2391,7 +2406,7 @@
                                    IRBuilder &b)
       : CallOperands(ops), FTy(FnTy), DestLoc(destloc),
         useReturnSlot(ReturnSlotOpt), Builder(b), isShadowRet(false),
-        isAggrRet(false) { }
+        isAggrRet(false), Offset(0) { }
 
     // Push the address of an argument.
     void pushAddress(Value *Loc) {
@@ -2472,12 +2487,13 @@
     /// HandleAggregateResultAsScalar - This callback is invoked if the function
     /// returns an aggregate value by bit converting it to the specified scalar
     /// type and returning that.
-    void HandleAggregateResultAsScalar(const Type *ScalarTy) {
-      // There is nothing to do here.
+    void HandleAggregateResultAsScalar(const Type *ScalarTy, 
+                                       unsigned Offset = 0) {
+      this->Offset = Offset;
     }
 
-    /// HandleAggregateResultAsAggregate - This callback is invoked if the function
-    /// returns an aggregate value using multiple return values.
+    /// HandleAggregateResultAsAggregate - This callback is invoked if the 
+    /// function returns an aggregate value using multiple return values.
     void HandleAggregateResultAsAggregate(const Type *AggrTy) {
       // There is nothing to do here.
       isAggrRet = true;
@@ -2734,12 +2750,18 @@
   // the current target specifies that the aggregate be returned in scalar
   // registers even though it is an aggregate.  We must bitconvert the scalar
   // to the destination aggregate type.  We do this by casting the DestLoc
-  // pointer and storing into it.
+  // pointer and storing into it.  The store does not necessarily start at the
+  // beginning of the aggregate (x86-64).
   if (!DestLoc)
     return Call;   // Normal scalar return.
 
-  Value *Ptr = BitCastToType(DestLoc->Ptr, 
-                             PointerType::getUnqual(Call->getType()));
+  Value *Ptr = DestLoc->Ptr;
+  if (Client.Offset) {
+    Ptr = BitCastToType(Ptr, PointerType::getUnqual(Type::Int8Ty));
+    Ptr = Builder.CreateGEP(Ptr, 
+                  ConstantInt::get(TD.getIntPtrType(), Client.Offset), "tmp");
+  }
+  Ptr = BitCastToType(Ptr, PointerType::getUnqual(Call->getType()));
   StoreInst *St = Builder.CreateStore(Call, Ptr, DestLoc->Volatile);
   St->setAlignment(DestLoc->Alignment);
   return 0;

Modified: llvm-gcc-4.2/trunk/gcc/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-internal.h?rev=52436&r1=52435&r2=52436&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-internal.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-internal.h Tue Jun 17 18:39:43 2008
@@ -274,6 +274,7 @@
   Function *Fn;
   BasicBlock *ReturnBB;
   BasicBlock *UnwindBB;
+  unsigned ReturnOffset;
 
   // State that changes as the function is emitted.
 

Modified: llvm-gcc-4.2/trunk/gcc/llvm-types.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-types.cpp?rev=52436&r1=52435&r2=52436&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-types.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-types.cpp Tue Jun 17 18:39:43 2008
@@ -936,10 +936,11 @@
     unsigned &CallingConv;
     bool isShadowRet;
     bool KNRPromotion;
+    unsigned Offset;
   public:
     FunctionTypeConversion(PATypeHolder &retty, std::vector<PATypeHolder> &AT,
                            unsigned &CC, bool KNR)
-      : RetTy(retty), ArgTypes(AT), CallingConv(CC), KNRPromotion(KNR) {
+      : RetTy(retty), ArgTypes(AT), CallingConv(CC), KNRPromotion(KNR), Offset(0) {
       CallingConv = CallingConv::C;
       isShadowRet = false;
     }
@@ -955,8 +956,9 @@
     /// HandleAggregateResultAsScalar - This callback is invoked if the function
     /// returns an aggregate value by bit converting it to the specified scalar
     /// type and returning that.
-    void HandleAggregateResultAsScalar(const Type *ScalarTy) {
+    void HandleAggregateResultAsScalar(const Type *ScalarTy, unsigned Offset=0) {
       RetTy = ScalarTy;
+      this->Offset = Offset;
     }
 
     /// HandleAggregateResultAsAggregate - This callback is invoked if the function





More information about the llvm-commits mailing list