diff options
author | Anders Carlsson <andersca@mac.com> | 2009-09-16 15:53:40 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-09-16 15:53:40 +0000 |
commit | 0a8f847e97f40cce51dc69051b964732333dc028 (patch) | |
tree | eb78e940410796b475e4b0c4345d2f5cbba63d10 | |
parent | 37473829cb2308af5b268a2d58bf3d7fa2056610 (diff) |
x86-64 ABI: If a type is a C++ record with either a non-trivial destructor or a non-trivial copy constructor, it should be passed in a pointer. Daniel, plz review.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82050 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 2 | ||||
-rw-r--r-- | lib/CodeGen/ABIInfo.h | 18 | ||||
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/TargetABIInfo.cpp | 31 | ||||
-rw-r--r-- | test/CodeGenCXX/x86_64-arguments.cpp | 10 |
5 files changed, 56 insertions, 9 deletions
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index e5275dcb25..119b4f501f 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -388,7 +388,7 @@ 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; }; 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; }; - 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = "<group>"; }; + 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = "clang-cc.cpp"; path = "tools/clang-cc/clang-cc.cpp"; sourceTree = "<group>"; tabWidth = 2; }; 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; }; diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index c1a9481c4b..1ab2f55295 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -72,11 +72,12 @@ namespace clang { Kind TheKind; const llvm::Type *TypeData; unsigned UIntData; + bool BoolData; ABIArgInfo(Kind K, const llvm::Type *TD=0, - unsigned UI=0) : TheKind(K), - TypeData(TD), - UIntData(UI) {} + unsigned UI=0, bool B = false) + : TheKind(K), TypeData(TD), UIntData(UI), BoolData(B) {} + public: ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} @@ -92,8 +93,8 @@ namespace clang { static ABIArgInfo getCoerce(const llvm::Type *T) { return ABIArgInfo(Coerce, T); } - static ABIArgInfo getIndirect(unsigned Alignment) { - return ABIArgInfo(Indirect, 0, Alignment); + static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true) { + return ABIArgInfo(Indirect, 0, Alignment, ByVal); } static ABIArgInfo getExpand() { return ABIArgInfo(Expand); @@ -113,12 +114,17 @@ namespace clang { return TypeData; } - // ByVal accessors + // Indirect accessors unsigned getIndirectAlign() const { assert(TheKind == Indirect && "Invalid kind!"); return UIntData; } + bool getIndirectByVal() const { + assert(TheKind == Indirect && "Invalid kind!"); + return BoolData; + } + void dump() const; }; diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index c63dab16a1..c58c0f6fbf 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -492,7 +492,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, break; case ABIArgInfo::Indirect: - Attributes |= llvm::Attribute::ByVal; + if (AI.getIndirectByVal()) + Attributes |= llvm::Attribute::ByVal; + Attributes |= llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign()); // byval disables readnone and readonly. diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index ebc3ecbd5c..a9d883b857 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -86,6 +86,27 @@ static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { return true; } +/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either +/// a non-trivial destructor or a non-trivial copy constructor. +static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) { + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + + return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor(); +} + +/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is +/// a record type with either a non-trivial destructor or a non-trivial copy +/// constructor. +static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + + return hasNonTrivialDestructorOrCopyConstructor(RT); +} + /// isSingleElementStruct - Determine if a structure is a "single /// element struct", i.e. it has exactly one non-empty field or /// exactly one field which is itself a single element @@ -717,6 +738,12 @@ void X86_64ABIInfo::classify(QualType Ty, if (Size > 128) return; + // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial + // copy constructor or a non-trivial destructor, it is passed by invisible + // reference. + if (hasNonTrivialDestructorOrCopyConstructor(RT)) + return; + const RecordDecl *RD = RT->getDecl(); // Assume variable sized types are passed in memory. @@ -830,8 +857,10 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty); + // FIXME: Set alignment correctly. - return ABIArgInfo::getIndirect(0); + return ABIArgInfo::getIndirect(0, ByVal); } ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp new file mode 100644 index 0000000000..426c867a7b --- /dev/null +++ b/test/CodeGenCXX/x86_64-arguments.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s && +struct A { ~A(); }; + +// RUN: grep 'define void @_Z2f11A(.struct.A\* .a)' %t && +void f1(A a) { } + +// RUN: grep 'define void @_Z2f2v(.struct.A\* noalias sret .agg.result)' %t && +A f2() { return A(); } + +// RUN: true |