Skip to content

[MC/DC] Introduce class TestVector with a pair of BitVector #82174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,58 @@ 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:
/// Default values are filled with DontCare.
TestVector(unsigned N) : Values(N), Visited(N) {}

/// Emulate RHS SmallVector::operator[]
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]; }

/// 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);
}

/// Emulate SmallVector::push_back.
void push_back(CondState Val) {
Visited.push_back(Val != MCDC_DontCare);
Values.push_back(Val == MCDC_True);
assert(Values.size() == Visited.size());
}

/// 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<std::pair<TestVector, CondState>>;
using BoolVector = llvm::SmallVector<bool>;
using TVRowPair = std::pair<unsigned, unsigned>;
Expand Down
33 changes: 11 additions & 22 deletions llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,26 +400,23 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
// 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,
int TVIdx, unsigned Index) {
assert((Index & (1 << ID)) == 0);

int TVIdx) {
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 = NextIDs[ID][MCDCCond];
auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
if (NextID >= 0) {
buildTestVector(TV, NextID, NextTVIdx, Index);
buildTestVector(TV, NextID, NextTVIdx);
continue;
}

assert(TVIdx < SavedNodes[ID].Width);
assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx");

if (!Bitmap[DecisionParams.BitmapIdx * CHAR_BIT + Index])
if (!Bitmap[DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()])
continue;

// Copy the completed test vector to the vector of testvectors.
Expand All @@ -429,7 +426,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
}

// 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
Expand All @@ -439,8 +436,8 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
// We start at the root node (ID == 0) with all values being DontCare.
// `TVIdx` starts with 0 and is in the traversal.
// `Index` encodes the bitmask of true values and is initially 0.
MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
buildTestVector(TV, 0, 0, 0);
MCDCRecord::TestVector TV(NumConditions);
buildTestVector(TV, 0, 0);
assert(TVIdxs.size() == unsigned(NumTestVectors) &&
"TVIdxs wasn't fulfilled");

Expand All @@ -465,20 +462,12 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
for (unsigned J = 0; J < NumExecVectorsF; ++J) {
const auto &[B, BCond] = ExecVectors[J];
assert(BCond == MCDCRecord::MCDC_False);
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);
if (AB.count() == 1)
IndependencePairs.insert(
{AB.find_first(), std::make_pair(J + 1, I + 1)});
}
}
}
Expand Down