Skip to content

Commit 0ca0d0d

Browse files
authored
Small refactoring to Extract for compile time. (#4444)
AFAICT #4363 made builds of extract.cpp go from ~15s to ~35s. I'm not sure how to really improve on this, short of adding boilerplate to the types in order to reduce template use (e.g., instead of using struct reflection to return fields, we could have something that directly returns fields). But, this switch to `MaybeTrace` seems to be about a 20% build time improvement (down to ~30s), with `noinline` accounting for a part of that.
1 parent 577fda1 commit 0ca0d0d

File tree

1 file changed

+58
-89
lines changed

1 file changed

+58
-89
lines changed

toolchain/parse/extract.cpp

Lines changed: 58 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ class NodeExtractor {
7575
auto ExtractTupleLikeType(std::index_sequence<Index...> /*indices*/,
7676
std::tuple<U...>* /*type*/) -> std::optional<T>;
7777

78+
// Split out trace logic. The noinline saves a few seconds on compilation.
79+
template <typename... ArgT>
80+
[[clang::noinline]] auto MaybeTrace(llvm::StringLiteral format,
81+
ArgT... args) const -> void {
82+
if (trace_) {
83+
*trace_ << llvm::formatv(format.data(), args...);
84+
}
85+
}
86+
7887
private:
7988
const TreeAndSubtrees* tree_;
8089
const Lex::TokenizedBuffer* tokens_;
@@ -113,34 +122,25 @@ template <>
113122
struct Extractable<NodeId> {
114123
static auto Extract(NodeExtractor& extractor) -> std::optional<NodeId> {
115124
if (extractor.at_end()) {
116-
if (auto* trace = extractor.trace()) {
117-
*trace << "NodeId error: no more children\n";
118-
}
125+
extractor.MaybeTrace("NodeId error: no more children\n");
119126
return std::nullopt;
120127
}
121-
if (auto* trace = extractor.trace()) {
122-
*trace << "NodeId: " << extractor.kind() << " consumed\n";
123-
}
128+
extractor.MaybeTrace("NodeId: {0} consumed\n", extractor.kind());
124129
return extractor.ExtractNode();
125130
}
126131
};
127132

128133
auto NodeExtractor::MatchesNodeIdForKind(NodeKind expected_kind) const -> bool {
129-
if (at_end() || kind() != expected_kind) {
130-
if (trace_) {
131-
if (at_end()) {
132-
*trace_ << "NodeIdForKind error: no more children, expected "
133-
<< expected_kind << "\n";
134-
} else {
135-
*trace_ << "NodeIdForKind error: wrong kind " << kind() << ", expected "
136-
<< expected_kind << "\n";
137-
}
138-
}
134+
if (at_end()) {
135+
MaybeTrace("NodeIdForKind error: no more children, expected {0}\n",
136+
expected_kind);
137+
return false;
138+
} else if (kind() != expected_kind) {
139+
MaybeTrace("NodeIdForKind error: wrong kind {0}, expected {1}\n", kind(),
140+
expected_kind);
139141
return false;
140142
}
141-
if (trace_) {
142-
*trace_ << "NodeIdForKind: " << expected_kind << " consumed\n";
143-
}
143+
MaybeTrace("NodeIdForKind: {0} consumed\n", expected_kind);
144144
return true;
145145
}
146146

@@ -160,21 +160,15 @@ struct Extractable<NodeIdForKind<Kind>> {
160160

161161
auto NodeExtractor::MatchesNodeIdInCategory(NodeCategory category) const
162162
-> bool {
163-
if (at_end() || !kind().category().HasAnyOf(category)) {
164-
if (trace_) {
165-
*trace_ << "NodeIdInCategory " << category << " error: ";
166-
if (at_end()) {
167-
*trace_ << "no more children\n";
168-
} else {
169-
*trace_ << "kind " << kind() << " doesn't match\n";
170-
}
171-
}
163+
if (at_end()) {
164+
MaybeTrace("NodeIdInCategory {0} error: no more children\n", category);
165+
return false;
166+
} else if (!kind().category().HasAnyOf(category)) {
167+
MaybeTrace("NodeIdInCategory {0} error: kind {1} doesn't match\n", category,
168+
kind());
172169
return false;
173170
}
174-
if (trace_) {
175-
*trace_ << "NodeIdInCategory " << category << ": kind " << kind()
176-
<< " consumed\n";
177-
}
171+
MaybeTrace("NodeIdInCategory {0}: kind {1} consumed\n", category, kind());
178172
return true;
179173
}
180174

@@ -200,19 +194,18 @@ auto NodeExtractor::MatchesNodeIdOneOf(
200194
}
201195
};
202196
auto node_kind = kind();
203-
if (at_end() ||
204-
std::find(kinds.begin(), kinds.end(), node_kind) == kinds.end()) {
197+
if (at_end()) {
205198
if (trace_) {
206-
if (at_end()) {
207-
*trace_ << "NodeIdOneOf error: no more children, expected ";
208-
trace_kinds();
209-
*trace_ << "\n";
210-
} else {
211-
*trace_ << "NodeIdOneOf error: wrong kind " << node_kind
212-
<< ", expected ";
213-
trace_kinds();
214-
*trace_ << "\n";
215-
}
199+
*trace_ << "NodeIdOneOf error: no more children, expected ";
200+
trace_kinds();
201+
*trace_ << "\n";
202+
}
203+
return false;
204+
} else if (std::find(kinds.begin(), kinds.end(), node_kind) == kinds.end()) {
205+
if (trace_) {
206+
*trace_ << "NodeIdOneOf error: wrong kind " << node_kind << ", expected ";
207+
trace_kinds();
208+
*trace_ << "\n";
216209
}
217210
return false;
218211
}
@@ -242,20 +235,17 @@ struct Extractable<NodeIdOneOf<T...>> {
242235
template <typename T>
243236
struct Extractable<NodeIdNot<T>> {
244237
static auto Extract(NodeExtractor& extractor) -> std::optional<NodeIdNot<T>> {
245-
if (extractor.at_end() || extractor.kind() == T::Kind) {
246-
if (auto* trace = extractor.trace()) {
247-
if (extractor.at_end()) {
248-
*trace << "NodeIdNot " << T::Kind << " error: no more children\n";
249-
} else {
250-
*trace << "NodeIdNot error: unexpected " << T::Kind << "\n";
251-
}
252-
}
238+
// This converts NodeKind::Definition to NodeKind.
239+
constexpr NodeKind Kind = T::Kind;
240+
if (extractor.at_end()) {
241+
extractor.MaybeTrace("NodeIdNot {0} error: no more children\n", Kind);
242+
return std::nullopt;
243+
} else if (extractor.kind() == Kind) {
244+
extractor.MaybeTrace("NodeIdNot error: unexpected {0}\n", Kind);
253245
return std::nullopt;
254246
}
255-
if (auto* trace = extractor.trace()) {
256-
*trace << "NodeIdNot " << T::Kind << ": " << extractor.kind()
257-
<< " consumed\n";
258-
}
247+
extractor.MaybeTrace("NodeIdNot {0}: {1} consumed\n", Kind,
248+
extractor.kind());
259249
return NodeIdNot<T>(extractor.ExtractNode());
260250
}
261251
};
@@ -265,9 +255,7 @@ template <typename T>
265255
struct Extractable<llvm::SmallVector<T>> {
266256
static auto Extract(NodeExtractor& extractor)
267257
-> std::optional<llvm::SmallVector<T>> {
268-
if (auto* trace = extractor.trace()) {
269-
*trace << "Vector: begin\n";
270-
}
258+
extractor.MaybeTrace("Vector: begin\n");
271259
llvm::SmallVector<T> result;
272260
while (!extractor.at_end()) {
273261
auto checkpoint = extractor.Checkpoint();
@@ -279,9 +267,7 @@ struct Extractable<llvm::SmallVector<T>> {
279267
result.push_back(*item);
280268
}
281269
std::reverse(result.begin(), result.end());
282-
if (auto* trace = extractor.trace()) {
283-
*trace << "Vector: end\n";
284-
}
270+
extractor.MaybeTrace("Vector: end\n");
285271
return result;
286272
}
287273
};
@@ -292,32 +278,23 @@ template <typename T>
292278
struct Extractable<std::optional<T>> {
293279
static auto Extract(NodeExtractor& extractor)
294280
-> std::optional<std::optional<T>> {
295-
if (auto* trace = extractor.trace()) {
296-
*trace << "Optional " << typeid(T).name() << ": begin\n";
297-
}
281+
extractor.MaybeTrace("Optional {0}: begin\n", typeid(T).name());
298282
auto checkpoint = extractor.Checkpoint();
299283
std::optional<T> value = Extractable<T>::Extract(extractor);
300284
if (value) {
301-
if (auto* trace = extractor.trace()) {
302-
*trace << "Optional " << typeid(T).name() << ": found\n";
303-
}
304-
return value;
305-
}
306-
if (auto* trace = extractor.trace()) {
307-
*trace << "Optional " << typeid(T).name() << ": missing\n";
285+
extractor.MaybeTrace("Optional {0}: found\n", typeid(T).name());
286+
} else {
287+
extractor.MaybeTrace("Optional {0}: missing\n", typeid(T).name());
288+
extractor.RestoreCheckpoint(checkpoint);
308289
}
309-
extractor.RestoreCheckpoint(checkpoint);
310290
return value;
311291
}
312292
};
313293

314294
auto NodeExtractor::MatchesTokenKind(Lex::TokenKind expected_kind) const
315295
-> bool {
316296
if (!node_id_.is_valid()) {
317-
if (trace_) {
318-
*trace_ << "Token " << expected_kind
319-
<< " expected but processing root node\n";
320-
}
297+
MaybeTrace("Token {0} expected but processing root node\n", expected_kind);
321298
return false;
322299
}
323300
if (token_kind() != expected_kind) {
@@ -350,9 +327,7 @@ struct Extractable<Lex::TokenIndex> {
350327
static auto Extract(NodeExtractor& extractor)
351328
-> std::optional<Lex::TokenIndex> {
352329
if (!extractor.has_token()) {
353-
if (auto* trace = extractor.trace()) {
354-
*trace << "Token expected but processing root node\n";
355-
}
330+
extractor.MaybeTrace("Token expected but processing root node\n");
356331
return std::nullopt;
357332
}
358333
return extractor.token();
@@ -364,9 +339,7 @@ auto NodeExtractor::ExtractTupleLikeType(
364339
std::index_sequence<Index...> /*indices*/, std::tuple<U...>* /*type*/)
365340
-> std::optional<T> {
366341
std::tuple<std::optional<U>...> fields;
367-
if (trace_) {
368-
*trace_ << "Aggregate " << typeid(T).name() << ": begin\n";
369-
}
342+
MaybeTrace("Aggregate {0}: begin\n", typeid(T).name());
370343
// Use a fold over the `=` operator to parse fields from right to left.
371344
[[maybe_unused]] int unused;
372345
bool ok = true;
@@ -375,15 +348,11 @@ auto NodeExtractor::ExtractTupleLikeType(
375348
.has_value()),
376349
unused) = ... = 0));
377350
if (!ok) {
378-
if (trace_) {
379-
*trace_ << "Aggregate " << typeid(T).name() << ": error\n";
380-
}
351+
MaybeTrace("Aggregate {0}: error\n", typeid(T).name());
381352
return std::nullopt;
382353
}
383354

384-
if (trace_) {
385-
*trace_ << "Aggregate " << typeid(T).name() << ": success\n";
386-
}
355+
MaybeTrace("Aggregate {0}: success\n", typeid(T).name());
387356
return T{std::move(std::get<Index>(fields).value())...};
388357
}
389358

0 commit comments

Comments
 (0)