[llvm] [MC/DC] Introduce `class TestVector` with a pair of `BitVector` (PR #82174)
NAKAMURA Takumi via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 26 04:51:40 PST 2024
https://github.com/chapuni updated https://github.com/llvm/llvm-project/pull/82174
>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 1/5] 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)});
}
}
}
>From f9baabb0cd18a6a963d055da37ba3ad9dcd0cb55 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 19 Feb 2024 17:53:24 +0900
Subject: [PATCH 2/5] Strip namespace
---
llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 0f82f091107f5b..a54e37f4c9e3f4 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -398,7 +398,7 @@ struct MCDCRecord {
}
/// Emulate RHS SmallVector::operator[]
- MCDCRecord::CondState operator[](int I) const {
+ CondState operator[](int I) const {
return (Visited[I] ? (Values[I] ? MCDC_True : MCDC_False)
: MCDC_DontCare);
}
>From f9fc96d03306593312cee7b1067d2fac335090d3 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 19 Feb 2024 17:50:18 +0900
Subject: [PATCH 3/5] The ctor `TestVector(N)` takes only the length.
---
llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h | 8 ++------
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 3 +--
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index a54e37f4c9e3f4..8f2ca9a68eb2bc 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -390,12 +390,8 @@ struct MCDCRecord {
BitVector Visited; /// ~DontCare
public:
- /// Assume filling DontCare.
- TestVector(unsigned n, CondState Cond = MCDC_DontCare) {
- assert(Cond == MCDC_DontCare);
- Values.resize(n);
- Visited.resize(n);
- }
+ /// Default values are filled with DontCare.
+ TestVector(unsigned N) : Values(N), Visited(N) {}
/// Emulate RHS SmallVector::operator[]
CondState operator[](int I) const {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index f02ac27ed891af..23a6142c8c985e 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -303,8 +303,7 @@ class MCDCRecordProcessor {
void findExecutedTestVectors() {
// Walk the binary decision diagram to enumerate all possible test vectors.
// 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);
+ MCDCRecord::TestVector TV(NumConditions);
buildTestVector(TV, 0);
}
>From 4104cc887988a863bff65a229c817e4a6974f1f6 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 19 Feb 2024 17:54:35 +0900
Subject: [PATCH 4/5] Update the comment
---
llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 8f2ca9a68eb2bc..1fac79720bd274 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -402,7 +402,8 @@ struct MCDCRecord {
/// Equivalent to buildTestVector's Index.
auto getIndex() const { return Values.getData()[0]; }
- /// Emulate LHS SmallVector::operator[].
+ /// Set the condition \p Val at position \p I.
+ /// This emulates LHS SmallVector::operator[].
void set(int I, CondState Val) {
Visited[I] = (Val != MCDC_DontCare);
Values[I] = (Val == MCDC_True);
>From 970b4e2a8f00f6de6b792382da2a8fd782d4093e Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 19 Feb 2024 17:55:13 +0900
Subject: [PATCH 5/5] Add a nervous assertion
---
llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 1fac79720bd274..8a43c9a7b14ba6 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -413,6 +413,7 @@ struct MCDCRecord {
void push_back(CondState Val) {
Visited.push_back(Val != MCDC_DontCare);
Values.push_back(Val == MCDC_True);
+ assert(Values.size() == Visited.size());
}
/// Return the outcome is different each other.
More information about the llvm-commits
mailing list