https://github.com/Lambdaris updated https://github.com/llvm/llvm-project/pull/94137
>From 23669f721d056d6e4961e2572e438e5c1f91cab1 Mon Sep 17 00:00:00 2001 From: Lambdaris <lambda...@outlook.com> Date: Sun, 2 Jun 2024 10:19:31 +0800 Subject: [PATCH 1/3] [coverage] Mark branches with either counter is zero as folded --- clang/lib/CodeGen/CoverageMappingGen.cpp | 27 +++++++++---- .../CoverageMapping/branch-constfolded.cpp | 40 +++++++++---------- clang/test/CoverageMapping/if.cpp | 4 +- clang/test/CoverageMapping/macro-expansion.c | 10 ++--- .../test/CoverageMapping/mcdc-scratch-space.c | 4 +- .../CoverageMapping/mcdc-system-headers.cpp | 4 +- .../ProfileData/Coverage/CoverageMapping.h | 4 +- .../ProfileData/Coverage/CoverageMapping.cpp | 4 +- .../test/tools/llvm-cov/branch-c-general.test | 12 +++--- 9 files changed, 61 insertions(+), 48 deletions(-) diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 67a9caf8b4ec4..fb9da1a72f8dd 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1099,9 +1099,13 @@ struct CounterCoverageMappingBuilder } /// Determine whether the given condition can be constant folded. - bool ConditionFoldsToBool(const Expr *Cond) { + bool ConditionFoldsToBool(const Expr *Cond, bool &ResultBool) { Expr::EvalResult Result; - return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())); + if (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())) { + ResultBool = Result.Val.getInt().getBoolValue(); + return true; + } + return false; } /// Create a Branch Region around an instrumentable condition for coverage @@ -1128,15 +1132,22 @@ struct CounterCoverageMappingBuilder BranchParams = mcdc::BranchParameters{ID, Conds}; // If a condition can fold to true or false, the corresponding branch - // will be removed. Create a region with both counters hard-coded to - // zero. This allows us to visualize them in a special way. + // will be removed. Create a region with the relative counter hard-coded + // to zero. This allows us to visualize them in a special way. // Alternatively, we can prevent any optimization done via // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in // CodeGenFunction.c always returns false, but that is very heavy-handed. - if (ConditionFoldsToBool(C)) - popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C), - Counter::getZero(), BranchParams)); - else + bool ConstantBool = false; + if (ConditionFoldsToBool(C, ConstantBool)) { + if (ConstantBool) { + popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), + Counter::getZero(), BranchParams)); + } else { + popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C), + FalseCnt, BranchParams)); + } + + } else // Otherwise, create a region with the True counter and False counter. popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, BranchParams)); diff --git a/clang/test/CoverageMapping/branch-constfolded.cpp b/clang/test/CoverageMapping/branch-constfolded.cpp index 1e7e32808e838..a2ac1c1eacd28 100644 --- a/clang/test/CoverageMapping/branch-constfolded.cpp +++ b/clang/test/CoverageMapping/branch-constfolded.cpp @@ -5,94 +5,94 @@ // CHECK-LABEL: _Z6fand_0b: bool fand_0(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 - return false && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 + return false && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, (#0 - #1) } // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_1b: bool fand_1(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 return a && true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #1, (#0 - #1) -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = #2, 0 // CHECK-LABEL: _Z6fand_2bb: bool fand_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3 - return false && a && b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 + return false && a && b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, (#0 - #3) } // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = #4, (#3 - #4) // CHECK: Branch,File 0, [[@LINE-2]]:24 -> [[@LINE-2]]:25 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_3bb: bool fand_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3 return a && true && b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #3, (#0 - #3) -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = #4, 0 // CHECK: Branch,File 0, [[@LINE-2]]:23 -> [[@LINE-2]]:24 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_4bb: bool fand_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3 return a && b && false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #3, (#0 - #3) } // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:16 = #4, (#3 - #4) - // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:25 = 0, 0 + // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:25 = 0, (#1 - #2) // CHECK-LABEL: _Z6fand_5b: bool fand_5(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:3, C:2 - return false && true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 -} // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:23 = 0, 0 + return false && true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, (#0 - #1) +} // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:23 = #2, 0 // CHECK-LABEL: _Z6fand_6b: bool fand_6(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 - return true && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 + return true && a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = #1, 0 } // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = #2, (#1 - #2) // CHECK-LABEL: _Z6fand_7b: bool fand_7(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 return a && false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #1, (#0 - #1) -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, (#1 - #2) // CHECK-LABEL: _Z5for_0b: bool for_0(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 - return true || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 + return true || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = (#0 - #1), 0 } // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_1b: bool for_1(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 return a || false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #1), #1 -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, #2 // CHECK-LABEL: _Z5for_2bb: bool for_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3 - return true || a || b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 + return true || a || b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = (#0 - #3), 0 } // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = (#3 - #4), #4 // CHECK: Branch,File 0, [[@LINE-2]]:23 -> [[@LINE-2]]:24 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_3bb: bool for_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3 return a || false || b; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #3), #3 -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, #4 // CHECK: Branch,File 0, [[@LINE-2]]:24 -> [[@LINE-2]]:25 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_4bb: bool for_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3 return a || b || true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #3), #3 } // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:16 = (#3 - #4), #4 - // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:24 = 0, 0 + // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:24 = (#1 - #2), 0 // CHECK-LABEL: _Z5for_5b: bool for_5(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:3, C:2 - return true || false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0 -} // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:23 = 0, 0 + return true || false; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = (#0 - #1), 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:23 = 0, #2 // CHECK-LABEL: _Z5for_6b: bool for_6(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2 - return false || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0 + return false || a; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, #1 } // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = (#1 - #2), #2 // CHECK-LABEL: _Z5for_7b: bool for_7(bool a) { // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2 return a || true; // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #1), #1 -} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0 +} // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = (#1 - #2), 0 // CHECK-LABEL: _Z5for_8b: bool for_8(bool a) { // MCDC: Decision,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:20 = M:3, C:2 - // CHECK: Branch,File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:11 = 0, 0 - // CHECK: Branch,File 0, [[@LINE+1]]:15 -> [[@LINE+1]]:20 = 0, 0 + // CHECK: Branch,File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:11 = #2, 0 + // CHECK: Branch,File 0, [[@LINE+1]]:15 -> [[@LINE+1]]:20 = 0, (#2 - #3) if (true && false) return true; else diff --git a/clang/test/CoverageMapping/if.cpp b/clang/test/CoverageMapping/if.cpp index 445cdfc20e2af..b6fd525e930f9 100644 --- a/clang/test/CoverageMapping/if.cpp +++ b/clang/test/CoverageMapping/if.cpp @@ -14,7 +14,7 @@ struct S { // CHECK-LABEL: _Z3foov: // CHECK-NEXT: [[@LINE+3]]:12 -> [[@LINE+8]]:2 = #0 // CHECK-NEXT: [[@LINE+3]]:15 -> [[@LINE+3]]:19 = #0 - // CHECK-NEXT: Branch,File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:19 = 0, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:19 = #2, 0 void foo() { // CHECK-NEXT: Gap,File 0, [[@LINE+1]]:21 -> [[@LINE+1]]:22 = #2 if (int j = true ? nop() // CHECK-NEXT: [[@LINE]]:22 -> [[@LINE]]:27 = #2 : nop(); // CHECK-NEXT: [[@LINE]]:22 -> [[@LINE]]:27 = (#0 - #2) @@ -168,7 +168,7 @@ int main() { // CHECK: File 0, [[@LINE]]:12 -> {{[0-9]+}}:2 = // GH-45481 S s; s.the_prop = 0? 1 : 2; // CHECK-NEXT: File 0, [[@LINE]]:16 -> [[@LINE]]:17 = #0 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:16 -> [[@LINE-1]]:17 = 0, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:16 -> [[@LINE-1]]:17 = 0, (#0 - #7) // CHECK-NEXT: Gap,File 0, [[@LINE-2]]:18 -> [[@LINE-2]]:19 = #7 // CHECK-NEXT: File 0, [[@LINE-3]]:19 -> [[@LINE-3]]:20 = #7 // CHECK-NEXT: File 0, [[@LINE-4]]:23 -> [[@LINE-4]]:24 = (#0 - #7) diff --git a/clang/test/CoverageMapping/macro-expansion.c b/clang/test/CoverageMapping/macro-expansion.c index ad71fb15eda42..4cd2c93437193 100644 --- a/clang/test/CoverageMapping/macro-expansion.c +++ b/clang/test/CoverageMapping/macro-expansion.c @@ -4,29 +4,29 @@ // CHECK: File 1, [[@LINE+7]]:12 -> [[@LINE+7]]:38 = #0 // CHECK-NEXT: File 1, [[@LINE+6]]:15 -> [[@LINE+6]]:28 = (#0 + #2) // CHECK-NEXT: File 1, [[@LINE+5]]:21 -> [[@LINE+5]]:22 = (#0 + #2) -// CHECK: Branch,File 1, [[@LINE+4]]:21 -> [[@LINE+4]]:22 = 0, 0 +// CHECK: Branch,File 1, [[@LINE+4]]:21 -> [[@LINE+4]]:22 = 0, ((#0 + #2) - #3) // CHECK-NEXT: File 1, [[@LINE+3]]:24 -> [[@LINE+3]]:26 = #3 // CHECK-NEXT: File 1, [[@LINE+2]]:36 -> [[@LINE+2]]:37 = (#0 + #2) -// CHECK-NEXT: Branch,File 1, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, 0 +// CHECK-NEXT: Branch,File 1, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, #0 #define M1 do { if (0) {} } while (0) // CHECK-NEXT: File 2, [[@LINE+12]]:15 -> [[@LINE+12]]:41 = #0 // CHECK-NEXT: File 2, [[@LINE+11]]:18 -> [[@LINE+11]]:31 = (#0 + #4) // CHECK-NEXT: File 2, [[@LINE+10]]:24 -> [[@LINE+10]]:25 = (#0 + #4) // CHECK: File 2, [[@LINE+9]]:27 -> [[@LINE+9]]:29 = #5 // CHECK-NEXT: File 2, [[@LINE+8]]:39 -> [[@LINE+8]]:40 = (#0 + #4) -// CHECK-NEXT: Branch,File 2, [[@LINE+7]]:39 -> [[@LINE+7]]:40 = 0, 0 +// CHECK-NEXT: Branch,File 2, [[@LINE+7]]:39 -> [[@LINE+7]]:40 = 0, #0 // CHECK-NEXT: File 3, [[@LINE+6]]:15 -> [[@LINE+6]]:41 = #0 // CHECK-NEXT: File 3, [[@LINE+5]]:18 -> [[@LINE+5]]:31 = (#0 + #6) // CHECK-NEXT: File 3, [[@LINE+4]]:24 -> [[@LINE+4]]:25 = (#0 + #6) // CHECK: File 3, [[@LINE+3]]:27 -> [[@LINE+3]]:29 = #7 // CHECK-NEXT: File 3, [[@LINE+2]]:39 -> [[@LINE+2]]:40 = (#0 + #6) -// CHECK-NEXT: Branch,File 3, [[@LINE+1]]:39 -> [[@LINE+1]]:40 = 0, 0 +// CHECK-NEXT: Branch,File 3, [[@LINE+1]]:39 -> [[@LINE+1]]:40 = 0, #0 #define M2(x) do { if (x) {} } while (0) // CHECK-NEXT: File 4, [[@LINE+5]]:15 -> [[@LINE+5]]:38 = #0 // CHECK-NEXT: File 4, [[@LINE+4]]:18 -> [[@LINE+4]]:28 = (#0 + #8) // CHECK-NEXT: Expansion,File 4, [[@LINE+3]]:20 -> [[@LINE+3]]:22 = (#0 + #8) // CHECK-NEXT: File 4, [[@LINE+2]]:36 -> [[@LINE+2]]:37 = (#0 + #8) -// CHECK-NEXT: Branch,File 4, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, 0 +// CHECK-NEXT: Branch,File 4, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, #0 #define M3(x) do { M2(x); } while (0) // CHECK-NEXT: File 5, [[@LINE+4]]:15 -> [[@LINE+4]]:27 = #0 // CHECK-NEXT: File 5, [[@LINE+3]]:16 -> [[@LINE+3]]:19 = #0 diff --git a/clang/test/CoverageMapping/mcdc-scratch-space.c b/clang/test/CoverageMapping/mcdc-scratch-space.c index a263e9b688fae..60e456948a518 100644 --- a/clang/test/CoverageMapping/mcdc-scratch-space.c +++ b/clang/test/CoverageMapping/mcdc-scratch-space.c @@ -3,7 +3,7 @@ // CHECK: builtin_macro0: int builtin_macro0(int a) { // CHECK: Decision,File 0, [[@LINE+1]]:11 -> [[@LINE+2]]:15 = M:3, C:2 - return (__LINE__ // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:11 = 0, 0 [1,2,0] + return (__LINE__ // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:11 = #1, 0 [1,2,0] && a); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:15 = #2, (#1 - #2) [2,0,0] } @@ -11,7 +11,7 @@ int builtin_macro0(int a) { int builtin_macro1(int a) { // CHECK: Decision,File 0, [[@LINE+1]]:11 -> [[@LINE+2]]:22 = M:3, C:2 return (a // CHECK: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = (#0 - #1), #1 [1,0,2] - || __LINE__); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:14 = 0, 0 [2,0,0] + || __LINE__); // CHECK: Branch,File 0, [[@LINE]]:14 -> [[@LINE]]:14 = (#1 - #2), 0 [2,0,0] } #define PRE(x) pre_##x diff --git a/clang/test/CoverageMapping/mcdc-system-headers.cpp b/clang/test/CoverageMapping/mcdc-system-headers.cpp index ae26ed5fe469f..cb1c8743c36e8 100644 --- a/clang/test/CoverageMapping/mcdc-system-headers.cpp +++ b/clang/test/CoverageMapping/mcdc-system-headers.cpp @@ -17,10 +17,10 @@ int func0(int a) { // CHECK: Decision,File 0, [[@LINE+3]]:11 -> [[@LINE+3]]:21 = M:3, C:2 // W_SYS: Expansion,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:16 = #0 (Expanded file = 1) - // X_SYS: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:11 = 0, 0 [1,2,0] + // X_SYS: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:11 = #1, 0 [1,2,0] return (CONST && a); // CHECK: Branch,File 0, [[@LINE-1]]:20 -> [[@LINE-1]]:21 = #2, (#1 - #2) [2,0,0] - // W_SYS: Branch,File 1, [[@LINE-16]]:15 -> [[@LINE-16]]:17 = 0, 0 [1,2,0] + // W_SYS: Branch,File 1, [[@LINE-16]]:15 -> [[@LINE-16]]:17 = #1, 0 [1,2,0] } // CHECK: _Z5func1ii: diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index 5fc497db8df54..8e2ff015d1501 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -719,9 +719,9 @@ struct FunctionRecord { Region.Kind == CounterMappingRegion::MCDCBranchRegion) { CountedBranchRegions.emplace_back(Region, Count, FalseCount, HasSingleByteCoverage); - // If both counters are hard-coded to zero, then this region represents a + // If either counter is hard-coded to zero, then this region represents a // constant-folded branch. - if (Region.Count.isZero() && Region.FalseCount.isZero()) + if (Region.Count.isZero() || Region.FalseCount.isZero()) CountedBranchRegions.back().Folded = true; return; } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 21ce0ac17d618..2dcebba828806 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -506,7 +506,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { const auto &BranchParams = B->getBranchParams(); PosToID[I] = BranchParams.ID; CondLoc[I] = B->startLoc(); - Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero()); + Folded[I++] = (B->Count.isZero() || B->FalseCount.isZero()); } // Using Profile Bitmap from runtime, mark the executed test vectors. @@ -611,6 +611,8 @@ static unsigned getMaxCounterID(const CounterMappingContext &Ctx, unsigned MaxCounterID = 0; for (const auto &Region : Record.MappingRegions) { MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count)); + MaxCounterID = + std::max(MaxCounterID, Ctx.getMaxCounterID(Region.FalseCount)); } return MaxCounterID; } diff --git a/llvm/test/tools/llvm-cov/branch-c-general.test b/llvm/test/tools/llvm-cov/branch-c-general.test index 9b5889babde36..419e92d3fa521 100644 --- a/llvm/test/tools/llvm-cov/branch-c-general.test +++ b/llvm/test/tools/llvm-cov/branch-c-general.test @@ -47,7 +47,7 @@ // CHECK: Branch (103:9): [True: 9, False: 1] // CHECK: switches() -// CHECK: Branch (113:3): [True: 1, False: 0] +// CHECK: Branch (113:3): [Folded - Ignored] // CHECK: Branch (117:63): [True: 15, False: 0] // CHECK: Branch (119:5): [True: 1, False: 14] // CHECK: Branch (120:11): [True: 0, False: 1] @@ -57,7 +57,7 @@ // CHECK: Branch (126:11): [True: 3, False: 0] // CHECK: Branch (128:5): [True: 4, False: 11] // CHECK: Branch (129:11): [True: 4, False: 0] -// CHECK: Branch (131:7): [True: 4, False: 0] +// CHECK: Branch (131:7): [Folded - Ignored] // CHECK: Branch (132:13): [True: 4, False: 0] // CHECK: Branch (136:5): [True: 5, False: 10] // CHECK: Branch (137:11): [True: 1, False: 4] @@ -120,7 +120,7 @@ // REPORT-NEXT: conditionals 24 0 100.00% 15 0 100.00% 16 2 87.50% // REPORT-NEXT: early_exits 20 4 80.00% 25 2 92.00% 16 6 62.50% // REPORT-NEXT: jumps 39 12 69.23% 48 2 95.83% 26 9 65.38% -// REPORT-NEXT: switches 28 5 82.14% 38 4 89.47% 30 9 70.00% +// REPORT-NEXT: switches 28 5 82.14% 38 4 89.47% 26 7 73.08% // REPORT-NEXT: big_switch 25 1 96.00% 32 0 100.00% 30 6 80.00% // REPORT-NEXT: boolean_operators 16 0 100.00% 13 0 100.00% 22 2 90.91% // REPORT-NEXT: boolop_loops 19 0 100.00% 14 0 100.00% 16 2 87.50% @@ -129,12 +129,12 @@ // REPORT-NEXT: main 1 0 100.00% 16 0 100.00% 0 0 0.00% // REPORT-NEXT: c-general.c:static_func 4 0 100.00% 4 0 100.00% 2 0 100.00% // REPORT-NEXT: --- -// REPORT-NEXT: TOTAL 197 24 87.82% 234 8 96.58% 174 38 78.16% +// REPORT-NEXT: TOTAL 197 24 87.82% 234 8 96.58% 170 36 78.82% // Test file-level report. // RUN: llvm-profdata merge %S/Inputs/branch-c-general.proftext -o %t.profdata // RUN: llvm-cov report %S/Inputs/branch-c-general.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-c-general.c | FileCheck %s -check-prefix=FILEREPORT -// FILEREPORT: TOTAL{{.*}}174 38 78.16% +// FILEREPORT: TOTAL{{.*}}170 36 78.82% // Test color True/False output. // RUN: llvm-cov show --use-color --show-branches=count %S/Inputs/branch-c-general.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-c-general.c | FileCheck %s -check-prefix=USECOLOR @@ -161,6 +161,6 @@ // HTML-INDEX: <td class='column-entry-yellow'> // HTML-INDEX: 87.82% (173/197) // HTML-INDEX: <td class='column-entry-red'> -// HTML-INDEX: 78.16% (136/174) +// HTML-INDEX: 78.82% (134/170) // HTML-INDEX: <tr class='light-row-bold'> // HTML-INDEX: Totals >From 217f1ebc982b9d4ef92664e557dbb4fa4eb5f141 Mon Sep 17 00:00:00 2001 From: Lambdaris <lambda...@outlook.com> Date: Sat, 13 Jul 2024 10:45:29 +0800 Subject: [PATCH 2/3] [coverage] MC/DC reports unrechable and uncoverable conditions --- clang/docs/SourceBasedCodeCoverage.rst | 11 ++ .../ProfileData/Coverage/CoverageMapping.h | 74 +++++++--- .../ProfileData/Coverage/CoverageMapping.cpp | 138 ++++++++++++++---- .../llvm-cov/Inputs/mcdc-const-folding.o | Bin 34528 -> 34616 bytes llvm/test/tools/llvm-cov/Inputs/mcdc-const.o | Bin 5208 -> 5296 bytes llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o | Bin 6408 -> 6488 bytes llvm/test/tools/llvm-cov/mcdc-const.test | 70 ++++----- llvm/tools/llvm-cov/CoverageReport.cpp | 4 +- .../tools/llvm-cov/SourceCoverageViewHTML.cpp | 7 +- .../tools/llvm-cov/SourceCoverageViewText.cpp | 14 +- 10 files changed, 232 insertions(+), 86 deletions(-) diff --git a/clang/docs/SourceBasedCodeCoverage.rst b/clang/docs/SourceBasedCodeCoverage.rst index 73910e134a589..e51b940034f58 100644 --- a/clang/docs/SourceBasedCodeCoverage.rst +++ b/clang/docs/SourceBasedCodeCoverage.rst @@ -517,6 +517,17 @@ starts a new boolean expression that is separated from the other conditions by the operator ``func()``. When this is encountered, a warning will be generated and the boolean expression will not be instrumented. +Besides, MC/DC may report conditions with three states: ``uncoverable``, ``constant`` and ``unreachable``. +``uncoverable`` means the condition could be evaluated but it cannot affect outcome of the decision. +``constant`` means the condition is always evaluated to the same value. +While ``unreachable`` means the condition is never evaluated. +For instance, in ``a || true || b``, value of the decision is always ``true``. +``a`` can not make the decision be ``false`` as it varies. And the second condition, ``true`` can not be evaluated to ``false``. +While ``b`` is always short-circuited. Hence ``a`` is ``uncoverable``, ``true`` is ``constant`` and ``b`` is ``unreachable``. +By default statistics of MCDC counts uncoverable conditions but excludes constant conditions or unreachable conditions. Users can pass options like +``--mcdc-exclude=uncoverable,constant`` to control this behavior. +If a decision is proved to no branch theoretically, it shows ``Folded`` rather than coverage percent. + Switch statements ----------------- diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index 8e2ff015d1501..8e74277ffef52 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -384,6 +384,13 @@ struct MCDCRecord { /// are effectively ignored. enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 }; + enum CondResult { + MCDC_Normal, + MCDC_Constant, + MCDC_Uncoverable, + MCDC_Unreachable + }; + /// Emulate SmallVector<CondState> with a pair of BitVector. /// /// True False DontCare (Impossible) @@ -442,30 +449,43 @@ struct MCDCRecord { using TVPairMap = llvm::DenseMap<unsigned, TVRowPair>; using CondIDMap = llvm::DenseMap<unsigned, unsigned>; using LineColPairMap = llvm::DenseMap<unsigned, LineColPair>; + using ResultVector = llvm::SmallVector<CondResult>; private: CounterMappingRegion Region; TestVectors TV; TVPairMap IndependencePairs; - BoolVector Folded; + ResultVector CondResults; CondIDMap PosToID; LineColPairMap CondLoc; public: MCDCRecord(const CounterMappingRegion &Region, TestVectors &&TV, - TVPairMap &&IndependencePairs, BoolVector &&Folded, + TVPairMap &&IndependencePairs, ResultVector &&CondResults, CondIDMap &&PosToID, LineColPairMap &&CondLoc) : Region(Region), TV(std::move(TV)), IndependencePairs(std::move(IndependencePairs)), - Folded(std::move(Folded)), PosToID(std::move(PosToID)), - CondLoc(std::move(CondLoc)){}; + CondResults(std::move(CondResults)), PosToID(std::move(PosToID)), + CondLoc(std::move(CondLoc)) {}; CounterMappingRegion getDecisionRegion() const { return Region; } unsigned getNumConditions() const { return Region.getDecisionParams().NumConditions; } unsigned getNumTestVectors() const { return TV.size(); } - bool isCondFolded(unsigned Condition) const { return Folded[Condition]; } + bool isCondUncoverable(unsigned Condition) const { + return getCondResult(Condition) == CondResult::MCDC_Uncoverable; + } + bool isCondConstant(unsigned Condition) const { + return getCondResult(Condition) == CondResult::MCDC_Constant; + } + bool isCondFolded(unsigned Condition) const { + return getCondResult(Condition) == CondResult::MCDC_Constant || + getCondResult(Condition) == CondResult::MCDC_Unreachable; + } + CondResult getCondResult(unsigned Condition) const { + return CondResults[Condition]; + } /// Return the evaluation of a condition (indicated by Condition) in an /// executed test vector (indicated by TestVectorIndex), which will be True, @@ -505,20 +525,25 @@ struct MCDCRecord { return IndependencePairs[PosToID[Condition]]; } - float getPercentCovered() const { - unsigned Folded = 0; + /// Return if the decision is coverable and percent of covered conditions. + /// Only coverable conditions are counted as denominator. + std::pair<bool, float> getPercentCovered() const { + unsigned Excluded = 0; unsigned Covered = 0; for (unsigned C = 0; C < getNumConditions(); C++) { if (isCondFolded(C)) - Folded++; + Excluded++; else if (isConditionIndependencePairCovered(C)) Covered++; } - unsigned Total = getNumConditions() - Folded; + unsigned Total = getNumConditions() - Excluded; if (Total == 0) - return 0.0; - return (static_cast<double>(Covered) / static_cast<double>(Total)) * 100.0; + return {false, 0.0}; + return { + true, + (static_cast<double>(Covered) / static_cast<double>(Total)) * 100.0, + }; } std::string getConditionHeaderString(unsigned Condition) { @@ -553,7 +578,7 @@ struct MCDCRecord { // Add individual condition values to the string. OS << " " << TestVectorIndex + 1 << " { "; for (unsigned Condition = 0; Condition < NumConditions; Condition++) { - if (isCondFolded(Condition)) + if (isCondConstant(Condition)) OS << "C"; else { switch (getTVCondition(TestVectorIndex, Condition)) { @@ -589,14 +614,25 @@ struct MCDCRecord { std::ostringstream OS; OS << " C" << Condition + 1 << "-Pair: "; - if (isCondFolded(Condition)) { + switch (getCondResult(Condition)) { + case CondResult::MCDC_Normal: + if (isConditionIndependencePairCovered(Condition)) { + TVRowPair rows = getConditionIndependencePair(Condition); + OS << "covered: (" << rows.first << ","; + OS << rows.second << ")\n"; + } else + OS << "not covered\n"; + break; + case CondResult::MCDC_Constant: OS << "constant folded\n"; - } else if (isConditionIndependencePairCovered(Condition)) { - TVRowPair rows = getConditionIndependencePair(Condition); - OS << "covered: (" << rows.first << ","; - OS << rows.second << ")\n"; - } else - OS << "not covered\n"; + break; + case CondResult::MCDC_Uncoverable: + OS << "uncoverable\n"; + break; + case CondResult::MCDC_Unreachable: + OS << "unreachable\n"; + break; + } return OS.str(); } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 2dcebba828806..75084b5395e64 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -365,11 +365,15 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { unsigned NumConditions; /// Vector used to track whether a condition is constant folded. - MCDCRecord::BoolVector Folded; + MCDCRecord::ResultVector CondResults; /// Mapping of calculated MC/DC Independence Pairs for each condition. MCDCRecord::TVPairMap IndependencePairs; + /// All possible Test Vectors for the boolean expression derived from + /// binary decision diagran of the expression. + MCDCRecord::TestVectors TestVectors; + /// Storage for ExecVectors /// ExecVectors is the alias of its 0th element. std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond; @@ -395,8 +399,9 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap), Region(Region), DecisionParams(Region.getDecisionParams()), Branches(Branches), NumConditions(DecisionParams.NumConditions), - Folded(NumConditions, false), IndependencePairs(NumConditions), - ExecVectors(ExecVectorsByCond[false]), IsVersion11(IsVersion11) {} + CondResults(NumConditions, MCDCRecord::CondResult::MCDC_Normal), + IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false]), + IsVersion11(IsVersion11) {} private: // Walk the binary decision diagram and try assigning both false and true to @@ -418,6 +423,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { assert(TVIdx < SavedNodes[ID].Width); assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx"); + TestVectors.push_back({TV, MCDCCond}); if (!Bitmap[IsVersion11 ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex() @@ -445,7 +451,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { buildTestVector(TV, 0, 0); assert(TVIdxs.size() == unsigned(NumTestVectors) && "TVIdxs wasn't fulfilled"); - // Fill ExecVectors order by False items and True items. // ExecVectors is the alias of ExecVectorsByCond[false], so // Append ExecVectorsByCond[true] on it. @@ -477,48 +482,130 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder { } } + void findCoverablePairs(const MCDCRecord::CondIDMap &PosToID) { + llvm::SmallVector<unsigned> FoldedCondPos; + for (unsigned I = 0; I < CondResults.size(); ++I) { + if (CondResults[I] == MCDCRecord::MCDC_Constant || + CondResults[I] == MCDCRecord::MCDC_Unreachable) { + FoldedCondPos.push_back(I); + } + } + if (FoldedCondPos.empty()) { + return; + } + std::array<MCDCRecord::TestVectors, 2> PracticalTestVectorsByCond; + for (const auto &TVWithCond : TestVectors) { + const bool Practical = + llvm::all_of(FoldedCondPos, [&](const unsigned &Pos) { + const auto &[TV, Cond] = TVWithCond; + const auto ID = PosToID.at(Pos); + if (TV[ID] == MCDCRecord::MCDC_DontCare) { + return true; + } + if (CondResults[Pos] == MCDCRecord::MCDC_Constant) { + const auto ConstantValue = Branches[Pos]->Count.isZero() + ? MCDCRecord::MCDC_False + : MCDCRecord::MCDC_True; + if (TV[ID] == ConstantValue) { + return true; + } + } + return false; + }); + + if (Practical) { + PracticalTestVectorsByCond[TVWithCond.second].push_back(TVWithCond); + } + } + + // If a condition: + // - is uncoverable, all test vectors in exact one element of + // `PracticalTestVectorsByCond` show it is `DontCare`; + // - is unreachable, all test vectors in both elements of + // `PracticalTestVectorsByCond` show it is `DontCare`; + // + // Otherwise, the condition is coverable as long as it has not been marked + // as constant or unreachable before. + for (unsigned Pos = 0; Pos < Branches.size(); ++Pos) { + if (CondResults[Pos] != MCDCRecord::MCDC_Normal) { + continue; + } + const auto ID = PosToID.at(Pos); + unsigned InaccessibleCondCount = + llvm::count_if(PracticalTestVectorsByCond, + [=](const MCDCRecord::TestVectors &TestVectors) { + for (const auto &[TV, Cond] : TestVectors) { + if (TV[ID] != MCDCRecord::MCDC_DontCare) { + return false; + } + } + return true; + }); + switch (InaccessibleCondCount) { + case 1: + CondResults[Pos] = MCDCRecord::CondResult::MCDC_Uncoverable; + break; + case 2: + CondResults[Pos] = MCDCRecord::CondResult::MCDC_Unreachable; + break; + default: + break; + } + } + } + public: /// Process the MC/DC Record in order to produce a result for a boolean /// expression. This process includes tracking the conditions that comprise /// the decision region, calculating the list of all possible test vectors, /// marking the executed test vectors, and then finding an Independence Pair /// out of the executed test vectors for each condition in the boolean - /// expression. A condition is tracked to ensure that its ID can be mapped to - /// its ordinal position in the boolean expression. The condition's source - /// location is also tracked, as well as whether it is constant folded (in - /// which case it is excuded from the metric). + /// expression. A condition is tracked to ensure that its ID can be mapped + /// to its ordinal position in the boolean expression. The condition's + /// source location is also tracked, as well as whether it is constant + /// folded (in which case it is excuded from the metric). MCDCRecord processMCDCRecord() { unsigned I = 0; MCDCRecord::CondIDMap PosToID; MCDCRecord::LineColPairMap CondLoc; // Walk the Record's BranchRegions (representing Conditions) in order to: - // - Hash the condition based on its corresponding ID. This will be used to + // - Hash the condition based on its corresponding ID. This will be used + // to // calculate the test vectors. // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its // actual ID. This will be used to visualize the conditions in the // correct order. // - Keep track of the condition source location. This will be used to // visualize where the condition is. - // - Record whether the condition is constant folded so that we exclude it + // - Record whether the condition is folded so that we exclude it // from being measured. for (const auto *B : Branches) { const auto &BranchParams = B->getBranchParams(); PosToID[I] = BranchParams.ID; CondLoc[I] = B->startLoc(); - Folded[I++] = (B->Count.isZero() || B->FalseCount.isZero()); + if (B->Count.isZero() && B->FalseCount.isZero()) { + CondResults[I] = MCDCRecord::CondResult::MCDC_Unreachable; + } else if (B->Count.isZero() || B->FalseCount.isZero()) { + CondResults[I] = MCDCRecord::CondResult::MCDC_Constant; + } + ++I; } // Using Profile Bitmap from runtime, mark the executed test vectors. findExecutedTestVectors(); - // Compare executed test vectors against each other to find an independence - // pairs for each condition. This processing takes the most time. + // Compare executed test vectors against each other to find an + // independence pairs for each condition. This processing takes the most + // time. findIndependencePairs(); + // Identify all conditions making no difference on outcome of the decision. + findCoverablePairs(PosToID); + // Record Test vectors, executed vectors, and independence pairs. return MCDCRecord(Region, std::move(ExecVectors), - std::move(IndependencePairs), std::move(Folded), + std::move(IndependencePairs), std::move(CondResults), std::move(PosToID), std::move(CondLoc)); } }; @@ -910,8 +997,8 @@ Error CoverageMapping::loadFunctionRecord( } // Don't create records for (filenames, function) pairs we've already seen. - auto FilenamesHash = hash_combine_range(Record.Filenames.begin(), - Record.Filenames.end()); + auto FilenamesHash = + hash_combine_range(Record.Filenames.begin(), Record.Filenames.end()); if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second) return Error::success(); @@ -961,12 +1048,11 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load( // If E is a no_data_found error, returns success. Otherwise returns E. static Error handleMaybeNoDataFoundError(Error E) { - return handleErrors( - std::move(E), [](const CoverageMapError &CME) { - if (CME.get() == coveragemap_error::no_data_found) - return static_cast<Error>(Error::success()); - return make_error<CoverageMapError>(CME.get(), CME.getMessage()); - }); + return handleErrors(std::move(E), [](const CoverageMapError &CME) { + if (CME.get() == coveragemap_error::no_data_found) + return static_cast<Error>(Error::success()); + return make_error<CoverageMapError>(CME.get(), CME.getMessage()); + }); } Error CoverageMapping::loadFromFile( @@ -1058,7 +1144,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load( std::string Path = std::move(*PathOpt); StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef(); if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader, - *Coverage, DataFound)) + *Coverage, DataFound)) return std::move(E); } else if (CheckBinaryIDs) { return createFileError( @@ -1152,9 +1238,9 @@ class SegmentBuilder { // emit closing segments in sorted order. auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion; std::stable_sort(CompletedRegionsIt, ActiveRegions.end(), - [](const CountedRegion *L, const CountedRegion *R) { - return L->endLoc() < R->endLoc(); - }); + [](const CountedRegion *L, const CountedRegion *R) { + return L->endLoc() < R->endLoc(); + }); // Emit segments for all completed regions. for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E; diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.o index 7a16162f29c00777d9a05f5fed1cc4cbf333c56c..29aabadc9c6e50e605191bb6c7e00a4ca91619d9 100644 GIT binary patch delta 1920 zcmaJ<Urbw77{BM#cD<#AmX+?GVEMDrEjn5XqZgB2NZ7!T5CYTjuN{91gRP7XI@YqS z7q&r`43+JB;Yl&^!G|So!9_}9@8;7IO=OA5O!NU0qsFJ{(~3U$opbLB8fTN<-}jy0 z_xrx{JLhb^OV{3`OCB2NxPN5COse6wx#&$wj7HH!3{FZ3u?jYifeKck&?`_v1&nM) z!GWo0!i+_NaA$1)<EIDZTU>ACddQl~%`Yn8ka&z3AtZ)fqL5Pw!m?X=KT%oIUJXyg z+}whH&!qxEQEskD%ykgQ{%W3j<<9S1ug{e%WuocD5E!x4;ouJ};i7GoAbj~-acr~u zL8t{Bc|`^Tu|Z{Cv7ZtHw`b$_9455QBBS6E_IO1Ln~D*Bg^G$c*EfHD*va)q)Y}|z zJMYMzmq_5-JQ-&=t<%H-x2y+A3*5IBS-8$9io^r?c9$Pr8kkFMyvboe6S?sgzI}cC z$uCaym#p~j@;3T-pY8Bo6E^rS4a98?IRAl-&3`?=0_UUeUHW`DmtR-3)7|p-H$VOS ztt-<z-95>FxjSb;h=?#*(1qQ<D$w2Ky64%Cxh(uX^xcO?zW(Fr&maF|_ZRH{v-{8N zVeG%#!TLuXKR{EV2V#W*jvG39cWe2Qj?Z*#cWUeR5P!nIyGX+&4ez+LG^XRGj_rH2 z^@loo_iFiyj`n?8KC9z19sBod>l->Y9MJN6h)sp|)#nFJlP<SsG#-yl)mK%W8H<lz z96UNSF<upoPHUexVv`eRhlk=vk#zfg!$Y;cI{%2THsT$u^$iS5J}FY`4fy?%zs6f# zCq*PAY7Vnkxq7PD;oR58Li}~&do88Av;@CxFz0K|vHgUx1v}Uuk&Wm%<y!vK`AP&D ztGC%-xc0T2HUb~*U@vpFatBNN+uB!gy_8mMv#SICrzKQuh5C*ZHP^s;M-UQSPOx^? zkT!VK)e4I|YV2+W>&YlQ?{>l>Vxk9Y-sUwuSi_^nUaWZsYkIK;G0}%Lr)o$99`#`j zj~YAcAQ8g#F04abL`;M+@8)%3tmDz#Y3$V#C8Ln+QAiB3J<ZsMsRIM3>SfiKky*(0 zD&!_4`xICk#6F=H%rYcHnkE3*kOF}S>cUZS53*sEtU>y;LLP$Dud*KfGT8uWKq22j zdO*dR<e*G`h4i38o`E!^l1<1C$y6wX`Usv=DXd2_)ZPR$!$G<iv*8qVBR7(v4Nb5$ z5~N<t&ZKAnxicBue{xi&Etrg^XggA48L|S|F`4v(bXGx^>9Z>CAbCzE2}qw)a8FWH zrNVL8iU!FNNaG4whV-~fy~knZe2{zs>GKNiQ<_k*M|MJHUSbM)4C$DPg5(96dAXqA z&ZS8e+3cjuyi6(NIi#mljFWMhn#*84o}%_LsK1z@?h~+eF-YB*O{b^_x#<jTKLInB zf;52Hr4(&IE|FnpmXK*XCdm}(f^?D}+KkMs%&-fSF7rdXEHf)t*cGL(sMOvJGgpJm z%2fqVKuW2!p&7PPL1sl!*tIAsJFZ!oS(#PXwalsPu;yfD<(k5-<r+V%>oT))U7<ob w)ZfTZp#`>XERb=So3EpHi=nj81sn4ocH{Fh^|nC$LXbU`1)18*VSVAy-_Q>W3jhEB delta 1736 zcmZWpT})eL7(QPou`LC9+5&~HvrCE+huRI)8g<<gBmTv-gRz!DDR5vg3Y7mde#?Gv z$uezuZ_3TYq!(T^84Fpg7v`W>OEj^)8b&W_(ir0vdNrdaKHoV=o7ju*eZJ>=-rw&# z&3>#a+|?zTb%nr#=ZE#=F*q#8Y&sodCZVeNm`*SW7LP!^28VugwDHm7Cf^;38yxhH z{-jaR34$OB7D1qA4X-e+3fBrHRuEFIwNK>dPWUNibXaTt7gnHq#zwti^zZhWr#645 zJ)?u(G`cFwLeQ}BRRq3g4BN`%e)F3%RtP=pr9!2XUaG7oo2f<bc7Is+{a>GUkgKMl zqQYQc&rqz|4evW9C+%0h4rDXUtNSL3S2<ZTc`EC$e^_-&-}%+skrUgk8QL>z&Zo$1 zcB4URsXk6})f=jgd$&}(k-<rm)i2knHPs3Am;-*PA8+6P;@#!>qXN8T1=wpsaGtIS zV*R$J33;4UV{U^hpW;!B@bGtky!cDHRL5K8b!5%maJPy)NL2iZnva_|YwZ-Xc>jaB z67*P)*hC2)l%U^sB-qg)`7bn+t5&5|oG9VVx)L2L!-X>JuP<r#%CN^?;<wANxuL|z z%kV)Njx?4uxiWmtQQ~(ry!*t_$9C^KMH~BozCK-#^@r2#SWlke__Z_bY=G8*2WU&h zKdbmp6`ybAe5jRcKI3@z%htyysvf+j-mUP$)39{j;-Kt>pl+v?EFEWAiUJ)xenZ$x zc@=E|1v;!Gbw=5aii$v4jl0-JsZKB3(|Eq?^0G(TSyz<hG#+SQ<1RrF^s<7+AMSqD z&Vo_$ci5;1n}d}?ZDbF5@h<YAc1m@7Dc1?M8>)*?!RBD4%Wdecq3eArs%Q&H>Vf7G zG_W~XsTWy$yyOpp;}{*~fTb{WA#kucSg9{V{%#w&BiMKADHX}$iwgAnD0kUL>3*nt z^kg5%vLNLLeB|$ib`aWLXa}?GHU%VT!_Z35_VEZNat~$rwEC@79BQFNL{Gs^u)|Tz zDH*X+dN{){0h~)$TF5-0ou{uvF(rQP9?38}<wty!7(DbHjj|`2?`Vd-LxHP4G7ll! zRhgMd98;J~`7!A6?`Mz7=ph+Z*yofVLXL6d7=d<NX6HzpP;fJxFHWGgQRpXSbeEh| zn4SVL#2te+CbJlcQwsA^ehP7;&`rzeH#x1a5em#eHv!#@%(h9KRq%@Pv(Qa~lhErN ze=j1kq~|jHb&R8qdDJnbou}vdOX274g$z35=fwroGkxeUM=>GQU(WCwxrThRhrZXM zcp>7V!tZ1eIp<K@l8lKZmlS>@%g`=ByDT#gi7N`fi+RLfL3|n7RT&dZt}6Tvz)NeW zYZ3Z2nMFv9D}45G#9e}RUB+aS>k6Owb;MnP?z+qpB;HVGegnEy=x)lGc5)8=-pug1 tuORNN*@_1K-Qk0?(!nhk>J>M9SOXhA-F`c5Zk$Dd`3;1PBg99pe*v}NJ%#`P diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-const.o index bc38b71b5de072cedeb2172d160d6705d4855c47..a204a1095745fb232d19b23a9ea30688bfbbfdd5 100644 GIT binary patch delta 342 zcmXAhu}{Kq5QXo41)?S`#e#x_h?8IxT1x|EanMBm1Xh768W7NGa3VV42HxUGA_JRN zG;tCKcO6+xoE%Kp9Bp;^?&ZD9H;&!KJ258n*2*)6+W^r0%)H&$cW`l-eawB;5IGF^ zB7`iH3V{na;6d<#1YsZeAs~Z?b2BGJAOs8Y(u^CJlcr%2qB8JQWg%*_vD<b6BZIrl zM`LBvtRH8S$-RBEd{RghYt>|>a{7<8`cdt`D4Gd-jH-%J)ReTkt7s*;peZ|suIMFA z&Zw%crsVasUefI$6?g2zZ|;g=e|YY>_24}zd<%cbve_X;*v3Ac32D40OBi8~8r~KT zXyP4VkSs}}S8)}eXd<@og&MvQ=Kk8P*$1prmzyV1in2`?eXu#|aU$iVAl1E7)RZ#V Ov|l$Inay`n{L8=NVqaAN delta 236 zcmWlQF-yZ>7=-VAzc!FyQ)5ygidZM3QwO2Jp*m^1>FVSnIN8-L;82K@dViqQ#Z9HS z8YiJH;#S=RCl~t@{BpzH19$hZF-@)#oz6XOK1)0RaQ&0M-`c#pINN^e{`N&w8Z?@2 z0Tme3;0Fk?93VoY1(>Rqw1OB*tu?0#Ey=|ynzm(MV-EDoj;wfM^6_5fMrAbqbnYEF zVqVK+NY~FKW$y3Gh#!7icInm&>2gxf<bb{TLSH<3K}U|+3o<$7Bq(&|@p9o+VjhNV c{WJX5MGnJ6XNGTKN1Ak_o$_t{oO!hV4~J4bW&i*H diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o index 5b3934816bd222383c5e63188c29bf390a1f19fa..bda7b179db43f8eb409811aadefcd1bd7b9b6b25 100644 GIT binary patch delta 687 zcmZ9IO=uHQ5XawaOo;6!>?WJO-CH7xtzwhSCM2t1P$=!egMtSI!F*~WTUvB2o}$H% zDio;<lzI{3MO%8XS<#D71rhaRJ>?>}cu>%bAnHM=Z#TP8IxqwO`TgI_d+&C(mt7d< zWZ~Yvwy3D@CN_hF#n{c?X8Vb-_Oc9?!nFYQ;Pt>!Q1MM*H=MA(2R;G54hq-{woWF8 zo2EH^>0mm2zGXHqS4V48lWD`4>6Zi37pE>XYUU_|Nlk6k@@hdlr{?RKYF@20bXBkC zGeu3)wOl4!(Caz_xe*)-9fB2{4M}jvS`2kLaRr=v5%Pg$jBuoDo!&VP(8kUHRpwko zSeuXt%N?Gc#|=i8w$U@5e&C#iN2m@`c<$C0jvwA)WsoY)A}5@g0ha$Z`_Xgh7YDKM zH{R$=@&jM7vwuD1Q_0u(lkEz-Rl*cc#r@v1e5ZjbPqEC0;h5_>g|j?W&Tezfd-G;+ zji)e&VuZp1+RS<1b2>keVCmm_+3_gPw#<obq3`iX<STTok?0?QyO<Kj;Ul($0!Ie$ zq0q+iP#C`@c+80gB+*X9@u_IwXW8q<Rw3hdf5i+aqAkVIjIY9DOi3k}aEU1yaGa5K z=wT;Of->t~g(g;p*12#LchOrgiOaMAi)hmlEMZD6am6TB<->3dJ8}uGpe^tH53RAb AUH||9 delta 612 zcmZ9JKS&!<9LL}9r8yGy%;nGda<oGV9g35eMMdyX5S_Yo=};&-6bc<oap}-&#Rv`( zlrQ3_4h~(4$t`g(QVJ!~p#};~2eDHt?Gy`DK}dghJt5@5@AuyKeLuhVx0zqbuicmR z#QLCX=Io=Hc2sbiTK=0TF7n{b5e~^Le|kV(PR<btEJY?ce~jEC;r))B5bB13X7t%D zzYZJP7?sh`GPLIX&?+)nCVyUtV~&)NV&8ikpC(#Ht4CR-z!E$ygw7GH!98%dS6N$K z?&DDJ`nB{9i@l0!LH^+L^ciKY`r1(y;qi6*e>)A_UmdQ$V=>f!knB@dyUWdlI*y4x zMTsEaMuEwEc&(e0KM%=K>@fK-AfKSY<kK#4H6&kwbVVi1a^8fkD{DI>{Z}wKZce`E zGuA=JI;jq~fpz^S?Rzi#FNnrbFs7s5d=&4a3SW#naxac^!<BUnFOsf2)^N^UlU1rF zziY^+U3sRVlCIGs6f%yyWRY?Ck8SgiR?spXGGGt9#(Xk{>OhsMjHOXj3uNI+4bvp- atV1&>WF2{?qmmt`A+)j%=2J0@Sh;_1qnm92 diff --git a/llvm/test/tools/llvm-cov/mcdc-const.test b/llvm/test/tools/llvm-cov/mcdc-const.test index 5424625cf6a6b..1e029fe4aded2 100644 --- a/llvm/test/tools/llvm-cov/mcdc-const.test +++ b/llvm/test/tools/llvm-cov/mcdc-const.test @@ -28,9 +28,9 @@ // CHECKGENERALCASE-NEXT: | C1-Pair: covered: (1,2) // CHECKGENERALCASE-NEXT: | C2-Pair: constant folded // CHECKGENERALCASE-NEXT: | C3-Pair: constant folded -// CHECKGENERALCASE-NEXT: | C4-Pair: not covered +// CHECKGENERALCASE-NEXT: | C4-Pair: unreachable // CHECKGENERALCASE-NEXT: | C5-Pair: constant folded -// CHECKGENERALCASE-NEXT: | MC/DC Coverage for Decision: 50.00% +// CHECKGENERALCASE-NEXT: | MC/DC Coverage for Decision: 100.00% // CHECKGENERALCASE-NEXT: | // CHECKGENERALCASE-NEXT: ------------------ @@ -40,11 +40,11 @@ // CHECKFULLCASE: | 1 { C, - = F } // CHECKFULLCASE: | C1-Pair: constant folded -// CHECKFULLCASE-NEXT: | C2-Pair: not covered -// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% +// CHECKFULLCASE-NEXT: | C2-Pair: unreachable +// CHECKFULLCASE: | MC/DC Coverage for Decision: Folded // CHECKFULLCASE: | 1 { F, C = F } // CHECKFULLCASE-NEXT: | 2 { T, C = F } -// CHECKFULLCASE: | C1-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable // CHECKFULLCASE-NEXT: | C2-Pair: constant folded // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { C, F = F } @@ -59,11 +59,11 @@ // CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00% // CHECKFULLCASE: | 1 { C, - = T } // CHECKFULLCASE: | C1-Pair: constant folded -// CHECKFULLCASE-NEXT: | C2-Pair: not covered -// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% +// CHECKFULLCASE-NEXT: | C2-Pair: unreachable +// CHECKFULLCASE: | MC/DC Coverage for Decision: Folded // CHECKFULLCASE: | 1 { F, C = T } // CHECKFULLCASE-NEXT: | 2 { T, C = T } -// CHECKFULLCASE: | C1-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable // CHECKFULLCASE-NEXT: | C2-Pair: constant folded // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { C, F = F } @@ -78,14 +78,14 @@ // CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00% // CHECKFULLCASE: | 1 { C, -, - = F } // CHECKFULLCASE: | C1-Pair: constant folded -// CHECKFULLCASE-NEXT: | C2-Pair: not covered -// CHECKFULLCASE-NEXT: | C3-Pair: not covered -// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% +// CHECKFULLCASE-NEXT: | C2-Pair: unreachable +// CHECKFULLCASE-NEXT: | C3-Pair: unreachable +// CHECKFULLCASE: | MC/DC Coverage for Decision: Folded // CHECKFULLCASE: | 1 { F, C, - = F } // CHECKFULLCASE-NEXT: | 2 { T, C, - = F } -// CHECKFULLCASE: | C1-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable // CHECKFULLCASE-NEXT: | C2-Pair: constant folded -// CHECKFULLCASE-NEXT: | C3-Pair: not covered +// CHECKFULLCASE-NEXT: | C3-Pair: unreachable // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { C, F, - = F } // CHECKFULLCASE-NEXT: | 2 { C, T, F = F } @@ -103,14 +103,14 @@ // CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00% // CHECKFULLCASE: | 1 { C, -, - = T } // CHECKFULLCASE: | C1-Pair: constant folded -// CHECKFULLCASE-NEXT: | C2-Pair: not covered -// CHECKFULLCASE-NEXT: | C3-Pair: not covered -// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% +// CHECKFULLCASE-NEXT: | C2-Pair: unreachable +// CHECKFULLCASE-NEXT: | C3-Pair: unreachable +// CHECKFULLCASE: | MC/DC Coverage for Decision: Folded // CHECKFULLCASE: | 1 { F, C, - = T } // CHECKFULLCASE-NEXT: | 2 { T, C, - = T } -// CHECKFULLCASE: | C1-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable // CHECKFULLCASE-NEXT: | C2-Pair: constant folded -// CHECKFULLCASE-NEXT: | C3-Pair: not covered +// CHECKFULLCASE-NEXT: | C3-Pair: unreachable // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { C, F, T = T } // CHECKFULLCASE-NEXT: | 2 { C, T, - = T } @@ -127,15 +127,15 @@ // CHECKFULLCASE: | 1 { F, -, C = F } // CHECKFULLCASE-NEXT: | 2 { T, F, C = F } // CHECKFULLCASE-NEXT: | 3 { T, T, C = F } -// CHECKFULLCASE: | C1-Pair: not covered -// CHECKFULLCASE-NEXT: | C2-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable +// CHECKFULLCASE-NEXT: | C2-Pair: uncoverable // CHECKFULLCASE-NEXT: | C3-Pair: constant folded // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { F, C, - = F } // CHECKFULLCASE-NEXT: | 2 { T, C, - = F } -// CHECKFULLCASE: | C1-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable // CHECKFULLCASE-NEXT: | C2-Pair: constant folded -// CHECKFULLCASE-NEXT: | C3-Pair: not covered +// CHECKFULLCASE-NEXT: | C3-Pair: unreachable // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { F, -, C = F } // CHECKFULLCASE-NEXT: | 2 { T, F, C = F } @@ -153,15 +153,15 @@ // CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00% // CHECKFULLCASE: | 1 { F, T, C = T } // CHECKFULLCASE-NEXT: | 2 { T, -, C = T } -// CHECKFULLCASE: | C1-Pair: not covered -// CHECKFULLCASE-NEXT: | C2-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable +// CHECKFULLCASE-NEXT: | C2-Pair: uncoverable // CHECKFULLCASE-NEXT: | C3-Pair: constant folded // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { F, C, - = T } // CHECKFULLCASE-NEXT: | 2 { T, C, - = T } -// CHECKFULLCASE: | C1-Pair: not covered +// CHECKFULLCASE: | C1-Pair: uncoverable // CHECKFULLCASE-NEXT: | C2-Pair: constant folded -// CHECKFULLCASE-NEXT: | C3-Pair: not covered +// CHECKFULLCASE-NEXT: | C3-Pair: unreachable // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% // CHECKFULLCASE: | 1 { F, T, C = T } // CHECKFULLCASE-NEXT: | 2 { T, -, C = T } @@ -176,31 +176,31 @@ // CHECKFULLCASE-NEXT: | C3-Pair: not covered // CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00% -// REPORT: _Z5case0b {{.*}} 1 1 0.00% +// REPORT: _Z5case0b {{.*}} 0 0 0.00% // REPORT-NEXT: _Z5case1b {{.*}} 1 1 0.00% // REPORT-NEXT: _Z5case2b {{.*}} 1 0 100.00% // REPORT-NEXT: _Z5case3b {{.*}} 1 0 100.00% -// REPORT-NEXT: _Z5case4b {{.*}} 1 1 0.00% +// REPORT-NEXT: _Z5case4b {{.*}} 0 0 0.00% // REPORT-NEXT: _Z5case5b {{.*}} 1 1 0.00% // REPORT-NEXT: _Z5case6b {{.*}} 1 0 100.00% // REPORT-NEXT: _Z5case7b {{.*}} 1 0 100.00% -// REPORT-NEXT: _Z5case8bb {{.*}} 2 2 0.00% -// REPORT-NEXT: _Z5case9bb {{.*}} 2 2 0.00% +// REPORT-NEXT: _Z5case8bb {{.*}} 0 0 0.00% +// REPORT-NEXT: _Z5case9bb {{.*}} 1 1 0.00% // REPORT-NEXT: _Z5caseabb {{.*}} 2 0 100.00% // REPORT-NEXT: _Z5casebbb {{.*}} 2 0 100.00% -// REPORT-NEXT: _Z5casecbb {{.*}} 2 2 0.00% -// REPORT-NEXT: _Z5casedbb {{.*}} 2 2 0.00% +// REPORT-NEXT: _Z5casecbb {{.*}} 0 0 0.00% +// REPORT-NEXT: _Z5casedbb {{.*}} 1 1 0.00% // REPORT-NEXT: _Z5caseebb {{.*}} 2 2 0.00% // REPORT-NEXT: _Z5casefbb {{.*}} 2 2 0.00% // REPORT-NEXT: _Z5casegbb {{.*}} 2 2 0.00% -// REPORT-NEXT: _Z5casehbb {{.*}} 2 2 0.00% +// REPORT-NEXT: _Z5casehbb {{.*}} 1 1 0.00% // REPORT-NEXT: _Z5caseibb {{.*}} 2 0 100.00% // REPORT-NEXT: _Z5casejbb {{.*}} 2 0 100.00% // REPORT-NEXT: _Z5casekbb {{.*}} 2 2 0.00% -// REPORT-NEXT: _Z5caselbb {{.*}} 2 2 0.00% +// REPORT-NEXT: _Z5caselbb {{.*}} 1 1 0.00% // REPORT-NEXT: _Z5casembb {{.*}} 2 2 0.00% // REPORT-NEXT: _Z5casenbb {{.*}} 2 2 0.00% -// REPORT: TOTAL {{.*}} 40 28 30.00% +// REPORT: TOTAL {{.*}} 30 18 40.00% Instructions for regenerating the test: diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp index 00aea4039bfde..5091ac09d142c 100644 --- a/llvm/tools/llvm-cov/CoverageReport.cpp +++ b/llvm/tools/llvm-cov/CoverageReport.cpp @@ -379,7 +379,9 @@ void CoverageReport::render(const FunctionCoverageSummary &Function, (unsigned)(Function.MCDCCoverage.getNumPairs() - Function.MCDCCoverage.getCoveredPairs())); Options.colored_ostream( - OS, determineCoveragePercentageColor(Function.MCDCCoverage)) + OS, Function.MCDCCoverage.getNumPairs() == 0 + ? raw_ostream::GREEN + : determineCoveragePercentageColor(Function.MCDCCoverage)) << format("%*.2f", FunctionReportColumns[12] - 1, Function.MCDCCoverage.getPercentCovered()) << '%'; diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp index 6f4d327679d6b..3724d25d16bf0 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp @@ -1200,7 +1200,12 @@ void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV, for (unsigned i = 0; i < Record.getNumConditions(); i++) OS << Record.getConditionCoverageString(i); OS << " MC/DC Coverage for Expression: "; - OS << format("%0.2f", Record.getPercentCovered()) << "%\n"; + const auto [Coverable, Percent] = Record.getPercentCovered(); + if (Coverable) { + OS << format("%0.2f", Percent) << "%\n"; + } else { + OS << "Folded\n"; + } OS << EndPre; OS << EndExpansionDiv; } diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp index cab60c2d9034e..42a5da44f3eaf 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp @@ -379,10 +379,16 @@ void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV, } renderLinePrefix(OS, ViewDepth); OS << " MC/DC Coverage for Decision: "; - colored_ostream(OS, raw_ostream::RED, - getOptions().Colors && Record.getPercentCovered() < 100.0, - /*Bold=*/false, /*BG=*/true) - << format("%0.2f", Record.getPercentCovered()) << "%"; + const auto [Coverable, Percent] = Record.getPercentCovered(); + if (Coverable) { + colored_ostream(OS, raw_ostream::RED, + getOptions().Colors && Percent < 100.0, + /*Bold=*/false, /*BG=*/true) + << format("%0.2f", Percent) << "%"; + } else { + OS << "Folded"; + } + OS << "\n"; renderLinePrefix(OS, ViewDepth); OS << "\n"; >From e7a5e19490ef97b80a8db702081dec823cc67f34 Mon Sep 17 00:00:00 2001 From: Lambdaris <lambda...@outlook.com> Date: Sat, 13 Jul 2024 14:20:53 +0800 Subject: [PATCH 3/3] [coverage] add option to exclude special conditions from MC/DC report --- llvm/docs/CommandGuide/llvm-cov.rst | 12 +++++ .../ProfileData/Coverage/CoverageMapping.h | 15 +++--- .../test/tools/llvm-cov/Inputs/mcdc-count.cpp | 25 +++++++++ llvm/test/tools/llvm-cov/Inputs/mcdc-count.o | Bin 0 -> 4384 bytes .../tools/llvm-cov/Inputs/mcdc-count.proftext | 34 ++++++++++++ llvm/test/tools/llvm-cov/mcdc-count.test | 50 ++++++++++++++++++ llvm/tools/llvm-cov/CodeCoverage.cpp | 25 +++++++++ llvm/tools/llvm-cov/CoverageReport.cpp | 6 ++- llvm/tools/llvm-cov/CoverageSummaryInfo.cpp | 13 +++-- llvm/tools/llvm-cov/CoverageSummaryInfo.h | 4 +- llvm/tools/llvm-cov/CoverageViewOptions.h | 1 + llvm/tools/llvm-cov/SourceCoverageView.h | 10 ++-- .../tools/llvm-cov/SourceCoverageViewHTML.cpp | 3 +- .../tools/llvm-cov/SourceCoverageViewText.cpp | 3 +- 14 files changed, 180 insertions(+), 21 deletions(-) create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-count.cpp create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-count.o create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-count.proftext create mode 100644 llvm/test/tools/llvm-cov/mcdc-count.test diff --git a/llvm/docs/CommandGuide/llvm-cov.rst b/llvm/docs/CommandGuide/llvm-cov.rst index 968f3c452f558..b6f80ca61d79a 100644 --- a/llvm/docs/CommandGuide/llvm-cov.rst +++ b/llvm/docs/CommandGuide/llvm-cov.rst @@ -227,6 +227,12 @@ OPTIONS Show modified condition/decision coverage (MC/DC) for each applicable boolean expression. +.. option:: -mcdc-exclude + + Set which special states of conditions should be excluded from coverage (MC/DC). Possible + values are: "none", "uncoverable", "constant", "unreachable", separated by comma. Default + to "constant,unreachable". + .. option:: -show-line-counts Show the execution counts for each line. Defaults to true, unless another @@ -435,6 +441,12 @@ OPTIONS Show MC/DC statistics. Defaults to false. +.. option:: -mcdc-exclude-uncoverable + + MC/DC does not count uncoverable conditions. Default to false. + Uncoverable conditions are conditions that may be evaluated but can not affect + the outcome of decisions due to constants. + .. option:: -show-functions Show coverage summaries for each function. Defaults to false. diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index 8e74277ffef52..eaa8d74946d8c 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -385,10 +385,10 @@ struct MCDCRecord { enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 }; enum CondResult { - MCDC_Normal, - MCDC_Constant, - MCDC_Uncoverable, - MCDC_Unreachable + MCDC_Normal = 0x1, + MCDC_Constant = 0x2, + MCDC_Uncoverable = 0x4, + MCDC_Unreachable = 0x8 }; /// Emulate SmallVector<CondState> with a pair of BitVector. @@ -527,11 +527,14 @@ struct MCDCRecord { /// Return if the decision is coverable and percent of covered conditions. /// Only coverable conditions are counted as denominator. - std::pair<bool, float> getPercentCovered() const { + std::pair<bool, float> getPercentCovered(int32_t CountedStates) const { unsigned Excluded = 0; unsigned Covered = 0; + auto IsExcluded = [&](unsigned Condition) { + return (getCondResult(Condition) & CountedStates) == 0; + }; for (unsigned C = 0; C < getNumConditions(); C++) { - if (isCondFolded(C)) + if (IsExcluded(C)) Excluded++; else if (isConditionIndependencePairCovered(C)) Covered++; diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-count.cpp b/llvm/test/tools/llvm-cov/Inputs/mcdc-count.cpp new file mode 100644 index 0000000000000..ebf4d5e1200d4 --- /dev/null +++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-count.cpp @@ -0,0 +1,25 @@ +#include <stdio.h> + + + + + + + + +void test(bool a,bool b, bool c, bool d) { + + if (a && (b || true || c) && ( true || d) && true) + printf("test 1 decision true\n"); + +} + +int main() +{ + test(true,false,true,false); + test(true,false,true,true); + test(true,true,false,false); + test(false,true,true,false); + test(true,false,false,false); + return 0; +} diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-count.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-count.o new file mode 100644 index 0000000000000000000000000000000000000000..828ad64bd7a7555221cff86ef99294b36128834a GIT binary patch literal 4384 zcmcInU1(fY5T3i6{YjdiP1=P1B(jmVG_|?Cn`}0_rPXbkqydW-(T7@evwL?pjb?w? zy&I}8jbagm+A0XX_~e_uwBUoHR7)QuC<sMS@TH(=ebh=7mByK~GrK3(T?&c=_s-0B z=FH4FXU^Q+b8{!=J%-^0CIcP>LllkQ>})DYB_?46Ef+R?q@CYzPO*5!pM2>~ty8qX z?Y@#S$@i_U=llM=cDwJK(k~k~ZU&Xqv}lelTsT60f1=k~k9uD}$v!`(1S5AMHzMn| zXr!fnRT+s1&ty;T36W1uT_;CKudIJo*tmN4^$$^g?bpK>zl(Rl(A|qYKYaet5yS8s zgM*`^dv=WUkByD*G`jZtJR!pX!!QC6G#~)O^g2MVseSzcV%DI?=m3<0gU}7bgU|!L z^cu4Kqa9v9siQD}Y8UvuK9Y98PS|Djj`;9UQ0j*;9O#GpVXrj+UQd9eG1w0eSVQ9h z50KOe5e(D=sFCD@m~nn>Z7t|Ce6U9)2!DKa;m26^jc@4~x8p<9To<ljz#wOewleo4 z_k;j?3wG8Xw@bC6W7_31kN&?*&Oy%LUeUTWgGMnUChL|pYi2D)ckPED^<>n^Rh<ly zQAjTrNeM^7*_^#xT`m>FPNkLuuvgN>rSNL5qOeH9v`lMh*$MAE<2dE&p@RoeIaAA+ zcByc1Wo5Pg8ZTE$&*W^!B+H4|gq4_#PDNr_YdW5>qERaoPsAs(>HK6ip0N{?wiU4_ zV`D1sZJfRF{9|C84H>(-1Hns}JRTPe^VkY=TD!&aQ^b$<hCHWxgCx>==@JqT;6v0^ zXIQR)<%#FdI{79Vz=vu?av;o2uOiR^KX15k(!HusH;=r4ssTd{aIhhfy-HO>(3TPg zttn}v-o^@=;E=N4(gZZgt5&K3EPB=IH{%~DwQn=nu$LWb4u7h|{wAPFUbT}Nz@k^} zZYx~hmHPO7xUK<hKjq9H#^HZv1MmgnWG{BA9uT9N8TF`kj1s`t>RqpkQEWOwdsvV= zMm>X0=dX=ANv#OJo9(401wYLAUgm;JO~u;aNe!p|BykrsobthztLSm&;$QI78cu5w zKZ}f$9i5usdB(|)9=ELFbXUZFjdAir=OFl{Hu&3Z@OK!O{Kd~@4cGIz*2WLzKt#QO z_D9zRCqL3B^>JF4u8Te0Cb16_h(vkPBNSypaH+ek+dBNg&MiH?eUM7orPWH#PR-6F zree{_*xYn{c6Mt1XstPvn3$iNnVX-F%^sUMmWbn!S;?)WO(%EO0cxs+T+xAY&8gxX z>aVGCC7-g3oAu1{X1$m$<f>qvs5%uemnx-N8C;(_c7_QS(q(atTE1394cm7<Q%KQQ zfi=6Xn8lKlGmk&=#CX+7+s}fjQc7pD_<303)N^N2`3fe`^rL-g8t!z=#5|pJ2F&Vn z1;uF#wB=^gP8yw;h?8x^jL0$kYrY@*i`;eH$%|A(NKdQ2T9@hVQi1L{VN_c>C0SY5 zL6qfw3OvnNQUK<0c6gZsQh$*<LMBp|FQeSD`*I*&hU$OxO_TV--$hJ?@PtunQi$V9 zpOg{tCwja1!4~nU_eosg?c(3!_|lIho;&_qI8ZkYi;3bPzNEW1q4nONL+$bpwaA~o z9+J24MZ_q+S8ocaM_G5*7B34e>eMd&b`BtYiOxTOkHi&z60uhC;~akx$8~b=-$OXL z)%-Vkeo~)|vU~m^oUC$jt^XD!i)7WAsz2(pGXGxnyN?$r_OyQb-6rc6zKB?>{J(MK zgJz1zR;PCRZ*c&9|LOOl#1-Cd|0TZUFEQPEyZyiUANPMd2h#VS?!UyB{VyX%d*XpG zzMB;0!lmEBI=T1nQ3ME^(2Ypv`R-qIGGF)%+LA1Jikss+zaRi}nJ4^9#6{Lk-*aC) z*L<=4tv<i(E|>Rt{(=}Xm;Dp?7Zj)#k^(SaXtDo0a7^aQ{(p~{_ryjC*&03#I?IOg cUxn(Q$i3DH1l+lkU6Kp*cb-5jgpWJ^-@>oCE&u=k literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-count.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-count.proftext new file mode 100644 index 0000000000000..e1f88453360cf --- /dev/null +++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-count.proftext @@ -0,0 +1,34 @@ +_Z4testbbbb +# Func Hash: +2877299778974865 +# Num Counters: +12 +# Counter Values: +5 +4 +4 +4 +4 +4 +0 +0 +3 +0 +0 +0 +# Num Bitmap Bytes: +$3 +# Bitmap Byte Values: +0xc0 +0x80 +0x0 + + +main +# Func Hash: +24 +# Num Counters: +1 +# Counter Values: +1 + diff --git a/llvm/test/tools/llvm-cov/mcdc-count.test b/llvm/test/tools/llvm-cov/mcdc-count.test new file mode 100644 index 0000000000000..3a00b0a6d0331 --- /dev/null +++ b/llvm/test/tools/llvm-cov/mcdc-count.test @@ -0,0 +1,50 @@ +// Test visualization of MC/DC constructs for constant-folded condition masking with different counted states. + +// RUN: llvm-profdata merge %S/Inputs/mcdc-count.proftext -o %t.profdata +// RUN: llvm-cov show --show-mcdc %S/Inputs/mcdc-count.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=DEFAULTCASE +// RUN: llvm-cov report --show-mcdc-summary %S/Inputs/mcdc-count.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-count.cpp | FileCheck %s -check-prefix=REPORTDEFAULT + +// DEFAULTCASE: | MC/DC Coverage for Decision: 50.00% + +// REPORTDEFAULT: TOTAL {{.*}} 2 1 50.00% + +// RUN: llvm-cov show --show-mcdc --mcdc-exclude=uncoverable %S/Inputs/mcdc-count.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=EXCLUDEUNCOVERABECASE +// RUN: llvm-cov report --show-mcdc-summary --mcdc-exclude=uncoverable %S/Inputs/mcdc-count.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-count.cpp | FileCheck %s -check-prefix=REPORTEXCLUDEUNCOVERABLE + +// EXCLUDEUNCOVERABECASE: | MC/DC Coverage for Decision: 16.67% + +// REPORTEXCLUDEUNCOVERABLE: TOTAL {{.*}} 6 5 16.67% + +// RUN: llvm-cov show --show-mcdc --mcdc-exclude=constant %S/Inputs/mcdc-count.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=EXCLUDECONSTANTCASE +// RUN: llvm-cov report --show-mcdc-summary --mcdc-exclude=constant %S/Inputs/mcdc-count.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-count.cpp | FileCheck %s -check-prefix=REPORTEXCLUDECONSTANT + +// EXCLUDECONSTANTCASE: | MC/DC Coverage for Decision: 25.00% + +// REPORTEXCLUDECONSTANT: TOTAL {{.*}} 4 3 25.00% + +// RUN: llvm-cov show --show-mcdc --mcdc-exclude=unreachable %S/Inputs/mcdc-count.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=EXCLUDEUNREACHABLECASE +// RUN: llvm-cov report --show-mcdc-summary --mcdc-exclude=unreachable %S/Inputs/mcdc-count.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-count.cpp | FileCheck %s -check-prefix=REPORTEXCLUDEUNREACHABLE + +// EXCLUDEUNREACHABLECASE: | MC/DC Coverage for Decision: 20.00% + +// REPORTEXCLUDEUNREACHABLE: TOTAL {{.*}} 5 4 20.00% + +Instructions for regenerating the test: + +cd %S/Inputs # Or copy files into the working directory + +clang++ -c -Os \ + -fcoverage-compilation-dir=. -mllvm -enable-name-compression=false \ + -fcoverage-mcdc -fprofile-instr-generate -fcoverage-mapping \ + mcdc-count.cpp + +# Instructions for regenerating proftext + +for x in mcdc-count; do ( + clang++ -fprofile-instr-generate $x.o -o $x + find -name '*.profraw' | xargs rm -f + export LLVM_PROFILE_FILE=$x-%p.profraw + ./$x 0 1 + llvm-profdata merge --sparse -o $x.profdata $(find -name '*.profraw') + llvm-profdata merge --text -o $x.proftext $x.profdata +); done diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index d06fd86fe52af..259174e9cc3c3 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -773,6 +773,13 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { cl::desc("Show MCDC statistics in summary table"), cl::init(false)); + cl::list<std::string> MCDCExcludeStates( + "mcdc-exclude", cl::Optional, + cl::desc( + "Set which abnormal kinds of conditions are excluded from MC/DC"), + cl::CommaSeparated, + cl::list_init<std::string>({"constant", "unreachable"})); + cl::opt<bool> InstantiationSummary( "show-instantiation-summary", cl::Optional, cl::desc("Show instantiation statistics in summary table")); @@ -944,6 +951,24 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { ::exit(0); } + ViewOpts.MCDCCountedStates = + MCDCRecord::MCDC_Normal | MCDCRecord::MCDC_Uncoverable | + MCDCRecord::MCDC_Constant | MCDCRecord::MCDC_Unreachable; + for (const auto &State : MCDCExcludeStates) { + if (State == "uncoverable") { + ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Uncoverable; + } else if (State == "constant") { + ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Constant; + } else if (State == "unreachable") { + ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Unreachable; + } else if (State != "none") { + error("invalid argument '" + State + + "', must be in one of 'uncoverable, constant, unreachable'", + "--mcdc-exclude"); + return 1; + } + } + ViewOpts.ShowMCDCSummary = MCDCSummary; ViewOpts.ShowBranchSummary = BranchSummary; ViewOpts.ShowRegionSummary = RegionSummary; diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp index 5091ac09d142c..0d45a59e97fbc 100644 --- a/llvm/tools/llvm-cov/CoverageReport.cpp +++ b/llvm/tools/llvm-cov/CoverageReport.cpp @@ -428,7 +428,8 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files, OS << "\n"; FunctionCoverageSummary Totals("TOTAL"); for (const auto &F : Functions) { - auto Function = FunctionCoverageSummary::get(Coverage, F); + auto Function = + FunctionCoverageSummary::get(Coverage, F, Options.MCDCCountedStates); ++Totals.ExecutionCount; Totals.RegionCoverage += Function.RegionCoverage; Totals.LineCoverage += Function.LineCoverage; @@ -453,7 +454,8 @@ void CoverageReport::prepareSingleFileReport(const StringRef Filename, for (const coverage::FunctionRecord *F : Group.getInstantiations()) { if (!Filters->matches(*Coverage, *F)) continue; - auto InstantiationSummary = FunctionCoverageSummary::get(*Coverage, *F); + auto InstantiationSummary = FunctionCoverageSummary::get( + *Coverage, *F, Options.MCDCCountedStates); FileReport->addInstantiation(InstantiationSummary); InstantiationSummaries.push_back(InstantiationSummary); } diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp index 4f150020ee381..104d3ad5bc11f 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CoverageSummaryInfo.h" +#include "llvm/ProfileData/Coverage/CoverageMapping.h" using namespace llvm; using namespace coverage; @@ -44,13 +45,13 @@ static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches, } } -static std::pair<size_t, size_t> -sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) { +static std::tuple<size_t, size_t> +sumMCDCPairs(const ArrayRef<MCDCRecord> &Records, const int32_t CountFlags) { size_t NumPairs = 0, CoveredPairs = 0; for (const auto &Record : Records) { const auto NumConditions = Record.getNumConditions(); for (unsigned C = 0; C < NumConditions; C++) { - if (!Record.isCondFolded(C)) + if (Record.getCondResult(C) & CountFlags) ++NumPairs; if (Record.isConditionIndependencePairCovered(C)) ++CoveredPairs; @@ -61,7 +62,8 @@ sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) { FunctionCoverageSummary FunctionCoverageSummary::get(const CoverageMapping &CM, - const coverage::FunctionRecord &Function) { + const coverage::FunctionRecord &Function, + const int32_t MCDCCountedFlags) { // Compute the region coverage. size_t NumCodeRegions = 0, CoveredRegions = 0; for (auto &CR : Function.CountedRegions) { @@ -89,7 +91,8 @@ FunctionCoverageSummary::get(const CoverageMapping &CM, sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions()); size_t NumPairs = 0, CoveredPairs = 0; - std::tie(NumPairs, CoveredPairs) = sumMCDCPairs(CD.getMCDCRecords()); + std::tie(NumPairs, CoveredPairs) = + sumMCDCPairs(CD.getMCDCRecords(), MCDCCountedFlags); return FunctionCoverageSummary( Function.Name, Function.ExecutionCount, diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h index 64c2c8406cf3e..d4ca70948df9e 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h @@ -16,6 +16,7 @@ #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/Support/raw_ostream.h" +#include <cstdint> namespace llvm { @@ -247,7 +248,8 @@ struct FunctionCoverageSummary { /// Compute the code coverage summary for the given function coverage /// mapping record. static FunctionCoverageSummary get(const coverage::CoverageMapping &CM, - const coverage::FunctionRecord &Function); + const coverage::FunctionRecord &Function, + int32_t MCDCCountedFlags = 0); /// Compute the code coverage summary for an instantiation group \p Group, /// given a list of summaries for each instantiation in \p Summaries. diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h index 6925cffd8246d..0282964ed449e 100644 --- a/llvm/tools/llvm-cov/CoverageViewOptions.h +++ b/llvm/tools/llvm-cov/CoverageViewOptions.h @@ -45,6 +45,7 @@ struct CoverageViewOptions { bool SkipExpansions; bool SkipFunctions; bool SkipBranches; + int32_t MCDCCountedStates; OutputFormat Format; BranchOutputType ShowBranches; std::string ShowOutputDirectory; diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h index 2b1570d399dd0..27ae7e9208bd3 100644 --- a/llvm/tools/llvm-cov/SourceCoverageView.h +++ b/llvm/tools/llvm-cov/SourceCoverageView.h @@ -161,9 +161,6 @@ class SourceCoverageView { /// A memory buffer backing the source on display. const MemoryBuffer &File; - /// Various options to guide the coverage renderer. - const CoverageViewOptions &Options; - /// Complete coverage information about the source on display. CoverageData CoverageInfo; @@ -193,6 +190,9 @@ class SourceCoverageView { using CoverageSegmentArray = ArrayRef<const CoverageSegment *>; + /// Various options to guide the coverage renderer. + const CoverageViewOptions &Options; + /// @name Rendering Interface /// @{ @@ -275,8 +275,8 @@ class SourceCoverageView { SourceCoverageView(StringRef SourceName, const MemoryBuffer &File, const CoverageViewOptions &Options, CoverageData &&CoverageInfo) - : SourceName(SourceName), File(File), Options(Options), - CoverageInfo(std::move(CoverageInfo)) {} + : SourceName(SourceName), File(File), + CoverageInfo(std::move(CoverageInfo)), Options(Options) {} public: static std::unique_ptr<SourceCoverageView> diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp index 3724d25d16bf0..f94339dfe74ab 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp @@ -1200,7 +1200,8 @@ void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV, for (unsigned i = 0; i < Record.getNumConditions(); i++) OS << Record.getConditionCoverageString(i); OS << " MC/DC Coverage for Expression: "; - const auto [Coverable, Percent] = Record.getPercentCovered(); + const auto [Coverable, Percent] = + Record.getPercentCovered(Options.MCDCCountedStates); if (Coverable) { OS << format("%0.2f", Percent) << "%\n"; } else { diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp index 42a5da44f3eaf..c69b5c8bdd2a7 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp @@ -379,7 +379,8 @@ void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV, } renderLinePrefix(OS, ViewDepth); OS << " MC/DC Coverage for Decision: "; - const auto [Coverable, Percent] = Record.getPercentCovered(); + const auto [Coverable, Percent] = + Record.getPercentCovered(Options.MCDCCountedStates); if (Coverable) { colored_ostream(OS, raw_ostream::RED, getOptions().Colors && Percent < 100.0, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits