Skip to content

Commit 55f0b69

Browse files
committed
[coverage] add option to exclude special conditions from MC/DC report
1 parent 10e2be0 commit 55f0b69

14 files changed

+183
-21
lines changed

llvm/docs/CommandGuide/llvm-cov.rst

+12
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ OPTIONS
227227
Show modified condition/decision coverage (MC/DC) for each applicable boolean
228228
expression.
229229

230+
.. option:: -mcdc-exclude
231+
232+
Set which special states of conditions should be excluded from coverage (MC/DC). Possible
233+
values are: "none", "uncoverable", "constant", "unreachable", separated by comma. Default
234+
to "constant".
235+
230236
.. option:: -show-line-counts
231237

232238
Show the execution counts for each line. Defaults to true, unless another
@@ -435,6 +441,12 @@ OPTIONS
435441

436442
Show MC/DC statistics. Defaults to false.
437443

444+
.. option:: -mcdc-exclude-uncoverable
445+
446+
MC/DC does not count uncoverable conditions. Default to false.
447+
Uncoverable conditions are conditions that may be evaluated but can not affect
448+
the outcome of decisions due to constants.
449+
438450
.. option:: -show-functions
439451

440452
Show coverage summaries for each function. Defaults to false.

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

+7-6
Original file line numberDiff line numberDiff line change
@@ -386,10 +386,10 @@ struct MCDCRecord {
386386
enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
387387

388388
enum CondResult {
389-
MCDC_Normal,
390-
MCDC_Constant,
391-
MCDC_Uncoverable,
392-
MCDC_Unreachable
389+
MCDC_Normal = 0x1,
390+
MCDC_Constant = 0x2,
391+
MCDC_Uncoverable = 0x4,
392+
MCDC_Unreachable = 0x8
393393
};
394394

395395
/// Emulate SmallVector<CondState> with a pair of BitVector.
@@ -521,11 +521,12 @@ struct MCDCRecord {
521521

522522
/// Return if the decision is coverable and percent of covered conditions.
523523
/// Only coverable conditions are counted as denominator.
524-
std::pair<bool, float> getPercentCovered() const {
524+
std::pair<bool, float> getPercentCovered(int32_t CountedStates) const {
525525
unsigned Excluded = 0;
526526
unsigned Covered = 0;
527+
auto ExcludedStates = ~CountedStates;
527528
for (unsigned C = 0; C < getNumConditions(); C++) {
528-
if (isCondConstant(C))
529+
if (getCondResult(C) & ExcludedStates)
529530
Excluded++;
530531
else if (isConditionIndependencePairCovered(C))
531532
Covered++;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <stdio.h>
2+
3+
4+
5+
6+
7+
8+
9+
10+
void test(bool a,bool b, bool c, bool d) {
11+
12+
if (a && (b || true || c) && ( true || d) && true)
13+
printf("test 1 decision true\n");
14+
15+
}
16+
17+
int main()
18+
{
19+
test(true,false,true,false);
20+
test(true,false,true,true);
21+
test(true,true,false,false);
22+
test(false,true,true,false);
23+
test(true,false,false,false);
24+
return 0;
25+
}
4.3 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
_Z4testbbbb
2+
# Func Hash:
3+
2877299778974865
4+
# Num Counters:
5+
12
6+
# Counter Values:
7+
5
8+
4
9+
4
10+
4
11+
4
12+
4
13+
0
14+
0
15+
3
16+
0
17+
0
18+
0
19+
# Num Bitmap Bytes:
20+
$3
21+
# Bitmap Byte Values:
22+
0xc0
23+
0x80
24+
0x0
25+
26+
27+
main
28+
# Func Hash:
29+
24
30+
# Num Counters:
31+
1
32+
# Counter Values:
33+
1
34+
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Test visualization of MC/DC constructs for constant-folded condition masking with different counted states.
2+
3+
// RUN: llvm-profdata merge %S/Inputs/mcdc-exclude.proftext -o %t.profdata
4+
// RUN: llvm-cov show --show-mcdc %S/Inputs/mcdc-exclude.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefix=DEFAULTCASE
5+
// 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
6+
7+
// DEFAULTCASE: | MC/DC Coverage for Decision: 25.00%
8+
9+
// REPORTDEFAULT: TOTAL {{.*}} 4 3 25.00%
10+
11+
// 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
12+
// 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
13+
14+
// EXCLUDEUNCOVERABECASE: | MC/DC Coverage for Decision: 16.67%
15+
16+
// REPORTEXCLUDEUNCOVERABLE: TOTAL {{.*}} 6 5 16.67%
17+
18+
// 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
19+
// 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
20+
21+
// EXCLUDECONSTANTCASE: | MC/DC Coverage for Decision: 25.00%
22+
23+
// REPORTEXCLUDECONSTANT: TOTAL {{.*}} 4 3 25.00%
24+
25+
// 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
26+
// 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
27+
28+
// EXCLUDEUNREACHABLECASE: | MC/DC Coverage for Decision: 20.00%
29+
30+
// REPORTEXCLUDEUNREACHABLE: TOTAL {{.*}} 5 4 20.00%
31+
32+
// 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
33+
// 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
34+
35+
// INCLUDEALLCASE: | MC/DC Coverage for Decision: 14.29%
36+
37+
// REPORTALL: TOTAL {{.*}} 7 6 14.29%
38+
Instructions for regenerating the test:
39+
40+
cd %S/Inputs # Or copy files into the working directory
41+
42+
clang++ -c -Os \
43+
-fcoverage-compilation-dir=. -mllvm -enable-name-compression=false \
44+
-fcoverage-mcdc -fprofile-instr-generate -fcoverage-mapping \
45+
mcdc-exclude.cpp
46+
47+
# Instructions for regenerating proftext
48+
49+
for x in mcdc-exclude; do (
50+
clang++ -fprofile-instr-generate $x.o -o $x
51+
find -name '*.profraw' | xargs rm -f
52+
export LLVM_PROFILE_FILE=$x-%p.profraw
53+
./$x 0 1
54+
llvm-profdata merge --sparse -o $x.profdata $(find -name '*.profraw')
55+
llvm-profdata merge --text -o $x.proftext $x.profdata
56+
); done

llvm/tools/llvm-cov/CodeCoverage.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,12 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
773773
cl::desc("Show MCDC statistics in summary table"),
774774
cl::init(false));
775775

776+
cl::list<std::string> MCDCExcludeStates(
777+
"mcdc-exclude", cl::Optional,
778+
cl::desc(
779+
"Set which abnormal kinds of conditions are excluded from MC/DC"),
780+
cl::CommaSeparated, cl::list_init<std::string>({"constant"}));
781+
776782
cl::opt<bool> InstantiationSummary(
777783
"show-instantiation-summary", cl::Optional,
778784
cl::desc("Show instantiation statistics in summary table"));
@@ -944,6 +950,24 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
944950
::exit(0);
945951
}
946952

953+
ViewOpts.MCDCCountedStates =
954+
MCDCRecord::MCDC_Normal | MCDCRecord::MCDC_Uncoverable |
955+
MCDCRecord::MCDC_Constant | MCDCRecord::MCDC_Unreachable;
956+
for (const auto &State : MCDCExcludeStates) {
957+
if (State == "uncoverable") {
958+
ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Uncoverable;
959+
} else if (State == "constant") {
960+
ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Constant;
961+
} else if (State == "unreachable") {
962+
ViewOpts.MCDCCountedStates &= ~MCDCRecord::MCDC_Unreachable;
963+
} else if (State != "none") {
964+
error("invalid argument '" + State +
965+
"', must be in one of 'uncoverable, constant, unreachable'",
966+
"--mcdc-exclude");
967+
return 1;
968+
}
969+
}
970+
947971
ViewOpts.ShowMCDCSummary = MCDCSummary;
948972
ViewOpts.ShowBranchSummary = BranchSummary;
949973
ViewOpts.ShowRegionSummary = RegionSummary;

llvm/tools/llvm-cov/CoverageReport.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,8 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
428428
OS << "\n";
429429
FunctionCoverageSummary Totals("TOTAL");
430430
for (const auto &F : Functions) {
431-
auto Function = FunctionCoverageSummary::get(Coverage, F);
431+
auto Function =
432+
FunctionCoverageSummary::get(Coverage, F, Options.MCDCCountedStates);
432433
++Totals.ExecutionCount;
433434
Totals.RegionCoverage += Function.RegionCoverage;
434435
Totals.LineCoverage += Function.LineCoverage;
@@ -453,7 +454,8 @@ void CoverageReport::prepareSingleFileReport(const StringRef Filename,
453454
for (const coverage::FunctionRecord *F : Group.getInstantiations()) {
454455
if (!Filters->matches(*Coverage, *F))
455456
continue;
456-
auto InstantiationSummary = FunctionCoverageSummary::get(*Coverage, *F);
457+
auto InstantiationSummary = FunctionCoverageSummary::get(
458+
*Coverage, *F, Options.MCDCCountedStates);
457459
FileReport->addInstantiation(InstantiationSummary);
458460
InstantiationSummaries.push_back(InstantiationSummary);
459461
}

llvm/tools/llvm-cov/CoverageSummaryInfo.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "CoverageSummaryInfo.h"
15+
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
1516

1617
using namespace llvm;
1718
using namespace coverage;
@@ -44,13 +45,13 @@ static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches,
4445
}
4546
}
4647

47-
static std::pair<size_t, size_t>
48-
sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
48+
static std::tuple<size_t, size_t>
49+
sumMCDCPairs(const ArrayRef<MCDCRecord> &Records, const int32_t CountFlags) {
4950
size_t NumPairs = 0, CoveredPairs = 0;
5051
for (const auto &Record : Records) {
5152
const auto NumConditions = Record.getNumConditions();
5253
for (unsigned C = 0; C < NumConditions; C++) {
53-
if (!Record.isCondConstant(C))
54+
if (Record.getCondResult(C) & CountFlags)
5455
++NumPairs;
5556
if (Record.isConditionIndependencePairCovered(C))
5657
++CoveredPairs;
@@ -61,7 +62,8 @@ sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
6162

6263
FunctionCoverageSummary
6364
FunctionCoverageSummary::get(const CoverageMapping &CM,
64-
const coverage::FunctionRecord &Function) {
65+
const coverage::FunctionRecord &Function,
66+
const int32_t MCDCCountedFlags) {
6567
// Compute the region coverage.
6668
size_t NumCodeRegions = 0, CoveredRegions = 0;
6769
for (auto &CR : Function.CountedRegions) {
@@ -89,7 +91,8 @@ FunctionCoverageSummary::get(const CoverageMapping &CM,
8991
sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
9092

9193
size_t NumPairs = 0, CoveredPairs = 0;
92-
std::tie(NumPairs, CoveredPairs) = sumMCDCPairs(CD.getMCDCRecords());
94+
std::tie(NumPairs, CoveredPairs) =
95+
sumMCDCPairs(CD.getMCDCRecords(), MCDCCountedFlags);
9396

9497
return FunctionCoverageSummary(
9598
Function.Name, Function.ExecutionCount,

llvm/tools/llvm-cov/CoverageSummaryInfo.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
1818
#include "llvm/Support/raw_ostream.h"
19+
#include <cstdint>
1920

2021
namespace llvm {
2122

@@ -247,7 +248,8 @@ struct FunctionCoverageSummary {
247248
/// Compute the code coverage summary for the given function coverage
248249
/// mapping record.
249250
static FunctionCoverageSummary get(const coverage::CoverageMapping &CM,
250-
const coverage::FunctionRecord &Function);
251+
const coverage::FunctionRecord &Function,
252+
int32_t MCDCCountedFlags = 0);
251253

252254
/// Compute the code coverage summary for an instantiation group \p Group,
253255
/// given a list of summaries for each instantiation in \p Summaries.

llvm/tools/llvm-cov/CoverageViewOptions.h

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct CoverageViewOptions {
4545
bool SkipExpansions;
4646
bool SkipFunctions;
4747
bool SkipBranches;
48+
int32_t MCDCCountedStates;
4849
OutputFormat Format;
4950
BranchOutputType ShowBranches;
5051
std::string ShowOutputDirectory;

llvm/tools/llvm-cov/SourceCoverageView.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,6 @@ class SourceCoverageView {
161161
/// A memory buffer backing the source on display.
162162
const MemoryBuffer &File;
163163

164-
/// Various options to guide the coverage renderer.
165-
const CoverageViewOptions &Options;
166-
167164
/// Complete coverage information about the source on display.
168165
CoverageData CoverageInfo;
169166

@@ -193,6 +190,9 @@ class SourceCoverageView {
193190

194191
using CoverageSegmentArray = ArrayRef<const CoverageSegment *>;
195192

193+
/// Various options to guide the coverage renderer.
194+
const CoverageViewOptions &Options;
195+
196196
/// @name Rendering Interface
197197
/// @{
198198

@@ -275,8 +275,8 @@ class SourceCoverageView {
275275
SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
276276
const CoverageViewOptions &Options,
277277
CoverageData &&CoverageInfo)
278-
: SourceName(SourceName), File(File), Options(Options),
279-
CoverageInfo(std::move(CoverageInfo)) {}
278+
: SourceName(SourceName), File(File),
279+
CoverageInfo(std::move(CoverageInfo)), Options(Options) {}
280280

281281
public:
282282
static std::unique_ptr<SourceCoverageView>

llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,8 @@ void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
12091209
for (unsigned i = 0; i < Record.getNumConditions(); i++)
12101210
OS << Record.getConditionCoverageString(i);
12111211
OS << " MC/DC Coverage for Expression: ";
1212-
const auto [Coverable, Percent] = Record.getPercentCovered();
1212+
const auto [Coverable, Percent] =
1213+
Record.getPercentCovered(Options.MCDCCountedStates);
12131214
if (Coverable) {
12141215
OS << format("%0.2f", Percent) << "%\n";
12151216
} else {

llvm/tools/llvm-cov/SourceCoverageViewText.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
386386
}
387387
renderLinePrefix(OS, ViewDepth);
388388
OS << " MC/DC Coverage for Decision: ";
389-
const auto [Coverable, Percent] = Record.getPercentCovered();
389+
const auto [Coverable, Percent] =
390+
Record.getPercentCovered(Options.MCDCCountedStates);
390391
if (Coverable) {
391392
colored_ostream(OS, raw_ostream::RED,
392393
getOptions().Colors && Percent < 100.0,

0 commit comments

Comments
 (0)