[PATCH] D53925: [modules] Defer emission of inline key functions.
Vassil Vassilev via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 31 03:47:39 PDT 2018
v.g.vassilev created this revision.
v.g.vassilev added reviewers: rsmith, bruno.
Herald added a subscriber: cfe-commits.
If the ABI supports inline key functions we must emit them eagerly. The generic reason is that CodeGen might assume they are emitted and generate a reference to the vtable. In deserialization this rule becomes a little less clear because if a reference is generated, CodeGen will make a request and we will emit the vtable on demand.
This patch improves the performance of loading modules by slimming down the EAGERLY_DESERIALIZED_DECLS sections. It is equivalent to 'pinning' the vtable, with two benefits: (a) it does not require expertise in modules to find out that outlining the key function brings performance; (b) it also helps with third-party codebases.
We ran this change through our codebase and we saw no observable changes in behavior.
Patch by Yuka Takahashi and me!
Repository:
rC Clang
https://reviews.llvm.org/D53925
Files:
include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Serialization/ASTWriterDecl.cpp
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -2264,6 +2264,19 @@
return false;
}
+ // If the ABI supports inline key functions we must emit them eagerly. The
+ // generic reason is that CodeGen might assume they are emitted and generate a
+ // reference to the vtable. In deserialization this rule becomes a little less
+ // clear because if a reference is generated, CodeGen will make a request and
+ // we will emit the vtable on demand.
+ //
+ // This change in behavior is driven mostly by performance considerations and
+ // is equivalent in outlining the key function (aka pinning the vtable). It
+ // also works in cases where we cannot modify the source code.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
+ if (Context.isKeyFunction(MD))
+ return false;
+
return Context.DeclMustBeEmitted(D);
}
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -9700,6 +9700,20 @@
basicGVALinkageForVariable(*this, VD)));
}
+bool ASTContext::isKeyFunction(const CXXMethodDecl *MD) {
+ assert(MD);
+
+ if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+ const CXXRecordDecl *RD = MD->getParent();
+ if (MD->isOutOfLine() && RD->isDynamicClass()) {
+ const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD);
+ if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
+ return true;
+ }
+ }
+ return false;
+}
+
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
@@ -9781,18 +9795,11 @@
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return true;
- // The key function for a class is required. This rule only comes
+ // The key function for a class is required. This rule only comes
// into play when inline functions can be key functions, though.
- if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const CXXRecordDecl *RD = MD->getParent();
- if (MD->isOutOfLine() && RD->isDynamicClass()) {
- const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD);
- if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
- return true;
- }
- }
- }
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ if (isKeyFunction(MD))
+ return true;
GVALinkage Linkage = GetGVALinkageForFunction(FD);
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -2733,6 +2733,12 @@
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
+ /// Determines if the decl is the key function for a class.
+ ///
+ /// \ returns true if the function is the key and it was inline requiring
+ /// emission even if it is not used.
+ bool isKeyFunction(const CXXMethodDecl *MD);
+
/// Determines if the decl can be CodeGen'ed or deserialized from PCH
/// lazily, only when used; this is only relevant for function or file scoped
/// var definitions.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D53925.171885.patch
Type: text/x-patch
Size: 3498 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20181031/ac7472d6/attachment-0001.bin>
More information about the cfe-commits
mailing list