From 20759ad54c8d0f20a84739528bf6efd06b0a1404 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Wed, 16 Sep 2009 15:53:40 +0000 Subject: [PATCH] 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. llvm-svn: 82050 --- clang/clang.xcodeproj/project.pbxproj | 2 +- clang/lib/CodeGen/ABIInfo.h | 18 ++++++++----- clang/lib/CodeGen/CGCall.cpp | 4 ++- clang/lib/CodeGen/TargetABIInfo.cpp | 31 +++++++++++++++++++++- clang/test/CodeGenCXX/x86_64-arguments.cpp | 10 +++++++ 5 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 clang/test/CodeGenCXX/x86_64-arguments.cpp diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index e5275dcb2523..119b4f501fd4 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/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 = ""; tabWidth = 2; }; 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = ""; tabWidth = 2; }; 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = ""; tabWidth = 2; }; - 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = ""; }; + 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = ""; 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 = ""; tabWidth = 2; }; 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = ""; tabWidth = 2; }; 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = ""; tabWidth = 2; }; diff --git a/clang/lib/CodeGen/ABIInfo.h b/clang/lib/CodeGen/ABIInfo.h index c1a9481c4b1e..1ab2f55295fa 100644 --- a/clang/lib/CodeGen/ABIInfo.h +++ b/clang/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/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index c63dab16a139..c58c0f6fbf0c 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/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/clang/lib/CodeGen/TargetABIInfo.cpp b/clang/lib/CodeGen/TargetABIInfo.cpp index ebc3ecbd5cce..a9d883b8579c 100644 --- a/clang/lib/CodeGen/TargetABIInfo.cpp +++ b/clang/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(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(); + 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/clang/test/CodeGenCXX/x86_64-arguments.cpp b/clang/test/CodeGenCXX/x86_64-arguments.cpp new file mode 100644 index 000000000000..426c867a7b6b --- /dev/null +++ b/clang/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