[llvm-commits] [llvm-gcc-4.2] r50491 - 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-types.cpp

Evan Cheng evan.cheng at apple.com
Wed Apr 30 12:18:08 PDT 2008


Author: evancheng
Date: Wed Apr 30 14:18:07 2008
New Revision: 50491

URL: http://llvm.org/viewvc/llvm-project?rev=50491&view=rev
Log:
x86-64 abi specifies small aggregates can be broken up and passed in registers. However, this is only true when there are enough argument registers to pass the whole aggregate in registers. Keep track of the number of scalar parameter registers used so far. If there are only enough registers to "partially" satisfy the requirement, pass the aggregate byval in memory instead. Note, if there are no argument registers left at all, then treat it as if it's being passed in registers and left codegen do the right thing.

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-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=50491&r1=50490&r2=50491&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 Wed Apr 30 14:18:07 2008
@@ -164,10 +164,20 @@
 llvm_x86_32_should_pass_aggregate_in_mixed_regs(tree, const Type *Ty,
                                                 std::vector<const Type*>&);
 
-#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, E)            \
-  (TARGET_64BIT ?                                                     \
-   llvm_x86_64_should_pass_aggregate_in_mixed_regs((T), (TY), (E)) :  \
+#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, E)           \
+  (TARGET_64BIT ?                                                    \
+   llvm_x86_64_should_pass_aggregate_in_mixed_regs((T), (TY), (E)) : \
    llvm_x86_32_should_pass_aggregate_in_mixed_regs((T), (TY), (E)))
+
+extern
+bool llvm_x86_64_aggregate_partially_passed_in_regs(std::vector<const Type*>&,
+                                                    std::vector<const Type*>&);
+
+#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE)         \
+  (TARGET_64BIT ?                                              \
+   llvm_x86_64_aggregate_partially_passed_in_regs((E), (SE)) : \
+   false)
+
 #endif /* LLVM_ABI_H */
 
 /* LLVM LOCAL end (ENTIRE FILE!)  */

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=50491&r1=50490&r2=50491&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 30 14:18:07 2008
@@ -744,6 +744,82 @@
   return llvm_x86_64_should_pass_aggregate_in_memory(TreeType, Mode);
 }
 
+/* count_num_registers_uses - Return the number of GPRs and XMMs parameter
+   register used so far. */
+static void count_num_registers_uses(std::vector<const Type*> &ScalarElts,
+                                     unsigned &NumGPRs, unsigned &NumXMMs) {
+  NumGPRs = 0;
+  NumXMMs = 0;
+  for (unsigned i = 0, e = ScalarElts.size(); i != e; ++i) {
+    const Type *Ty = ScalarElts[i];
+    if (const VectorType *VTy = dyn_cast<VectorType>(Ty)) {
+      if (!TARGET_MACHO)
+        continue;
+      if (VTy->getNumElements() == 1)
+        // v1i64 is passed in GPRs on Darwin.
+        ++NumGPRs;
+      else
+        // All other vector scalar values are passed in XMM registers.
+        ++NumXMMs;
+    } else if (Ty->isInteger() || isa<PointerType>(Ty)) {
+      ++NumGPRs;
+    } else {
+      // Floating point scalar argument.
+      assert(Ty->isFloatingPoint() && Ty->isPrimitiveType() &&
+             "Expecting a floating point primitive type!");
+      if (Ty->getTypeID() == Type::FloatTyID
+          || Ty->getTypeID() == Type::DoubleTyID)
+        ++NumXMMs;
+    }
+  }
+}
+
+/* Target hook for llvm-abi.h. This is called when an aggregate is being passed
+   in registers. If there are only enough available parameter registers to pass
+   part of the aggregate, return true. That means the aggregate should instead
+   be passed in memory. */
+bool
+llvm_x86_64_aggregate_partially_passed_in_regs(std::vector<const Type*> &Elts,
+                                         std::vector<const Type*> &ScalarElts) {
+  // Counting number of GPRs and XMMs used so far. According to AMD64 ABI
+  // document: "If there are no registers available for any eightbyte of an
+  // argument, the whole  argument is passed on the stack." X86-64 uses 6
+  // integer 
+  // For example, if two GPRs are required but only one is available, then
+  // both parts will be in memory.
+  // FIXME: This is a temporary solution. To be removed when llvm has first
+  // class aggregate values.
+  unsigned NumGPRs = 0;
+  unsigned NumXMMs = 0;
+  count_num_registers_uses(ScalarElts, NumGPRs, NumXMMs);
+
+  unsigned NumGPRsNeeded = 0;
+  unsigned NumXMMsNeeded = 0;
+  count_num_registers_uses(Elts, NumGPRsNeeded, NumXMMsNeeded);
+
+  bool GPRsSatisfied = true;
+  if (NumGPRsNeeded) {
+    if (NumGPRs < 6) {
+      if ((NumGPRs + NumGPRsNeeded) > 6)
+        // Only partially satisfied.
+        return true;
+    } else
+      GPRsSatisfied = false;
+  }
+
+  bool XMMsSatisfied = true;
+  if (NumXMMsNeeded) {
+    if (NumXMMs < 8) {
+      if ((NumXMMs + NumXMMsNeeded) > 8)
+        // Only partially satisfied.
+        return true;
+    } else
+      XMMsSatisfied = false;
+  }
+
+  return !GPRsSatisfied || !XMMsSatisfied;
+}
+
 /* Target hook for llvm-abi.h. It returns true if an aggregate of the
    specified type should be passed in a number of registers of mixed types.
    It also returns a vector of types that correspond to the registers used
@@ -792,17 +868,19 @@
               Ty = STy->getElementType(0);
           if (const VectorType *VTy = dyn_cast<VectorType>(Ty)) {
             if (VTy->getNumElements() == 2) {
-              if (VTy->getElementType()->isInteger())
+              if (VTy->getElementType()->isInteger()) {
                 Elts.push_back(VectorType::get(Type::Int64Ty, 2));
-              else
+              } else {
                 Elts.push_back(VectorType::get(Type::DoubleTy, 2));
+              }
               Bytes -= 8;
             } else {
               assert(VTy->getNumElements() == 4);
-              if (VTy->getElementType()->isInteger())
+              if (VTy->getElementType()->isInteger()) {
                 Elts.push_back(VectorType::get(Type::Int32Ty, 4));
-              else
+              } else {
                 Elts.push_back(VectorType::get(Type::FloatTy, 4));
+              }
               Bytes -= 4;
             }
           } else if (llvm_x86_is_all_integer_types(Ty)) {
@@ -850,6 +928,7 @@
     default: assert(0 && "Unexpected register class!");
     }
   }
+
   return true;
 }
 

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=50491&r1=50490&r2=50491&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi.h Wed Apr 30 14:18:07 2008
@@ -247,6 +247,16 @@
     false
 #endif
 
+// LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS - Only called if
+// LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS returns true. This returns true if
+// there are only enough unused argument passing registers to pass a part of
+// the aggregate. Note, this routine should return false if none of the needed
+// registers are available.
+#ifndef LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS
+#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE) \
+    false
+#endif
+
 // LLVM_BYVAL_ALIGNMENT - Returns the alignment of the type in bytes, if known,
 // in the context of its use as a function parameter.
 // Note that the alignment in the TYPE node is usually the alignment appropriate
@@ -387,23 +397,37 @@
   /// argument and invokes methods on the client that indicate how its pieces
   /// should be handled.  This handles things like decimating structures into
   /// their fields.
-  void HandleArgument(tree type, ParameterAttributes *Attributes = NULL) {
+  void HandleArgument(tree type, std::vector<const Type*> &ScalarElts,
+                      ParameterAttributes *Attributes = NULL) {
     const Type *Ty = ConvertType(type);
     // Figure out if this field is zero bits wide, e.g. {} or [0 x int].  Do
     // not include variable sized fields here.
     std::vector<const Type*> Elts;
     if (isPassedByInvisibleReference(type)) { // variable size -> by-ref.
-      C.HandleByInvisibleReferenceArgument(PointerType::getUnqual(Ty), type);
+      const Type *PtrTy = PointerType::getUnqual(Ty);
+      C.HandleByInvisibleReferenceArgument(PtrTy, type);
+      ScalarElts.push_back(PtrTy);
     } else if (Ty->getTypeID()==Type::VectorTyID) {
       if (LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(type)) {
-        PassInIntegerRegisters(type, Ty);
+        PassInIntegerRegisters(type, Ty, ScalarElts);
       } else {
         C.HandleScalarArgument(Ty, type);
+        ScalarElts.push_back(Ty);
       }
     } else if (Ty->isFirstClassType()) {
       C.HandleScalarArgument(Ty, type);
+      ScalarElts.push_back(Ty);
     } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(type, Ty, Elts)) {
-      PassInMixedRegisters(type, Ty, Elts);
+      if (!LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(Elts, ScalarElts))
+        PassInMixedRegisters(type, Ty, Elts, ScalarElts);
+      else {
+        C.HandleByValArgument(Ty, type);
+        if (Attributes) {
+          *Attributes |= ParamAttr::ByVal;
+          *Attributes |= 
+            ParamAttr::constructAlignmentFromInt(LLVM_BYVAL_ALIGNMENT(type));
+        }
+      }
     } else if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type, Ty)) {
       C.HandleByValArgument(Ty, type);
       if (Attributes) {
@@ -412,7 +436,7 @@
           ParamAttr::constructAlignmentFromInt(LLVM_BYVAL_ALIGNMENT(type));
       }
     } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(type)) {
-      PassInIntegerRegisters(type, Ty);
+      PassInIntegerRegisters(type, Ty, ScalarElts);
     } else if (isZeroSizedStructOrUnion(type)) {
       // Zero sized struct or union, just drop it!
       ;
@@ -423,24 +447,24 @@
           assert(FNo != ~0U && "Case not handled yet!");
           
           C.EnterField(FNo, Ty);
-          HandleArgument(getDeclaredType(Field));
+          HandleArgument(getDeclaredType(Field), ScalarElts);
           C.ExitField();
         }
     } else if (TREE_CODE(type) == COMPLEX_TYPE) {
       C.EnterField(0, Ty);
-      HandleArgument(TREE_TYPE(type));
+      HandleArgument(TREE_TYPE(type), ScalarElts);
       C.ExitField();
       C.EnterField(1, Ty);
-      HandleArgument(TREE_TYPE(type));
+      HandleArgument(TREE_TYPE(type), ScalarElts);
       C.ExitField();
     } else if ((TREE_CODE(type) == UNION_TYPE) ||
                (TREE_CODE(type) == QUAL_UNION_TYPE)) {
-      HandleUnion(type);
+      HandleUnion(type, ScalarElts);
     } else if (TREE_CODE(type) == ARRAY_TYPE) {
       const ArrayType *ATy = cast<ArrayType>(Ty);
       for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
         C.EnterField(i, Ty);
-        HandleArgument(TREE_TYPE(type));
+        HandleArgument(TREE_TYPE(type), ScalarElts);
         C.ExitField();
       }
     } else {
@@ -451,7 +475,7 @@
 
   /// HandleUnion - Handle a UNION_TYPE or QUAL_UNION_TYPE tree.
   ///
-  void HandleUnion(tree type) {
+  void HandleUnion(tree type, std::vector<const Type*> &ScalarElts) {
     if (TYPE_TRANSPARENT_UNION(type)) {
       tree Field = TYPE_FIELDS(type);
       assert(Field && "Transparent union must have some elements!");
@@ -460,7 +484,7 @@
         assert(Field && "Transparent union must have some elements!");
       }
       
-      HandleArgument(TREE_TYPE(Field));
+      HandleArgument(TREE_TYPE(Field), ScalarElts);
     } else {
       // Unions pass the largest element.
       unsigned MaxSize = 0;
@@ -487,14 +511,15 @@
       }
       
       if (MaxElt)
-        HandleArgument(TREE_TYPE(MaxElt));
+        HandleArgument(TREE_TYPE(MaxElt), ScalarElts);
     }
   }
     
   /// PassInIntegerRegisters - Given an aggregate value that should be passed in
   /// integer registers, convert it to a structure containing ints and pass all
   /// of the struct elements in.
-  void PassInIntegerRegisters(tree type, const Type *Ty) {
+  void PassInIntegerRegisters(tree type, const Type *Ty,
+                              std::vector<const Type*> &ScalarElts) {
     unsigned Size = TREE_INT_CST_LOW(TYPE_SIZE(type))/8;
 
     // FIXME: We should preserve all aggregate value alignment information.
@@ -543,6 +568,7 @@
       for (unsigned j = 0; j < ArraySize; ++j) {
         C.EnterField(j, ATy);
         C.HandleScalarArgument(ArrayElementType, 0);
+        ScalarElts.push_back(ArrayElementType);
         C.ExitField();
       }
       C.ExitField();
@@ -551,6 +577,7 @@
     for (unsigned e = Elts.size(); i != e; ++i) {
       C.EnterField(i, STy);
       C.HandleScalarArgument(Elts[i], 0);
+      ScalarElts.push_back(Elts[i]);
       C.ExitField();
     }
   }
@@ -559,11 +586,13 @@
   /// mixed integer, floating point, and vector registers, convert it to a
   /// structure containing the specified struct elements in.
   void PassInMixedRegisters(tree type, const Type *Ty,
-                            std::vector<const Type*> &Elts) {
+                            std::vector<const Type*> &Elts,
+                            std::vector<const Type*> &ScalarElts) {
     const StructType *STy = StructType::get(Elts, false);
     for (unsigned i = 0, e = Elts.size(); i != e; ++i) {
       C.EnterField(i, STy);
       C.HandleScalarArgument(Elts[i], 0);
+      ScalarElts.push_back(Elts[i]);
       C.ExitField();
     }
   }

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=50491&r1=50490&r2=50491&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Wed Apr 30 14:18:07 2008
@@ -498,7 +498,7 @@
       AI->setName(NameStack.back());
       ++AI;
     }
-        
+
     void HandleByValArgument(const llvm::Type *LLVMTy, tree type) {
       // Should not get here.
       abort();
@@ -521,6 +521,22 @@
   };
 }
 
+// isPassedByVal - Return true if an aggregate of the specified type will be
+// passed in memory byval.
+static bool isPassedByVal(tree type, const Type *Ty,
+                          std::vector<const Type*> &ScalarArgs) {
+  if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type, Ty))
+    return true;
+
+  std::vector<const Type*> Args;
+  if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(type, Ty, Args) &&
+      LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(Args, ScalarArgs))
+    // We want to pass the whole aggregate in registers but only some of the
+    // registers are available.
+    return true;
+  return false;
+}
+
 void TreeToLLVM::StartFunctionBody() {
   const char *Name = "";
   // Get the name of the function.
@@ -668,6 +684,8 @@
   // Prepend the static chain (if any) to the list of arguments.
   tree Args = static_chain ? static_chain : DECL_ARGUMENTS(FnDecl);
 
+  // Scalar arguments processed so far.
+  std::vector<const Type*> ScalarArgs;
   while (Args) {
     const char *Name = "unnamed_arg";
     if (DECL_NAME(Args)) Name = IDENTIFIER_POINTER(DECL_NAME(Args));
@@ -676,7 +694,7 @@
     bool isInvRef = isPassedByInvisibleReference(TREE_TYPE(Args));
     if (isInvRef ||
         (!ArgTy->isFirstClassType() &&
-         LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(TREE_TYPE(Args), ArgTy))) {
+         isPassedByVal(TREE_TYPE(Args), ArgTy, ScalarArgs))) {
       // If the value is passed by 'invisible reference' or 'byval reference',
       // the l-value for the argument IS the argument itself.
       AI->setName(Name);
@@ -710,7 +728,7 @@
       
       Client.setName(Name);
       Client.setLocation(Tmp);
-      ABIConverter.HandleArgument(TREE_TYPE(Args));
+      ABIConverter.HandleArgument(TREE_TYPE(Args), ScalarArgs);
       Client.clear();
     }
 
@@ -2469,7 +2487,7 @@
 
       // Perform any implicit type conversions.
       if (CallOperands.size() < FTy->getNumParams()) {
-        const Type *CalledTy = FTy->getParamType(CallOperands.size());
+        const Type *CalledTy= FTy->getParamType(CallOperands.size());
         if (Loc->getType() != CalledTy) {
           assert(type && "Inconsistent parameter types?");
           bool isSigned = !TYPE_UNSIGNED(type);
@@ -2581,6 +2599,7 @@
     CallOperands.push_back(Emit(TREE_OPERAND(exp, 2), 0));
 
   // Loop over the arguments, expanding them and adding them to the op list.
+  std::vector<const Type*> ScalarArgs;
   for (tree arg = TREE_OPERAND(exp, 1); arg; arg = TREE_CHAIN(arg)) {
     const Type *ArgTy = ConvertType(TREE_TYPE(TREE_VALUE(arg)));
 
@@ -2596,7 +2615,8 @@
     }
 
     ParameterAttributes Attributes = ParamAttr::None;
-    ABIConverter.HandleArgument(TREE_TYPE(TREE_VALUE(arg)), &Attributes);
+    ABIConverter.HandleArgument(TREE_TYPE(TREE_VALUE(arg)), ScalarArgs,
+                                &Attributes);
     if (Attributes != ParamAttr::None)
       PAL = PAL.addAttr(CallOperands.size(), Attributes);
 

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=50491&r1=50490&r2=50491&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-types.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-types.cpp Wed Apr 30 14:18:07 2008
@@ -1068,9 +1068,10 @@
     Attrs.push_back(ParamAttrsWithIndex::get(ArgTys.size(),
                                     ParamAttr::StructRet | ParamAttr::NoAlias));
 
+  std::vector<const Type*> ScalarArgs;
   if (static_chain) {
     // Pass the static chain as the first parameter.
-    ABIConverter.HandleArgument(TREE_TYPE(static_chain));
+    ABIConverter.HandleArgument(TREE_TYPE(static_chain), ScalarArgs);
     // Mark it as the chain argument.
     Attrs.push_back(ParamAttrsWithIndex::get(ArgTys.size(),
                                              ParamAttr::Nest));
@@ -1082,7 +1083,7 @@
     // Determine if there are any attributes for this param.
     ParameterAttributes Attributes = ParamAttr::None;
 
-    ABIConverter.HandleArgument(ArgTy, &Attributes);
+    ABIConverter.HandleArgument(ArgTy, ScalarArgs, &Attributes);
 
     // Compute zext/sext attributes.
     Attributes |= HandleArgumentExtension(ArgTy);
@@ -1165,9 +1166,10 @@
     Attrs.push_back(ParamAttrsWithIndex::get(ArgTypes.size(),
                                     ParamAttr::StructRet | ParamAttr::NoAlias));
 
+  std::vector<const Type*> ScalarArgs;
   if (static_chain) {
     // Pass the static chain as the first parameter.
-    ABIConverter.HandleArgument(TREE_TYPE(static_chain));
+    ABIConverter.HandleArgument(TREE_TYPE(static_chain), ScalarArgs);
     // Mark it as the chain argument.
     Attrs.push_back(ParamAttrsWithIndex::get(ArgTypes.size(),
                                              ParamAttr::Nest));
@@ -1207,7 +1209,7 @@
     // Determine if there are any attributes for this param.
     ParameterAttributes Attributes = ParamAttr::None;
     
-    ABIConverter.HandleArgument(ArgTy, &Attributes);
+    ABIConverter.HandleArgument(ArgTy, ScalarArgs, &Attributes);
 
     // Compute zext/sext attributes.
     Attributes |= HandleArgumentExtension(ArgTy);





More information about the llvm-commits mailing list