[llvm-commits] [llvm-gcc-4.2] r85539 - in /llvm-gcc-4.2/trunk/gcc: config/arm/llvm-arm-target.h config/arm/llvm-arm.cpp config/i386/llvm-i386-target.h llvm-abi.h llvm-types.cpp

Bob Wilson bob.wilson at apple.com
Thu Oct 29 16:35:11 PDT 2009


Author: bwilson
Date: Thu Oct 29 18:35:11 2009
New Revision: 85539

URL: http://llvm.org/viewvc/llvm-project?rev=85539&view=rev
Log:
Fix ARM AAPCS-VFP return of homogeneous aggregates.  Patch by Sandeep Patel.

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

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

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm-target.h (original)
+++ llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm-target.h Thu Oct 29 18:35:11 2009
@@ -25,17 +25,17 @@
    specification says that varargs functions must use the base standard
    instead of the VFP hard float variant. We check for that with
    (isVoid || hasArgList). */
-#define TARGET_ADJUST_LLVM_CC(CC, type)				\
-  {								\
-    if (TARGET_AAPCS_BASED)					\
-      CC = ((TARGET_VFP && TARGET_HARD_FLOAT_ABI &&		\
-             ((TYPE_ARG_TYPES(type) == 0) ||			\
-              (TREE_VALUE(tree_last(TYPE_ARG_TYPES(type))) ==	\
-               void_type_node))) ?				\
-	    CallingConv::ARM_AAPCS_VFP :			\
-	    CallingConv::ARM_AAPCS);				\
-    else							\
-      CC = CallingConv::ARM_APCS;				\
+#define TARGET_ADJUST_LLVM_CC(CC, type)                       \
+  {                                                           \
+    if (TARGET_AAPCS_BASED)                                   \
+      CC = ((TARGET_VFP && TARGET_HARD_FLOAT_ABI &&           \
+             ((TYPE_ARG_TYPES(type) == 0) ||                  \
+              (TREE_VALUE(tree_last(TYPE_ARG_TYPES(type))) == \
+               void_type_node))) ?                            \
+      CallingConv::ARM_AAPCS_VFP :                            \
+      CallingConv::ARM_AAPCS);                                \
+    else                                                      \
+      CC = CallingConv::ARM_APCS;                             \
   }
 
 #ifdef LLVM_ABI_H
@@ -45,7 +45,7 @@
                                              CallingConv::ID&,
                                              std::vector<const Type*>&);
 
-#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, CC, E)		\
+#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, CC, E)    \
    llvm_arm_should_pass_aggregate_in_mixed_regs((T), (TY), (CC), (E))
 
 extern
@@ -53,9 +53,35 @@
                                                  std::vector<const Type*>&,
                                                  bool, CallingConv::ID&);
 
-#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC)		\
+#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC)   \
    llvm_arm_aggregate_partially_passed_in_regs((E), (SE), (ISR), (CC))
 
+extern const Type *llvm_arm_aggr_type_for_struct_return(tree type,
+                                                        CallingConv::ID &CC);
+
+/* LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be 
+  returned as an aggregate, otherwise return NULL. */
+#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X, CC) \
+    llvm_arm_aggr_type_for_struct_return((X), (CC))
+
+extern void llvm_arm_extract_multiple_return_value(Value *Src, Value *Dest,
+                                                   bool isVolatile,
+                                                   LLVMBuilder &B);
+
+/* LLVM_EXTRACT_MULTIPLE_RETURN_VALUE - Extract multiple return value from
+  SRC and assign it to DEST. */
+#define LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Src,Dest,V,B)       \
+    llvm_arm_extract_multiple_return_value((Src),(Dest),(V),(B))
+
+extern
+bool llvm_arm_should_pass_or_return_aggregate_in_regs(tree TreeType,
+                                                      CallingConv::ID &CC);
+
+/* LLVM_SHOULD_NOT_USE_SHADOW_RETURN = Return true is the given type should
+  not be returned via a shadow parameter with the given calling conventions. */
+#define LLVM_SHOULD_NOT_USE_SHADOW_RETURN(X, CC) \
+    llvm_arm_should_pass_or_return_aggregate_in_regs((X), (CC))
+
 #endif /* LLVM_ABI_H */
 #endif /* ENABLE_LLVM */
 /* LLVM LOCAL end (ENTIRE FILE!)  */

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

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm.cpp Thu Oct 29 18:35:11 2009
@@ -2524,24 +2524,14 @@
 llvm_arm_should_pass_aggregate_in_mixed_regs(tree TreeType, const Type *Ty,
                                              CallingConv::ID &CC,
                                              std::vector<const Type*> &Elts) {
-  // Homogeneous aggregates are an AAPCS-VFP feature.
-  if ((CC != CallingConv::ARM_AAPCS_VFP) ||
-      !(TARGET_AAPCS_BASED && TARGET_VFP && TARGET_HARD_FLOAT_ABI))
+  if (!llvm_arm_should_pass_or_return_aggregate_in_regs(TreeType, CC))
     return false;
 
-  // Alas, we can't use LLVM Types to figure this out because we need to
-  // examine unions closely.  We'll have to walk the GCC TreeType.
-  int fdt_counts[ARM_FDT_MAX] = { 0 };
-  bool result = false;
-  result = vfp_arg_homogeneous_aggregate_p(TYPE_MODE(TreeType), TreeType,
-                                           fdt_counts);
-
   // Walk Ty and push LLVM types corresponding to register types onto
   // Elts.
-  if (result)
-    push_elts(Ty, Elts);
+  push_elts(Ty, Elts);
   
-  return result;
+  return true;
 }  
 
 static bool alloc_next_spr(bool *SPRs)
@@ -2645,4 +2635,124 @@
   return false;                            // it all fit in registers!
 }
 
+// Return LLVM Type if TYPE can be returned as an aggregate, 
+// otherwise return NULL.
+const Type *llvm_arm_aggr_type_for_struct_return(tree TreeType,
+                                                 CallingConv::ID &CC) {
+  if (!llvm_arm_should_pass_or_return_aggregate_in_regs(TreeType, CC))
+    return NULL;
+    
+  // Walk Ty and push LLVM types corresponding to register types onto
+  // Elts.
+  std::vector<const Type*> Elts;
+  const Type *Ty = ConvertType(TreeType);
+  push_elts(Ty, Elts);
+
+  return StructType::get(Context, Elts, false);
+}
+
+// llvm_arm_extract_mrv_array_element - Helper function that helps extract 
+// an array element from multiple return value.
+//
+// Here, SRC is returning multiple values. DEST's DESTFIELDNO field is an array.
+// Extract SRCFIELDNO's ELEMENO value and store it in DEST's FIELDNO field's 
+// ELEMENTNO.
+//
+static void llvm_arm_extract_mrv_array_element(Value *Src, Value *Dest,
+                                               unsigned SrcFieldNo, 
+                                               unsigned SrcElemNo,
+                                               unsigned DestFieldNo, 
+                                               unsigned DestElemNo,
+                                               LLVMBuilder &Builder,
+                                               bool isVolatile) {
+  Value *EVI = Builder.CreateExtractValue(Src, SrcFieldNo, "mrv_gr");
+  const StructType *STy = cast<StructType>(Src->getType());
+  llvm::Value *Idxs[3];
+  Idxs[0] = ConstantInt::get(llvm::Type::getInt32Ty(Context), 0);
+  Idxs[1] = ConstantInt::get(llvm::Type::getInt32Ty(Context), DestFieldNo);
+  Idxs[2] = ConstantInt::get(llvm::Type::getInt32Ty(Context), DestElemNo);
+  Value *GEP = Builder.CreateGEP(Dest, Idxs, Idxs+3, "mrv_gep");
+  if (isa<VectorType>(STy->getElementType(SrcFieldNo))) {
+    Value *ElemIndex = ConstantInt::get(Type::getInt32Ty(Context), SrcElemNo);
+    Value *EVIElem = Builder.CreateExtractElement(EVI, ElemIndex, "mrv");
+    Builder.CreateStore(EVIElem, GEP, isVolatile);
+  } else {
+    Builder.CreateStore(EVI, GEP, isVolatile);
+  }
+}
+
+// llvm_arm_extract_multiple_return_value - Extract multiple values returned
+// by SRC and store them in DEST. It is expected that SRC and
+// DEST types are StructType, but they may not match.
+void llvm_arm_extract_multiple_return_value(Value *Src, Value *Dest,
+                                            bool isVolatile,
+                                            LLVMBuilder &Builder) {
+  
+  const StructType *STy = cast<StructType>(Src->getType());
+  unsigned NumElements = STy->getNumElements();
+
+  const PointerType *PTy = cast<PointerType>(Dest->getType());
+  const StructType *DestTy = cast<StructType>(PTy->getElementType());
+
+  unsigned SNO = 0;
+  unsigned DNO = 0;
+
+  while (SNO < NumElements) {
+
+    const Type *DestElemType = DestTy->getElementType(DNO);
+
+    // Directly access first class values.
+    if (DestElemType->isSingleValueType()) {
+      Value *GEP = Builder.CreateStructGEP(Dest, DNO, "mrv_gep");
+      Value *EVI = Builder.CreateExtractValue(Src, SNO, "mrv_gr");
+      Builder.CreateStore(EVI, GEP, isVolatile);
+      ++DNO; ++SNO;
+      continue;
+    } 
+
+    // Access array elements individually. Note, Src and Dest type may
+    // not match. For example { <2 x float>, float } and { float[3]; }
+    const ArrayType *ATy = cast<ArrayType>(DestElemType);
+    unsigned ArraySize = ATy->getNumElements();
+    unsigned DElemNo = 0; // DestTy's DNO field's element number
+    while (DElemNo < ArraySize) {
+      unsigned i = 0;
+      unsigned Size = 1;
+      
+      if (const VectorType *SElemTy = 
+          dyn_cast<VectorType>(STy->getElementType(SNO))) {
+        Size = SElemTy->getNumElements();
+      }
+      while (i < Size) {
+        llvm_arm_extract_mrv_array_element(Src, Dest, SNO, i++, 
+                                           DNO, DElemNo++, 
+                                           Builder, isVolatile);
+      }
+      // Consumed this src field. Try next one.
+      ++SNO;
+    }
+    // Finished building current dest field. 
+    ++DNO;
+  }
+}
+
+// Target hook for llvm-abi.h for LLVM_SHOULD_NOT_USE_SHADOW_RETURN and is
+// also a utility function used for other target hooks in this file. Returns
+// true if the aggregate should be passed or returned in registers.
+bool llvm_arm_should_pass_or_return_aggregate_in_regs(tree TreeType,
+                                                      CallingConv::ID &CC) {
+  // Homogeneous aggregates are an AAPCS-VFP feature.
+  if ((CC != CallingConv::ARM_AAPCS_VFP) ||
+      !(TARGET_AAPCS_BASED && TARGET_VFP && TARGET_HARD_FLOAT_ABI))
+    return false;
+
+  // Alas, we can't use LLVM Types to figure this out because we need to
+  // examine unions closely.  We'll have to walk the GCC TreeType.
+  int fdt_counts[ARM_FDT_MAX] = { 0 };
+  bool result = false;
+  result = vfp_arg_homogeneous_aggregate_p(TYPE_MODE(TreeType), TreeType,
+                                           fdt_counts);
+  return result;
+}
+
 /* LLVM LOCAL end (ENTIRE FILE!)  */

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=85539&r1=85538&r2=85539&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 Thu Oct 29 18:35:11 2009
@@ -139,7 +139,7 @@
 
 /* LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be 
    returned as an aggregate, otherwise return NULL. */
-#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X) \
+#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X, CC) \
   llvm_x86_aggr_type_for_struct_return(X)
 
 extern void llvm_x86_extract_multiple_return_value(Value *Src, Value *Dest,

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=85539&r1=85538&r2=85539&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi.h Thu Oct 29 18:35:11 2009
@@ -126,15 +126,24 @@
  false
 #endif
 
+// LLVM_SHOULD_NOT_USE_SHADOW_RETURN - A hook to allow aggregates to be
+// returned in registers.
+#ifndef LLVM_SHOULD_NOT_USE_SHADOW_RETURN
+#define LLVM_SHOULD_NOT_USE_SHADOW_RETURN(X, CC) \
+ false
+#endif
+
 // doNotUseShadowReturn - Return true if the specified GCC type 
 // should not be returned using a pointer to struct parameter. 
-static inline bool doNotUseShadowReturn(tree type, tree fndecl) {
+static inline bool doNotUseShadowReturn(tree type, tree fndecl,
+                                        CallingConv::ID CC) {
   if (!TYPE_SIZE(type))
     return false;
   if (TREE_CODE(TYPE_SIZE(type)) != INTEGER_CST)
     return false;
   // LLVM says do not use shadow argument.
-  if (LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY(type))
+  if (LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY(type) ||
+     LLVM_SHOULD_NOT_USE_SHADOW_RETURN(type, CC))
     return true;
   // GCC says use shadow argument.
   if (aggregate_value_p(type, fndecl))
@@ -396,7 +405,7 @@
     } else if (Ty->isSingleValueType() || Ty->isVoidTy()) {
       // Return scalar values normally.
       C.HandleScalarResult(Ty);
-    } else if (doNotUseShadowReturn(type, fn)) {
+    } else if (doNotUseShadowReturn(type, fn, C.getCallingConv())) {
       tree SingleElt = LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR(type);
       if (SingleElt && TYPE_SIZE(SingleElt) && 
           TREE_CODE(TYPE_SIZE(SingleElt)) == INTEGER_CST &&
@@ -406,7 +415,8 @@
       } else {
         // Otherwise return as an integer value large enough to hold the entire
         // aggregate.
-        if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type))
+        if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type,
+                                    C.getCallingConv()))
           C.HandleAggregateResultAsAggregate(AggrTy);
         else if (const Type* ScalarTy = 
                     LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(type, &Offset))
@@ -752,7 +762,7 @@
     } else if (Ty->isSingleValueType() || Ty->isVoidTy()) {
       // Return scalar values normally.
       C.HandleScalarResult(Ty);
-    } else if (doNotUseShadowReturn(type, fn)) {
+    } else if (doNotUseShadowReturn(type, fn, C.getCallingConv())) {
       tree SingleElt = LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR(type);
       if (SingleElt && TYPE_SIZE(SingleElt) && 
           TREE_CODE(TYPE_SIZE(SingleElt)) == INTEGER_CST &&
@@ -762,7 +772,8 @@
       } else {
         // Otherwise return as an integer value large enough to hold the entire
         // aggregate.
-        if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type))
+        if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type,
+                                    C.getCallingConv()))
           C.HandleAggregateResultAsAggregate(AggrTy);
         else if (const Type* ScalarTy = 
                     LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(type, &Offset))

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=85539&r1=85538&r2=85539&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-types.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-types.cpp Thu Oct 29 18:35:11 2009
@@ -1052,16 +1052,16 @@
   tree ReturnType = TREE_TYPE(type);
   std::vector<PATypeHolder> ArgTys;
   PATypeHolder RetTy(Type::getVoidTy(Context));
-  
+
   FunctionTypeConversion Client(RetTy, ArgTys, CallingConv, true /*K&R*/);
   TheLLVMABI<FunctionTypeConversion> ABIConverter(Client);
-  
-  // Builtins are always prototyped, so this isn't one.
-  ABIConverter.HandleReturnType(ReturnType, current_function_decl, false);
 
 #ifdef TARGET_ADJUST_LLVM_CC
-    TARGET_ADJUST_LLVM_CC(CallingConv, type);
+  TARGET_ADJUST_LLVM_CC(CallingConv, type);
 #endif
+  
+  // Builtins are always prototyped, so this isn't one.
+  ABIConverter.HandleReturnType(ReturnType, current_function_decl, false);
 
   SmallVector<AttributeWithIndex, 8> Attrs;
 
@@ -1118,15 +1118,15 @@
   bool isVarArg = false;
   FunctionTypeConversion Client(RetTy, ArgTypes, CallingConv, false/*not K&R*/);
   TheLLVMABI<FunctionTypeConversion> ABIConverter(Client);
-  
-  ABIConverter.HandleReturnType(TREE_TYPE(type), current_function_decl,
-                                decl ? DECL_BUILT_IN(decl) : false);
-  
+
   // Allow the target to set the CC for things like fastcall etc.
 #ifdef TARGET_ADJUST_LLVM_CC
   TARGET_ADJUST_LLVM_CC(CallingConv, type);
 #endif
 
+  ABIConverter.HandleReturnType(TREE_TYPE(type), current_function_decl,
+                                decl ? DECL_BUILT_IN(decl) : false);
+  
   // Compute attributes for return type (and function attributes).
   SmallVector<AttributeWithIndex, 8> Attrs;
   Attributes FnAttributes = Attribute::None;





More information about the llvm-commits mailing list