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); _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits