diff options
author | Akira Hatanaka <ahatanaka@apple.com> | 2018-02-05 20:23:22 +0000 |
---|---|---|
committer | Akira Hatanaka <ahatanaka@apple.com> | 2018-02-05 20:23:22 +0000 |
commit | 02914dc1278cf9b472e9cd4357d641b5dd3f5834 (patch) | |
tree | ea2b88bc4177716dd38b8cacae2c87d7d90567ff /clang/lib/CodeGen | |
parent | 02f6845095ee1ea0e54824a650a8f4c5d0ffd156 (diff) | |
download | bcm5719-llvm-02914dc1278cf9b472e9cd4357d641b5dd3f5834.tar.gz bcm5719-llvm-02914dc1278cf9b472e9cd4357d641b5dd3f5834.zip |
Add support for attribute 'trivial_abi'.
The 'trivial_abi' attribute can be applied to a C++ class, struct, or
union. It makes special functions of the annotated class (the destructor
and copy/move constructors) to be trivial for the purpose of calls and,
as a result, enables the annotated class or containing classes to be
passed or returned using the C ABI for the underlying type.
When a type that is considered trivial for the purpose of calls despite
having a non-trivial destructor (which happens only when the class type
or one of its subobjects is a 'trivial_abi' class) is passed to a
function, the callee is responsible for destroying the object.
For more background, see the discussions that took place on the mailing
list:
http://lists.llvm.org/pipermail/cfe-dev/2017-November/055955.html
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20180101/thread.html#214043
rdar://problem/35204524
Differential Revision: https://reviews.llvm.org/D41039
llvm-svn: 324269
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 7 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGDecl.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 63 |
4 files changed, 45 insertions, 31 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 655bc6659a9..d8b8e78ebf2 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -3144,7 +3144,6 @@ static void emitWritebacks(CodeGenFunction &CGF, static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF, const CallArgList &CallArgs) { - assert(CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()); ArrayRef<CallArgList::CallArgCleanup> Cleanups = CallArgs.getCleanupsToDeactivate(); // Iterate in reverse to increase the likelihood of popping the cleanup. @@ -3501,8 +3500,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // In the Microsoft C++ ABI, aggregate arguments are destructed by the callee. // However, we still have to push an EH-only cleanup in case we unwind before // we make it to the call. - if (HasAggregateEvalKind && - CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) { + if (HasAggregateEvalKind && getContext().isParamDestroyedInCallee(type)) { // If we're using inalloca, use the argument memory. Otherwise, use a // temporary. AggValueSlot Slot; @@ -3514,7 +3512,8 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, const CXXRecordDecl *RD = type->getAsCXXRecordDecl(); bool DestroyedInCallee = RD && RD->hasNonTrivialDestructor() && - CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default; + (CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default || + RD->hasTrivialABIOverride()); if (DestroyedInCallee) Slot.setExternallyDestructed(); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 6a2004828f9..d2168ce1b0b 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1868,7 +1868,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // Don't push a cleanup in a thunk for a method that will also emit a // cleanup. if (!IsScalar && !CurFuncIsThunk && - getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) { + getContext().isParamDestroyedInCallee(Ty)) { const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); if (RD && RD->hasNonTrivialDestructor()) pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 8fd0839487d..8963fc17b0c 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -68,8 +68,8 @@ public: if (CGM.getCodeGenOpts().getClangABICompat() <= CodeGenOptions::ClangABI::Ver4 || CGM.getTriple().getOS() == llvm::Triple::PS4) - return RD->hasNonTrivialDestructor() || - RD->hasNonTrivialCopyConstructor(); + return RD->hasNonTrivialDestructorForCall() || + RD->hasNonTrivialCopyConstructorForCall(); return !canCopyArgument(RD); } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index ffb3681c258..420d2843af8 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -820,19 +820,8 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const { return RAA_Default; case llvm::Triple::x86_64: - // If a class has a destructor, we'd really like to pass it indirectly - // because it allows us to elide copies. Unfortunately, MSVC makes that - // impossible for small types, which it will pass in a single register or - // stack slot. Most objects with dtors are large-ish, so handle that early. - // We can't call out all large objects as being indirect because there are - // multiple x64 calling conventions and the C++ ABI code shouldn't dictate - // how we pass large POD types. - // - // Note: This permits small classes with nontrivial destructors to be - // passed in registers, which is non-conforming. - if (RD->hasNonTrivialDestructor() && - getContext().getTypeSize(RD->getTypeForDecl()) > 64) - return RAA_Indirect; + bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false; + bool DtorIsTrivialForCall = false; // If a class has at least one non-deleted, trivial copy constructor, it // is passed according to the C ABI. Otherwise, it is passed indirectly. @@ -841,23 +830,49 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const { // passed in registers, so long as they *also* have a trivial copy ctor, // which is non-conforming. if (RD->needsImplicitCopyConstructor()) { - // If the copy ctor has not yet been declared, we can read its triviality - // off the AST. - if (!RD->defaultedCopyConstructorIsDeleted() && - RD->hasTrivialCopyConstructor()) - return RAA_Default; + if (!RD->defaultedCopyConstructorIsDeleted()) { + if (RD->hasTrivialCopyConstructor()) + CopyCtorIsTrivial = true; + if (RD->hasTrivialCopyConstructorForCall()) + CopyCtorIsTrivialForCall = true; + } } else { - // Otherwise, we need to find the copy constructor(s) and ask. for (const CXXConstructorDecl *CD : RD->ctors()) { - if (CD->isCopyConstructor()) { - // We had at least one nondeleted trivial copy ctor. Return directly. - if (!CD->isDeleted() && CD->isTrivial()) - return RAA_Default; + if (CD->isCopyConstructor() && !CD->isDeleted()) { + if (CD->isTrivial()) + CopyCtorIsTrivial = true; + if (CD->isTrivialForCall()) + CopyCtorIsTrivialForCall = true; } } } - // We have no trivial, non-deleted copy constructor. + if (RD->needsImplicitDestructor()) { + if (!RD->defaultedDestructorIsDeleted() && + RD->hasTrivialDestructorForCall()) + DtorIsTrivialForCall = true; + } else if (const auto *D = RD->getDestructor()) { + if (!D->isDeleted() && D->isTrivialForCall()) + DtorIsTrivialForCall = true; + } + + // If the copy ctor and dtor are both trivial-for-calls, pass direct. + if (CopyCtorIsTrivialForCall && DtorIsTrivialForCall) + return RAA_Default; + + // If a class has a destructor, we'd really like to pass it indirectly + // because it allows us to elide copies. Unfortunately, MSVC makes that + // impossible for small types, which it will pass in a single register or + // stack slot. Most objects with dtors are large-ish, so handle that early. + // We can't call out all large objects as being indirect because there are + // multiple x64 calling conventions and the C++ ABI code shouldn't dictate + // how we pass large POD types. + + // Note: This permits small classes with nontrivial destructors to be + // passed in registers, which is non-conforming. + if (CopyCtorIsTrivial && + getContext().getTypeSize(RD->getTypeForDecl()) <= 64) + return RAA_Default; return RAA_Indirect; } |