[llvm] [MC/DC] Introduce `class TestVector` with a pair of `BitVector` (PR #82174)

NAKAMURA Takumi via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 18 08:43:16 PST 2024


https://github.com/chapuni created https://github.com/llvm/llvm-project/pull/82174

This replaces `SmallVector<CondState>` and emulates it.

- -------- True  False DontCare
- Values:  True  False False
- Visited: True  True  False

`findIndependencePairs()` can be optimized with logical ops.

FIXME: Specialize `findIndependencePairs()` for the single word.

>From 9ef9ea31b6fd1d351b019129758f7869519aa23a Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 17 Feb 2024 23:33:55 +0900
Subject: [PATCH] Introduce `class TestVector` with a pair of `BitVector`

This replaces `SmallVector<CondState>` and emulates it.

-          True  False DontCare (Impossible)
- Values:  True  False False    True
- Visited: True  True  False    False

`findIndependencePairs()` can be optimized with logical ops.

FIXME: Specialize `findIndependencePairs()` for the single word.
---
 .../ProfileData/Coverage/CoverageMapping.h    | 65 ++++++++++++++++++-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 35 ++++------
 2 files changed, 76 insertions(+), 24 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index c5c9740f25c2ce..0f82f091107f5b 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -380,7 +380,70 @@ struct MCDCRecord {
   /// are effectively ignored.
   enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
 
-  using TestVector = llvm::SmallVector<CondState>;
+  /// Emulate SmallVector<CondState> with a pair of BitVector.
+  ///
+  ///          True  False DontCare (Impossible)
+  /// Values:  True  False False    True
+  /// Visited: True  True  False    False
+  class TestVector {
+    BitVector Values;  /// True/False (False when DontCare)
+    BitVector Visited; /// ~DontCare
+
+  public:
+    /// Assume filling DontCare.
+    TestVector(unsigned n, CondState Cond = MCDC_DontCare) {
+      assert(Cond == MCDC_DontCare);
+      Values.resize(n);
+      Visited.resize(n);
+    }
+
+    /// Emulate RHS SmallVector::operator[]
+    MCDCRecord::CondState operator[](int I) const {
+      return (Visited[I] ? (Values[I] ? MCDC_True : MCDC_False)
+                         : MCDC_DontCare);
+    }
+
+    /// Equivalent to buildTestVector's Index.
+    auto getIndex() const { return Values.getData()[0]; }
+
+    /// Emulate LHS SmallVector::operator[].
+    void set(int I, CondState Val) {
+      Visited[I] = (Val != MCDC_DontCare);
+      Values[I] = (Val == MCDC_True);
+    }
+
+    /// Emulate SmallVector::push_back.
+    void push_back(CondState Val) {
+      Visited.push_back(Val != MCDC_DontCare);
+      Values.push_back(Val == MCDC_True);
+    }
+
+    /// Return the outcome is different each other.
+    /// Assumes back() is the outcome
+    /// Dedicated to findIndependencePairs().
+    bool isDifferentOutcome(const TestVector &B) const {
+      const auto &A = *this;
+      assert(A.Visited.back() && B.Visited.back() &&
+             "Both shouldn't be DontCare");
+      return (A.Values.back() ^ B.Values.back());
+    }
+
+    /// For each element:
+    /// - False if either is DontCare
+    /// - False if both have the same value
+    /// - True if both have the opposite value
+    /// ((A.Values ^ B.Values) & A.Visited & B.Visited)
+    /// Dedicated to findIndependencePairs().
+    auto getDifferences(const TestVector &B) const {
+      const auto &A = *this;
+      BitVector AB = A.Values;
+      AB ^= B.Values;
+      AB &= A.Visited;
+      AB &= B.Visited;
+      return AB;
+    }
+  };
+
   using TestVectors = llvm::SmallVector<TestVector>;
   using BoolVector = llvm::SmallVector<bool>;
   using TVRowPair = std::pair<unsigned, unsigned>;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index ddce7580729170..f02ac27ed891af 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -272,22 +272,18 @@ class MCDCRecordProcessor {
   // Walk the binary decision diagram and try assigning both false and true to
   // each node. When a terminal node (ID == 0) is reached, fill in the value in
   // the truth table.
-  void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
-                       unsigned Index) {
-    assert((Index & (1 << ID)) == 0);
-
+  void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID) {
     for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
       static_assert(MCDCRecord::MCDC_False == 0);
       static_assert(MCDCRecord::MCDC_True == 1);
-      Index |= MCDCCond << ID;
-      TV[ID] = MCDCCond;
+      TV.set(ID, MCDCCond);
       auto NextID = CondsMap[ID][MCDCCond];
       if (NextID >= 0) {
-        buildTestVector(TV, NextID, Index);
+        buildTestVector(TV, NextID);
         continue;
       }
 
-      if (!Bitmap[BitmapIdx + Index])
+      if (!Bitmap[BitmapIdx + TV.getIndex()])
         continue;
 
       // Copy the completed test vector to the vector of testvectors.
@@ -299,7 +295,7 @@ class MCDCRecordProcessor {
     }
 
     // Reset back to DontCare.
-    TV[ID] = MCDCRecord::MCDC_DontCare;
+    TV.set(ID, MCDCRecord::MCDC_DontCare);
   }
 
   /// Walk the bits in the bitmap.  A bit set to '1' indicates that the test
@@ -309,7 +305,7 @@ class MCDCRecordProcessor {
     // We start at the root node (ID == 0) with all values being DontCare.
     // `Index` encodes the bitmask of true values and is initially 0.
     MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
-    buildTestVector(TV, 0, 0);
+    buildTestVector(TV, 0);
   }
 
   // Find an independence pair for each condition:
@@ -323,22 +319,15 @@ class MCDCRecordProcessor {
       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])
+        if (!A.isDifferentOutcome(B))
           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 (Flip != NumConditions)
-            break;
-          Flip = Idx;
-        }
         // If the two vectors differ in exactly one condition, ignoring DontCare
         // conditions, we have found an independence pair.
-        if (Idx == NumConditions && Flip != NumConditions)
-          IndependencePairs.insert({Flip, std::make_pair(J + 1, I + 1)});
+        auto AB = A.getDifferences(B);
+        assert(AB[NumConditions] && "The last element should be different");
+        if (AB.count() == 2) // The single condition and the last element
+          IndependencePairs.insert(
+              {AB.find_first(), std::make_pair(J + 1, I + 1)});
       }
     }
   }



More information about the llvm-commits mailing list