[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