summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-05-14 16:02:09 +0000
committerReid Kleckner <reid@kleckner.net>2014-05-14 16:02:09 +0000
commitcf87e10f9db91f0c4eed6c3f49e7b83ea2126660 (patch)
treead80663fb850439ea0c5b42f2b96b52dfa7253c1 /clang/lib/CodeGen
parente92ab94d4a291fedd7de6b47d801a9e937d5928a (diff)
downloadbcm5719-llvm-cf87e10f9db91f0c4eed6c3f49e7b83ea2126660.tar.gz
bcm5719-llvm-cf87e10f9db91f0c4eed6c3f49e7b83ea2126660.zip
Don't copy objects with trivial, deleted copy ctors
This affects both the Itanium and Microsoft C++ ABIs. This is in anticipation of a change to the Itanium C++ ABI, and should match GCC's current behavior. The new text will likely be: """ Pass an object of class type by value if every copy constructor and move constructor is deleted or trivial and at least one of them is not deleted, and the destructor is trivial. """ http://sourcerytools.com/pipermail/cxx-abi-dev/2014-May/002728.html On x86 Windows, we can mostly use the same logic, where we use inalloca instead of passing by address. However, on Win64, there are register parameters, and we have to do what MSVC does. MSVC ignores the presence of non-trivial move constructors and only considers the presence of non-trivial or deleted copy constructors. If a non-trivial or deleted copy ctor is present, it passes the argument indirectly. This change fixes bugs and makes us more ABI compatible with both GCC and MSVC. Fixes PR19668. Reviewers: rsmith Differential Revision: http://reviews.llvm.org/D3660 llvm-svn: 208786
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGCXXABI.cpp31
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h4
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp11
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp33
4 files changed, 69 insertions, 10 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp
index 2bb3907ef06..933fe2db208 100644
--- a/clang/lib/CodeGen/CGCXXABI.cpp
+++ b/clang/lib/CodeGen/CGCXXABI.cpp
@@ -28,6 +28,37 @@ void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
<< S;
}
+bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
+ // If RD has a non-trivial move or copy constructor, we cannot copy the
+ // argument.
+ if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor())
+ return false;
+
+ // If RD has a non-trivial destructor, we cannot copy the argument.
+ if (RD->hasNonTrivialDestructor())
+ return false;
+
+ // We can only copy the argument if there exists at least one trivial,
+ // non-deleted copy or move constructor.
+ // FIXME: This assumes that all lazily declared copy and move constructors are
+ // not deleted. This assumption might not be true in some corner cases.
+ bool CopyOrMoveDeleted = false;
+ for (const CXXConstructorDecl *CD : RD->ctors()) {
+ if (CD->isCopyConstructor() || CD->isMoveConstructor()) {
+ assert(CD->isTrivial());
+ // We had at least one undeleted trivial copy or move ctor. Return
+ // directly.
+ if (!CD->isDeleted())
+ return true;
+ CopyOrMoveDeleted = true;
+ }
+ }
+
+ // If all trivial copy and move constructors are deleted, we cannot copy the
+ // argument.
+ return !CopyOrMoveDeleted;
+}
+
llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
}
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index b6e85ca7e77..615ec23aa7d 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -112,6 +112,10 @@ public:
RAA_Indirect
};
+ /// Returns true if C++ allows us to copy the memory of an object of type RD
+ /// when it is passed as an argument.
+ bool canCopyArgument(const CXXRecordDecl *RD) const;
+
/// Returns how an argument of the given record type should be passed.
virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0;
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 201a7534776..e3605e1b9cb 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -55,9 +55,8 @@ public:
bool classifyReturnType(CGFunctionInfo &FI) const override;
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (!RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor())
+ // If C++ prohibits us from making a copy, pass by address.
+ if (!canCopyArgument(RD))
return RAA_Indirect;
return RAA_Default;
}
@@ -762,13 +761,11 @@ bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
if (!RD)
return false;
- // Return indirectly if we have a non-trivial copy ctor or non-trivial dtor.
- if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) {
+ // If C++ prohibits us from making a copy, return by address.
+ if (!canCopyArgument(RD)) {
FI.getReturnInfo() = ABIArgInfo::getIndirect(0, /*ByVal=*/false);
return true;
}
-
- // Otherwise, use the normal C ABI rules.
return false;
}
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 1b05b93b076..88a0d9ab474 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -404,19 +404,46 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
return RAA_Default;
case llvm::Triple::x86:
- // 32-bit x86 constructs non-trivial objects directly in outgoing argument
- // slots. LLVM uses the inalloca attribute to implement this.
- if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialDestructor())
+ // All record arguments are passed in memory on x86. Decide whether to
+ // construct the object directly in argument memory, or to construct the
+ // argument elsewhere and copy the bytes during the call.
+
+ // If C++ prohibits us from making a copy, construct the arguments directly
+ // into argument memory.
+ if (!canCopyArgument(RD))
return RAA_DirectInMemory;
+
+ // Otherwise, construct the argument into a temporary and copy the bytes
+ // into the outgoing argument memory.
return RAA_Default;
case llvm::Triple::x86_64:
// Win64 passes objects with non-trivial copy ctors indirectly.
if (RD->hasNonTrivialCopyConstructor())
return RAA_Indirect;
+
// Win64 passes objects larger than 8 bytes indirectly.
if (getContext().getTypeSize(RD->getTypeForDecl()) > 64)
return RAA_Indirect;
+
+ // We have a trivial copy constructor or no copy constructors, but we have
+ // to make sure it isn't deleted.
+ bool CopyDeleted = false;
+ for (const CXXConstructorDecl *CD : RD->ctors()) {
+ if (CD->isCopyConstructor()) {
+ assert(CD->isTrivial());
+ // We had at least one undeleted trivial copy ctor. Return directly.
+ if (!CD->isDeleted())
+ return RAA_Default;
+ CopyDeleted = true;
+ }
+ }
+
+ // The trivial copy constructor was deleted. Return indirectly.
+ if (CopyDeleted)
+ return RAA_Indirect;
+
+ // There were no copy ctors. Return in RAX.
return RAA_Default;
}
OpenPOWER on IntegriCloud