Skip to content

Commit 512a8a7

Browse files
authored
[MC/DC] Introduce class TestVector with a pair of BitVector (#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.
1 parent d7c80bb commit 512a8a7

File tree

2 files changed

+63
-23
lines changed

2 files changed

+63
-23
lines changed

llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,58 @@ struct MCDCRecord {
384384
/// are effectively ignored.
385385
enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
386386

387-
using TestVector = llvm::SmallVector<CondState>;
387+
/// Emulate SmallVector<CondState> with a pair of BitVector.
388+
///
389+
/// True False DontCare (Impossible)
390+
/// Values: True False False True
391+
/// Visited: True True False False
392+
class TestVector {
393+
BitVector Values; /// True/False (False when DontCare)
394+
BitVector Visited; /// ~DontCare
395+
396+
public:
397+
/// Default values are filled with DontCare.
398+
TestVector(unsigned N) : Values(N), Visited(N) {}
399+
400+
/// Emulate RHS SmallVector::operator[]
401+
CondState operator[](int I) const {
402+
return (Visited[I] ? (Values[I] ? MCDC_True : MCDC_False)
403+
: MCDC_DontCare);
404+
}
405+
406+
/// Equivalent to buildTestVector's Index.
407+
auto getIndex() const { return Values.getData()[0]; }
408+
409+
/// Set the condition \p Val at position \p I.
410+
/// This emulates LHS SmallVector::operator[].
411+
void set(int I, CondState Val) {
412+
Visited[I] = (Val != MCDC_DontCare);
413+
Values[I] = (Val == MCDC_True);
414+
}
415+
416+
/// Emulate SmallVector::push_back.
417+
void push_back(CondState Val) {
418+
Visited.push_back(Val != MCDC_DontCare);
419+
Values.push_back(Val == MCDC_True);
420+
assert(Values.size() == Visited.size());
421+
}
422+
423+
/// For each element:
424+
/// - False if either is DontCare
425+
/// - False if both have the same value
426+
/// - True if both have the opposite value
427+
/// ((A.Values ^ B.Values) & A.Visited & B.Visited)
428+
/// Dedicated to findIndependencePairs().
429+
auto getDifferences(const TestVector &B) const {
430+
const auto &A = *this;
431+
BitVector AB = A.Values;
432+
AB ^= B.Values;
433+
AB &= A.Visited;
434+
AB &= B.Visited;
435+
return AB;
436+
}
437+
};
438+
388439
using TestVectors = llvm::SmallVector<std::pair<TestVector, CondState>>;
389440
using BoolVector = llvm::SmallVector<bool>;
390441
using TVRowPair = std::pair<unsigned, unsigned>;

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -400,26 +400,23 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
400400
// each node. When a terminal node (ID == 0) is reached, fill in the value in
401401
// the truth table.
402402
void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
403-
int TVIdx, unsigned Index) {
404-
assert((Index & (1 << ID)) == 0);
405-
403+
int TVIdx) {
406404
for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
407405
static_assert(MCDCRecord::MCDC_False == 0);
408406
static_assert(MCDCRecord::MCDC_True == 1);
409-
Index |= MCDCCond << ID;
410-
TV[ID] = MCDCCond;
407+
TV.set(ID, MCDCCond);
411408
auto NextID = NextIDs[ID][MCDCCond];
412409
auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
413410
assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
414411
if (NextID >= 0) {
415-
buildTestVector(TV, NextID, NextTVIdx, Index);
412+
buildTestVector(TV, NextID, NextTVIdx);
416413
continue;
417414
}
418415

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

422-
if (!Bitmap[DecisionParams.BitmapIdx * CHAR_BIT + Index])
419+
if (!Bitmap[DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()])
423420
continue;
424421

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

431428
// Reset back to DontCare.
432-
TV[ID] = MCDCRecord::MCDC_DontCare;
429+
TV.set(ID, MCDCRecord::MCDC_DontCare);
433430
}
434431

435432
/// Walk the bits in the bitmap. A bit set to '1' indicates that the test
@@ -439,8 +436,8 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
439436
// We start at the root node (ID == 0) with all values being DontCare.
440437
// `TVIdx` starts with 0 and is in the traversal.
441438
// `Index` encodes the bitmask of true values and is initially 0.
442-
MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
443-
buildTestVector(TV, 0, 0, 0);
439+
MCDCRecord::TestVector TV(NumConditions);
440+
buildTestVector(TV, 0, 0);
444441
assert(TVIdxs.size() == unsigned(NumTestVectors) &&
445442
"TVIdxs wasn't fulfilled");
446443

@@ -465,20 +462,12 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
465462
for (unsigned J = 0; J < NumExecVectorsF; ++J) {
466463
const auto &[B, BCond] = ExecVectors[J];
467464
assert(BCond == MCDCRecord::MCDC_False);
468-
unsigned Flip = NumConditions, Idx;
469-
for (Idx = 0; Idx < NumConditions; ++Idx) {
470-
MCDCRecord::CondState ACond = A[Idx], BCond = B[Idx];
471-
if (ACond == BCond || ACond == MCDCRecord::MCDC_DontCare ||
472-
BCond == MCDCRecord::MCDC_DontCare)
473-
continue;
474-
if (Flip != NumConditions)
475-
break;
476-
Flip = Idx;
477-
}
478465
// If the two vectors differ in exactly one condition, ignoring DontCare
479466
// conditions, we have found an independence pair.
480-
if (Idx == NumConditions && Flip != NumConditions)
481-
IndependencePairs.insert({Flip, std::make_pair(J + 1, I + 1)});
467+
auto AB = A.getDifferences(B);
468+
if (AB.count() == 1)
469+
IndependencePairs.insert(
470+
{AB.find_first(), std::make_pair(J + 1, I + 1)});
482471
}
483472
}
484473
}

0 commit comments

Comments
 (0)