diff options
author | Samuel Benzaquen <sbenza@google.com> | 2014-10-01 15:08:07 +0000 |
---|---|---|
committer | Samuel Benzaquen <sbenza@google.com> | 2014-10-01 15:08:07 +0000 |
commit | f28d997083c5387220e41ca28cff12f6ae479357 (patch) | |
tree | 654c2c81ee9d3144aad15f8586505d047fde5f0e /clang/lib/ASTMatchers/ASTMatchersInternal.cpp | |
parent | c4c202a9a750912a76c9cb7cea2114426672071e (diff) | |
download | bcm5719-llvm-f28d997083c5387220e41ca28cff12f6ae479357.tar.gz bcm5719-llvm-f28d997083c5387220e41ca28cff12f6ae479357.zip |
Refactor Matcher<T> and DynTypedMatcher to reduce overhead of casts.
Summary:
This change introduces DynMatcherInterface and changes the internal
representation of DynTypedMatcher and Matcher<T> to use a generic
interface instead.
It removes unnecessary indirections and virtual function calls when
converting matchers by implicit and dynamic casts.
DynTypedMatcher now remembers the stricter type in the chain of casts
and checks it before calling into DynMatcherInterface.
This change improves our clang-tidy related benchmark by ~14%.
Also, it opens the door for more optimizations of this kind that are
coming in future changes.
As a side effect of removing these template instantiations, it also
speeds up compilation of Dynamic/Registry.cpp by ~17% and reduces the
number of
symbols generated by ~30%.
Reviewers: klimek
Subscribers: klimek, cfe-commits
Differential Revision: http://reviews.llvm.org/D5542
llvm-svn: 218769
Diffstat (limited to 'clang/lib/ASTMatchers/ASTMatchersInternal.cpp')
-rw-r--r-- | clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 109 |
1 files changed, 107 insertions, 2 deletions
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index b95004a6d43..4cff381f3f4 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -26,6 +26,113 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { } } +namespace { + +class VariadicMatcher : public DynMatcherInterface { + public: + VariadicMatcher(VariadicOperatorFunction Func, + std::vector<DynTypedMatcher> InnerMatchers) + : Func(Func), InnerMatchers(std::move(InnerMatchers)) {} + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Func(DynNode, Finder, Builder, InnerMatchers); + } + + private: + VariadicOperatorFunction Func; + std::vector<DynTypedMatcher> InnerMatchers; +}; + +class IdDynMatcher : public DynMatcherInterface { + public: + IdDynMatcher(StringRef ID, + const IntrusiveRefCntPtr<DynMatcherInterface> &InnerMatcher) + : ID(ID), InnerMatcher(InnerMatcher) {} + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder); + if (Result) Builder->setBinding(ID, DynNode); + return Result; + } + + private: + const std::string ID; + const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; +}; + +/// \brief Return the most derived type between \p Kind1 and \p Kind2. +/// +/// Return the null type if they are not related. +ast_type_traits::ASTNodeKind getMostDerivedType( + const ast_type_traits::ASTNodeKind Kind1, + const ast_type_traits::ASTNodeKind Kind2) { + if (Kind1.isBaseOf(Kind2)) return Kind2; + if (Kind2.isBaseOf(Kind1)) return Kind1; + return ast_type_traits::ASTNodeKind(); +} + +/// \brief Return the least derived type between \p Kind1 and \p Kind2. +/// +/// Return the null type if they are not related. +static ast_type_traits::ASTNodeKind getLeastDerivedType( + const ast_type_traits::ASTNodeKind Kind1, + const ast_type_traits::ASTNodeKind Kind2) { + if (Kind1.isBaseOf(Kind2)) return Kind1; + if (Kind2.isBaseOf(Kind1)) return Kind2; + return ast_type_traits::ASTNodeKind(); +} + +} // namespace + +DynTypedMatcher DynTypedMatcher::constructVariadic( + VariadicOperatorFunction Func, std::vector<DynTypedMatcher> InnerMatchers) { + assert(InnerMatchers.size() > 0 && "Array must not be empty."); + DynTypedMatcher Result = InnerMatchers[0]; + // Use the least derived type as the restriction for the wrapper. + // This allows mismatches to be resolved on the inner matchers. + for (const DynTypedMatcher &M : InnerMatchers) { + assert(Result.SupportedKind.isSame(M.SupportedKind) && + "SupportedKind must match!"); + Result.RestrictKind = + getLeastDerivedType(Result.RestrictKind, M.RestrictKind); + } + Result.Implementation = new VariadicMatcher(Func, std::move(InnerMatchers)); + return Result; +} + +DynTypedMatcher DynTypedMatcher::dynCastTo( + const ast_type_traits::ASTNodeKind Kind) const { + auto Copy = *this; + Copy.SupportedKind = Kind; + Copy.RestrictKind = getMostDerivedType(Kind, RestrictKind); + return Copy; +} + +bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + if (RestrictKind.isBaseOf(DynNode.getNodeKind()) && + Implementation->dynMatches(DynNode, Finder, Builder)) { + return true; + } + // Delete all bindings when a matcher does not match. + // This prevents unexpected exposure of bound nodes in unmatches + // branches of the match tree. + Builder->removeBindings([](const BoundNodesMap &) { return true; }); + return false; +} + +llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const { + if (!AllowBind) return llvm::None; + auto Result = *this; + Result.Implementation = new IdDynMatcher(ID, Result.Implementation); + return Result; +} + bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const { const auto From = getSupportedKind(); auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(); @@ -37,8 +144,6 @@ bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const { return From.isBaseOf(To); } -DynTypedMatcher::MatcherStorage::~MatcherStorage() {} - void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) { Bindings.push_back(Other.Bindings[i]); |