mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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
This commit is contained in:
@@ -1066,19 +1066,41 @@ public:
|
||||
if (SourceRegions.empty())
|
||||
return nullptr;
|
||||
|
||||
using MappedRegion = SILCoverageMap::MappedRegion;
|
||||
|
||||
llvm::coverage::CounterExpressionBuilder Builder;
|
||||
std::vector<SILCoverageMap::MappedRegion> Regions;
|
||||
std::vector<MappedRegion> Regions;
|
||||
SourceRange OuterRange;
|
||||
for (const auto &Region : SourceRegions) {
|
||||
assert(Region.hasStartLoc() && "invalid region");
|
||||
assert(Region.hasEndLoc() && "incomplete region");
|
||||
|
||||
// Build up the outer range from the union of all coverage regions.
|
||||
SourceRange Range(Region.getStartLoc(), Region.getEndLoc());
|
||||
if (!OuterRange) {
|
||||
OuterRange = Range;
|
||||
} else {
|
||||
OuterRange.widen(Range);
|
||||
}
|
||||
|
||||
auto Start = SM.getLineAndColumnInBuffer(Region.getStartLoc());
|
||||
auto End = SM.getLineAndColumnInBuffer(Region.getEndLoc());
|
||||
assert(Start.first <= End.first && "region start and end out of order");
|
||||
|
||||
auto Counter = Region.getCounter(CounterMap);
|
||||
Regions.emplace_back(Start.first, Start.second, End.first, End.second,
|
||||
Counter.expand(Builder, CounterIndices));
|
||||
Regions.push_back(
|
||||
MappedRegion::code(Start.first, Start.second, End.first, End.second,
|
||||
Counter.expand(Builder, CounterIndices)));
|
||||
}
|
||||
// Add any skipped regions present in the outer range.
|
||||
for (auto IfConfig : SF->getIfConfigsWithin(OuterRange)) {
|
||||
for (auto SkipRange : IfConfig.getRangesWithoutActiveBody(SM)) {
|
||||
auto Start = SM.getLineAndColumnInBuffer(SkipRange.getStart());
|
||||
auto End = SM.getLineAndColumnInBuffer(SkipRange.getEnd());
|
||||
assert(Start.first <= End.first && "region start and end out of order");
|
||||
Regions.push_back(MappedRegion::skipped(Start.first, Start.second,
|
||||
End.first, End.second));
|
||||
}
|
||||
}
|
||||
return SILCoverageMap::create(M, SF, Filename, Name, PGOFuncName, Hash,
|
||||
Regions, Builder.getExpressions());
|
||||
|
||||
154
test/Profiler/coverage_pound_if.swift
Normal file
154
test/Profiler/coverage_pound_if.swift
Normal file
@@ -0,0 +1,154 @@
|
||||
// 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
|
||||
// RUN: %target-swift-frontend -profile-generate -profile-coverage-mapping -emit-ir %s
|
||||
|
||||
func poundIf1() -> Int {
|
||||
#if true
|
||||
#if true
|
||||
return 1
|
||||
#else
|
||||
return 2
|
||||
#endif
|
||||
#else
|
||||
#if true
|
||||
return 3
|
||||
#else
|
||||
return 4
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If1SiyF"
|
||||
// CHECK-NEXT: [[@LINE-16]]:24 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-16]]:3 -> [[@LINE-16]]:11 : skipped
|
||||
// CHECK-NEXT: [[@LINE-16]]:5 -> [[@LINE-16]]:13 : skipped
|
||||
// CHECK-NEXT: [[@LINE-15]]:5 -> [[@LINE-13]]:11 : skipped
|
||||
// CHECK-NEXT: [[@LINE-13]]:3 -> [[@LINE-7]]:9 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf2(_ x: [Int]) -> [Int] {
|
||||
return x
|
||||
#if false
|
||||
.map { $0 + 1 }
|
||||
#endif
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If2ySaySiGACF"
|
||||
// CHECK-NEXT: [[@LINE-7]]:36 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-4]]:9 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
|
||||
func poundIf3() -> Any {
|
||||
#if false
|
||||
@objc
|
||||
#endif
|
||||
class C {}
|
||||
return C()
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If3ypyF"
|
||||
// CHECK-NEXT: [[@LINE-8]]:24 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-8]]:1 -> [[@LINE-6]]:7 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf4(_ x: Bool) -> Int {
|
||||
switch x {
|
||||
#if true
|
||||
case true:
|
||||
return 0
|
||||
#else
|
||||
case false:
|
||||
return 0
|
||||
#endif
|
||||
#if false
|
||||
case false:
|
||||
return 1
|
||||
#endif
|
||||
case false:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If4ySiSbF"
|
||||
// CHECK-NEXT: [[@LINE-18]]:33 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-18]]:10 -> [[@LINE-18]]:11 : 0
|
||||
// CHECK-NEXT: [[@LINE-18]]:3 -> [[@LINE-18]]:11 : skipped
|
||||
// CHECK-NEXT: [[@LINE-18]]:3 -> [[@LINE-17]]:13 : 1
|
||||
// CHECK-NEXT: [[@LINE-17]]:3 -> [[@LINE-14]]:9 : skipped
|
||||
// CHECK-NEXT: [[@LINE-14]]:3 -> [[@LINE-11]]:9 : skipped
|
||||
// CHECK-NEXT: [[@LINE-11]]:3 -> [[@LINE-10]]:13 : 2
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf5() {
|
||||
struct S {
|
||||
#if false
|
||||
var foo: Int
|
||||
#else
|
||||
var foo: Int
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If5yyF"
|
||||
// CHECK-NEXT: [[@LINE-10]]:17 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-9]]:1 -> [[@LINE-7]]:6 : skipped
|
||||
// CHECK-NEXT: [[@LINE-6]]:1 -> [[@LINE-6]]:7 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf6() -> Int {
|
||||
#if true
|
||||
struct S {
|
||||
var foo: Int
|
||||
}
|
||||
#else
|
||||
struct S {
|
||||
var foo: Int
|
||||
}
|
||||
#endif
|
||||
return S(foo: 0).foo
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If6SiyF"
|
||||
// CHECK-NEXT: [[@LINE-13]]:24 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-13]]:3 -> [[@LINE-13]]:11 : skipped
|
||||
// CHECK-NEXT: [[@LINE-10]]:3 -> [[@LINE-6]]:9 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf7() -> Int {
|
||||
#if false
|
||||
#endif
|
||||
return 0
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If7SiyF"
|
||||
// CHECK-NEXT: [[@LINE-6]]:24 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-5]]:9 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf8() -> Int {
|
||||
#if true
|
||||
#endif
|
||||
return 0
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If8SiyF"
|
||||
// CHECK-NEXT: [[@LINE-6]]:24 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-6]]:11 : skipped
|
||||
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-6]]:9 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf9() -> Int {
|
||||
#if true
|
||||
#else
|
||||
#endif
|
||||
return 0
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B3If9SiyF"
|
||||
// CHECK-NEXT: [[@LINE-7]]:24 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-7]]:3 -> [[@LINE-7]]:11 : skipped
|
||||
// CHECK-NEXT: [[@LINE-7]]:3 -> [[@LINE-6]]:9 : skipped
|
||||
// CHECK-NEXT: }
|
||||
|
||||
func poundIf10() -> Int {
|
||||
#if true
|
||||
return 0
|
||||
#else
|
||||
return 1#endif
|
||||
}
|
||||
// CHECK-LABEL: sil_coverage_map {{.*}} "$s17coverage_pound_if0B4If10SiyF"
|
||||
// CHECK-NEXT: [[@LINE-7]]:25 -> [[@LINE-2]]:2 : 0
|
||||
// CHECK-NEXT: [[@LINE-7]]:3 -> [[@LINE-7]]:11 : skipped
|
||||
// CHECK-NEXT: [[@LINE-6]]:3 -> [[@LINE-5]]:17 : skipped
|
||||
// CHECK-NEXT: }
|
||||
129
test/Profiler/coverage_pound_if_exec.swift
Normal file
129
test/Profiler/coverage_pound_if_exec.swift
Normal file
@@ -0,0 +1,129 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
|
||||
// RUN: %target-build-swift %s -profile-generate -profile-coverage-mapping -o %t/main
|
||||
|
||||
// This unusual use of 'sh' allows the path of the profraw file to be
|
||||
// substituted by %target-run.
|
||||
// RUN: %target-codesign %t/main
|
||||
// RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main
|
||||
|
||||
// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
|
||||
// RUN: %llvm-cov export -summary-only %t/main -instr-profile=%t/default.profdata | %FileCheck --check-prefix SUMMARY %s
|
||||
// RUN: %llvm-cov show %t/main -instr-profile=%t/default.profdata | %FileCheck --implicit-check-not "{{[ ]*\|[ ]*[0-9]+}}" %s
|
||||
|
||||
// REQUIRES: profile_runtime
|
||||
// REQUIRES: executable_test
|
||||
// REQUIRES: OS=macosx
|
||||
|
||||
// The line count here excludes the inactive regions.
|
||||
// SUMMARY: "lines":{"count":41,"covered":0
|
||||
|
||||
// This test works by marking active lines with the pattern. The implicit
|
||||
// CHECK-NOT in the FileCheck invocation ensures everything else is a skipped
|
||||
// region (or doesn't have any coverage mapping such as these comments).
|
||||
|
||||
func poundIfDecl() -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if true
|
||||
#if true
|
||||
return 1 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#else
|
||||
return 2
|
||||
#endif
|
||||
#else
|
||||
#if true
|
||||
return 3
|
||||
#else
|
||||
return 4
|
||||
#endif
|
||||
#endif
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func poundIfMember(
|
||||
_ x: [Int]
|
||||
) -> [Int] { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
return x // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if false
|
||||
.map { $0 + 1 }
|
||||
#endif
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func poundIfAttr() -> Any { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if false
|
||||
@objc
|
||||
#endif
|
||||
class C {} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
return C() // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func poundIfSwitch(
|
||||
_ x: Bool
|
||||
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
switch x { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if true
|
||||
case true: // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#else
|
||||
case false:
|
||||
return 0
|
||||
#endif
|
||||
#if false
|
||||
case false:
|
||||
return 1
|
||||
#endif
|
||||
case false: // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func poundIfMember() { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
struct S { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if false
|
||||
var foo: Int
|
||||
#else
|
||||
var foo: Int // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#endif
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func poundIfDecl2() -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if true
|
||||
struct S { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
var foo: Int // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#else
|
||||
struct S {
|
||||
var foo: Int
|
||||
}
|
||||
#endif
|
||||
return S(foo: 0).foo // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func emptyPoundIf1(
|
||||
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if false
|
||||
#endif
|
||||
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func emptyPoundIf2(
|
||||
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if true
|
||||
#endif
|
||||
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func emptyPoundIf3(
|
||||
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if true
|
||||
#else
|
||||
#endif
|
||||
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
|
||||
func poundEndIfSameLine(
|
||||
) -> Int { // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#if true
|
||||
return 0 // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
#else
|
||||
return 1#endif
|
||||
} // CHECK: [[@LINE]]{{[ ]*\|[ ]*[0-9]+}}
|
||||
Reference in New Issue
Block a user