Skip to content

Commit 5aab237

Browse files
committed
[Profiler] Emit skipped regions for inactive #if branches
For any `#if` blocks in the function we're emitting, emit skipped ranges for the inactive clauses, including the syntax for the `#if` itself, since that should not be considered executable code. rdar://116860865
1 parent d31f768 commit 5aab237

File tree

3 files changed

+308
-3
lines changed

3 files changed

+308
-3
lines changed

lib/SIL/IR/SILProfiler.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,19 +1066,41 @@ struct CoverageMapping : public ASTWalker {
10661066
if (SourceRegions.empty())
10671067
return nullptr;
10681068

1069+
using MappedRegion = SILCoverageMap::MappedRegion;
1070+
10691071
llvm::coverage::CounterExpressionBuilder Builder;
1070-
std::vector<SILCoverageMap::MappedRegion> Regions;
1072+
std::vector<MappedRegion> Regions;
1073+
SourceRange OuterRange;
10711074
for (const auto &Region : SourceRegions) {
10721075
assert(Region.hasStartLoc() && "invalid region");
10731076
assert(Region.hasEndLoc() && "incomplete region");
10741077

1078+
// Build up the outer range from the union of all coverage regions.
1079+
SourceRange Range(Region.getStartLoc(), Region.getEndLoc());
1080+
if (!OuterRange) {
1081+
OuterRange = Range;
1082+
} else {
1083+
OuterRange.widen(Range);
1084+
}
1085+
10751086
auto Start = SM.getLineAndColumnInBuffer(Region.getStartLoc());
10761087
auto End = SM.getLineAndColumnInBuffer(Region.getEndLoc());
10771088
assert(Start.first <= End.first && "region start and end out of order");
10781089

10791090
auto Counter = Region.getCounter(CounterMap);
1080-
Regions.emplace_back(Start.first, Start.second, End.first, End.second,
1081-
Counter.expand(Builder, CounterIndices));
1091+
Regions.push_back(
1092+
MappedRegion::code(Start.first, Start.second, End.first, End.second,
1093+
Counter.expand(Builder, CounterIndices)));
1094+
}
1095+
// Add any skipped regions present in the outer range.
1096+
for (auto IfConfig : SF->getIfConfigsWithin(OuterRange)) {
1097+
for (auto SkipRange : IfConfig.getRangesWithoutActiveBody(SM)) {
1098+
auto Start = SM.getLineAndColumnInBuffer(SkipRange.getStart());
1099+
auto End = SM.getLineAndColumnInBuffer(SkipRange.getEnd());
1100+
assert(Start.first <= End.first && "region start and end out of order");
1101+
Regions.push_back(MappedRegion::skipped(Start.first, Start.second,
1102+
End.first, End.second));
1103+
}
10821104
}
10831105
return SILCoverageMap::create(M, SF, Filename, Name, PGOFuncName, Hash,
10841106
Regions, Builder.getExpressions());

test/Profiler/coverage_pound_if.swift

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -suppress-warnings -profile-generate -profile-coverage-mapping -emit-sorted-sil -emit-sil -module-name coverage_pound_if %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -profile-generate -profile-coverage-mapping -emit-ir %s
3+
4+
func poundIf1() -> Int {
5+
#if true
6+
#if true
7+
return 1
8+
#else
9+
return 2
10+
#endif
11+
#else
12+
#if true
13+
return 3
14+
#else
15+
return 4
16+
#endif
17+
#endif
18+
}
19+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If1SiyF"
20+
// CHECK-NEXT: [[@LINE-16]]:24 -> [[@LINE-2]]:2 : 0
21+
// CHECK-NEXT: [[@LINE-16]]:3 -> [[@LINE-16]]:11 : skipped
22+
// CHECK-NEXT: [[@LINE-16]]:5 -> [[@LINE-16]]:13 : skipped
23+
// CHECK-NEXT: [[@LINE-15]]:5 -> [[@LINE-13]]:11 : skipped
24+
// CHECK-NEXT: [[@LINE-13]]:3 -> [[@LINE-7]]:9 : skipped
25+
// CHECK-NEXT: }
26+
27+
func poundIf2(_ x: [Int]) -> [Int] {
28+
return x
29+
#if false
30+
.map { $0 + 1 }
31+
#endif
32+
}
33+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If2ySaySiGACF"
34+
// CHECK-NEXT: [[@LINE-7]]:36 -> [[@LINE-2]]:2 : 0
35+
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-4]]:9 : skipped
36+
// CHECK-NEXT: }
37+
38+
39+
func poundIf3() -> Any {
40+
#if false
41+
@objc
42+
#endif
43+
class C {}
44+
return C()
45+
}
46+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If3ypyF"
47+
// CHECK-NEXT: [[@LINE-8]]:24 -> [[@LINE-2]]:2 : 0
48+
// CHECK-NEXT: [[@LINE-8]]:1 -> [[@LINE-6]]:7 : skipped
49+
// CHECK-NEXT: }
50+
51+
func poundIf4(_ x: Bool) -> Int {
52+
switch x {
53+
#if true
54+
case true:
55+
return 0
56+
#else
57+
case false:
58+
return 0
59+
#endif
60+
#if false
61+
case false:
62+
return 1
63+
#endif
64+
case false:
65+
return 0
66+
}
67+
}
68+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If4ySiSbF"
69+
// CHECK-NEXT: [[@LINE-18]]:33 -> [[@LINE-2]]:2 : 0
70+
// CHECK-NEXT: [[@LINE-18]]:10 -> [[@LINE-18]]:11 : 0
71+
// CHECK-NEXT: [[@LINE-18]]:3 -> [[@LINE-18]]:11 : skipped
72+
// CHECK-NEXT: [[@LINE-18]]:3 -> [[@LINE-17]]:13 : 1
73+
// CHECK-NEXT: [[@LINE-17]]:3 -> [[@LINE-14]]:9 : skipped
74+
// CHECK-NEXT: [[@LINE-14]]:3 -> [[@LINE-11]]:9 : skipped
75+
// CHECK-NEXT: [[@LINE-11]]:3 -> [[@LINE-10]]:13 : 2
76+
// CHECK-NEXT: }
77+
78+
func poundIf5() {
79+
struct S {
80+
#if false
81+
var foo: Int
82+
#else
83+
var foo: Int
84+
#endif
85+
}
86+
}
87+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If5yyF"
88+
// CHECK-NEXT: [[@LINE-10]]:17 -> [[@LINE-2]]:2 : 0
89+
// CHECK-NEXT: [[@LINE-9]]:1 -> [[@LINE-7]]:6 : skipped
90+
// CHECK-NEXT: [[@LINE-6]]:1 -> [[@LINE-6]]:7 : skipped
91+
// CHECK-NEXT: }
92+
93+
func poundIf6() -> Int {
94+
#if true
95+
struct S {
96+
var foo: Int
97+
}
98+
#else
99+
struct S {
100+
var foo: Int
101+
}
102+
#endif
103+
return S(foo: 0).foo
104+
}
105+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If6SiyF"
106+
// CHECK-NEXT: [[@LINE-13]]:24 -> [[@LINE-2]]:2 : 0
107+
// CHECK-NEXT: [[@LINE-13]]:3 -> [[@LINE-13]]:11 : skipped
108+
// CHECK-NEXT: [[@LINE-10]]:3 -> [[@LINE-6]]:9 : skipped
109+
// CHECK-NEXT: }
110+
111+
func poundIf7() -> Int {
112+
#if false
113+
#endif
114+
return 0
115+
}
116+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If7SiyF"
117+
// CHECK-NEXT: [[@LINE-6]]:24 -> [[@LINE-2]]:2 : 0
118+
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-5]]:9 : skipped
119+
// CHECK-NEXT: }
120+
121+
func poundIf8() -> Int {
122+
#if true
123+
#endif
124+
return 0
125+
}
126+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If8SiyF"
127+
// CHECK-NEXT: [[@LINE-6]]:24 -> [[@LINE-2]]:2 : 0
128+
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-6]]:11 : skipped
129+
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-6]]:9 : skipped
130+
// CHECK-NEXT: }
131+
132+
func poundIf9() -> Int {
133+
#if true
134+
#else
135+
#endif
136+
return 0
137+
}
138+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If9SiyF"
139+
// CHECK-NEXT: [[@LINE-7]]:24 -> [[@LINE-2]]:2 : 0
140+
// CHECK-NEXT: [[@LINE-7]]:3 -> [[@LINE-7]]:11 : skipped
141+
// CHECK-NEXT: [[@LINE-7]]:3 -> [[@LINE-6]]:9 : skipped
142+
// CHECK-NEXT: }
143+
144+
func poundIf10() -> Int {
145+
#if true
146+
return 0
147+
#else
148+
return 1#endif
149+
}
150+
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B4If10SiyF"
151+
// CHECK-NEXT: [[@LINE-7]]:25 -> [[@LINE-2]]:2 : 0
152+
// CHECK-NEXT: [[@LINE-7]]:3 -> [[@LINE-7]]:11 : skipped
153+
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-5]]:17 : skipped
154+
// CHECK-NEXT: }
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-build-swift %s -profile-generate -profile-coverage-mapping -o %t/main
4+
5+
// This unusual use of 'sh' allows the path of the profraw file to be
6+
// substituted by %target-run.
7+
// RUN: %target-codesign %t/main
8+
// RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main
9+
10+
// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
11+
// RUN: %llvm-cov export -summary-only %t/main -instr-profile=%t/default.profdata | %FileCheck --check-prefix SUMMARY %s
12+
// RUN: %llvm-cov show %t/main -instr-profile=%t/default.profdata | %FileCheck --implicit-check-not "{{[ ]*\|[ ]*[0-9]+}}" %s
13+
14+
// REQUIRES: profile_runtime
15+
// REQUIRES: executable_test
16+
// REQUIRES: OS=macosx
17+
18+
// The line count here excludes the inactive regions.
19+
// SUMMARY: "lines":{"count":41,"covered":0
20+
21+
// This test works by marking active lines with the pattern. The implicit
22+
// CHECK-NOT in the FileCheck invocation ensures everything else is a skipped
23+
// region (or doesn't have any coverage mapping such as these comments).
24+
25+
func poundIfDecl() -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
26+
#if true
27+
#if true
28+
return 1 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
29+
#else
30+
return 2
31+
#endif
32+
#else
33+
#if true
34+
return 3
35+
#else
36+
return 4
37+
#endif
38+
#endif
39+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
40+
41+
func poundIfMember(
42+
_ x: [Int]
43+
) -> [Int] { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
44+
return x // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
45+
#if false
46+
.map { $0 + 1 }
47+
#endif
48+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
49+
50+
func poundIfAttr() -> Any { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
51+
#if false
52+
@objc
53+
#endif
54+
class C {} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
55+
return C() // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
56+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
57+
58+
func poundIfSwitch(
59+
_ x: Bool
60+
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
61+
switch x { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
62+
#if true
63+
case true: // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
64+
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
65+
#else
66+
case false:
67+
return 0
68+
#endif
69+
#if false
70+
case false:
71+
return 1
72+
#endif
73+
case false: // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
74+
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
75+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
76+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
77+
78+
func poundIfMember() { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
79+
struct S { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
80+
#if false
81+
var foo: Int
82+
#else
83+
var foo: Int // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
84+
#endif
85+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
86+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
87+
88+
func poundIfDecl2() -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
89+
#if true
90+
struct S { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
91+
var foo: Int // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
92+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
93+
#else
94+
struct S {
95+
var foo: Int
96+
}
97+
#endif
98+
return S(foo: 0).foo // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
99+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
100+
101+
func emptyPoundIf1(
102+
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
103+
#if false
104+
#endif
105+
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
106+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
107+
108+
func emptyPoundIf2(
109+
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
110+
#if true
111+
#endif
112+
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
113+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
114+
115+
func emptyPoundIf3(
116+
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
117+
#if true
118+
#else
119+
#endif
120+
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
121+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
122+
123+
func poundEndIfSameLine(
124+
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
125+
#if true
126+
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
127+
#else
128+
return 1#endif
129+
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}

0 commit comments

Comments
 (0)