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 5447d71196debe8119a8fc392ca1f5d57f57c376 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    |  69 ++++++---
 .../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      |  42 +++---
 llvm/tools/llvm-cov/CoverageReport.cpp        |   4 +-
 llvm/tools/llvm-cov/CoverageSummaryInfo.cpp   |   2 +-
 .../tools/llvm-cov/SourceCoverageViewHTML.cpp |   7 +-
 .../tools/llvm-cov/SourceCoverageViewText.cpp |  14 +-
 11 files changed, 213 insertions(+), 74 deletions(-)

diff --git a/clang/docs/SourceBasedCodeCoverage.rst 
b/clang/docs/SourceBasedCodeCoverage.rst
index 73910e134a589..0cc846747e385 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 and unreachable conditions 
but excludes constants. Users can pass option
+``--mcdc-exclude`` 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..e3a04d169364c 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,36 @@ 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 isCondConstant(unsigned Condition) const {
+    return getCondResult(Condition) == CondResult::MCDC_Constant;
+  }
+  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 +518,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++;
+      if (isCondConstant(C))
+        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 +571,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 +607,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..c97b5d4f72558 100644
--- a/llvm/test/tools/llvm-cov/mcdc-const.test
+++ b/llvm/test/tools/llvm-cov/mcdc-const.test
@@ -28,7 +28,7 @@
 // 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:  |
@@ -40,11 +40,11 @@
 
 //      CHECKFULLCASE: |  1 { C,  -  = F      }
 //      CHECKFULLCASE: |  C1-Pair: constant folded
-// CHECKFULLCASE-NEXT: |  C2-Pair: not covered
+// CHECKFULLCASE-NEXT: |  C2-Pair: unreachable
 //      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: |  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-NEXT: |  C2-Pair: unreachable
 //      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: |  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-NEXT: |  C2-Pair: unreachable
+// CHECKFULLCASE-NEXT: |  C3-Pair: unreachable
 //      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 { 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-NEXT: |  C2-Pair: unreachable
+// CHECKFULLCASE-NEXT: |  C3-Pair: unreachable
 //      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 { 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      }
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/CoverageSummaryInfo.cpp 
b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 4f150020ee381..c68167d461ce2 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -50,7 +50,7 @@ sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
   for (const auto &Record : Records) {
     const auto NumConditions = Record.getNumConditions();
     for (unsigned C = 0; C < NumConditions; C++) {
-      if (!Record.isCondFolded(C))
+      if (!Record.isCondConstant(C))
         ++NumPairs;
       if (Record.isConditionIndependencePairCovered(C))
         ++CoveredPairs;
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 5d421afd8cff8d536a8497c116a501bea0d368f7 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    |  13 ++---
 .../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          |  24 +++++++++
 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, 177 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..26b881fc6a4ae 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".
+
 .. 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 e3a04d169364c..74f03d75ea8a8 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.
@@ -520,11 +520,12 @@ 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 ExcludedStates = ~CountedStates;
     for (unsigned C = 0; C < getNumConditions(); C++) {
-      if (isCondConstant(C))
+      if (getCondResult(C) & ExcludedStates)
         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..0a5440851d618
--- /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: 25.00%
+
+// REPORTDEFAULT: TOTAL {{.*}} 4       3  25.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..bdce427638874 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -773,6 +773,12 @@ 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"}));
+
   cl::opt<bool> InstantiationSummary(
       "show-instantiation-summary", cl::Optional,
       cl::desc("Show instantiation statistics in summary table"));
@@ -944,6 +950,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 c68167d461ce2..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.isCondConstant(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

Reply via email to