[llvm-commits] [llvm-gcc-4.2] r46191 - in /llvm-gcc-4.2/trunk/gcc: config/i386/i386-protos.h config/i386/i386.c config/i386/i386.h config/i386/llvm-i386-target.h config/i386/llvm-i386.cpp llvm-abi.h

Evan Cheng evan.cheng at apple.com
Fri Jan 18 22:03:45 PST 2008


Author: evancheng
Date: Sat Jan 19 00:03:38 2008
New Revision: 46191

URL: http://llvm.org/viewvc/llvm-project?rev=46191&view=rev
Log:
Much improved x86-64 ABI compliance.

Modified:
    llvm-gcc-4.2/trunk/gcc/config/i386/i386-protos.h
    llvm-gcc-4.2/trunk/gcc/config/i386/i386.c
    llvm-gcc-4.2/trunk/gcc/config/i386/i386.h
    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

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

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/i386/i386-protos.h (original)
+++ llvm-gcc-4.2/trunk/gcc/config/i386/i386-protos.h Sat Jan 19 00:03:38 2008
@@ -257,7 +257,13 @@
 extern int asm_preferred_eh_data_format (int, int);
 
 /* LLVM LOCAL begin */
+#ifdef ENABLE_LLVM
+#define MAX_CLASSES 4
 enum machine_mode ix86_getNaturalModeForType(tree type);
 int ix86_HowToPassArgument(enum machine_mode mode, tree type, int in_return,
                            int *int_nregs, int *sse_nregs);
+int ix86_ClassifyArgument(enum machine_mode mode, tree type,
+                          enum x86_64_reg_class classes[MAX_CLASSES],
+                          int bit_offset);
+#endif
 /* LLVM LOCAL end */

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

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/i386/i386.c (original)
+++ llvm-gcc-4.2/trunk/gcc/config/i386/i386.c Sat Jan 19 00:03:38 2008
@@ -1246,6 +1246,9 @@
 static void i386_solaris_elf_named_section (const char *, unsigned int, tree)
   ATTRIBUTE_UNUSED;
 
+/* LLVM LOCAL begin */
+
+#ifndef ENABLE_LLVM
 /* Register class used for passing given 64bit part of the argument.
    These represent classes as documented by the PS ABI, with the exception
    of SSESF, SSEDF classes, that are basically SSE class, just gcc will
@@ -1268,6 +1271,10 @@
     X86_64_COMPLEX_X87_CLASS,
     X86_64_MEMORY_CLASS
   };
+#endif /* !ENABLE_LLVM */
+
+/* LLVM LOCAL end */
+
 static const char * const x86_64_reg_class_name[] = {
   "no", "integer", "integerSI", "sse", "sseSF", "sseDF",
   "sseup", "x87", "x87up", "cplx87", "no"
@@ -3263,9 +3270,16 @@
 		   int offset = tree_low_cst (BINFO_OFFSET (base_binfo), 0) * 8;
 		   tree type = BINFO_TYPE (base_binfo);
 
+/* LLVM local */
+#ifdef ENABLE_LLVM
+		   num = classify_argument (type_natural_mode (type),
+					    type, subclasses,
+					    (offset + bit_offset) % 256);
+#else                   
 		   num = classify_argument (TYPE_MODE (type),
 					    type, subclasses,
 					    (offset + bit_offset) % 256);
+#endif
 		   if (!num)
 		     return 0;
 		   for (i = 0; i < num; i++)
@@ -3301,10 +3315,18 @@
 		    }
 		  else
 		    {
+/* LLVM local */
+#ifdef ENABLE_LLVM
+		      num = classify_argument (type_natural_mode (TREE_TYPE (field)),
+					       TREE_TYPE (field), subclasses,
+					       (int_bit_position (field)
+						+ bit_offset) % 256);
+#else
 		      num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
 					       TREE_TYPE (field), subclasses,
 					       (int_bit_position (field)
 						+ bit_offset) % 256);
+#endif
 		      if (!num)
 			return 0;
 		      for (i = 0; i < num; i++)
@@ -3323,8 +3345,14 @@
 	  /* Arrays are handled as small records.  */
 	  {
 	    int num;
+/* LLVM local */
+#ifdef ENABLE_LLVM
+	    num = classify_argument (type_natural_mode (TREE_TYPE (type)),
+				     TREE_TYPE (type), subclasses, bit_offset);
+#else
 	    num = classify_argument (TYPE_MODE (TREE_TYPE (type)),
 				     TREE_TYPE (type), subclasses, bit_offset);
+#endif
 	    if (!num)
 	      return 0;
 
@@ -3356,9 +3384,16 @@
 		  if (TREE_TYPE (field) == error_mark_node)
 		    continue;
 
+/* LLVM local */
+#ifdef ENABLE_LLVM
+		  num = classify_argument (type_natural_mode (TREE_TYPE (field)),
+					   TREE_TYPE (field), subclasses,
+					   bit_offset);
+#else
 		  num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
 					   TREE_TYPE (field), subclasses,
 					   bit_offset);
+#endif
 		  if (!num)
 		    return 0;
 		  for (i = 0; i < num; i++)
@@ -21554,10 +21589,16 @@
 }
 
 int ix86_HowToPassArgument(enum machine_mode mode, tree type, int in_return,
-                             int *int_nregs, int *sse_nregs) {
+                           int *int_nregs, int *sse_nregs) {
   return examine_argument(mode, type, in_return, int_nregs, sse_nregs);
 }
 
+int ix86_ClassifyArgument(enum machine_mode mode, tree type,
+                          enum x86_64_reg_class classes[MAX_CLASSES],
+                          int bit_offset) {
+  return classify_argument(mode, type, classes, bit_offset);
+}
+
   
 /* APPLE LOCAL end LLVM */
 

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

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/i386/i386.h (original)
+++ llvm-gcc-4.2/trunk/gcc/config/i386/i386.h Sat Jan 19 00:03:38 2008
@@ -34,6 +34,36 @@
    ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE, PRINT_B_I_S, and many
    that start with ASM_ or end in ASM_OP.  */
 
+/* LLVM LOCAL begin */
+
+#ifdef ENABLE_LLVM
+/* Register class used for passing given 64bit part of the argument.
+   These represent classes as documented by the PS ABI, with the exception
+   of SSESF, SSEDF classes, that are basically SSE class, just gcc will
+   use SF or DFmode move instead of DImode to avoid reformatting penalties.
+
+   Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
+   whenever possible (upper half does contain padding).
+ */
+enum x86_64_reg_class
+  {
+    X86_64_NO_CLASS,
+    X86_64_INTEGER_CLASS,
+    X86_64_INTEGERSI_CLASS,
+    X86_64_SSE_CLASS,
+    X86_64_SSESF_CLASS,
+    X86_64_SSEDF_CLASS,
+    X86_64_SSEUP_CLASS,
+    X86_64_X87_CLASS,
+    X86_64_X87UP_CLASS,
+    X86_64_COMPLEX_X87_CLASS,
+    X86_64_MEMORY_CLASS
+  };
+
+#endif /* ENABLE_LLVM */
+
+/* LLVM LOCAL end */
+
 /* Define the specific costs for a given cpu */
 
 struct processor_costs {

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=46191&r1=46190&r2=46191&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 Sat Jan 19 00:03:38 2008
@@ -67,5 +67,16 @@
 #define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X)          \
   llvm_x86_should_pass_aggregate_in_memory(X)
 
+
+#ifdef LLVM_ABI_H
+extern bool
+llvm_x86_64_should_pass_aggregate_in_mixed_regs(tree,
+                                                std::vector<const Type*>&);
+
+#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, E)          \
+  (TARGET_64BIT &&                                              \
+   llvm_x86_64_should_pass_aggregate_in_mixed_regs((T), (E)))
+#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=46191&r1=46190&r2=46191&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 Sat Jan 19 00:03:38 2008
@@ -26,6 +26,7 @@
 
 #include "llvm-abi.h"
 #include "llvm-internal.h"
+#include "llvm/DerivedTypes.h"
 #include "llvm/Instructions.h"
 #include "llvm/Intrinsics.h"
 #include "llvm/Module.h"
@@ -661,25 +662,37 @@
 }
 
 /* These are defined in i386.c */
+#define MAX_CLASSES 4
 extern "C" enum machine_mode ix86_getNaturalModeForType(tree);
 extern "C" int ix86_HowToPassArgument(enum machine_mode, tree, int, int*, int*);
+extern "C" int ix86_ClassifyArgument(enum machine_mode, tree,
+                               enum x86_64_reg_class classes[MAX_CLASSES], int);
 
 /* Target hook for llvm-abi.h. It returns true if an aggregate of the
    specified type should be passed in memory. This is only called for
    x86-64. */
-static bool llvm_x86_64_should_pass_aggregate_in_memory(tree type,
+static bool llvm_x86_64_should_pass_aggregate_in_memory(tree TreeType,
                                                         enum machine_mode Mode){
   int IntRegs, SSERegs;
   /* If ix86_HowToPassArgument return 0, then it's passed byval in memory.*/
-  return !ix86_HowToPassArgument(Mode, type, 0, &IntRegs, &SSERegs);
+  return !ix86_HowToPassArgument(Mode, TreeType, 0, &IntRegs, &SSERegs);
+}
+
+/* Returns true if all elements of the type are integer types. */
+static bool llvm_x86_is_all_integer_types(const Type *Ty) {
+  for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end();
+       I != E; ++I)
+    if (!I->get()->isIntOrIntVector())
+      return false;
+  return true;
 }
 
 /* Target hook for llvm-abi.h. It returns true if an aggregate of the
    specified type should be passed in memory. */
-bool llvm_x86_should_pass_aggregate_in_memory(tree type) {
-  enum machine_mode Mode = ix86_getNaturalModeForType(type);
+bool llvm_x86_should_pass_aggregate_in_memory(tree TreeType) {
+  enum machine_mode Mode = ix86_getNaturalModeForType(TreeType);
   HOST_WIDE_INT Bytes =
-    (Mode == BLKmode) ? int_size_in_bytes(type) : (int) GET_MODE_SIZE(Mode);
+    (Mode == BLKmode) ? int_size_in_bytes(TreeType) : (int) GET_MODE_SIZE(Mode);
 
   // Zero sized array, struct, or class, not passed in memory.
   if (Bytes == 0)
@@ -687,20 +700,101 @@
 
   if (Bytes == GET_MODE_SIZE(SImode) || Bytes == GET_MODE_SIZE(DImode)) {
     // 32-bit or 64-bit and all elements are integers, not passed in memory.
-    bool AllIntegers = true;
-    const Type *Ty = ConvertType(type);
-    for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end();
-         I != E; ++I)
-      if (!I->get()->isIntOrIntVector()) {
-        AllIntegers = false;
-        break;
-      }
-    if (AllIntegers)
+    const Type *Ty = ConvertType(TreeType);
+    if (llvm_x86_is_all_integer_types(Ty))
       return false;
   }
   if (!TARGET_64BIT)
     return true;
-  return llvm_x86_64_should_pass_aggregate_in_memory(type, Mode);
+  return llvm_x86_64_should_pass_aggregate_in_memory(TreeType, Mode);
+}
+
+/* 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
+   for parameter passing. This is only called for x86-64. */
+bool
+llvm_x86_64_should_pass_aggregate_in_mixed_regs(tree TreeType,
+                                                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)
+    return false;
+ 
+  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);
+      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 == 1) {
+        if (Bytes == 8)
+          Elts.push_back(Type::DoubleTy);
+        else
+          assert(0 && "Not yet handled!");
+      } else if (NumClasses == 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));
+            } 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));
+            }
+          } else if (llvm_x86_is_all_integer_types(Ty))
+            Elts.push_back(VectorType::get(Type::Int32Ty, 4));
+          else
+            Elts.push_back(VectorType::get(Type::FloatTy, 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);
+        } else if (Class[i+1] == X86_64_SSE_CLASS) {
+          Elts.push_back(Type::DoubleTy);
+          Elts.push_back(Type::DoubleTy);
+        } 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);
+      break;
+    case X86_64_SSEDF_CLASS:
+      Elts.push_back(Type::DoubleTy);
+      break;
+    case X86_64_X87_CLASS:
+    case X86_64_X87UP_CLASS:
+    case X86_64_COMPLEX_X87_CLASS:
+      return false;
+    case X86_64_NO_CLASS:
+      return false;
+    default: assert(0 && "Unexpected register class!");
+    }
+  }
+  return true;
 }
 
 /* LLVM LOCAL end (ENTIRE FILE!)  */

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=46191&r1=46190&r2=46191&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi.h Sat Jan 19 00:03:38 2008
@@ -120,6 +120,23 @@
   }
 }
 
+// LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR - Return true if this aggregate
+// value should be passed by value, i.e. passing its address with the byval
+// attribute bit set. The default is false.
+#ifndef LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X)
+#define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X) \
+    false
+#endif
+
+// LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS - Return true if this aggregate
+// value should be passed in a mixture of integer, floating point, and vector
+// registers. The routine should also return by reference a vector of the
+// types of the registers being used. The default is false.
+#ifndef LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, E)
+#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, E) \
+    false
+#endif
+
 // LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS - Return true if this aggregate
 // value should be passed in integer registers.  By default, we do this for all
 // values that are not single-element structs.  This ensures that things like
@@ -130,14 +147,6 @@
    !isSingleElementStructOrArray(X)
 #endif
 
-// LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR - Return true if this aggregate
-// value should be passed by value, i.e. passing its address with the byval
-// attribute bit set. The default is false.
-#ifndef LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR
-#define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X) \
-    false
-#endif
-
 /// DefaultABI - This class implements the default LLVM ABI where structures are
 /// passed by decimating them into individual components and unions are passed
 /// by passing the largest member of the union.
@@ -212,38 +221,43 @@
       C.HandleByValArgument(Ty, type);
       if (Attributes)
         *Attributes |= ParamAttr::ByVal;
-    } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(type)) {
-      PassInIntegerRegisters(type, Ty);
-    } else if (TREE_CODE(type) == RECORD_TYPE) {
-      for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field))
-        if (TREE_CODE(Field) == FIELD_DECL) {
-          unsigned FNo = GetFieldIndex(Field);
-          assert(FNo != ~0U && "Case not handled yet!");
-
-          C.EnterField(FNo, Ty);
-          HandleArgument(getDeclaredType(Field));
-          C.ExitField();
-        }
-    } else if (TREE_CODE(type) == COMPLEX_TYPE) {
-      C.EnterField(0, Ty);
-      HandleArgument(TREE_TYPE(type));
-      C.ExitField();
-      C.EnterField(1, Ty);
-      HandleArgument(TREE_TYPE(type));
-      C.ExitField();
-    } else if ((TREE_CODE(type) == UNION_TYPE) ||
-               (TREE_CODE(type) == QUAL_UNION_TYPE)) {
-      HandleUnion(type);
-    } 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);
+    } else {
+      std::vector<const Type*> Elts;
+      if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(type, Elts)) {
+        PassInMixedRegisters(type, Ty, Elts);
+      } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(type)) {
+        PassInIntegerRegisters(type, Ty);
+      } else if (TREE_CODE(type) == RECORD_TYPE) {
+        for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field))
+          if (TREE_CODE(Field) == FIELD_DECL) {
+            unsigned FNo = GetFieldIndex(Field);
+            assert(FNo != ~0U && "Case not handled yet!");
+
+            C.EnterField(FNo, Ty);
+            HandleArgument(getDeclaredType(Field));
+            C.ExitField();
+          }
+      } else if (TREE_CODE(type) == COMPLEX_TYPE) {
+        C.EnterField(0, Ty);
+        HandleArgument(TREE_TYPE(type));
+        C.ExitField();
+        C.EnterField(1, Ty);
         HandleArgument(TREE_TYPE(type));
         C.ExitField();
+      } else if ((TREE_CODE(type) == UNION_TYPE) ||
+                 (TREE_CODE(type) == QUAL_UNION_TYPE)) {
+        HandleUnion(type);
+      } 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));
+          C.ExitField();
+        }
+      } else {
+        assert(0 && "unknown aggregate type!");
+        abort();
       }
-    } else {
-      assert(0 && "unknown aggregate type!");
-      abort();
     }
   }
 
@@ -352,6 +366,19 @@
       C.ExitField();
     }
   }
+
+  /// PassInMixedRegisters - Given an aggregate value that should be passed in
+  /// 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) {
+    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);
+      C.ExitField();
+    }
+  }
 };
 
 /// TheLLVMABI - This can be defined by targets if they want total control over





More information about the llvm-commits mailing list