[clang] [llvm] [Coverage][MC/DC] Show uncoverable and unreachable conditions (PR #94137)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 23 06:27:19 PDT 2024
https://github.com/Lambdaris updated https://github.com/llvm/llvm-project/pull/94137
>From 755d8f253fc23b1ef1001095e0310d5f0fac07ab Mon Sep 17 00:00:00 2001
From: Lambdaris <Lambdaris at outlook.com>
Date: Thu, 22 Aug 2024 21:31:03 +0800
Subject: [PATCH 1/3] [coverage] Count false counters when calculating max
counter id
---
clang/lib/CodeGen/CoverageMappingGen.cpp | 4 ++--
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 0a63c50d44f4b7..377f1641192bd7 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1122,8 +1122,8 @@ struct CounterCoverageMappingBuilder
BranchParams = mcdc::BranchParameters{ID, Conds};
// If a condition can fold to true or false, the corresponding branch
- // will be removed. Create a region with both counters hard-coded to
- // zero. This allows us to visualize them in a special way.
+ // will be removed. Create a region with the relative counter hard-coded
+ // to zero. This allows us to visualize them in a special way.
// Alternatively, we can prevent any optimization done via
// constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
// CodeGenFunction.c always returns false, but that is very heavy-handed.
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 119e09187b9080..fac59e6fd83f56 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -608,6 +608,8 @@ static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
unsigned MaxCounterID = 0;
for (const auto &Region : Record.MappingRegions) {
MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
+ MaxCounterID =
+ std::max(MaxCounterID, Ctx.getMaxCounterID(Region.FalseCount));
}
return MaxCounterID;
}
>From 10e2be064a7dfc7693893f3b3685be767003441c Mon Sep 17 00:00:00 2001
From: Lambdaris <Lambdaris at outlook.com>
Date: Sat, 13 Jul 2024 10:45:29 +0800
Subject: [PATCH 2/3] [coverage] MC/DC reports unrechable and uncoverable
conditions
---
clang/docs/SourceBasedCodeCoverage.rst | 11 ++
.../ProfileData/Coverage/CoverageMapping.h | 69 ++++++---
.../ProfileData/Coverage/CoverageMapping.cpp | 138 ++++++++++++++----
.../llvm-cov/Inputs/mcdc-const-folding.o | Bin 34528 -> 34616 bytes
llvm/test/tools/llvm-cov/Inputs/mcdc-const.o | Bin 5208 -> 5296 bytes
llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o | Bin 6408 -> 6488 bytes
llvm/test/tools/llvm-cov/mcdc-const.test | 48 +++---
llvm/test/tools/llvm-cov/mcdc-macro.test | 6 +-
llvm/tools/llvm-cov/CoverageReport.cpp | 4 +-
llvm/tools/llvm-cov/CoverageSummaryInfo.cpp | 2 +-
.../tools/llvm-cov/SourceCoverageViewHTML.cpp | 7 +-
.../tools/llvm-cov/SourceCoverageViewText.cpp | 14 +-
12 files changed, 219 insertions(+), 80 deletions(-)
diff --git a/clang/docs/SourceBasedCodeCoverage.rst b/clang/docs/SourceBasedCodeCoverage.rst
index 73910e134a5891..0cc846747e3857 100644
--- a/clang/docs/SourceBasedCodeCoverage.rst
+++ b/clang/docs/SourceBasedCodeCoverage.rst
@@ -517,6 +517,17 @@ starts a new boolean expression that is separated from the other conditions by
the operator ``func()``. When this is encountered, a warning will be generated
and the boolean expression will not be instrumented.
+Besides, MC/DC may report conditions with three states: ``uncoverable``, ``constant`` and ``unreachable``.
+``uncoverable`` means the condition could be evaluated but it cannot affect outcome of the decision.
+``constant`` means the condition is always evaluated to the same value.
+While ``unreachable`` means the condition is never evaluated.
+For instance, in ``a || true || b``, value of the decision is always ``true``.
+``a`` can not make the decision be ``false`` as it varies. And the second condition, ``true`` can not be evaluated to ``false``.
+While ``b`` is always short-circuited. Hence ``a`` is ``uncoverable``, ``true`` is ``constant`` and ``b`` is ``unreachable``.
+By default statistics of MCDC counts uncoverable and unreachable conditions but excludes constants. Users can pass option
+``--mcdc-exclude`` to control this behavior.
+If a decision is proved to no branch theoretically, it shows ``Folded`` rather than coverage percent.
+
Switch statements
-----------------
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index e631e3899fd4de..3136a1d26cca5e 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -385,6 +385,13 @@ struct MCDCRecord {
/// are effectively ignored.
enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
+ enum CondResult {
+ MCDC_Normal,
+ MCDC_Constant,
+ MCDC_Uncoverable,
+ MCDC_Unreachable
+ };
+
/// Emulate SmallVector<CondState> with a pair of BitVector.
///
/// True False DontCare (Impossible)
@@ -443,30 +450,36 @@ struct MCDCRecord {
using TVPairMap = llvm::DenseMap<unsigned, TVRowPair>;
using CondIDMap = llvm::DenseMap<unsigned, unsigned>;
using LineColPairMap = llvm::DenseMap<unsigned, LineColPair>;
+ using ResultVector = llvm::SmallVector<CondResult>;
private:
CounterMappingRegion Region;
TestVectors TV;
TVPairMap IndependencePairs;
- BoolVector Folded;
+ ResultVector CondResults;
CondIDMap PosToID;
LineColPairMap CondLoc;
public:
MCDCRecord(const CounterMappingRegion &Region, TestVectors &&TV,
- TVPairMap &&IndependencePairs, BoolVector &&Folded,
+ TVPairMap &&IndependencePairs, ResultVector &&CondResults,
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)){};
+ CondResults(std::move(CondResults)), PosToID(std::move(PosToID)),
+ CondLoc(std::move(CondLoc)) {};
CounterMappingRegion getDecisionRegion() const { return Region; }
unsigned getNumConditions() const {
return Region.getDecisionParams().NumConditions;
}
unsigned getNumTestVectors() const { return TV.size(); }
- bool isCondFolded(unsigned Condition) const { return Folded[Condition]; }
+ bool isCondConstant(unsigned Condition) const {
+ return getCondResult(Condition) == CondResult::MCDC_Constant;
+ }
+ CondResult getCondResult(unsigned Condition) const {
+ return CondResults[Condition];
+ }
/// Return the evaluation of a condition (indicated by Condition) in an
/// executed test vector (indicated by TestVectorIndex), which will be True,
@@ -506,20 +519,25 @@ struct MCDCRecord {
return IndependencePairs[PosToID[Condition]];
}
- float getPercentCovered() const {
- unsigned Folded = 0;
+ /// Return if the decision is coverable and percent of covered conditions.
+ /// Only coverable conditions are counted as denominator.
+ std::pair<bool, float> getPercentCovered() const {
+ unsigned Excluded = 0;
unsigned Covered = 0;
for (unsigned C = 0; C < getNumConditions(); C++) {
- if (isCondFolded(C))
- Folded++;
+ if (isCondConstant(C))
+ Excluded++;
else if (isConditionIndependencePairCovered(C))
Covered++;
}
- unsigned Total = getNumConditions() - Folded;
+ unsigned Total = getNumConditions() - Excluded;
if (Total == 0)
- return 0.0;
- return (static_cast<double>(Covered) / static_cast<double>(Total)) * 100.0;
+ return {false, 0.0};
+ return {
+ true,
+ (static_cast<double>(Covered) / static_cast<double>(Total)) * 100.0,
+ };
}
std::string getConditionHeaderString(unsigned Condition) {
@@ -554,7 +572,7 @@ struct MCDCRecord {
// Add individual condition values to the string.
OS << " " << TestVectorIndex + 1 << " { ";
for (unsigned Condition = 0; Condition < NumConditions; Condition++) {
- if (isCondFolded(Condition))
+ if (isCondConstant(Condition))
OS << "C";
else {
switch (getTVCondition(TestVectorIndex, Condition)) {
@@ -590,14 +608,25 @@ struct MCDCRecord {
std::ostringstream OS;
OS << " C" << Condition + 1 << "-Pair: ";
- if (isCondFolded(Condition)) {
+ switch (getCondResult(Condition)) {
+ case CondResult::MCDC_Normal:
+ if (isConditionIndependencePairCovered(Condition)) {
+ TVRowPair rows = getConditionIndependencePair(Condition);
+ OS << "covered: (" << rows.first << ",";
+ OS << rows.second << ")\n";
+ } else
+ OS << "not covered\n";
+ break;
+ case CondResult::MCDC_Constant:
OS << "constant folded\n";
- } else if (isConditionIndependencePairCovered(Condition)) {
- TVRowPair rows = getConditionIndependencePair(Condition);
- OS << "covered: (" << rows.first << ",";
- OS << rows.second << ")\n";
- } else
- OS << "not covered\n";
+ break;
+ case CondResult::MCDC_Uncoverable:
+ OS << "uncoverable\n";
+ break;
+ case CondResult::MCDC_Unreachable:
+ OS << "unreachable\n";
+ break;
+ }
return OS.str();
}
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index fac59e6fd83f56..30308cfdf4243c 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -362,11 +362,15 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
unsigned NumConditions;
/// Vector used to track whether a condition is constant folded.
- MCDCRecord::BoolVector Folded;
+ MCDCRecord::ResultVector CondResults;
/// Mapping of calculated MC/DC Independence Pairs for each condition.
MCDCRecord::TVPairMap IndependencePairs;
+ /// All possible Test Vectors for the boolean expression derived from
+ /// binary decision diagran of the expression.
+ MCDCRecord::TestVectors TestVectors;
+
/// Storage for ExecVectors
/// ExecVectors is the alias of its 0th element.
std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
@@ -392,8 +396,9 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
: NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
Region(Region), DecisionParams(Region.getDecisionParams()),
Branches(Branches), NumConditions(DecisionParams.NumConditions),
- Folded(NumConditions, false), IndependencePairs(NumConditions),
- ExecVectors(ExecVectorsByCond[false]), IsVersion11(IsVersion11) {}
+ CondResults(NumConditions, MCDCRecord::CondResult::MCDC_Normal),
+ IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false]),
+ IsVersion11(IsVersion11) {}
private:
// Walk the binary decision diagram and try assigning both false and true to
@@ -415,6 +420,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
assert(TVIdx < SavedNodes[ID].Width);
assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx");
+ TestVectors.push_back({TV, MCDCCond});
if (!Bitmap[IsVersion11
? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()
@@ -442,7 +448,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
buildTestVector(TV, 0, 0);
assert(TVIdxs.size() == unsigned(NumTestVectors) &&
"TVIdxs wasn't fulfilled");
-
// Fill ExecVectors order by False items and True items.
// ExecVectors is the alias of ExecVectorsByCond[false], so
// Append ExecVectorsByCond[true] on it.
@@ -474,48 +479,130 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
}
}
+ void findCoverablePairs(const MCDCRecord::CondIDMap &PosToID) {
+ llvm::SmallVector<unsigned> FoldedCondPos;
+ for (unsigned I = 0; I < CondResults.size(); ++I) {
+ if (CondResults[I] == MCDCRecord::MCDC_Constant ||
+ CondResults[I] == MCDCRecord::MCDC_Unreachable) {
+ FoldedCondPos.push_back(I);
+ }
+ }
+ if (FoldedCondPos.empty()) {
+ return;
+ }
+ std::array<MCDCRecord::TestVectors, 2> PracticalTestVectorsByCond;
+ for (const auto &TVWithCond : TestVectors) {
+ const bool Practical =
+ llvm::all_of(FoldedCondPos, [&](const unsigned &Pos) {
+ const auto &[TV, Cond] = TVWithCond;
+ const auto ID = PosToID.at(Pos);
+ if (TV[ID] == MCDCRecord::MCDC_DontCare) {
+ return true;
+ }
+ if (CondResults[Pos] == MCDCRecord::MCDC_Constant) {
+ const auto ConstantValue = Branches[Pos]->Count.isZero()
+ ? MCDCRecord::MCDC_False
+ : MCDCRecord::MCDC_True;
+ if (TV[ID] == ConstantValue) {
+ return true;
+ }
+ }
+ return false;
+ });
+
+ if (Practical) {
+ PracticalTestVectorsByCond[TVWithCond.second].push_back(TVWithCond);
+ }
+ }
+
+ // If a condition:
+ // - is uncoverable, all test vectors in exact one element of
+ // `PracticalTestVectorsByCond` show it is `DontCare`;
+ // - is unreachable, all test vectors in both elements of
+ // `PracticalTestVectorsByCond` show it is `DontCare`;
+ //
+ // Otherwise, the condition is coverable as long as it has not been marked
+ // as constant or unreachable before.
+ for (unsigned Pos = 0; Pos < Branches.size(); ++Pos) {
+ if (CondResults[Pos] != MCDCRecord::MCDC_Normal) {
+ continue;
+ }
+ const auto ID = PosToID.at(Pos);
+ unsigned InaccessibleCondCount =
+ llvm::count_if(PracticalTestVectorsByCond,
+ [=](const MCDCRecord::TestVectors &TestVectors) {
+ for (const auto &[TV, Cond] : TestVectors) {
+ if (TV[ID] != MCDCRecord::MCDC_DontCare) {
+ return false;
+ }
+ }
+ return true;
+ });
+ switch (InaccessibleCondCount) {
+ case 1:
+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Uncoverable;
+ break;
+ case 2:
+ CondResults[Pos] = MCDCRecord::CondResult::MCDC_Unreachable;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
public:
/// Process the MC/DC Record in order to produce a result for a boolean
/// expression. This process includes tracking the conditions that comprise
/// the decision region, calculating the list of all possible test vectors,
/// marking the executed test vectors, and then finding an Independence Pair
/// out of the executed test vectors for each condition in the boolean
- /// expression. A condition is tracked to ensure that its ID can be mapped to
- /// its ordinal position in the boolean expression. The condition's source
- /// location is also tracked, as well as whether it is constant folded (in
- /// which case it is excuded from the metric).
+ /// expression. A condition is tracked to ensure that its ID can be mapped
+ /// to its ordinal position in the boolean expression. The condition's
+ /// source location is also tracked, as well as whether it is constant
+ /// folded (in which case it is excuded from the metric).
MCDCRecord processMCDCRecord() {
unsigned I = 0;
MCDCRecord::CondIDMap PosToID;
MCDCRecord::LineColPairMap CondLoc;
// Walk the Record's BranchRegions (representing Conditions) in order to:
- // - Hash the condition based on its corresponding ID. This will be used to
+ // - Hash the condition based on its corresponding ID. This will be used
+ // to
// calculate the test vectors.
// - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
// actual ID. This will be used to visualize the conditions in the
// correct order.
// - Keep track of the condition source location. This will be used to
// visualize where the condition is.
- // - Record whether the condition is constant folded so that we exclude it
+ // - Record whether the condition is folded so that we exclude it
// from being measured.
for (const auto *B : Branches) {
const auto &BranchParams = B->getBranchParams();
PosToID[I] = BranchParams.ID;
CondLoc[I] = B->startLoc();
- Folded[I++] = (B->Count.isZero() || B->FalseCount.isZero());
+ if (B->Count.isZero() && B->FalseCount.isZero()) {
+ CondResults[I] = MCDCRecord::CondResult::MCDC_Unreachable;
+ } else if (B->Count.isZero() || B->FalseCount.isZero()) {
+ CondResults[I] = MCDCRecord::CondResult::MCDC_Constant;
+ }
+ ++I;
}
// 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.
+ // Compare executed test vectors against each other to find an
+ // independence pairs for each condition. This processing takes the most
+ // time.
findIndependencePairs();
+ // Identify all conditions making no difference on outcome of the decision.
+ findCoverablePairs(PosToID);
+
// Record Test vectors, executed vectors, and independence pairs.
return MCDCRecord(Region, std::move(ExecVectors),
- std::move(IndependencePairs), std::move(Folded),
+ std::move(IndependencePairs), std::move(CondResults),
std::move(PosToID), std::move(CondLoc));
}
};
@@ -907,8 +994,8 @@ Error CoverageMapping::loadFunctionRecord(
}
// Don't create records for (filenames, function) pairs we've already seen.
- auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
- Record.Filenames.end());
+ auto FilenamesHash =
+ hash_combine_range(Record.Filenames.begin(), Record.Filenames.end());
if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
return Error::success();
@@ -958,12 +1045,11 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
// If E is a no_data_found error, returns success. Otherwise returns E.
static Error handleMaybeNoDataFoundError(Error E) {
- return handleErrors(
- std::move(E), [](const CoverageMapError &CME) {
- if (CME.get() == coveragemap_error::no_data_found)
- return static_cast<Error>(Error::success());
- return make_error<CoverageMapError>(CME.get(), CME.getMessage());
- });
+ return handleErrors(std::move(E), [](const CoverageMapError &CME) {
+ if (CME.get() == coveragemap_error::no_data_found)
+ return static_cast<Error>(Error::success());
+ return make_error<CoverageMapError>(CME.get(), CME.getMessage());
+ });
}
Error CoverageMapping::loadFromFile(
@@ -1055,7 +1141,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
std::string Path = std::move(*PathOpt);
StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
- *Coverage, DataFound))
+ *Coverage, DataFound))
return std::move(E);
} else if (CheckBinaryIDs) {
return createFileError(
@@ -1149,9 +1235,9 @@ class SegmentBuilder {
// emit closing segments in sorted order.
auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
- [](const CountedRegion *L, const CountedRegion *R) {
- return L->endLoc() < R->endLoc();
- });
+ [](const CountedRegion *L, const CountedRegion *R) {
+ return L->endLoc() < R->endLoc();
+ });
// Emit segments for all completed regions.
for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.o
index 7a16162f29c00777d9a05f5fed1cc4cbf333c56c..29aabadc9c6e50e605191bb6c7e00a4ca91619d9 100644
GIT binary patch
delta 1920
zcmaJ<Urbw77{BM#cD<#AmX+?GVEMDrEjn5XqZgB2NZ7!T5CYTjuN{91gRP7XI at YqS
z7q&r`43+JB;Yl&^!G|So!9_}9 at 8;7IO=OA5O!NU0qsFJ{(~3U$opbLB8fTN<-}jy0
z_xrx{JLhb^OV{3`OCB2NxPN5COse6wx#&$wj7HH!3{FZ3u?jYifeKck&?`_v1&nM)
z!GWo0!i+_NaA$1)<EIDZTU>ACddQl~%`Yn8ka&z3AtZ)fqL5Pw!m?X=KT%oIUJXyg
z+}whH&!qxEQEskD%ykgQ{%W3j<<9S1ug{e%WuocD5E!x4;ouJ};i7GoAbj~-acr~u
zL8t{Bc|`^Tu|Z{Cv7ZtHw`b$_9455QBBS6E_IO1Ln~D*Bg^G$c*EfHD*va)q)Y}|z
zJMYMzmq_5-JQ-&=t<%H-x2y+A3*5IBS-8$9io^r?c9$Pr8kkFMyvboe6S?sgzI}cC
z$uCaym#p~j@;3T-pY8Bo6E^rS4a98?IRAl-&3`?=0_UUeUHW`DmtR-3)7|p-H$VOS
ztt-<z-95>FxjSb;h=?#*(1qQ<D$w2Ky64%Cxh(uX^xcO?zW(Fr&maF|_ZRH{v-{8N
zVeG%#!TLuXKR{EV2V#W*jvG39cWe2Qj?Z*#cWUeR5P!nIyGX+&4ez+LG^XRGj_rH2
z^@loo_iFiyj`n?8KC9z19sBod>l->Y9MJN6h)sp|)#nFJlP<SsG#-yl)mK%W8H<lz
z96UNSF<upoPHUexVv`eRhlk=vk#zfg!$Y;cI{%2THsT$u^$iS5J}FY`4fy?%zs6f#
zCq*PAY7Vnkxq7PD;oR58Li}~&do88Av;@CxFz0K|vHgUx1v}Uuk&Wm%<y!vK`AP&D
ztGC%-xc0T2HUb~*U at vpFatBNN+uB!gy_8mMv#SICrzKQuh5C*ZHP^s;M-UQSPOx^?
zkT!VK)e4I|YV2+W>&YlQ?{>l>Vxk9Y-sUwuSi_^nUaWZsYkIK;G0}%Lr)o$99`#`j
zj~YAcAQ8g#F04abL`;M+ at 8)%3tmDz#Y3$V#C8Ln+QAiB3J<ZsMsRIM3>SfiKky*(0
zD&!_4`xICk#6F=H%rYcHnkE3*kOF}S>cUZS53*sEtU>y;LLP$Dud*KfGT8uWKq22j
zdO*dR<e*G`h4i38o`E!^l1<1C$y6wX`Usv=DXd2_)ZPR$!$G<iv*8qVBR7(v4Nb5$
z5~N<t&ZKAnxicBue{xi&Etrg^XggA48L|S|F`4v(bXGx^>9Z>CAbCzE2}qw)a8FWH
zrNVL8iU!FNNaG4whV-~fy~knZe2{zs>GKNiQ<_k*M|MJHUSbM)4C$DPg5(96dAXqA
z&ZS8e+3cjuyi6(NIi#mljFWMhn#*84o}%_LsK1z@?h~+eF-YB*O{b^_x#<jTKLInB
zf;52Hr4(&IE|FnpmXK*XCdm}(f^?D}+KkMs%&-fSF7rdXEHf)t*cGL(sMOvJGgpJm
z%2fqVKuW2!p&7PPL1sl!*tIAsJFZ!oS(#PXwalsPu;yfD<(k5-<r+V%>oT))U7<ob
w)ZfTZp#`>XERb=So3EpHi=nj81sn4ocH{Fh^|nC$LXbU`1)18*VSVAy-_Q>W3jhEB
delta 1736
zcmZWpT})eL7(QPou`LC9+5&~HvrCE+huRI)8g<<gBmTv-gRz!DDR5vg3Y7mde#?Gv
z$uezuZ_3TYq!(T^84Fpg7v`W>OEj^)8b&W_(ir0vdNrdaKHoV=o7ju*eZJ>=-rw&#
z&3>#a+|?zTb%nr#=ZE#=F*q#8Y&sodCZVeNm`*SW7LP!^28VugwDHm7Cf^;38yxhH
z{-jaR34$OB7D1qA4X-e+3fBrHRuEFIwNK>dPWUNibXaTt7gnHq#zwti^zZhWr#645
zJ)?u(G`cFwLeQ}BRRq3g4BN`%e)F3%RtP=pr9!2XUaG7oo2f<bc7Is+{a>GUkgKMl
zqQYQc&rqz|4evW9C+%0h4rDXUtNSL3S2<ZTc`EC$e^_-&-}%+skrUgk8QL>z&Zo$1
zcB4URsXk6})f=jgd$&}(k-<rm)i2knHPs3Am;-*PA8+6P;@#!>qXN8T1=wpsaGtIS
zV*R$J33;4UV{U^hpW;!B at bGtky!cDHRL5K8b!5%maJPy)NL2iZnva_|YwZ-Xc>jaB
z67*P)*hC2)l%U^sB-qg)`7bn+t5&5|oG9VVx)L2L!-X>JuP<r#%CN^?;<wANxuL|z
z%kV)Njx?4uxiWmtQQ~(ry!*t_$9C^KMH~BozCK-#^@r2#SWlke__Z_bY=G8*2WU&h
zKdbmp6`ybAe5jRcKI3 at z%htyysvf+j-mUP$)39{j;-Kt>pl+v?EFEWAiUJ)xenZ$x
zc@=E|1v;!Gbw=5aii$v4jl0-JsZKB3(|Eq?^0G(TSyz<hG#+SQ<1RrF^s<7+AMSqD
z&Vo_$ci5;1n}d}?ZDbF5 at h<YAc1m at 7Dc1?M8>)*?!RBD4%Wdecq3eArs%Q&H>Vf7G
zG_W~XsTWy$yyOpp;}{*~fTb{WA#kucSg9{V{%#w&BiMKADHX}$iwgAnD0kUL>3*nt
z^kg5%vLNLLeB|$ib`aWLXa}?GHU%VT!_Z35_VEZNat~$rwEC at 79BQFNL{Gs^u)|Tz
zDH*X+dN{){0h~)$TF5-0ou{uvF(rQP9?38}<wty!7(DbHjj|`2?`Vd-LxHP4G7ll!
zRhgMd98;J~`7!A6?`Mz7=ph+Z*yofVLXL6d7=d<NX6HzpP;fJxFHWGgQRpXSbeEh|
zn4SVL#2te+CbJlcQwsA^ehP7;&`rzeH#x1a5em#eHv!#@%(h9KRq%@Pv(Qa~lhErN
ze=j1kq~|jHb&R8qdDJnbou}vdOX274g$z35=fwroGkxeUM=>GQU(WCwxrThRhrZXM
zcp>7V!tZ1eIp<K at l8lKZmlS>@%g`=ByDT#gi7N`fi+RLfL3|n7RT&dZt}6Tvz)NeW
zYZ3Z2nMFv9D}45G#9e}RUB+aS>k6Owb;MnP?z+qpB;HVGegnEy=x)lGc5)8=-pug1
tuORNN*@_1K-Qk0?(!nhk>J>M9SOXhA-F`c5Zk$Dd`3;1PBg99pe*v}NJ%#`P
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-const.o
index bc38b71b5de072cedeb2172d160d6705d4855c47..a204a1095745fb232d19b23a9ea30688bfbbfdd5 100644
GIT binary patch
delta 342
zcmXAhu}{Kq5QXo41)?S`#e#x_h?8IxT1x|EanMBm1Xh768W7NGa3VV42HxUGA_JRN
zG;tCKcO6+xoE%Kp9Bp;^?&ZD9H;&!KJ258n*2*)6+W^r0%)H&$cW`l-eawB;5IGF^
zB7`iH3V{na;6d<#1YsZeAs~Z?b2BGJAOs8Y(u^CJlcr%2qB8JQWg%*_vD<b6BZIrl
zM`LBvtRH8S$-RBEd{RghYt>|>a{7<8`cdt`D4Gd-jH-%J)ReTkt7s*;peZ|suIMFA
z&Zw%crsVasUefI$6?g2zZ|;g=e|YY>_24}zd<%cbve_X;*v3Ac32D40OBi8~8r~KT
zXyP4VkSs}}S8)}eXd<@og&MvQ=Kk8P*$1prmzyV1in2`?eXu#|aU$iVAl1E7)RZ#V
Ov|l$Inay`n{L8=NVqaAN
delta 236
zcmWlQF-yZ>7=-VAzc!FyQ)5ygidZM3QwO2Jp*m^1>FVSnIN8-L;82K at dViqQ#Z9HS
z8YiJH;#S=RCl~t@{BpzH19$hZF-@)#oz6XOK1)0RaQ&0M-`c#pINN^e{`N&w8Z?@2
z0Tme3;0Fk?93VoY1(>Rqw1OB*tu?0#Ey=|ynzm(MV-EDoj;wfM^6_5fMrAbqbnYEF
zVqVK+NY~FKW$y3Gh#!7icInm&>2gxf<bb{TLSH<3K}U|+3o<$7Bq(&|@p9o+VjhNV
c{WJX5MGnJ6XNGTKN1Ak_o$_t{oO!hV4~J4bW&i*H
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o
index 5b3934816bd222383c5e63188c29bf390a1f19fa..bda7b179db43f8eb409811aadefcd1bd7b9b6b25 100644
GIT binary patch
delta 687
zcmZ9IO=uHQ5XawaOo;6!>?WJO-CH7xtzwhSCM2t1P$=!egMtSI!F*~WTUvB2o}$H%
zDio;<lzI{3MO%8XS<#D71rhaRJ>?>}cu>%bAnHM=Z#TP8IxqwO`TgI_d+&C(mt7d<
zWZ~Yvwy3D at CN_hF#n{c?X8Vb-_Oc9?!nFYQ;Pt>!Q1MM*H=MA(2R;G54hq-{woWF8
zo2EH^>0mm2zGXHqS4V48lWD`4>6Zi37pE>XYUU_|Nlk6k@@hdlr{?RKYF at 20bXBkC
zGeu3)wOl4!(Caz_xe*)-9fB2{4M}jvS`2kLaRr=v5%Pg$jBuoDo!&VP(8kUHRpwko
zSeuXt%N?Gc#|=i8w$U at 5e&C#iN2m@`c<$C0jvwA)WsoY)A}5 at g0ha$Z`_Xgh7YDKM
zH{R$=@&jM7vwuD1Q_0u(lkEz-Rl*cc#r at v1e5ZjbPqEC0;h5_>g|j?W&Tezfd-G;+
zji)e&VuZp1+RS<1b2>keVCmm_+3_gPw#<obq3`iX<STTok?0?QyO<Kj;Ul($0!Ie$
zq0q+iP#C`@c+80gB+*X9 at u_IwXW8q<Rw3hdf5i+aqAkVIjIY9DOi3k}aEU1yaGa5K
z=wT;Of->t~g(g;p*12#LchOrgiOaMAi)hmlEMZD6am6TB<->3dJ8}uGpe^tH53RAb
AUH||9
delta 612
zcmZ9JKS&!<9LL}9r8yGy%;nGda<oGV9g35eMMdyX5S_Yo=};&-6bc<oap}-&#Rv`(
zlrQ3_4h~(4$t`g(QVJ!~p#};~2eDHt?Gy`DK}dghJt5 at 5@AuyKeLuhVx0zqbuicmR
z#QLCX=Io=Hc2sbiTK=0TF7n{b5e~^Le|kV(PR<btEJY?ce~jEC;r))B5bB13X7t%D
zzYZJP7?sh`GPLIX&?+)nCVyUtV~&)NV&8ikpC(#Ht4CR-z!E$ygw7GH!98%dS6N$K
z?&DDJ`nB{9i at l0!LH^+L^ciKY`r1(y;qi6*e>)A_UmdQ$V=>f!knB at dyUWdlI*y4x
zMTsEaMuEwEc&(e0KM%=K>@fK-AfKSY<kK#4H6&kwbVVi1a^8fkD{DI>{Z}wKZce`E
zGuA=JI;jq~fpz^S?Rzi#FNnrbFs7s5d=&4a3SW#naxac^!<BUnFOsf2)^N^UlU1rF
zziY^+U3sRVlCIGs6f%yyWRY?Ck8SgiR?spXGGGt9#(Xk{>OhsMjHOXj3uNI+4bvp-
atV1&>WF2{?qmmt`A+)j%=2J0 at Sh;_1qnm92
diff --git a/llvm/test/tools/llvm-cov/mcdc-const.test b/llvm/test/tools/llvm-cov/mcdc-const.test
index 5424625cf6a6b5..9b6daebb36c6a8 100644
--- a/llvm/test/tools/llvm-cov/mcdc-const.test
+++ b/llvm/test/tools/llvm-cov/mcdc-const.test
@@ -5,10 +5,10 @@
// CHECKGENERALCASE: ------------------
// CHECKGENERALCASE-NEXT: | Branch (12:8): [True: 4, False: 1]
-// CHECKGENERALCASE-NEXT: | Branch (12:13): [Folded - Ignored]
-// CHECKGENERALCASE-NEXT: | Branch (12:20): [Folded - Ignored]
+// CHECKGENERALCASE-NEXT: | Branch (12:13): [True: 4, Folded]
+// CHECKGENERALCASE-NEXT: | Branch (12:20): [Folded, False: 1]
// CHECKGENERALCASE-NEXT: | Branch (12:25): [True: 0, False: 0]
-// CHECKGENERALCASE-NEXT: | Branch (12:31): [Folded - Ignored]
+// CHECKGENERALCASE-NEXT: | Branch (12:31): [Folded, False: 1]
// CHECKGENERALCASE-NEXT: ------------------
// CHECKGENERALCASE-NEXT: |---> MC/DC Decision Region (12:7) to (12:32)
// CHECKGENERALCASE-NEXT: |
@@ -28,7 +28,7 @@
// CHECKGENERALCASE-NEXT: | C1-Pair: covered: (1,2)
// CHECKGENERALCASE-NEXT: | C2-Pair: constant folded
// CHECKGENERALCASE-NEXT: | C3-Pair: constant folded
-// CHECKGENERALCASE-NEXT: | C4-Pair: not covered
+// CHECKGENERALCASE-NEXT: | C4-Pair: unreachable
// CHECKGENERALCASE-NEXT: | C5-Pair: constant folded
// CHECKGENERALCASE-NEXT: | MC/DC Coverage for Decision: 50.00%
// CHECKGENERALCASE-NEXT: |
@@ -40,11 +40,11 @@
// CHECKFULLCASE: | 1 { C, - = F }
// CHECKFULLCASE: | C1-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C2-Pair: not covered
+// CHECKFULLCASE-NEXT: | C2-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, C = F }
// CHECKFULLCASE-NEXT: | 2 { T, C = F }
-// CHECKFULLCASE: | C1-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C2-Pair: constant folded
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { C, F = F }
@@ -59,11 +59,11 @@
// CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00%
// CHECKFULLCASE: | 1 { C, - = T }
// CHECKFULLCASE: | C1-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C2-Pair: not covered
+// CHECKFULLCASE-NEXT: | C2-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, C = T }
// CHECKFULLCASE-NEXT: | 2 { T, C = T }
-// CHECKFULLCASE: | C1-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C2-Pair: constant folded
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { C, F = F }
@@ -78,14 +78,14 @@
// CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00%
// CHECKFULLCASE: | 1 { C, -, - = F }
// CHECKFULLCASE: | C1-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C2-Pair: not covered
-// CHECKFULLCASE-NEXT: | C3-Pair: not covered
+// CHECKFULLCASE-NEXT: | C2-Pair: unreachable
+// CHECKFULLCASE-NEXT: | C3-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, C, - = F }
// CHECKFULLCASE-NEXT: | 2 { T, C, - = F }
-// CHECKFULLCASE: | C1-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C2-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C3-Pair: not covered
+// CHECKFULLCASE-NEXT: | C3-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { C, F, - = F }
// CHECKFULLCASE-NEXT: | 2 { C, T, F = F }
@@ -103,14 +103,14 @@
// CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00%
// CHECKFULLCASE: | 1 { C, -, - = T }
// CHECKFULLCASE: | C1-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C2-Pair: not covered
-// CHECKFULLCASE-NEXT: | C3-Pair: not covered
+// CHECKFULLCASE-NEXT: | C2-Pair: unreachable
+// CHECKFULLCASE-NEXT: | C3-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, C, - = T }
// CHECKFULLCASE-NEXT: | 2 { T, C, - = T }
-// CHECKFULLCASE: | C1-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C2-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C3-Pair: not covered
+// CHECKFULLCASE-NEXT: | C3-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { C, F, T = T }
// CHECKFULLCASE-NEXT: | 2 { C, T, - = T }
@@ -127,15 +127,15 @@
// CHECKFULLCASE: | 1 { F, -, C = F }
// CHECKFULLCASE-NEXT: | 2 { T, F, C = F }
// CHECKFULLCASE-NEXT: | 3 { T, T, C = F }
-// CHECKFULLCASE: | C1-Pair: not covered
-// CHECKFULLCASE-NEXT: | C2-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
+// CHECKFULLCASE-NEXT: | C2-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C3-Pair: constant folded
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, C, - = F }
// CHECKFULLCASE-NEXT: | 2 { T, C, - = F }
-// CHECKFULLCASE: | C1-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C2-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C3-Pair: not covered
+// CHECKFULLCASE-NEXT: | C3-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, -, C = F }
// CHECKFULLCASE-NEXT: | 2 { T, F, C = F }
@@ -153,15 +153,15 @@
// CHECKFULLCASE: | MC/DC Coverage for Decision: 100.00%
// CHECKFULLCASE: | 1 { F, T, C = T }
// CHECKFULLCASE-NEXT: | 2 { T, -, C = T }
-// CHECKFULLCASE: | C1-Pair: not covered
-// CHECKFULLCASE-NEXT: | C2-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
+// CHECKFULLCASE-NEXT: | C2-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C3-Pair: constant folded
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, C, - = T }
// CHECKFULLCASE-NEXT: | 2 { T, C, - = T }
-// CHECKFULLCASE: | C1-Pair: not covered
+// CHECKFULLCASE: | C1-Pair: uncoverable
// CHECKFULLCASE-NEXT: | C2-Pair: constant folded
-// CHECKFULLCASE-NEXT: | C3-Pair: not covered
+// CHECKFULLCASE-NEXT: | C3-Pair: unreachable
// CHECKFULLCASE: | MC/DC Coverage for Decision: 0.00%
// CHECKFULLCASE: | 1 { F, T, C = T }
// CHECKFULLCASE-NEXT: | 2 { T, -, C = T }
diff --git a/llvm/test/tools/llvm-cov/mcdc-macro.test b/llvm/test/tools/llvm-cov/mcdc-macro.test
index 14dd5ebd68eb1a..9d0da4b0ad02c2 100644
--- a/llvm/test/tools/llvm-cov/mcdc-macro.test
+++ b/llvm/test/tools/llvm-cov/mcdc-macro.test
@@ -3,7 +3,7 @@
// RUN: llvm-profdata merge %S/Inputs/mcdc-macro.proftext -o %t.profdata
// RUN: llvm-cov show --show-expansions --show-branches=count --show-mcdc %S/Inputs/mcdc-macro.o -instr-profile %t.profdata --compilation-dir=%S/Inputs | FileCheck %s
-// CHECK: | | | Branch (2:11): [Folded - Ignored]
+// CHECK: | | | Branch (2:11): [True: 1, Folded]
// CHECK: | | | Branch (3:11): [True: 1, False: 0]
// CHECK: | | | Branch (3:23): [True: 1, False: 0]
// CHECK: | Branch (9:7): [True: 1, False: 0]
@@ -32,7 +32,7 @@
// CHECK-NEXT: |
// CHECK-NEXT: ------------------
-// CHECK: | | | Branch (2:11): [Folded - Ignored]
+// CHECK: | | | Branch (2:11): [True: 1, Folded]
// CHECK: | Branch (11:7): [True: 1, False: 0]
// CHECK-NEXT: ------------------
// CHECK-NEXT: |---> MC/DC Decision Region (11:7) to (11:13)
@@ -53,7 +53,7 @@
// CHECK-NEXT: ------------------
// CHECK: | | | Branch (1:11): [True: 1, False: 0]
-// CHECK: | | | Branch (2:11): [Folded - Ignored]
+// CHECK: | | | Branch (2:11): [True: 0, Folded]
// CHECK: | | | | | Branch (3:11): [True: 0, False: 0]
// CHECK: | | | | | Branch (3:23): [True: 0, False: 0]
// CHECK: | Branch (13:7): [True: 1, False: 0]
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 00aea4039bfdeb..5091ac09d142c0 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -379,7 +379,9 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
(unsigned)(Function.MCDCCoverage.getNumPairs() -
Function.MCDCCoverage.getCoveredPairs()));
Options.colored_ostream(
- OS, determineCoveragePercentageColor(Function.MCDCCoverage))
+ OS, Function.MCDCCoverage.getNumPairs() == 0
+ ? raw_ostream::GREEN
+ : determineCoveragePercentageColor(Function.MCDCCoverage))
<< format("%*.2f", FunctionReportColumns[12] - 1,
Function.MCDCCoverage.getPercentCovered())
<< '%';
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 58e7918d392709..6d94bfc65f3365 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -50,7 +50,7 @@ sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
for (const auto &Record : Records) {
const auto NumConditions = Record.getNumConditions();
for (unsigned C = 0; C < NumConditions; C++) {
- if (!Record.isCondFolded(C))
+ if (!Record.isCondConstant(C))
++NumPairs;
if (Record.isConditionIndependencePairCovered(C))
++CoveredPairs;
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 7421763dd7a427..35bc2c49178e83 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -1209,7 +1209,12 @@ void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
for (unsigned i = 0; i < Record.getNumConditions(); i++)
OS << Record.getConditionCoverageString(i);
OS << " MC/DC Coverage for Expression: ";
- OS << format("%0.2f", Record.getPercentCovered()) << "%\n";
+ const auto [Coverable, Percent] = Record.getPercentCovered();
+ if (Coverable) {
+ OS << format("%0.2f", Percent) << "%\n";
+ } else {
+ OS << "Folded\n";
+ }
OS << EndPre;
OS << EndExpansionDiv;
}
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 444f33dac10837..a9c80d09fc1bb6 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -386,10 +386,16 @@ void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
}
renderLinePrefix(OS, ViewDepth);
OS << " MC/DC Coverage for Decision: ";
- colored_ostream(OS, raw_ostream::RED,
- getOptions().Colors && Record.getPercentCovered() < 100.0,
- /*Bold=*/false, /*BG=*/true)
- << format("%0.2f", Record.getPercentCovered()) << "%";
+ const auto [Coverable, Percent] = Record.getPercentCovered();
+ if (Coverable) {
+ colored_ostream(OS, raw_ostream::RED,
+ getOptions().Colors && Percent < 100.0,
+ /*Bold=*/false, /*BG=*/true)
+ << format("%0.2f", Percent) << "%";
+ } else {
+ OS << "Folded";
+ }
+
OS << "\n";
renderLinePrefix(OS, ViewDepth);
OS << "\n";
>From 55f0b692e09b99c1c4150cb296ae02f9d298d743 Mon Sep 17 00:00:00 2001
From: Lambdaris <Lambdaris at outlook.com>
Date: Sat, 13 Jul 2024 14:20:53 +0800
Subject: [PATCH 3/3] [coverage] add option to exclude special conditions from
MC/DC report
---
llvm/docs/CommandGuide/llvm-cov.rst | 12 ++++
.../ProfileData/Coverage/CoverageMapping.h | 13 ++--
.../tools/llvm-cov/Inputs/mcdc-exclude.cpp | 25 ++++++++
.../test/tools/llvm-cov/Inputs/mcdc-exclude.o | Bin 0 -> 4400 bytes
.../llvm-cov/Inputs/mcdc-exclude.proftext | 34 +++++++++++
llvm/test/tools/llvm-cov/mcdc-exclude.test | 56 ++++++++++++++++++
llvm/tools/llvm-cov/CodeCoverage.cpp | 24 ++++++++
llvm/tools/llvm-cov/CoverageReport.cpp | 6 +-
llvm/tools/llvm-cov/CoverageSummaryInfo.cpp | 13 ++--
llvm/tools/llvm-cov/CoverageSummaryInfo.h | 4 +-
llvm/tools/llvm-cov/CoverageViewOptions.h | 1 +
llvm/tools/llvm-cov/SourceCoverageView.h | 10 ++--
.../tools/llvm-cov/SourceCoverageViewHTML.cpp | 3 +-
.../tools/llvm-cov/SourceCoverageViewText.cpp | 3 +-
14 files changed, 183 insertions(+), 21 deletions(-)
create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.cpp
create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.o
create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.proftext
create mode 100644 llvm/test/tools/llvm-cov/mcdc-exclude.test
diff --git a/llvm/docs/CommandGuide/llvm-cov.rst b/llvm/docs/CommandGuide/llvm-cov.rst
index 968f3c452f5584..26b881fc6a4aed 100644
--- a/llvm/docs/CommandGuide/llvm-cov.rst
+++ b/llvm/docs/CommandGuide/llvm-cov.rst
@@ -227,6 +227,12 @@ OPTIONS
Show modified condition/decision coverage (MC/DC) for each applicable boolean
expression.
+.. option:: -mcdc-exclude
+
+ Set which special states of conditions should be excluded from coverage (MC/DC). Possible
+ values are: "none", "uncoverable", "constant", "unreachable", separated by comma. Default
+ to "constant".
+
.. option:: -show-line-counts
Show the execution counts for each line. Defaults to true, unless another
@@ -435,6 +441,12 @@ OPTIONS
Show MC/DC statistics. Defaults to false.
+.. option:: -mcdc-exclude-uncoverable
+
+ MC/DC does not count uncoverable conditions. Default to false.
+ Uncoverable conditions are conditions that may be evaluated but can not affect
+ the outcome of decisions due to constants.
+
.. option:: -show-functions
Show coverage summaries for each function. Defaults to false.
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 3136a1d26cca5e..47c283a29da868 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -386,10 +386,10 @@ struct MCDCRecord {
enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
enum CondResult {
- MCDC_Normal,
- MCDC_Constant,
- MCDC_Uncoverable,
- MCDC_Unreachable
+ MCDC_Normal = 0x1,
+ MCDC_Constant = 0x2,
+ MCDC_Uncoverable = 0x4,
+ MCDC_Unreachable = 0x8
};
/// Emulate SmallVector<CondState> with a pair of BitVector.
@@ -521,11 +521,12 @@ struct MCDCRecord {
/// Return if the decision is coverable and percent of covered conditions.
/// Only coverable conditions are counted as denominator.
- std::pair<bool, float> getPercentCovered() const {
+ std::pair<bool, float> getPercentCovered(int32_t CountedStates) const {
unsigned Excluded = 0;
unsigned Covered = 0;
+ auto ExcludedStates = ~CountedStates;
for (unsigned C = 0; C < getNumConditions(); C++) {
- if (isCondConstant(C))
+ if (getCondResult(C) & ExcludedStates)
Excluded++;
else if (isConditionIndependencePairCovered(C))
Covered++;
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.cpp b/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.cpp
new file mode 100644
index 00000000000000..ebf4d5e1200d4a
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.cpp
@@ -0,0 +1,25 @@
+#include <stdio.h>
+
+
+
+
+
+
+
+
+void test(bool a,bool b, bool c, bool d) {
+
+ if (a && (b || true || c) && ( true || d) && true)
+ printf("test 1 decision true\n");
+
+}
+
+int main()
+{
+ test(true,false,true,false);
+ test(true,false,true,true);
+ test(true,true,false,false);
+ test(false,true,true,false);
+ test(true,false,false,false);
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.o
new file mode 100644
index 0000000000000000000000000000000000000000..ef0cab25965fe624626d1a3068b8efba4a9b2d8e
GIT binary patch
literal 4400
zcmcgvO>7%g5T5nMKS`U!Nt>#FksL&;q%<45jek-V<fci8L<9xFp%mme>vbB4e`K$t
z!lg!{LaJ0KNSs09hJ;kkKxx%e#EDA4flDPMD7T_k6 at MbkJkQwA8(SPIG1BhLd~e>&
zy!YnK+85`S7JP<b0+Rtxfgy^<@AbBnv=Y-Wik6F8e$p;&xo27YJdl3-VXarR;Qhgp
zGRY5aY~~05x_N)_qSCJ!x9^0M)Us%eE?#+({QgR>dcS(#I>SD{rUYXTW4B|QcWI=f
zeq9-f3D0Ct-U+cAXK#@sq|2M%6t=Ga^T8J=zyILmdq1W6V0QGYR~DnIhG7JZk&&^n
zL;FUDCMG8L8+}LozOZ2cjsziOKoAbn>nOeA<3mAW(Gj1~11N<?U?&_LfqodE*Pdu#
ztj7$HItIh2_Cdh(le7=^!-43)s2>jnr6GvG(II#Y4o8Q<^aV+pfFtlkbkAha2PE}E
z3<LE8Y9#p~VO*-$>mk44heIks`189fza(-W{z%8T7ayY5x^M-<202qS!aRW7Hw+Li
z*g1RBxnQr?a*kz}%RK&nFgXu7i~owbQ!{85HDa=US-WP|QS{z{Fl1hycAcubf at Bo3
zYeiBbu}IFb*Q#r!V#KY~8~}SgTU?E7I2DD(W~`_cU0rh{<L6zsTs<*0h06Kbie;Ay
zQ|s#+jn`zkQhLp?U5hN^)6>aZG8UUj<eU{Jg+ex!w~x;pv$L^$JQq*q<4OB?GBKg@
z-p$z?Z at vJ=g|Km8XE1aXlMf?)kjK`U)7qmfze at bnK-hO~AVeaqmo6jmAU;HW4Tfb4
zSf&62tdnmdEDhL&kK{m at m)=F72Y%b~;-s6ZVB1IDLe+phO;Bo)025TI%`t^h!k{%L
zZPaY8pat$#_B&dDCYfrb8o;8dR^N_Oe*hS42U#=K?zazZDs`wGY}(UKZYNXiZYNyd
zmBx4k*EOu|r=0mSI4tL-d- at g?vKKp54~S9CjQLbsR^~sbccU)Gu=xlbVnOa0^$t3n
zzqcABwIcZAY%et__({eOGZ$QHD$xZ`YdG~OiMy!bln=IEMK3ZJ|AL>>a9WG_S!SH<
z=+p$yGfsZ=xMdBeyCU{=#>o$zgWy-Y;GcBCKV at 9<7eCiDT+iob7eAB(5%mJvA6*xm
z{79eF$7x-<F7|Yr#6ChG66Hyc&@>BzOWp0--4h7)?&u#FgiOXRZB!gPGdDXEPfQ<A
z%qLTGbMb{!wbszgv4#2B`GtkV-09iVGbtRhD$aV=a-9n<P*W{9MHk97w~BM9zh=sn
ze8w)e>nm&RdNEsYs$eZu-3nN%l~Sz?+dg^h4pS^-%i<ihe65HYHt_sPAw%B<*6fC2
z6-%yTJ^k!UlT|lszYdm4Dx1sU2V#|zcg|<>6-=S!NBh<^-RYQxnY!5(u&Qqq6sJwl
z7M#nvS#(|^PPQ>CCI|6|9DmzjAKp%vshE(KRex>B^!BJg_nk1RF`d$^H2P#~MDD2|
zNfZc63&1?h4zF=Q>N8YpoK~|w-$ATX7Y=bCv8Va;ZIk%IKSNA~@I_E+QJCXOzmyU2
zCwjN|;STYs2TEMw-QwTn_|lgpo;UtSIM6VSh>7B1zO3VIXlwrj?w0 at F4*AnpMDiBC
zj2Oi?IUb6NQmlJxi<c#4&@Fz114w_O^9$l5afP2jtW*3n$6v;AoxJ;Z3MY4(|1r-`
z>yuIT&OeEhRW6?O-=k!aq7A0L!_;qOzVz2_>yPpR#h%trzu#ot!j}>2l>Z%1K4_+h
zY<21uKg9v`{iolJ5?6S){g?QXzr^(F-S+?PBkq5M1L^xu_g~`6{+AJ>J at G*V-z^&F
z!u9@=^X}jC2oQFxHC0I`c)s_Soy-?Li`FDdp5o>?o?j4vxy%#(J>nwkreAt5o at c(;
z{?V9U_Lj>Hp1&xD%w_)set-hiLRtXkXFBZvJ{*(zvj0CLW-e`&kk#>NQk at OuKMU1A
Zk$0`r2zYZRyG1V0-+2PDFh1V+{{mb$xK{uG
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.proftext
new file mode 100644
index 00000000000000..e1f88453360cf5
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-exclude.proftext
@@ -0,0 +1,34 @@
+_Z4testbbbb
+# Func Hash:
+2877299778974865
+# Num Counters:
+12
+# Counter Values:
+5
+4
+4
+4
+4
+4
+0
+0
+3
+0
+0
+0
+# Num Bitmap Bytes:
+$3
+# Bitmap Byte Values:
+0xc0
+0x80
+0x0
+
+
+main
+# Func Hash:
+24
+# Num Counters:
+1
+# Counter Values:
+1
+
diff --git a/llvm/test/tools/llvm-cov/mcdc-exclude.test b/llvm/test/tools/llvm-cov/mcdc-exclude.test
new file mode 100644
index 00000000000000..11161cbda18647
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/mcdc-exclude.test
@@ -0,0 +1,56 @@
+// Test visualization of MC/DC constructs for constant-folded condition masking with different counted states.
+
+// RUN: llvm-profdata merge %S/Inputs/mcdc-exclude.proftext -o %t.profdata
+// RUN: llvm-cov show --show-mcdc %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=DEFAULTCASE
+// RUN: llvm-cov report --show-mcdc-summary %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-exclude.cpp | FileCheck %s -check-prefix=REPORTDEFAULT
+
+// DEFAULTCASE: | MC/DC Coverage for Decision: 25.00%
+
+// REPORTDEFAULT: TOTAL {{.*}} 4 3 25.00%
+
+// RUN: llvm-cov show --show-mcdc --mcdc-exclude=uncoverable %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=EXCLUDEUNCOVERABECASE
+// RUN: llvm-cov report --show-mcdc-summary --mcdc-exclude=uncoverable %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-exclude.cpp | FileCheck %s -check-prefix=REPORTEXCLUDEUNCOVERABLE
+
+// EXCLUDEUNCOVERABECASE: | MC/DC Coverage for Decision: 16.67%
+
+// REPORTEXCLUDEUNCOVERABLE: TOTAL {{.*}} 6 5 16.67%
+
+// RUN: llvm-cov show --show-mcdc --mcdc-exclude=constant %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=EXCLUDECONSTANTCASE
+// RUN: llvm-cov report --show-mcdc-summary --mcdc-exclude=constant %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-exclude.cpp | FileCheck %s -check-prefix=REPORTEXCLUDECONSTANT
+
+// EXCLUDECONSTANTCASE: | MC/DC Coverage for Decision: 25.00%
+
+// REPORTEXCLUDECONSTANT: TOTAL {{.*}} 4 3 25.00%
+
+// RUN: llvm-cov show --show-mcdc --mcdc-exclude=unreachable %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=EXCLUDEUNREACHABLECASE
+// RUN: llvm-cov report --show-mcdc-summary --mcdc-exclude=unreachable %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-exclude.cpp | FileCheck %s -check-prefix=REPORTEXCLUDEUNREACHABLE
+
+// EXCLUDEUNREACHABLECASE: | MC/DC Coverage for Decision: 20.00%
+
+// REPORTEXCLUDEUNREACHABLE: TOTAL {{.*}} 5 4 20.00%
+
+// RUN: llvm-cov show --show-mcdc --mcdc-exclude=none %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=INCLUDEALLCASE
+// RUN: llvm-cov report --show-mcdc-summary --mcdc-exclude=none %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/mcdc-exclude.cpp | FileCheck %s -check-prefix=REPORTALL
+
+// INCLUDEALLCASE: | MC/DC Coverage for Decision: 14.29%
+
+// REPORTALL: TOTAL {{.*}} 7 6 14.29%
+Instructions for regenerating the test:
+
+cd %S/Inputs # Or copy files into the working directory
+
+clang++ -c -Os \
+ -fcoverage-compilation-dir=. -mllvm -enable-name-compression=false \
+ -fcoverage-mcdc -fprofile-instr-generate -fcoverage-mapping \
+ mcdc-exclude.cpp
+
+# Instructions for regenerating proftext
+
+for x in mcdc-exclude; do (
+ clang++ -fprofile-instr-generate $x.o -o $x
+ find -name '*.profraw' | xargs rm -f
+ export LLVM_PROFILE_FILE=$x-%p.profraw
+ ./$x 0 1
+ llvm-profdata merge --sparse -o $x.profdata $(find -name '*.profraw')
+ llvm-profdata merge --text -o $x.proftext $x.profdata
+); done
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index d06fd86fe52afb..bdce4276388748 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -773,6 +773,12 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
cl::desc("Show MCDC statistics in summary table"),
cl::init(false));
+ cl::list<std::string> MCDCExcludeStates(
+ "mcdc-exclude", cl::Optional,
+ cl::desc(
+ "Set which abnormal kinds of conditions are excluded from MC/DC"),
+ cl::CommaSeparated, cl::list_init<std::string>({"constant"}));
+
cl::opt<bool> InstantiationSummary(
"show-instantiation-summary", cl::Optional,
cl::desc("Show instantiation statistics in summary table"));
@@ -944,6 +950,24 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
::exit(0);
}
+ ViewOpts.MCDCCountedStates =
+ MCDCRecord::MCDC_Normal | MCDCRecord::MCDC_Uncoverable |
+ MCDCRecord::MCDC_Constant | MCDCRecord::MCDC_Unreachable;
+ for (const auto &State : MCDCExcludeStates) {
+ if (State == "uncoverable") {
+ ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Uncoverable;
+ } else if (State == "constant") {
+ ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Constant;
+ } else if (State == "unreachable") {
+ ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Unreachable;
+ } else if (State != "none") {
+ error("invalid argument '" + State +
+ "', must be in one of 'uncoverable, constant, unreachable'",
+ "--mcdc-exclude");
+ return 1;
+ }
+ }
+
ViewOpts.ShowMCDCSummary = MCDCSummary;
ViewOpts.ShowBranchSummary = BranchSummary;
ViewOpts.ShowRegionSummary = RegionSummary;
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 5091ac09d142c0..0d45a59e97fbc5 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -428,7 +428,8 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
OS << "\n";
FunctionCoverageSummary Totals("TOTAL");
for (const auto &F : Functions) {
- auto Function = FunctionCoverageSummary::get(Coverage, F);
+ auto Function =
+ FunctionCoverageSummary::get(Coverage, F, Options.MCDCCountedStates);
++Totals.ExecutionCount;
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
@@ -453,7 +454,8 @@ void CoverageReport::prepareSingleFileReport(const StringRef Filename,
for (const coverage::FunctionRecord *F : Group.getInstantiations()) {
if (!Filters->matches(*Coverage, *F))
continue;
- auto InstantiationSummary = FunctionCoverageSummary::get(*Coverage, *F);
+ auto InstantiationSummary = FunctionCoverageSummary::get(
+ *Coverage, *F, Options.MCDCCountedStates);
FileReport->addInstantiation(InstantiationSummary);
InstantiationSummaries.push_back(InstantiationSummary);
}
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 6d94bfc65f3365..b31c1ef30b26e8 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CoverageSummaryInfo.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
using namespace llvm;
using namespace coverage;
@@ -44,13 +45,13 @@ static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches,
}
}
-static std::pair<size_t, size_t>
-sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
+static std::tuple<size_t, size_t>
+sumMCDCPairs(const ArrayRef<MCDCRecord> &Records, const int32_t CountFlags) {
size_t NumPairs = 0, CoveredPairs = 0;
for (const auto &Record : Records) {
const auto NumConditions = Record.getNumConditions();
for (unsigned C = 0; C < NumConditions; C++) {
- if (!Record.isCondConstant(C))
+ if (Record.getCondResult(C) & CountFlags)
++NumPairs;
if (Record.isConditionIndependencePairCovered(C))
++CoveredPairs;
@@ -61,7 +62,8 @@ sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
FunctionCoverageSummary
FunctionCoverageSummary::get(const CoverageMapping &CM,
- const coverage::FunctionRecord &Function) {
+ const coverage::FunctionRecord &Function,
+ const int32_t MCDCCountedFlags) {
// Compute the region coverage.
size_t NumCodeRegions = 0, CoveredRegions = 0;
for (auto &CR : Function.CountedRegions) {
@@ -89,7 +91,8 @@ FunctionCoverageSummary::get(const CoverageMapping &CM,
sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
size_t NumPairs = 0, CoveredPairs = 0;
- std::tie(NumPairs, CoveredPairs) = sumMCDCPairs(CD.getMCDCRecords());
+ std::tie(NumPairs, CoveredPairs) =
+ sumMCDCPairs(CD.getMCDCRecords(), MCDCCountedFlags);
return FunctionCoverageSummary(
Function.Name, Function.ExecutionCount,
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 64c2c8406cf3eb..d4ca70948df9ea 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -16,6 +16,7 @@
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
namespace llvm {
@@ -247,7 +248,8 @@ struct FunctionCoverageSummary {
/// Compute the code coverage summary for the given function coverage
/// mapping record.
static FunctionCoverageSummary get(const coverage::CoverageMapping &CM,
- const coverage::FunctionRecord &Function);
+ const coverage::FunctionRecord &Function,
+ int32_t MCDCCountedFlags = 0);
/// Compute the code coverage summary for an instantiation group \p Group,
/// given a list of summaries for each instantiation in \p Summaries.
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index 6925cffd8246d2..0282964ed449e1 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -45,6 +45,7 @@ struct CoverageViewOptions {
bool SkipExpansions;
bool SkipFunctions;
bool SkipBranches;
+ int32_t MCDCCountedStates;
OutputFormat Format;
BranchOutputType ShowBranches;
std::string ShowOutputDirectory;
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index 2b1570d399dd0b..27ae7e9208bd3c 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -161,9 +161,6 @@ class SourceCoverageView {
/// A memory buffer backing the source on display.
const MemoryBuffer &File;
- /// Various options to guide the coverage renderer.
- const CoverageViewOptions &Options;
-
/// Complete coverage information about the source on display.
CoverageData CoverageInfo;
@@ -193,6 +190,9 @@ class SourceCoverageView {
using CoverageSegmentArray = ArrayRef<const CoverageSegment *>;
+ /// Various options to guide the coverage renderer.
+ const CoverageViewOptions &Options;
+
/// @name Rendering Interface
/// @{
@@ -275,8 +275,8 @@ class SourceCoverageView {
SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
const CoverageViewOptions &Options,
CoverageData &&CoverageInfo)
- : SourceName(SourceName), File(File), Options(Options),
- CoverageInfo(std::move(CoverageInfo)) {}
+ : SourceName(SourceName), File(File),
+ CoverageInfo(std::move(CoverageInfo)), Options(Options) {}
public:
static std::unique_ptr<SourceCoverageView>
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 35bc2c49178e83..11e119b518da9b 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -1209,7 +1209,8 @@ void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
for (unsigned i = 0; i < Record.getNumConditions(); i++)
OS << Record.getConditionCoverageString(i);
OS << " MC/DC Coverage for Expression: ";
- const auto [Coverable, Percent] = Record.getPercentCovered();
+ const auto [Coverable, Percent] =
+ Record.getPercentCovered(Options.MCDCCountedStates);
if (Coverable) {
OS << format("%0.2f", Percent) << "%\n";
} else {
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index a9c80d09fc1bb6..cbb076b859c85e 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -386,7 +386,8 @@ void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
}
renderLinePrefix(OS, ViewDepth);
OS << " MC/DC Coverage for Decision: ";
- const auto [Coverable, Percent] = Record.getPercentCovered();
+ const auto [Coverable, Percent] =
+ Record.getPercentCovered(Options.MCDCCountedStates);
if (Coverable) {
colored_ostream(OS, raw_ostream::RED,
getOptions().Colors && Percent < 100.0,
More information about the cfe-commits
mailing list