Skip to content

Commit 2bff1e0

Browse files
authored
Merge pull request #61071 from hamishknight/walk-that-way
2 parents 57d8231 + b582dbf commit 2bff1e0

File tree

2 files changed

+84
-37
lines changed

2 files changed

+84
-37
lines changed

lib/SIL/IR/SILProfiler.cpp

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,25 @@ visitFunctionDecl(ASTWalker &Walker, AbstractFunctionDecl *AFD, F Func) {
187187
return ASTWalker::Action::SkipChildren();
188188
}
189189

190-
/// Whether to skip visitation of an expression. Children of skipped exprs
191-
/// should still be visited.
192-
static bool skipExpr(Expr *E) {
193-
return !E->getStartLoc().isValid() || !E->getEndLoc().isValid();
190+
/// Whether to skip visitation of an expression. If the expression should be
191+
/// skipped, a walker action is returned that determines whether or not the
192+
/// children should also be skipped.
193+
static Optional<ASTWalker::PreWalkResult<Expr *>>
194+
shouldSkipExpr(Expr *E, ASTWalker::ParentTy Parent) {
195+
using Action = ASTWalker::Action;
196+
using Result = ASTWalker::PreWalkResult<Expr *>;
197+
198+
// Profiling for closures should be handled separately. Do not visit
199+
// closure expressions twice.
200+
if (isa<AbstractClosureExpr>(E) && !Parent.isNull())
201+
return Result(Action::SkipChildren(E));
202+
203+
// Expressions with no location should be skipped, but we still want to visit
204+
// their children.
205+
if (E->getStartLoc().isInvalid() || E->getEndLoc().isInvalid())
206+
return Result(Action::Continue(E));
207+
208+
return None;
194209
}
195210

196211
/// Whether the children of an unmapped decl should still be walked.
@@ -262,14 +277,16 @@ struct MapRegionCounters : public ASTWalker {
262277
return Action::Continue(S);
263278
}
264279

265-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
266-
if (skipExpr(E))
267-
return Action::Continue(E);
280+
PreWalkAction walkToParameterListPre(ParameterList *PL) override {
281+
// We don't walk into parameter lists. Default arguments should be visited
282+
// directly.
283+
// FIXME: We don't yet profile default argument generators at all.
284+
return Action::SkipChildren();
285+
}
268286

269-
// Profiling for closures should be handled separately. Do not visit
270-
// closure expressions twice.
271-
if (isa<AbstractClosureExpr>(E) && !Parent.isNull())
272-
return Action::SkipChildren(E);
287+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
288+
if (auto SkipAction = shouldSkipExpr(E, Parent))
289+
return *SkipAction;
273290

274291
// If AST visitation begins with an expression, the counter map must be
275292
// empty. Set up a counter for the root.
@@ -648,14 +665,16 @@ struct PGOMapping : public ASTWalker {
648665
return Action::Continue(S);
649666
}
650667

651-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
652-
if (skipExpr(E))
653-
return Action::Continue(E);
668+
PreWalkAction walkToParameterListPre(ParameterList *PL) override {
669+
// We don't walk into parameter lists. Default arguments should be visited
670+
// directly.
671+
// FIXME: We don't yet profile default argument generators at all.
672+
return Action::SkipChildren();
673+
}
654674

655-
// Profiling for closures should be handled separately. Do not visit
656-
// closure expressions twice.
657-
if (isa<AbstractClosureExpr>(E) && !Parent.isNull())
658-
return Action::SkipChildren(E);
675+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
676+
if (auto SkipAction = shouldSkipExpr(E, Parent))
677+
return *SkipAction;
659678

660679
unsigned parent = getParentCounter();
661680

@@ -1146,14 +1165,21 @@ struct CoverageMapping : public ASTWalker {
11461165
return Action::Continue(S);
11471166
}
11481167

1149-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
1150-
if (skipExpr(E))
1151-
return Action::Continue(E);
1168+
PreWalkAction walkToParameterListPre(ParameterList *PL) override {
1169+
// We don't walk into parameter lists. Default arguments should be visited
1170+
// directly.
1171+
// FIXME: We don't yet generate coverage for default argument generators at
1172+
// all. This is inconsistent with property initializers, which are
1173+
// effectively default values too. Seems like coverage doesn't offer much
1174+
// benefit in these cases, as they're unlikely to have side effects, and
1175+
// the values can be exercized explicitly, but we should probably at least
1176+
// have a consistent behavior for both no matter what we choose here.
1177+
return Action::SkipChildren();
1178+
}
11521179

1153-
// Profiling for closures should be handled separately. Do not visit
1154-
// closure expressions twice.
1155-
if (isa<AbstractClosureExpr>(E) && !Parent.isNull())
1156-
return Action::SkipChildren(E);
1180+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
1181+
if (auto SkipAction = shouldSkipExpr(E, Parent))
1182+
return *SkipAction;
11571183

11581184
// If we're in an 'incomplete' region, update it to include this node. This
11591185
// ensures we only create the region if needed.
@@ -1166,28 +1192,28 @@ struct CoverageMapping : public ASTWalker {
11661192
assert(RegionStack.empty() &&
11671193
"Mapped a region before visiting the root?");
11681194
assignCounter(E);
1169-
pushRegion(E);
1170-
}
1171-
1172-
// If there isn't an active region, we may be visiting a default
1173-
// initializer for a function argument.
1174-
if (!RegionStack.empty()) {
1175-
if (auto *IE = dyn_cast<IfExpr>(E)) {
1176-
CounterExpr &ThenCounter = assignCounter(IE->getThenExpr());
1177-
assignCounter(IE->getElseExpr(),
1178-
CounterExpr::Sub(getCurrentCounter(), ThenCounter));
1179-
}
11801195
}
11811196

11821197
if (isa<LazyInitializerExpr>(E))
11831198
assignCounter(E);
11841199

1185-
if (hasCounter(E) && !Parent.isNull())
1200+
if (hasCounter(E))
11861201
pushRegion(E);
1202+
1203+
assert(!RegionStack.empty() && "Must be within a region");
1204+
1205+
if (auto *IE = dyn_cast<IfExpr>(E)) {
1206+
CounterExpr &ThenCounter = assignCounter(IE->getThenExpr());
1207+
assignCounter(IE->getElseExpr(),
1208+
CounterExpr::Sub(getCurrentCounter(), ThenCounter));
1209+
}
11871210
return Action::Continue(E);
11881211
}
11891212

11901213
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
1214+
if (shouldSkipExpr(E, Parent))
1215+
return Action::Continue(E);
1216+
11911217
if (hasCounter(E))
11921218
popRegions(E);
11931219

test/Profiler/coverage_pc_macro.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -pc-macro -profile-generate -profile-coverage-mapping -emit-sorted-sil -emit-sil -module-name coverage_pc_macro %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -pc-macro -profile-generate -profile-coverage-mapping -emit-ir %s
3+
4+
// Make sure the PCMacro transform doesn't cause coverage to crash.
5+
6+
public func __builtin_pc_before(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) {
7+
print("[\(moduleId):\(fileId)] [\(sl):\(sc)-\(el):\(ec)] pc before")
8+
}
9+
10+
public func __builtin_pc_after(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) {
11+
print("[\(moduleId):\(fileId)] [\(sl):\(sc)-\(el):\(ec)] pc after")
12+
}
13+
14+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pc_macro3fooySiSbF"
15+
func foo(_ x: Bool) -> Int {
16+
if x {
17+
return 5
18+
} else {
19+
return 7
20+
}
21+
}

0 commit comments

Comments
 (0)