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

Chris Lattner sabre at nondot.org
Sat Jan 26 23:18:20 PST 2008


Author: lattner
Date: Sun Jan 27 01:18:20 2008
New Revision: 46412

URL: http://llvm.org/viewvc/llvm-project?rev=46412&view=rev
Log:
Change x86-32 aggregate passing code to pass many aggregates "by pieces"
instead of passing them with byval.  This allows us to get significantly
better code without affecting the ABI (because x86-32 passes stuff on the 
stack).  Most significantly, we pass _Complex as a two scalar fp values
now.  For example, before we compiled ccosf to:

_ccosf:
	pushl	%ebp
	movl	%esp, %ebp
	pushl	%edi
	pushl	%esi
	subl	$16, %esp
	movss	12(%ebp), %xmm0
	xorps	LCPI1_0, %xmm0
	movss	8(%ebp), %xmm1
	movss	%xmm0, -16(%ebp)
	movss	%xmm1, -12(%ebp)
	leal	-16(%ebp), %esi
	movl	$2, %ecx
	movl	%esp, %edi
	rep;movsl
	call	_ccoshf
	addl	$16, %esp
	popl	%esi
	popl	%edi
	popl	%ebp
	ret

now we get:

_ccosf:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movss	8(%ebp), %xmm0
	movss	%xmm0, 4(%esp)
	movss	12(%ebp), %xmm0
	xorps	LCPI1_0, %xmm0
	movss	%xmm0, (%esp)
	call	_ccoshf
	addl	$8, %esp
	popl	%ebp
	ret

Evan, please review this.  Thanks!


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

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=46412&r1=46411&r2=46412&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 Sun Jan 27 01:18:20 2008
@@ -62,20 +62,24 @@
     }                                                           \
   }
 
-extern bool llvm_x86_should_pass_aggregate_in_memory(tree);
+#ifdef LLVM_ABI_H
+extern bool llvm_x86_should_pass_aggregate_in_memory(tree, const Type *);
 
-#define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X)          \
-  llvm_x86_should_pass_aggregate_in_memory(X)
+#define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X, TY)      \
+  llvm_x86_should_pass_aggregate_in_memory(X, TY)
 
 
-#ifdef LLVM_ABI_H
 extern bool
-llvm_x86_64_should_pass_aggregate_in_mixed_regs(tree,
+llvm_x86_64_should_pass_aggregate_in_mixed_regs(tree, const Type *Ty,
+                                                std::vector<const Type*>&);
+extern bool
+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, E)          \
-  (TARGET_64BIT &&                                              \
-   llvm_x86_64_should_pass_aggregate_in_mixed_regs((T), (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)))
 #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=46412&r1=46411&r2=46412&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 Sun Jan 27 01:18:20 2008
@@ -691,7 +691,7 @@
 
 /* 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 TreeType) {
+bool llvm_x86_should_pass_aggregate_in_memory(tree TreeType, const Type *Ty) {
   enum machine_mode Mode = ix86_getNaturalModeForType(TreeType);
   HOST_WIDE_INT Bytes =
     (Mode == BLKmode) ? int_size_in_bytes(TreeType) : (int) GET_MODE_SIZE(Mode);
@@ -706,8 +706,10 @@
     if (llvm_x86_is_all_integer_types(Ty))
       return false;
   }
-  if (!TARGET_64BIT)
-    return true;
+  if (!TARGET_64BIT) {
+    std::vector<const Type*> Elts;
+    return !llvm_x86_32_should_pass_aggregate_in_mixed_regs(TreeType, Ty, Elts);
+  }
   return llvm_x86_64_should_pass_aggregate_in_memory(TreeType, Mode);
 }
 
@@ -716,7 +718,7 @@
    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,
+llvm_x86_64_should_pass_aggregate_in_mixed_regs(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);
@@ -799,4 +801,45 @@
   return true;
 }
 
+/* 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-32. */
+bool
+llvm_x86_32_should_pass_aggregate_in_mixed_regs(tree TreeType, const Type *Ty,
+                                                std::vector<const Type*> &Elts){
+  // If this is a small fixed size type, investigate it.
+  HOST_WIDE_INT SrcSize = int_size_in_bytes(TreeType);
+  if (SrcSize <= 0 || SrcSize > 128)
+    return false;
+  
+  // X86-32 passes aggregates on the stack.  If this is an extremely simple
+  // aggregate whose elements would be passed the same if passed as scalars,
+  // pass them that way in order to promote SROA on the caller and callee side.
+  // Note that we can't support passing all structs this way.  For example,
+  // {i16, i16} should be passed in on 32-bit unit, which is not how "i16, i16"
+  // would be passed as stand-alone arguments.
+  const StructType *STy = dyn_cast<StructType>(Ty);
+  if (!STy || STy->isPacked()) return false;
+  
+  for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+    const Type *EltTy = STy->getElementType(i);
+    // 32 and 64-bit integers are fine, as are float, double, and long double.
+    if (EltTy == Type::Int32Ty ||
+        EltTy == Type::Int64Ty || 
+        EltTy->isFloatingPoint() ||
+        isa<PointerType>(EltTy)) {
+      Elts.push_back(EltTy);
+      continue;
+    }
+    
+    // TODO: Vectors are also ok to pass if they don't require extra alignment.
+    // TODO: We can also pass structs like {i8, i32}.
+    
+    Elts.clear();
+    return false;
+  }
+  
+  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=46412&r1=46411&r2=46412&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi.h Sun Jan 27 01:18:20 2008
@@ -124,7 +124,7 @@
 // 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) \
+#define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X, TY) \
     false
 #endif
 
@@ -133,7 +133,7 @@
 // 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
-#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, E) \
+#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, E) \
     false
 #endif
 
@@ -212,55 +212,52 @@
   /// their fields.
   void HandleArgument(tree type, uint16_t *Attributes = NULL) {
     const Type *Ty = ConvertType(type);
-
+    std::vector<const Type*> Elts;
     if (isPassedByInvisibleReference(type)) { // variable size -> by-ref.
       C.HandleScalarArgument(PointerType::getUnqual(Ty), type);
     } else if (Ty->isFirstClassType()) {
       C.HandleScalarArgument(Ty, type);
-    } else if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type)) {
+    } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(type, Ty, Elts)) {
+      PassInMixedRegisters(type, Ty, Elts);
+    } else if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type, Ty)) {
       C.HandleByValArgument(Ty, type);
       if (Attributes)
         *Attributes |= ParamAttr::ByVal;
-    } 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 (isAggregateOfSizeZero(type)) {
-        // Zero sized aggregate, just drop it!
-        ;
-      } 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));
+    } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(type)) {
+      PassInIntegerRegisters(type, Ty);
+    } else if (isAggregateOfSizeZero(type)) {
+      // Zero sized aggregate, just drop it!
+      ;
+    } 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 {
-        assert(0 && "unknown aggregate type!");
-        abort();
+    } 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();
     }
   }
 

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=46412&r1=46411&r2=46412&view=diff

==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Sun Jan 27 01:18:20 2008
@@ -682,7 +682,7 @@
     const Type *ArgTy = ConvertType(TREE_TYPE(Args));
     if (isPassedByInvisibleReference(TREE_TYPE(Args)) ||
         (!ArgTy->isFirstClassType() &&
-         LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(TREE_TYPE(Args)))) {
+         LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(TREE_TYPE(Args), ArgTy))) {
       // If the value is passed by 'invisible reference' or 'byval reference',
       // the l-value for the argument IS the argument itself.
       SET_DECL_LLVM(Args, AI);





More information about the llvm-commits mailing list