Skip to content

Commit

Permalink
[Coverage] MCDC: Move findIndependencePairs deferred into MCDCRecord (l…
Browse files Browse the repository at this point in the history
…lvm#121188)

The result of "Independence pairs" is not mergeable. This change makes
defers re-calculation of "Independence pairs" after merging test
vectors.

No apparent behavior changes.
  • Loading branch information
chapuni authored Jan 6, 2025
1 parent 4dc34b0 commit 9709795
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 43 deletions.
27 changes: 16 additions & 11 deletions llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <cstdint>
#include <iterator>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include <system_error>
Expand Down Expand Up @@ -448,19 +449,22 @@ struct MCDCRecord {
private:
CounterMappingRegion Region;
TestVectors TV;
TVPairMap IndependencePairs;
std::optional<TVPairMap> IndependencePairs;
BoolVector Folded;
CondIDMap PosToID;
LineColPairMap CondLoc;

public:
MCDCRecord(const CounterMappingRegion &Region, TestVectors &&TV,
TVPairMap &&IndependencePairs, BoolVector &&Folded,
CondIDMap &&PosToID, LineColPairMap &&CondLoc)
: Region(Region), TV(std::move(TV)),
IndependencePairs(std::move(IndependencePairs)),
Folded(std::move(Folded)), PosToID(std::move(PosToID)),
CondLoc(std::move(CondLoc)){};
BoolVector &&Folded, CondIDMap &&PosToID, LineColPairMap &&CondLoc)
: Region(Region), TV(std::move(TV)), Folded(std::move(Folded)),
PosToID(std::move(PosToID)), CondLoc(std::move(CondLoc)) {
findIndependencePairs();
}

// Compare executed test vectors against each other to find an independence
// pairs for each condition. This processing takes the most time.
void findIndependencePairs();

const CounterMappingRegion &getDecisionRegion() const { return Region; }
unsigned getNumConditions() const {
Expand Down Expand Up @@ -493,10 +497,10 @@ struct MCDCRecord {
/// TestVectors requires a translation from a ordinal position to actual
/// condition ID. This is done via PosToID[].
bool isConditionIndependencePairCovered(unsigned Condition) const {
assert(IndependencePairs);
auto It = PosToID.find(Condition);
if (It != PosToID.end())
return IndependencePairs.contains(It->second);
llvm_unreachable("Condition ID without an Ordinal mapping");
assert(It != PosToID.end() && "Condition ID without an Ordinal mapping");
return IndependencePairs->contains(It->second);
}

/// Return the Independence Pair that covers the given condition. Because
Expand All @@ -506,7 +510,8 @@ struct MCDCRecord {
/// via PosToID[].
TVRowPair getConditionIndependencePair(unsigned Condition) {
assert(isConditionIndependencePairCovered(Condition));
return IndependencePairs[PosToID[Condition]];
assert(IndependencePairs);
return (*IndependencePairs)[PosToID[Condition]];
}

float getPercentCovered() const {
Expand Down
67 changes: 35 additions & 32 deletions llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,40 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
return LastPoppedValue;
}

// Find an independence pair for each condition:
// - The condition is true in one test and false in the other.
// - The decision outcome is true one test and false in the other.
// - All other conditions' values must be equal or marked as "don't care".
void MCDCRecord::findIndependencePairs() {
if (IndependencePairs)
return;

IndependencePairs.emplace();

unsigned NumTVs = TV.size();
// Will be replaced to shorter expr.
unsigned TVTrueIdx = std::distance(
TV.begin(),
std::find_if(TV.begin(), TV.end(),
[&](auto I) { return (I.second == MCDCRecord::MCDC_True); })

);
for (unsigned I = TVTrueIdx; I < NumTVs; ++I) {
const auto &[A, ACond] = TV[I];
assert(ACond == MCDCRecord::MCDC_True);
for (unsigned J = 0; J < TVTrueIdx; ++J) {
const auto &[B, BCond] = TV[J];
assert(BCond == MCDCRecord::MCDC_False);
// If the two vectors differ in exactly one condition, ignoring DontCare
// conditions, we have found an independence pair.
auto AB = A.getDifferences(B);
if (AB.count() == 1)
IndependencePairs->insert(
{AB.find_first(), std::make_pair(J + 1, I + 1)});
}
}
}

mcdc::TVIdxBuilder::TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs,
int Offset)
: Indices(NextIDs.size()) {
Expand Down Expand Up @@ -375,9 +409,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
/// ExecutedTestVectorBitmap.
MCDCRecord::TestVectors &ExecVectors;

/// Number of False items in ExecVectors
unsigned NumExecVectorsF;

#ifndef NDEBUG
DenseSet<unsigned> TVIdxs;
#endif
Expand Down Expand Up @@ -447,34 +478,11 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
// Fill ExecVectors order by False items and True items.
// ExecVectors is the alias of ExecVectorsByCond[false], so
// Append ExecVectorsByCond[true] on it.
NumExecVectorsF = ExecVectors.size();
auto &ExecVectorsT = ExecVectorsByCond[true];
ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
std::make_move_iterator(ExecVectorsT.end()));
}

// Find an independence pair for each condition:
// - The condition is true in one test and false in the other.
// - The decision outcome is true one test and false in the other.
// - All other conditions' values must be equal or marked as "don't care".
void findIndependencePairs() {
unsigned NumTVs = ExecVectors.size();
for (unsigned I = NumExecVectorsF; I < NumTVs; ++I) {
const auto &[A, ACond] = ExecVectors[I];
assert(ACond == MCDCRecord::MCDC_True);
for (unsigned J = 0; J < NumExecVectorsF; ++J) {
const auto &[B, BCond] = ExecVectors[J];
assert(BCond == MCDCRecord::MCDC_False);
// If the two vectors differ in exactly one condition, ignoring DontCare
// conditions, we have found an independence pair.
auto AB = A.getDifferences(B);
if (AB.count() == 1)
IndependencePairs.insert(
{AB.find_first(), std::make_pair(J + 1, I + 1)});
}
}
}

public:
/// Process the MC/DC Record in order to produce a result for a boolean
/// expression. This process includes tracking the conditions that comprise
Expand Down Expand Up @@ -510,13 +518,8 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
// Using Profile Bitmap from runtime, mark the executed test vectors.
findExecutedTestVectors();

// Compare executed test vectors against each other to find an independence
// pairs for each condition. This processing takes the most time.
findIndependencePairs();

// Record Test vectors, executed vectors, and independence pairs.
return MCDCRecord(Region, std::move(ExecVectors),
std::move(IndependencePairs), std::move(Folded),
return MCDCRecord(Region, std::move(ExecVectors), std::move(Folded),
std::move(PosToID), std::move(CondLoc));
}
};
Expand Down

0 comments on commit 9709795

Please sign in to comment.