From: Eli Friedman Date: Fri, 18 Nov 2011 01:25:50 +0000 (+0000) Subject: Simplify code for returning a struct for Darwin x86-32 ABI. Use a better type for... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bd4d3bcd2cd64d1bba29b2a52705b97d68ebccd5;p=clang Simplify code for returning a struct for Darwin x86-32 ABI. Use a better type for a function returning a struct containing only a pointer. Handle the edge case of a struct containing only a float or double plus some dead padding instead of asserting. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144960 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index b23ae304a8..7ad351050d 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -252,6 +252,11 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { } } + // We don't consider a struct a single-element struct if it has + // padding beyond the element type. + if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T)) + return 0; + return Found; } @@ -561,51 +566,21 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const { if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType()) return ABIArgInfo::getIndirect(0); - // Classify "single element" structs as their element type. - if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) { - if (const BuiltinType *BT = SeltTy->getAs()) { - if (BT->isIntegerType()) { - // We need to use the size of the structure, padding - // bit-fields can adjust that to be larger than the single - // element type. - uint64_t Size = getContext().getTypeSize(RetTy); - return ABIArgInfo::getDirect( - llvm::IntegerType::get(getVMContext(), (unsigned)Size)); - } - - if (BT->getKind() == BuiltinType::Float) { - assert(getContext().getTypeSize(RetTy) == - getContext().getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getDirect(llvm::Type::getFloatTy(getVMContext())); - } - - if (BT->getKind() == BuiltinType::Double) { - assert(getContext().getTypeSize(RetTy) == - getContext().getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getDirect(llvm::Type::getDoubleTy(getVMContext())); - } - } else if (SeltTy->isPointerType()) { - // FIXME: It would be really nice if this could come out as the proper - // pointer type. - llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(getVMContext()); - return ABIArgInfo::getDirect(PtrTy); - } else if (SeltTy->isVectorType()) { - // 64- and 128-bit vectors are never returned in a - // register when inside a structure. - uint64_t Size = getContext().getTypeSize(RetTy); - if (Size == 64 || Size == 128) - return ABIArgInfo::getIndirect(0); - - return classifyReturnType(QualType(SeltTy, 0)); - } - } - // Small structures which are register sized are generally returned // in a register. if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext())) { uint64_t Size = getContext().getTypeSize(RetTy); + + // As a special-case, if the struct is a "single-element" struct, and + // the field is of type "float" or "double", return it in a + // floating-point register. We apply a similar transformation for + // pointer types to improve the quality of the generated IR. + if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) + if (SeltTy->isRealFloatingType() || SeltTy->hasPointerRepresentation()) + return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); + + // FIXME: We should be able to narrow this integer in cases with dead + // padding. return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size)); } diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c index b31262fc96..856a6d72ea 100644 --- a/test/CodeGen/x86_32-arguments-darwin.c +++ b/test/CodeGen/x86_32-arguments-darwin.c @@ -173,7 +173,7 @@ struct s42 { enum e40 f0; } f42(void) { } // CHECK: define i64 @f43() struct s43 { enum e40 f0; int f1; } f43(void) { } -// CHECK: define i32 @f44() +// CHECK: define void ()* @f44() struct s44 { vvbp f0; } f44(void) { } // CHECK: define i64 @f45() @@ -281,6 +281,10 @@ void f56(char a0, struct s56_0 a1, struct s57 { _Complex int x; }; void f57(struct s57 x) {} void f57a(void) { f57((struct s57){1}); } +// CHECK: define void @f58() union u58 {}; void f58(union u58 x) {} -// CHECK: define void @f58() + +// CHECK: define i64 @f59() +struct s59 { float x __attribute((aligned(8))); }; +struct s59 f59() { while (1) {} } diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp index 1cbeb71b22..4404de0f88 100644 --- a/test/CodeGenCXX/x86_32-arguments.cpp +++ b/test/CodeGenCXX/x86_32-arguments.cpp @@ -84,7 +84,7 @@ struct s4_1 { float x; }; struct s4_2 : s4_0, s4_1 { }; s4_2 f4() { return s4_2(); } -// CHECK: define i32 @_Z2f5v() +// CHECK: define i32* @_Z2f5v() struct s5 { s5(); int &x; }; s5 f5() { return s5(); }