diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/CodeGen/CGCXXABI.cpp | 31 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 4 | ||||
| -rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 33 |
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; } |

