summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-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