summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorAkira Hatanaka <ahatanaka@apple.com>2018-02-05 20:23:22 +0000
committerAkira Hatanaka <ahatanaka@apple.com>2018-02-05 20:23:22 +0000
commit02914dc1278cf9b472e9cd4357d641b5dd3f5834 (patch)
treeea2b88bc4177716dd38b8cacae2c87d7d90567ff /clang/lib/CodeGen
parent02f6845095ee1ea0e54824a650a8f4c5d0ffd156 (diff)
downloadbcm5719-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.cpp7
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp2
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp4
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp63
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;
}
OpenPOWER on IntegriCloud