aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-09-16 15:53:40 +0000
committerAnders Carlsson <andersca@mac.com>2009-09-16 15:53:40 +0000
commit0a8f847e97f40cce51dc69051b964732333dc028 (patch)
treeeb78e940410796b475e4b0c4345d2f5cbba63d10
parent37473829cb2308af5b268a2d58bf3d7fa2056610 (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.pbxproj2
-rw-r--r--lib/CodeGen/ABIInfo.h18
-rw-r--r--lib/CodeGen/CGCall.cpp4
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp31
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp10
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