[flang-commits] [lldb] [clang] [compiler-rt] [libc] [libcxx] [flang] [clang-tools-extra] [llvm] [llvm-cov] Simplify and optimize MC/DC computation (PR #79727)

Fangrui Song via flang-commits flang-commits at lists.llvm.org
Mon Jan 29 10:34:58 PST 2024


================
@@ -353,71 +331,30 @@ class MCDCRecordProcessor {
     }
   }
 
-  /// For a given condition and two executed Test Vectors, A and B, see if the
-  /// two test vectors match forming an Independence Pair for the condition.
-  /// For two test vectors to match, the following must be satisfied:
-  /// - The condition's value in each test vector must be opposite.
-  /// - The result's value in each test vector must be opposite.
-  /// - All other conditions' values must be equal or marked as "don't care".
-  bool matchTestVectors(unsigned Aidx, unsigned Bidx, unsigned ConditionIdx) {
-    const MCDCRecord::TestVector &A = ExecVectors[Aidx];
-    const MCDCRecord::TestVector &B = ExecVectors[Bidx];
-
-    // If condition values in both A and B aren't opposites, no match.
-    // Because a value can be 0 (false), 1 (true), or -1 (DontCare), a check
-    // that "XOR != 1" will ensure that the values are opposites and that
-    // neither of them is a DontCare.
-    //  1 XOR  0 ==  1 | 0 XOR  0 ==  0 | -1 XOR  0 == -1
-    //  1 XOR  1 ==  0 | 0 XOR  1 ==  1 | -1 XOR  1 == -2
-    //  1 XOR -1 == -2 | 0 XOR -1 == -1 | -1 XOR -1 ==  0
-    if ((A[ConditionIdx] ^ B[ConditionIdx]) != 1)
-      return false;
-
-    // If the results of both A and B aren't opposites, no match.
-    if ((A[NumConditions] ^ B[NumConditions]) != 1)
-      return false;
-
-    for (unsigned Idx = 0; Idx < NumConditions; ++Idx) {
-      // Look for other conditions that don't match. Skip over the given
-      // Condition as well as any conditions marked as "don't care".
-      const auto ARecordTyForCond = A[Idx];
-      const auto BRecordTyForCond = B[Idx];
-      if (Idx == ConditionIdx ||
-          ARecordTyForCond == MCDCRecord::MCDC_DontCare ||
-          BRecordTyForCond == MCDCRecord::MCDC_DontCare)
-        continue;
-
-      // If there is a condition mismatch with any of the other conditions,
-      // there is no match for the test vectors.
-      if (ARecordTyForCond != BRecordTyForCond)
-        return false;
-    }
-
-    // Otherwise, match.
-    return true;
-  }
-
-  /// Find all possible Independence Pairs for a boolean expression given its
-  /// executed Test Vectors.  This process involves looking at each condition
-  /// and attempting to find two Test Vectors that "match", giving us a pair.
+  // Find an independence pair for each condition.
   void findIndependencePairs() {
     unsigned NumTVs = ExecVectors.size();
-
-    // For each condition.
-    for (unsigned C = 0; C < NumConditions; ++C) {
-      bool PairFound = false;
-
-      // For each executed test vector.
-      for (unsigned I = 0; !PairFound && I < NumTVs; ++I) {
-        // Compared to every other executed test vector.
-        for (unsigned J = 0; !PairFound && J < NumTVs; ++J) {
-          if (I == J)
+    for (unsigned I = 1; I < NumTVs; ++I) {
+      const MCDCRecord::TestVector &A = ExecVectors[I];
+      for (unsigned J = 0; J < I; ++J) {
+        const MCDCRecord::TestVector &B = ExecVectors[J];
+        // Enumerate two execution vectors whose outcomes are different.
+        if (A[NumConditions] == B[NumConditions])
+          continue;
+        unsigned Flip = NumConditions, Idx;
+        for (Idx = 0; Idx < NumConditions; ++Idx) {
+          MCDCRecord::CondState ACond = A[Idx], BCond = B[Idx];
+          if (ACond == BCond || ACond == MCDCRecord::MCDC_DontCare ||
+              BCond == MCDCRecord::MCDC_DontCare)
             continue;
-
-          // If a matching pair of vectors is found, record them.
-          if ((PairFound = matchTestVectors(I, J, C)))
-            IndependencePairs[C] = std::make_pair(I + 1, J + 1);
+          if (Flip != NumConditions)
+            break;
+          Flip = Idx;
         }
----------------
MaskRay wrote:

I left some notes on https://maskray.me/blog/2024-01-28-mc-dc-and-compiler-implementations

GCC has a pending patch implementing MC/DC as well and they apply an algorithm described by _Efficient Test Coverage Measurement for MC/DC_, which is linear in terms of the number of conditions.

https://github.com/llvm/llvm-project/pull/79727


More information about the flang-commits mailing list