Skip to content

Commit b7d3f50

Browse files
committed
[Profiler] Limit decl walking behavior
Unify the mapped behavior with the unmapped behavior and only ever walk into a pattern binding decls, top-level code decls, and non-nested functions. This avoids walking into e.g nested types, leading to duplicate coverage. We don't need to handle the unmapped behavior separately, as top-level code decls are always explicit, and non-nested functions are always checked when we create the profiler. rdar://99963912
1 parent 30568a6 commit b7d3f50

File tree

3 files changed

+43
-30
lines changed

3 files changed

+43
-30
lines changed

lib/SIL/IR/SILProfiler.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,9 @@ shouldSkipExpr(Expr *E, ASTWalker::ParentTy Parent) {
211211
return None;
212212
}
213213

214-
/// Whether the children of an unmapped decl should still be walked.
215-
static bool shouldWalkUnmappedDecl(const Decl *D) {
214+
/// Whether the children of a decl that isn't explicitly handled should be
215+
/// walked.
216+
static bool shouldWalkIntoUnhandledDecl(const Decl *D) {
216217
// We want to walk into the initializer for a pattern binding decl. This
217218
// allows us to map LazyInitializerExprs.
218219
return isa<PatternBindingDecl>(D);
@@ -252,15 +253,13 @@ struct MapRegionCounters : public ASTWalker {
252253
}
253254

254255
PreWalkAction walkToDeclPre(Decl *D) override {
255-
if (isUnmapped(D))
256-
return Action::VisitChildrenIf(shouldWalkUnmappedDecl(D));
257-
258256
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
259257
return visitFunctionDecl(*this, AFD, [&] { mapRegion(AFD->getBody()); });
260258
} else if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
261259
mapRegion(TLCD->getBody());
260+
return Action::Continue();
262261
}
263-
return Action::Continue();
262+
return Action::VisitChildrenIf(shouldWalkIntoUnhandledDecl(D));
264263
}
265264

266265
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
@@ -601,17 +600,16 @@ struct PGOMapping : public ASTWalker {
601600
}
602601

603602
PreWalkAction walkToDeclPre(Decl *D) override {
604-
if (isUnmapped(D))
605-
return Action::VisitChildrenIf(shouldWalkUnmappedDecl(D));
606603
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
607604
return visitFunctionDecl(*this, AFD, [&] {
608605
setKnownExecutionCount(AFD->getBody());
609606
});
610607
}
611-
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
608+
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
612609
setKnownExecutionCount(TLCD->getBody());
613-
614-
return Action::Continue();
610+
return Action::Continue();
611+
}
612+
return Action::VisitChildrenIf(shouldWalkIntoUnhandledDecl(D));
615613
}
616614

617615
LazyInitializerWalking getLazyInitializerWalkingBehavior() override {
@@ -974,18 +972,16 @@ struct CoverageMapping : public ASTWalker {
974972
}
975973

976974
PreWalkAction walkToDeclPre(Decl *D) override {
977-
if (isUnmapped(D))
978-
return Action::VisitChildrenIf(shouldWalkUnmappedDecl(D));
979-
980975
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
981976
return visitFunctionDecl(*this, AFD, [&] {
982977
assignCounter(AFD->getBody());
983978
});
984979
} else if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
985980
assignCounter(TLCD->getBody());
986981
ImplicitTopLevelBody = TLCD->getBody();
982+
return Action::Continue();
987983
}
988-
return Action::Continue();
984+
return Action::VisitChildrenIf(shouldWalkIntoUnhandledDecl(D));
989985
}
990986

991987
PostWalkAction walkToDeclPost(Decl *D) override {

test/Profiler/coverage_nested.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-frontend -emit-sil -profile-generate -profile-coverage-mapping -Xllvm -sil-full-demangle -emit-sorted-sil -module-name coverage_nested %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -profile-generate -profile-coverage-mapping -emit-ir %s
3+
4+
// https://github.com/apple/swift/issues/61129 – Make sure we don't emit
5+
// duplicate coverage for a nested type.
6+
7+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s15coverage_nested13hasNestedTypeyyF" {{.*}} // coverage_nested.hasNestedType() -> ()
8+
// CHECK-NEXT: [[@LINE+2]]:22 -> [[@LINE+11]]:2 : 0
9+
// CHECK-NEXT: }
10+
func hasNestedType() {
11+
struct S {
12+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s15coverage_nested13hasNestedTypeyyF1SL_V1iSivpfi" {{.*}} // variable initialization expression of i : Swift.Int in S #1 in coverage_nested.hasNestedType() -> ()
13+
// CHECK-NEXT: [[@LINE+4]]:13 -> [[@LINE+4]]:30 : 0
14+
// CHECK-NEXT: [[@LINE+3]]:25 -> [[@LINE+3]]:26 : 1
15+
// CHECK-NEXT: [[@LINE+2]]:29 -> [[@LINE+2]]:30 : (0 - 1)
16+
// CHECK-NEXT: }
17+
var i = .random() ? 0 : 1
18+
}
19+
}
20+
21+
// CHECK-LABEL: sil_coverage_map {{.*}}// coverage_nested.call_auto_closure()
22+
// CHECK-NEXT: [[@LINE+3]]:26 -> [[@LINE+10]]:2 : 0
23+
// CHECK-NEXT: }
24+
25+
func call_auto_closure() {
26+
// CHECK-LABEL: sil_coverage_map {{.*}}// use_auto_closure #1 (@autoclosure () -> Swift.Bool) -> Swift.Bool in coverage_nested.call_auto_closure()
27+
// CHECK-NEXT: [[@LINE+1]]:63 -> [[@LINE+3]]:4 : 0
28+
func use_auto_closure(_ x: @autoclosure () -> Bool) -> Bool {
29+
return x() // CHECK-COV: {{ *}}[[@LINE]]|{{ *}}1
30+
}
31+
let _ = use_auto_closure(false || true)
32+
}

test/Profiler/coverage_nested_func.swift

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)