From: Daniel Dunbar Date: Wed, 1 Apr 2009 07:08:38 +0000 (+0000) Subject: x86-32 Darwin ABI: Single element arrays can be part of "single X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dfc6b80ee13a9102cd67e0b2398fa999eebcbf8e;p=clang x86-32 Darwin ABI: Single element arrays can be part of "single element structures", which have different ABI rules. - Current return-arguments-32 status is: 1 out of 1000 failures (-7) - Also, vectors inside "single element structs" require special handling. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68196 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 58e448949e..945d52faa3 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -167,7 +167,7 @@ static bool isEmptyRecord(QualType T) { /// /// \return The field declaration for the single non-empty field, if /// it exists. -static const FieldDecl *isSingleElementStruct(QualType T) { +static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { const RecordType *RT = T->getAsStructureType(); if (!RT) return 0; @@ -176,20 +176,25 @@ static const FieldDecl *isSingleElementStruct(QualType T) { if (RD->hasFlexibleArrayMember()) return 0; - const FieldDecl *Found = 0; + const Type *Found = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { const FieldDecl *FD = *i; QualType FT = FD->getType(); + // Treat single element arrays as the element + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) + if (AT->getSize().getZExtValue() == 1) + FT = AT->getElementType(); + if (isEmptyRecord(FT)) { // Ignore } else if (Found) { return 0; } else if (!CodeGenFunction::hasAggregateLLVMType(FT)) { - Found = FD; + Found = FT.getTypePtr(); } else { - Found = isSingleElementStruct(FT); + Found = isSingleElementStruct(FT, Context); if (!Found) return 0; } @@ -253,6 +258,10 @@ class DefaultABIInfo : public ABIInfo { class X86_32ABIInfo : public ABIInfo { bool IsDarwin; + static bool isRegisterSize(unsigned Size) { + return (Size == 8 || Size == 16 || Size == 32 || Size == 64); + } + public: ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context) const; @@ -305,9 +314,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, if (!IsDarwin && !RetTy->isAnyComplexType()) return ABIArgInfo::getIndirect(0); // Classify "single element" structs as their element type. - const FieldDecl *SeltFD = isSingleElementStruct(RetTy); - if (SeltFD) { - QualType SeltTy = SeltFD->getType()->getDesugaredType(); + if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) { if (const BuiltinType *BT = SeltTy->getAsBuiltinType()) { // FIXME: This is gross, it would be nice if we could just // pass back SeltTy and have clients deal with it. Is it worth @@ -326,21 +333,22 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); return ABIArgInfo::getCoerce(PtrTy); + } else if (SeltTy->isVectorType()) { + // 64- and 128-bit vectors are never returned in a + // register when inside a structure. + uint64_t Size = Context.getTypeSize(RetTy); + if (Size == 64 || Size == 128) + return ABIArgInfo::getIndirect(0); + + return classifyReturnType(QualType(SeltTy, 0), Context); } } uint64_t Size = Context.getTypeSize(RetTy); - if (Size == 8) { - return ABIArgInfo::getCoerce(llvm::Type::Int8Ty); - } else if (Size == 16) { - return ABIArgInfo::getCoerce(llvm::Type::Int16Ty); - } else if (Size == 32) { - return ABIArgInfo::getCoerce(llvm::Type::Int32Ty); - } else if (Size == 64) { - return ABIArgInfo::getCoerce(llvm::Type::Int64Ty); - } else { - return ABIArgInfo::getIndirect(0); - } + if (isRegisterSize(Size)) + return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size)); + + return ABIArgInfo::getIndirect(0); } else { return ABIArgInfo::getDirect(); } diff --git a/test/CodeGen/x86_32-arguments.c b/test/CodeGen/x86_32-arguments.c index 58637d5253..8e8a2f9998 100644 --- a/test/CodeGen/x86_32-arguments.c +++ b/test/CodeGen/x86_32-arguments.c @@ -63,7 +63,7 @@ struct s9 f9_1(void) { void f9_2(struct s9 a0) { } -// Return of small structures and unions... +// Return of small structures and unions // RUN: grep 'float @f10()' %t && struct s10 { @@ -71,12 +71,14 @@ struct s10 { float f; } f10(void) {} -// Small vectors and 1 x {i64,double} are returned in registers... +// Small vectors and 1 x {i64,double} are returned in registers // RUN: grep 'i32 @f11()' %t && // RUN: grep -F 'void @f12(<2 x i32>* noalias sret %agg.result)' %t && // RUN: grep 'i64 @f13()' %t && // RUN: grep 'i64 @f14()' %t && +// RUN: grep '<2 x i64> @f15()' %t && +// RUN: grep '<2 x i64> @f16()' %t && typedef short T11 __attribute__ ((vector_size (4))); T11 f11(void) {} typedef int T12 __attribute__ ((vector_size (8))); @@ -85,5 +87,34 @@ typedef long long T13 __attribute__ ((vector_size (8))); T13 f13(void) {} typedef double T14 __attribute__ ((vector_size (8))); T14 f14(void) {} +typedef long long T15 __attribute__ ((vector_size (16))); +T15 f15(void) {} +typedef double T16 __attribute__ ((vector_size (16))); +T16 f16(void) {} + +// And when the single element in a struct (but not for 64 and +// 128-bits). + +// RUN: grep 'i32 @f17()' %t && +// RUN: grep -F 'void @f18(%0* noalias sret %agg.result)' %t && +// RUN: grep -F 'void @f19(%1* noalias sret %agg.result)' %t && +// RUN: grep -F 'void @f20(%2* noalias sret %agg.result)' %t && +// RUN: grep -F 'void @f21(%3* noalias sret %agg.result)' %t && +// RUN: grep -F 'void @f22(%4* noalias sret %agg.result)' %t && +struct { T11 a; } f17(void) {} +struct { T12 a; } f18(void) {} +struct { T13 a; } f19(void) {} +struct { T14 a; } f20(void) {} +struct { T15 a; } f21(void) {} +struct { T16 a; } f22(void) {} + +// Single element structures are handled specially + +// RUN: grep -F 'float @f23()' %t && +// RUN: grep -F 'float @f24()' %t && +// RUN: grep -F 'float @f25()' %t && +struct { float a; } f23(void) {} +struct { float a[1]; } f24(void) {} +struct { struct {} a; struct { float a[1]; } b; } f25(void) {} // RUN: true