Skip to content

Commit ab005ed

Browse files
committed
Refactor VariantMatcher::MatcherOps to reduce the amount of generated code.
Summary: Refactor VariantMatcher::MatcherOps to reduce the amount of generated code. - Make some code type agnostic and move it to the cpp file. - Return a DynTypedMatcher instead of storing the object in MatcherOps. This change reduces the number of symbols generated in Registry.cpp by ~19%, the object byte size by ~17% and the compilation time (in non-release mode) by ~20%. Reviewers: klimek Subscribers: klimek, cfe-commits Differential Revision: http://reviews.llvm.org/D5124 llvm-svn: 217152
1 parent 3c821c0 commit ab005ed

File tree

4 files changed

+126
-71
lines changed

4 files changed

+126
-71
lines changed

clang/include/clang/ASTMatchers/ASTMatchersInternal.h

+40-11
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,17 @@ class DynTypedMatcher {
342342
/// This version enables \c tryBind() on the \c DynTypedMatcher.
343343
template <typename T> inline DynTypedMatcher(const BindableMatcher<T> &M);
344344

345+
/// \brief Construct from a variadic function.
346+
typedef bool (*VariadicOperatorFunction)(
347+
const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder,
348+
BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
349+
static DynTypedMatcher
350+
constructVariadic(VariadicOperatorFunction Func,
351+
ArrayRef<DynTypedMatcher> InnerMatchers) {
352+
assert(InnerMatchers.size() > 0 && "Array must not be empty.");
353+
return DynTypedMatcher(new VariadicStorage(Func, InnerMatchers));
354+
}
355+
345356
/// \brief Returns true if the matcher matches the given \c DynNode.
346357
bool matches(const ast_type_traits::DynTypedNode DynNode,
347358
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const {
@@ -372,9 +383,9 @@ class DynTypedMatcher {
372383
/// This method verifies that the underlying matcher in \c Other can process
373384
/// nodes of types T.
374385
template <typename T> bool canConvertTo() const {
375-
return getSupportedKind().isBaseOf(
376-
ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
386+
return canConvertTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
377387
}
388+
bool canConvertTo(ast_type_traits::ASTNodeKind To) const;
378389

379390
/// \brief Construct a \c Matcher<T> interface around the dynamic matcher.
380391
///
@@ -416,9 +427,35 @@ class DynTypedMatcher {
416427
const uint64_t ID;
417428
};
418429

430+
class VariadicStorage : public MatcherStorage {
431+
public:
432+
VariadicStorage(VariadicOperatorFunction Func,
433+
ArrayRef<DynTypedMatcher> InnerMatchers)
434+
: MatcherStorage(InnerMatchers[0].getSupportedKind(),
435+
reinterpret_cast<uint64_t>(this)),
436+
Func(Func), InnerMatchers(InnerMatchers) {}
437+
438+
bool matches(const ast_type_traits::DynTypedNode DynNode,
439+
ASTMatchFinder *Finder,
440+
BoundNodesTreeBuilder *Builder) const override {
441+
return Func(DynNode, Finder, Builder, InnerMatchers);
442+
}
443+
444+
llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const override {
445+
return llvm::None;
446+
}
447+
448+
private:
449+
VariadicOperatorFunction Func;
450+
std::vector<DynTypedMatcher> InnerMatchers;
451+
};
452+
419453
/// \brief Typed implementation of \c MatcherStorage.
420454
template <typename T> class TypedMatcherStorage;
421455

456+
/// \brief Internal constructor for \c constructVariadic.
457+
DynTypedMatcher(MatcherStorage *Storage) : Storage(Storage) {}
458+
422459
IntrusiveRefCntPtr<const MatcherStorage> Storage;
423460
};
424461

@@ -460,16 +497,8 @@ inline DynTypedMatcher::DynTypedMatcher(const BindableMatcher<T> &M)
460497

461498
/// \brief Specialization of the conversion functions for QualType.
462499
///
463-
/// These specializations provide the Matcher<Type>->Matcher<QualType>
500+
/// This specialization provides the Matcher<Type>->Matcher<QualType>
464501
/// conversion that the static API does.
465-
template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const {
466-
const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind();
467-
return SourceKind.isSame(
468-
ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) ||
469-
SourceKind.isSame(
470-
ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>());
471-
}
472-
473502
template <>
474503
inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const {
475504
assert(canConvertTo<QualType>());

clang/include/clang/ASTMatchers/Dynamic/VariantValue.h

+38-53
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,25 @@ class VariantMatcher {
9393
/// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher.
9494
class MatcherOps {
9595
public:
96-
virtual ~MatcherOps();
97-
virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
98-
bool &IsExactMatch) const = 0;
99-
virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
100-
virtual void constructVariadicOperator(
96+
MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {}
97+
98+
bool canConstructFrom(const DynTypedMatcher &Matcher,
99+
bool &IsExactMatch) const;
100+
101+
/// \brief Convert \p Matcher the destination type and return it as a new
102+
/// DynTypedMatcher.
103+
virtual DynTypedMatcher
104+
convertMatcher(const DynTypedMatcher &Matcher) const = 0;
105+
106+
/// \brief Constructs a variadic typed matcher from \p InnerMatchers.
107+
/// Will try to convert each inner matcher to the destination type and
108+
/// return llvm::None if it fails to do so.
109+
llvm::Optional<DynTypedMatcher> constructVariadicOperator(
101110
ast_matchers::internal::VariadicOperatorFunction Func,
102-
ArrayRef<VariantMatcher> InnerMatchers) = 0;
111+
ArrayRef<VariantMatcher> InnerMatchers) const;
112+
113+
private:
114+
ast_type_traits::ASTNodeKind NodeKind;
103115
};
104116

105117
/// \brief Payload interface to be specialized by each matcher type.
@@ -110,7 +122,8 @@ class VariantMatcher {
110122
virtual ~Payload();
111123
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
112124
virtual std::string getTypeAsString() const = 0;
113-
virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
125+
virtual llvm::Optional<DynTypedMatcher>
126+
getTypedMatcher(const MatcherOps &Ops) const = 0;
114127
virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
115128
unsigned *Specificity) const = 0;
116129
};
@@ -158,9 +171,8 @@ class VariantMatcher {
158171
/// that can, the result would be ambiguous and false is returned.
159172
template <class T>
160173
bool hasTypedMatcher() const {
161-
TypedMatcherOps<T> Ops;
162-
if (Value) Value->makeTypedMatcher(Ops);
163-
return Ops.hasMatcher();
174+
if (!Value) return false;
175+
return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue();
164176
}
165177

166178
/// \brief Determines if the contained matcher can be converted to \p Kind.
@@ -182,10 +194,9 @@ class VariantMatcher {
182194
/// Asserts that \c hasTypedMatcher<T>() is true.
183195
template <class T>
184196
ast_matchers::internal::Matcher<T> getTypedMatcher() const {
185-
TypedMatcherOps<T> Ops;
186-
Value->makeTypedMatcher(Ops);
187-
assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false");
188-
return Ops.matcher();
197+
assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false");
198+
return Value->getTypedMatcher(TypedMatcherOps<T>())
199+
->template convertTo<T>();
189200
}
190201

191202
/// \brief String representation of the type of the value.
@@ -197,51 +208,25 @@ class VariantMatcher {
197208
private:
198209
explicit VariantMatcher(Payload *Value) : Value(Value) {}
199210

211+
template <typename T> struct TypedMatcherOps;
212+
200213
class SinglePayload;
201214
class PolymorphicPayload;
202215
class VariadicOpPayload;
203216

204-
template <typename T>
205-
class TypedMatcherOps : public MatcherOps {
206-
public:
207-
typedef ast_matchers::internal::Matcher<T> MatcherT;
208-
209-
virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
210-
bool &IsExactMatch) const {
211-
IsExactMatch = Matcher.getSupportedKind().isSame(
212-
ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
213-
return Matcher.canConvertTo<T>();
214-
}
215-
216-
virtual void constructFrom(const DynTypedMatcher& Matcher) {
217-
Out.reset(new MatcherT(Matcher.convertTo<T>()));
218-
}
219-
220-
virtual void constructVariadicOperator(
221-
ast_matchers::internal::VariadicOperatorFunction Func,
222-
ArrayRef<VariantMatcher> InnerMatchers) {
223-
std::vector<DynTypedMatcher> DynMatchers;
224-
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
225-
// Abort if any of the inner matchers can't be converted to
226-
// Matcher<T>.
227-
if (!InnerMatchers[i].hasTypedMatcher<T>()) {
228-
return;
229-
}
230-
DynMatchers.push_back(InnerMatchers[i].getTypedMatcher<T>());
231-
}
232-
Out.reset(new MatcherT(
233-
new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
234-
Func, DynMatchers)));
235-
}
236-
237-
bool hasMatcher() const { return Out.get() != nullptr; }
238-
const MatcherT &matcher() const { return *Out; }
217+
IntrusiveRefCntPtr<const Payload> Value;
218+
};
239219

240-
private:
241-
std::unique_ptr<MatcherT> Out;
242-
};
220+
template <typename T>
221+
struct VariantMatcher::TypedMatcherOps : VariantMatcher::MatcherOps {
222+
TypedMatcherOps()
223+
: MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {}
224+
typedef ast_matchers::internal::Matcher<T> MatcherT;
243225

244-
IntrusiveRefCntPtr<const Payload> Value;
226+
DynTypedMatcher
227+
convertMatcher(const DynTypedMatcher &Matcher) const override {
228+
return DynTypedMatcher(Matcher.convertTo<T>());
229+
}
245230
};
246231

247232
/// \brief Variant value class.

clang/lib/ASTMatchers/ASTMatchersInternal.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
2626
}
2727
}
2828

29+
bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
30+
const auto From = getSupportedKind();
31+
auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
32+
auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
33+
/// Mimic the implicit conversions of Matcher<>.
34+
/// - From Matcher<Type> to Matcher<QualType>
35+
if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
36+
/// - From Matcher<Base> to Matcher<Derived>
37+
return From.isBaseOf(To);
38+
}
39+
2940
DynTypedMatcher::MatcherStorage::~MatcherStorage() {}
3041

3142
void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {

clang/lib/ASTMatchers/Dynamic/VariantValue.cpp

+37-7
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,32 @@ bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const {
4949
return true;
5050
}
5151

52-
VariantMatcher::MatcherOps::~MatcherOps() {}
52+
bool
53+
VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher,
54+
bool &IsExactMatch) const {
55+
IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind);
56+
return Matcher.canConvertTo(NodeKind);
57+
}
58+
59+
llvm::Optional<DynTypedMatcher>
60+
VariantMatcher::MatcherOps::constructVariadicOperator(
61+
ast_matchers::internal::VariadicOperatorFunction Func,
62+
ArrayRef<VariantMatcher> InnerMatchers) const {
63+
std::vector<DynTypedMatcher> DynMatchers;
64+
for (const auto &InnerMatcher : InnerMatchers) {
65+
// Abort if any of the inner matchers can't be converted to
66+
// Matcher<T>.
67+
if (!InnerMatcher.Value)
68+
return llvm::None;
69+
llvm::Optional<DynTypedMatcher> Inner =
70+
InnerMatcher.Value->getTypedMatcher(*this);
71+
if (!Inner)
72+
return llvm::None;
73+
DynMatchers.push_back(*Inner);
74+
}
75+
return DynTypedMatcher::constructVariadic(Func, DynMatchers);
76+
}
77+
5378
VariantMatcher::Payload::~Payload() {}
5479

5580
class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
@@ -65,10 +90,12 @@ class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
6590
.str();
6691
}
6792

68-
void makeTypedMatcher(MatcherOps &Ops) const override {
93+
llvm::Optional<DynTypedMatcher>
94+
getTypedMatcher(const MatcherOps &Ops) const override {
6995
bool Ignore;
7096
if (Ops.canConstructFrom(Matcher, Ignore))
71-
Ops.constructFrom(Matcher);
97+
return Matcher;
98+
return llvm::None;
7299
}
73100

74101
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
@@ -104,7 +131,8 @@ class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
104131
return (Twine("Matcher<") + Inner + ">").str();
105132
}
106133

107-
void makeTypedMatcher(MatcherOps &Ops) const override {
134+
llvm::Optional<DynTypedMatcher>
135+
getTypedMatcher(const MatcherOps &Ops) const override {
108136
bool FoundIsExact = false;
109137
const DynTypedMatcher *Found = nullptr;
110138
int NumFound = 0;
@@ -124,7 +152,8 @@ class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
124152
}
125153
// We only succeed if we found exactly one, or if we found an exact match.
126154
if (Found && (FoundIsExact || NumFound == 1))
127-
Ops.constructFrom(*Found);
155+
return *Found;
156+
return llvm::None;
128157
}
129158

130159
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
@@ -165,8 +194,9 @@ class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
165194
return Inner;
166195
}
167196

168-
void makeTypedMatcher(MatcherOps &Ops) const override {
169-
Ops.constructVariadicOperator(Func, Args);
197+
llvm::Optional<DynTypedMatcher>
198+
getTypedMatcher(const MatcherOps &Ops) const override {
199+
return Ops.constructVariadicOperator(Func, Args);
170200
}
171201

172202
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,

0 commit comments

Comments
 (0)