[llvm-branch-commits] [llvm] llvm-cov: Introduce `--merge-instantiations=<MergeStrategy>` (PR #121194)
NAKAMURA Takumi via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jan 6 18:04:14 PST 2025
https://github.com/chapuni updated https://github.com/llvm/llvm-project/pull/121194
>From 273eea73c158acbf7140bd599554b2ba02d88097 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 27 Dec 2024 16:14:24 +0900
Subject: [PATCH] llvm-cov: Introduce `--merge-instantiations=<MergeStrategy>`
---
.../ProfileData/Coverage/CoverageMapping.h | 82 ++++++++-
.../ProfileData/Coverage/CoverageMapping.cpp | 170 ++++++++++++++++--
.../llvm-cov/Inputs/branch-templates.cpp | 6 +-
.../llvm-cov/Inputs/mcdc-templates-merge.cpp | 54 ++++++
.../Inputs/mcdc-templates-merge.proftext | 73 ++++++++
.../llvm-cov/Inputs/mcdc-templates-merge.yaml | 105 +++++++++++
.../tools/llvm-cov/branch-export-json.test | 2 +-
.../tools/llvm-cov/branch-export-lcov.test | 4 +-
llvm/test/tools/llvm-cov/branch-macros.test | 9 +
.../test/tools/llvm-cov/branch-templates.test | 4 +-
.../tools/llvm-cov/mcdc-templates-merge.test | 41 +++++
llvm/tools/llvm-cov/CodeCoverage.cpp | 12 +-
llvm/tools/llvm-cov/CoverageReport.cpp | 4 +-
llvm/tools/llvm-cov/CoverageViewOptions.h | 2 +
llvm/tools/llvm-cov/SourceCoverageView.cpp | 4 +-
15 files changed, 540 insertions(+), 32 deletions(-)
create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.cpp
create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.proftext
create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.yaml
create mode 100644 llvm/test/tools/llvm-cov/mcdc-templates-merge.test
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 64416fdba1b247..d6df8403a2cd1c 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -59,6 +59,12 @@ namespace coverage {
class CoverageMappingReader;
struct CoverageMappingRecord;
+enum class MergeStrategy {
+ Merge,
+ Any,
+ All,
+};
+
enum class coveragemap_error {
success = 0,
eof,
@@ -375,6 +381,32 @@ struct CountedRegion : public CounterMappingRegion {
: CounterMappingRegion(R), ExecutionCount(ExecutionCount),
FalseExecutionCount(FalseExecutionCount), TrueFolded(false),
FalseFolded(false) {}
+
+ LineColPair viewLoc() const { return startLoc(); }
+
+ bool isMergeable(const CountedRegion &RHS) const {
+ return (this->viewLoc() == RHS.viewLoc());
+ }
+
+ void merge(const CountedRegion &RHS, MergeStrategy Strategy);
+
+ /// Returns comparable rank value in selecting a better Record for merging.
+ auto getMergeRank(MergeStrategy Strategy) const {
+ assert(isBranch() && "Dedicated to Branch");
+ assert(Strategy == MergeStrategy::Any && "Dedicated to Any");
+ unsigned m = 0;
+ // Prefer both Counts have values.
+ m = (m << 1) | (ExecutionCount != 0 && FalseExecutionCount != 0);
+ // Prefer both are unfolded.
+ m = (m << 1) | (!TrueFolded && !FalseFolded);
+ // Prefer either Count has value.
+ m = (m << 1) | (ExecutionCount != 0 || FalseExecutionCount != 0);
+ // Prefer either is unfolded.
+ m = (m << 1) | (!TrueFolded || !FalseFolded);
+ return std::make_pair(m, ExecutionCount + FalseExecutionCount);
+ }
+
+ void commit() const {}
};
/// MCDC Record grouping all information together.
@@ -462,6 +494,19 @@ struct MCDCRecord {
findIndependencePairs();
}
+ inline LineColPair viewLoc() const { return Region.endLoc(); }
+
+ bool isMergeable(const MCDCRecord &RHS) const {
+ return (this->viewLoc() == RHS.viewLoc() && this->PosToID == RHS.PosToID &&
+ this->CondLoc == RHS.CondLoc);
+ }
+
+ // This may invalidate IndependencePairs
+ // MCDCRecord &operator+=(const MCDCRecord &RHS);
+ void merge(MCDCRecord &&RHS, MergeStrategy Strategy);
+
+ void commit() { findIndependencePairs(); }
+
// Compare executed test vectors against each other to find an independence
// pairs for each condition. This processing takes the most time.
void findIndependencePairs();
@@ -512,15 +557,42 @@ struct MCDCRecord {
return (*IndependencePairs)[PosToID[Condition]];
}
- float getPercentCovered() const {
- unsigned Folded = 0;
+ std::pair<unsigned, unsigned> getCoveredCount() const {
unsigned Covered = 0;
+ unsigned Folded = 0;
for (unsigned C = 0; C < getNumConditions(); C++) {
if (isCondFolded(C))
Folded++;
else if (isConditionIndependencePairCovered(C))
Covered++;
}
+ return {Covered, Folded};
+ }
+
+ /// Returns comparable rank value in selecting a better Record for merging.
+ std::tuple<unsigned, unsigned, unsigned>
+ getMergeRank(MergeStrategy Strategy) const {
+ auto [Covered, Folded] = getCoveredCount();
+ auto NumTVs = getNumTestVectors();
+ switch (Strategy) {
+ case MergeStrategy::Merge:
+ case MergeStrategy::Any:
+ return {
+ Covered, // The largest covered number
+ ~Folded, // Less folded is better
+ NumTVs, // Show more test vectors
+ };
+ case MergeStrategy::All:
+ return {
+ ~Covered, // The smallest covered number
+ ~Folded, // Less folded is better
+ NumTVs, // Show more test vectors
+ };
+ }
+ }
+
+ float getPercentCovered() const {
+ auto [Covered, Folded] = getCoveredCount();
unsigned Total = getNumConditions() - Folded;
if (Total == 0)
@@ -1013,11 +1085,13 @@ class CoverageMapping {
/// information. That is, only names returned from getUniqueSourceFiles will
/// yield a result.
CoverageData getCoverageForFile(
- StringRef Filename,
+ StringRef Filename, MergeStrategy Strategy = MergeStrategy::Merge,
const DenseSet<const FunctionRecord *> &FilteredOutFunctions = {}) const;
/// Get the coverage for a particular function.
- CoverageData getCoverageForFunction(const FunctionRecord &Function) const;
+ CoverageData
+ getCoverageForFunction(const FunctionRecord &Function,
+ MergeStrategy Strategy = MergeStrategy::Merge) const;
/// Get the coverage for an expansion within a coverage set.
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index e7780b465186df..dbbf5b03d0205e 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -221,6 +221,58 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
return LastPoppedValue;
}
+void CountedRegion::merge(const CountedRegion &RHS, MergeStrategy Strategy) {
+ assert(this->isBranch() && RHS.isBranch());
+ auto MergeCounts = [Strategy](uint64_t &LHSCount, bool &LHSFolded,
+ uint64_t RHSCount, bool RHSFolded) {
+ switch (Strategy) {
+ default:
+ llvm_unreachable("Don't perform by-parameter merging");
+ case MergeStrategy::Merge:
+ LHSCount += RHSCount;
+ LHSFolded = (LHSFolded && !LHSCount && RHSFolded);
+ break;
+ case MergeStrategy::All:
+ LHSCount = (LHSFolded ? RHSCount
+ : RHSFolded ? LHSCount
+ : std::min(LHSCount, RHSCount));
+ LHSFolded = (LHSFolded && RHSFolded);
+ break;
+ }
+ };
+
+ switch (Strategy) {
+ case MergeStrategy::Any:
+ // Take either better (more satisfied) hand side.
+ // FIXME: Really needed? Better just to merge?
+ if (this->getMergeRank(Strategy) < RHS.getMergeRank(Strategy))
+ *this = RHS;
+ break;
+ case MergeStrategy::Merge:
+ case MergeStrategy::All:
+ // Able to merge by parameter.
+ MergeCounts(this->ExecutionCount, this->TrueFolded, RHS.ExecutionCount,
+ RHS.TrueFolded);
+ MergeCounts(this->FalseExecutionCount, this->FalseFolded,
+ RHS.FalseExecutionCount, RHS.FalseFolded);
+ break;
+ }
+}
+
+void MCDCRecord::merge(MCDCRecord &&RHS, MergeStrategy Strategy) {
+ assert(this->PosToID == RHS.PosToID);
+ assert(this->CondLoc == RHS.CondLoc);
+
+ switch (Strategy) {
+ case MergeStrategy::Merge:
+ case MergeStrategy::Any:
+ case MergeStrategy::All:
+ if (this->getMergeRank(Strategy) < RHS.getMergeRank(Strategy))
+ *this = std::move(RHS);
+ return;
+ }
+}
+
// 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.
@@ -1272,7 +1324,8 @@ class SegmentBuilder {
/// Combine counts of regions which cover the same area.
static ArrayRef<CountedRegion>
- combineRegions(MutableArrayRef<CountedRegion> Regions) {
+ combineRegions(MutableArrayRef<CountedRegion> Regions,
+ MergeStrategy Strategy) {
if (Regions.empty())
return Regions;
auto Active = Regions.begin();
@@ -1298,8 +1351,22 @@ class SegmentBuilder {
// value for that area.
// We add counts of the regions of the same kind as the active region
// to handle the both situations.
- if (I->Kind == Active->Kind)
+ if (I->Kind != Active->Kind)
+ continue;
+
+ switch (Strategy) {
+ case MergeStrategy::Merge:
Active->ExecutionCount += I->ExecutionCount;
+ break;
+ case MergeStrategy::Any:
+ Active->ExecutionCount =
+ std::max(Active->ExecutionCount, I->ExecutionCount);
+ break;
+ case MergeStrategy::All:
+ Active->ExecutionCount =
+ std::min(Active->ExecutionCount, I->ExecutionCount);
+ break;
+ }
}
return Regions.drop_back(std::distance(++Active, End));
}
@@ -1307,12 +1374,13 @@ class SegmentBuilder {
public:
/// Build a sorted list of CoverageSegments from a list of Regions.
static std::vector<CoverageSegment>
- buildSegments(MutableArrayRef<CountedRegion> Regions) {
+ buildSegments(MutableArrayRef<CountedRegion> Regions,
+ MergeStrategy Strategy) {
std::vector<CoverageSegment> Segments;
SegmentBuilder Builder(Segments);
sortNestedRegions(Regions);
- ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
+ ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions, Strategy);
LLVM_DEBUG({
dbgs() << "Combined regions:\n";
@@ -1342,11 +1410,78 @@ class SegmentBuilder {
}
};
+template <class RecTy>
+static void mergeRecords(std::vector<RecTy> &Records, MergeStrategy Strategy) {
+ if (Records.empty())
+ return;
+
+ std::vector<RecTy> NewRecords;
+
+ assert(Records.size() <= std::numeric_limits<unsigned>::max());
+
+ // Build up sorted indices (rather than pointers) of Records.
+ SmallVector<unsigned, 1> BIdxs(Records.size());
+ std::iota(BIdxs.begin(), BIdxs.end(), 0);
+ llvm::stable_sort(BIdxs, [&](auto A, auto B) {
+ auto StartA = Records[A].viewLoc();
+ auto StartB = Records[B].viewLoc();
+ return (std::tie(StartA, A) < std::tie(StartB, B));
+ });
+
+ // 1st element should be stored into SubView.
+ auto I = BIdxs.begin(), E = BIdxs.end();
+ SmallVector<RecTy, 1> ViewRecords{Records[*I++]};
+
+ auto findMergeableInViewRecords = [&](const RecTy &Branch) {
+ auto I = ViewRecords.rbegin(), E = ViewRecords.rend();
+ for (; I != E; ++I)
+ if (I->isMergeable(Branch))
+ return I;
+
+ // Not mergeable.
+ return E;
+ };
+
+ auto addRecordToSubView = [&] {
+ assert(!ViewRecords.empty() && "Should have the back");
+ for (auto &Acc : ViewRecords) {
+ Acc.commit();
+ NewRecords.push_back(std::move(Acc));
+ }
+ };
+
+ for (; I != E; ++I) {
+ assert(!ViewRecords.empty() && "Should have the back in the loop");
+ auto &AccB = ViewRecords.back();
+ auto &Branch = Records[*I];
+
+ // Flush current and create the next SubView at the different line.
+ if (AccB.viewLoc().first != Branch.viewLoc().first) {
+ addRecordToSubView();
+ ViewRecords = {Branch};
+ } else if (auto AccI = findMergeableInViewRecords(Branch);
+ AccI != ViewRecords.rend()) {
+ // Merge the current Branch into the back of SubView.
+ AccI->merge(std::move(Branch), Strategy);
+ } else {
+ // Not mergeable.
+ ViewRecords.push_back(Branch);
+ }
+ }
+
+ // Flush the last SubView.
+ addRecordToSubView();
+
+ // Replace
+ Records = std::move(NewRecords);
+}
+
struct MergeableCoverageData : public CoverageData {
std::vector<CountedRegion> CodeRegions;
+ MergeStrategy Strategy;
- MergeableCoverageData(bool Single, StringRef Filename)
- : CoverageData(Single, Filename) {}
+ MergeableCoverageData(MergeStrategy Strategy, bool Single, StringRef Filename)
+ : CoverageData(Single, Filename), Strategy(Strategy) {}
void addFunctionRegions(
const FunctionRecord &Function,
@@ -1368,8 +1503,11 @@ struct MergeableCoverageData : public CoverageData {
MCDCRecords.push_back(MR);
}
- CoverageData buildSegments() {
- Segments = SegmentBuilder::buildSegments(CodeRegions);
+ CoverageData merge(MergeStrategy Strategy) {
+ mergeRecords(BranchRegions, Strategy);
+ mergeRecords(MCDCRecords, Strategy);
+
+ Segments = SegmentBuilder::buildSegments(CodeRegions, Strategy);
return CoverageData(std::move(*this));
}
};
@@ -1423,10 +1561,10 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
}
CoverageData CoverageMapping::getCoverageForFile(
- StringRef Filename,
+ StringRef Filename, MergeStrategy Strategy,
const DenseSet<const FunctionRecord *> &FilteredOutFunctions) const {
assert(SingleByteCoverage);
- MergeableCoverageData FileCoverage(*SingleByteCoverage, Filename);
+ MergeableCoverageData FileCoverage(Strategy, *SingleByteCoverage, Filename);
// Look up the function records in the given file. Due to hash collisions on
// the filename, we may get back some records that are not in the file.
@@ -1445,7 +1583,7 @@ CoverageData CoverageMapping::getCoverageForFile(
LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
- return FileCoverage.buildSegments();
+ return FileCoverage.merge(Strategy);
}
std::vector<InstantiationGroup>
@@ -1474,13 +1612,14 @@ CoverageMapping::getInstantiationGroups(StringRef Filename) const {
}
CoverageData
-CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
+CoverageMapping::getCoverageForFunction(const FunctionRecord &Function,
+ MergeStrategy Strategy) const {
auto MainFileID = findMainViewFileID(Function);
if (!MainFileID)
return CoverageData();
assert(SingleByteCoverage);
- MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
+ MergeableCoverageData FunctionCoverage(Strategy, *SingleByteCoverage,
Function.Filenames[*MainFileID]);
FunctionCoverage.addFunctionRegions(
Function, [&](auto &CR) { return (CR.FileID == *MainFileID); },
@@ -1489,7 +1628,7 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
<< "\n");
- return FunctionCoverage.buildSegments();
+ return FunctionCoverage.merge(Strategy);
}
CoverageData CoverageMapping::getCoverageForExpansion(
@@ -1511,7 +1650,8 @@ CoverageData CoverageMapping::getCoverageForExpansion(
LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
<< Expansion.FileID << "\n");
- ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
+ ExpansionCoverage.Segments =
+ SegmentBuilder::buildSegments(Regions, MergeStrategy::Merge);
return ExpansionCoverage;
}
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
index 4d932eaf5944a8..d8a7c056f36779 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
@@ -11,9 +11,9 @@ void unused(T x) {
template<typename T>
int func(T x) {
- if(x) // BRCOV: | Branch ([[@LINE]]:6): [True: 0, False: 1]
- return 0; // BRCOV: | Branch ([[@LINE-1]]:6): [True: 1, False: 0]
- else // BRCOV: | Branch ([[@LINE-2]]:6): [True: 0, False: 1]
+ if(x) // BRCOV: | Branch ([[@LINE]]:6): [True: 1, False: {{2|1}}]
+ return 0;
+ else
return 1;
int j = 1;
}
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.cpp b/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.cpp
new file mode 100644
index 00000000000000..09c2e0980cca85
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.cpp
@@ -0,0 +1,54 @@
+#include <cstdio>
+
+template <typename Ty>
+bool ab(Ty a, Ty b) {
+ return (a && b);
+}
+// MERGE: [[@LINE-2]]| 4| return
+// ANY: [[@LINE-3]]| 2| return
+// ALL: [[@LINE-4]]| 0| return
+
+// MERGE: MC/DC Coverage for Decision{{[:]}} 50.00%
+// ANY: MC/DC Coverage for Decision{{[:]}} 50.00%
+// ALL: MC/DC Coverage for Decision{{[:]}} 0.00%
+
+// CHECK: _Z2abIbEbT_S0_{{[:]}}
+// CHECK: MC/DC Coverage for Decision{{[:]}} 50.00%
+
+// CHECK: _Z2abIxEbT_S0_{{[:]}}
+// CHECK: MC/DC Coverage for Decision{{[:]}} 50.00%
+
+// CHECK: Unexecuted instantiation{{[:]}} _Z2abIdEbT_S0_
+
+template <bool C>
+bool Cab(bool a, bool b) {
+ return (a && b && C);
+}
+// MERGE: [[@LINE-2]]| 4| return
+// ANY: [[@LINE-3]]| 2| return
+// ALL: [[@LINE-4]]| 2| return
+
+// MERGE: MC/DC Coverage for Decision{{[:]}} 50.00%
+// ANY: MC/DC Coverage for Decision{{[:]}} 50.00%
+// ALL: MC/DC Coverage for Decision{{[:]}} 0.00%
+
+// CHECK: _Z3CabILb0EEbbb{{[:]}}
+// CHECK: MC/DC Coverage for Decision{{[:]}} 0.00%
+
+// CHECK: _Z3CabILb1EEbbb{{[:]}}
+// CHECK: MC/DC Coverage for Decision{{[:]}} 50.00%
+
+// CHECK: [[@LINE+1]]| 1|int main
+int main(int argc, char **argv) {
+ printf("%d\n", Cab<false>(false, false));
+ printf("%d\n", Cab<false>(true, true));
+ printf("%d\n", Cab<true>(true, false));
+ printf("%d\n", Cab<true>(true, true));
+ printf("%d\n", ab(false, false));
+ printf("%d\n", ab(true, true));
+ printf("%d\n", ab(1LL, 0LL));
+ printf("%d\n", ab(1LL, 1LL));
+ if (argc == 2)
+ printf("%d\n", ab(0.0, 0.0));
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.proftext
new file mode 100644
index 00000000000000..61369462b2fd46
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.proftext
@@ -0,0 +1,73 @@
+_Z2abIbEbT_S0_
+# Func Hash:
+1550
+# Num Counters:
+3
+# Counter Values:
+2
+1
+1
+# Num Bitmap Bytes:
+$1
+# Bitmap Byte Values:
+0x5
+
+
+_Z2abIxEbT_S0_
+# Func Hash:
+1550
+# Num Counters:
+3
+# Counter Values:
+2
+2
+1
+# Num Bitmap Bytes:
+$1
+# Bitmap Byte Values:
+0x6
+
+
+_Z3CabILb0EEbbb
+# Func Hash:
+99214
+# Num Counters:
+5
+# Counter Values:
+2
+1
+0
+1
+1
+# Num Bitmap Bytes:
+$1
+# Bitmap Byte Values:
+0x5
+
+
+_Z3CabILb1EEbbb
+# Func Hash:
+99214
+# Num Counters:
+5
+# Counter Values:
+2
+1
+1
+2
+1
+# Num Bitmap Bytes:
+$1
+# Bitmap Byte Values:
+0xa
+
+
+main
+# Func Hash:
+175973464
+# Num Counters:
+2
+# Counter Values:
+1
+0
+
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.yaml b/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.yaml
new file mode 100644
index 00000000000000..91d701a2172f82
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-templates-merge.yaml
@@ -0,0 +1,105 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+ SectionHeaderStringTable: .strtab
+Sections:
+ - Name: __llvm_covfun
+ Type: SHT_PROGBITS
+ Flags: [ SHF_GNU_RETAIN ]
+ AddressAlign: 0x8
+ Content: FAD58DE7366495DB2500000058247D0A00000000249EC986A505B62F010101010505012A210C020109070010200502000700100500110185808080080501050021
+ - Name: '__llvm_covfun (1)'
+ Type: SHT_PROGBITS
+ Flags: [ SHF_GNU_RETAIN ]
+ AddressAlign: 0x8
+ Content: 9CC3B348501DBFE8480000008E83010000000000249EC986A505B62F010103010D0D1105090901181A020201010B000C01000B0011280403000B0016300D02010300000B000C0D0010001130110603020000100011050015001630000A02000000150016
+ - Name: '__llvm_covfun (2)'
+ Type: SHT_PROGBITS
+ Flags: [ SHF_GNU_RETAIN ]
+ AddressAlign: 0x8
+ Content: 9873627177A03F8E460000008E83010000000000249EC986A505B62F010102010D0D110901181A020201010B000C01000B0011280403000B0016300D02010300000B000C0D0010001130110603020000100011050015001630090002000000150016
+ - Name: '__llvm_covfun (3)'
+ Type: SHT_PROGBITS
+ Flags: [ SHF_GNU_RETAIN ]
+ AddressAlign: 0x8
+ Content: BF407A207503B266320000000E06000000000000249EC986A505B62F0101020105050906010415020201010B000C280302000B0011300502010200000B000C050010001130090602000000100011
+ - Name: '__llvm_covfun (4)'
+ Type: SHT_PROGBITS
+ Flags: [ SHF_GNU_RETAIN ]
+ AddressAlign: 0x8
+ Content: 8A05A22CB467C37D320000000E06000000000000249EC986A505B62F0101020105050906010415020201010B000C280302000B0011300502010200000B000C050010001130090602000000100011
+ - Name: '__llvm_covfun (5)'
+ Type: SHT_PROGBITS
+ Flags: [ SHF_GNU_RETAIN ]
+ AddressAlign: 0x8
+ Content: 1700192CAC8F3F26320000000E06000000000000249EC986A505B62F0101020105050906010415020201010B000C280302000B0011300502010200000B000C050010001130090602000000100011
+ - Name: __llvm_covmap
+ Type: SHT_PROGBITS
+ Flags: [ SHF_GNU_RETAIN ]
+ AddressAlign: 0x8
+ Content: 000000001D0000000000000006000000021A0000186D6364632D74656D706C617465732D6D657267652E637070000000
+ - Name: __llvm_prf_names
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_GNU_RETAIN ]
+ AddressAlign: 0x1
+ Content: 51006D61696E015F5A33436162494C62304545626262015F5A33436162494C62314545626262015F5A32616249624562545F53305F015F5A32616249784562545F53305F015F5A32616249644562545F53305F
+ - Type: SectionHeaderTable
+ Sections:
+ - Name: .strtab
+ - Name: __llvm_covfun
+ - Name: '__llvm_covfun (1)'
+ - Name: '__llvm_covfun (2)'
+ - Name: '__llvm_covfun (3)'
+ - Name: '__llvm_covfun (4)'
+ - Name: '__llvm_covfun (5)'
+ - Name: __llvm_covmap
+ - Name: __llvm_prf_names
+ - Name: .symtab
+Symbols:
+ - Name: __llvm_covmap
+ Type: STT_SECTION
+ Section: __llvm_covmap
+ - Name: __llvm_prf_names
+ Type: STT_SECTION
+ Section: __llvm_prf_names
+ - Name: __covrec_DB956436E78DD5FAu
+ Type: STT_OBJECT
+ Section: __llvm_covfun
+ Binding: STB_WEAK
+ Size: 0x41
+ Other: [ STV_HIDDEN ]
+ - Name: __covrec_E8BF1D5048B3C39Cu
+ Type: STT_OBJECT
+ Section: '__llvm_covfun (1)'
+ Binding: STB_WEAK
+ Size: 0x64
+ Other: [ STV_HIDDEN ]
+ - Name: __covrec_8E3FA07771627398u
+ Type: STT_OBJECT
+ Section: '__llvm_covfun (2)'
+ Binding: STB_WEAK
+ Size: 0x62
+ Other: [ STV_HIDDEN ]
+ - Name: __covrec_66B20375207A40BFu
+ Type: STT_OBJECT
+ Section: '__llvm_covfun (3)'
+ Binding: STB_WEAK
+ Size: 0x4E
+ Other: [ STV_HIDDEN ]
+ - Name: __covrec_7DC367B42CA2058Au
+ Type: STT_OBJECT
+ Section: '__llvm_covfun (4)'
+ Binding: STB_WEAK
+ Size: 0x4E
+ Other: [ STV_HIDDEN ]
+ - Name: __covrec_263F8FAC2C190017u
+ Type: STT_OBJECT
+ Section: '__llvm_covfun (5)'
+ Binding: STB_WEAK
+ Size: 0x4E
+ Other: [ STV_HIDDEN ]
+...
diff --git a/llvm/test/tools/llvm-cov/branch-export-json.test b/llvm/test/tools/llvm-cov/branch-export-json.test
index 4278482c6d870e..77e2bab7d9eb33 100644
--- a/llvm/test/tools/llvm-cov/branch-export-json.test
+++ b/llvm/test/tools/llvm-cov/branch-export-json.test
@@ -46,4 +46,4 @@
// MACROS: 5,15,5,23,1,2,8,0,4
// MACROS: 6,15,6,23,0,1,9,0,4
// MACROS: 8,15,8,38,1,2,2,0,4
-// MACROS: {"count":40,"covered":24,"notcovered":16,"percent":60}
+// MACROS: {"count":16,"covered":6,"notcovered":10,"percent":37.5}
diff --git a/llvm/test/tools/llvm-cov/branch-export-lcov.test b/llvm/test/tools/llvm-cov/branch-export-lcov.test
index fe43dd66de8d04..444277435d60d6 100644
--- a/llvm/test/tools/llvm-cov/branch-export-lcov.test
+++ b/llvm/test/tools/llvm-cov/branch-export-lcov.test
@@ -71,8 +71,8 @@
// MACROS-COUNT-10: BRDA:37
// MACROS-NOT: BRDA:37
// MACROS-NOT: BRDA
-// MACROS: BRF:40
-// MACROS: BRH:24
+// MACROS: BRF:16
+// MACROS: BRH:6
// NOBRANCH-NOT: BRDA
// NOBRANCH-NOT: BRF
diff --git a/llvm/test/tools/llvm-cov/branch-macros.test b/llvm/test/tools/llvm-cov/branch-macros.test
index b892aba0a044a3..1023d7cc47d4d9 100644
--- a/llvm/test/tools/llvm-cov/branch-macros.test
+++ b/llvm/test/tools/llvm-cov/branch-macros.test
@@ -1,5 +1,8 @@
// RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata
// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -check-prefixes=CHECK,BRCOV -D#C=999
+// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-macros.cpp | FileCheck %s -check-prefix=REPORT
+// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-macros.cpp | FileCheck %s -check-prefix=FILE
+
// RUN: llvm-cov show --binary-counters=true --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -check-prefixes=CHECK,BRCOV -D#C=1
// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-macros.cpp | FileCheck %s -check-prefix=REPORT
@@ -14,3 +17,9 @@
// REPORT-NEXT: main 1 0 100.00% 6 0 100.00% 0 0 0.00%
// REPORT-NEXT: ---
// REPORT-NEXT: TOTAL 16 4 75.00% 32 0 100.00% 40 16 60.00%
+
+// FILE: Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover
+// FILE-NEXT: ---
+// FILE-NEXT: branch-macros.cpp 28 5 82.14% 3 0 100.00% 39 0 100.00% 16 10 37.50%
+// FILE-NEXT: ---
+// FILE-NEXT: TOTAL 28 5 82.14% 3 0 100.00% 39 0 100.00% 16 10 37.50%
diff --git a/llvm/test/tools/llvm-cov/branch-templates.test b/llvm/test/tools/llvm-cov/branch-templates.test
index 594a3ca533678b..c4fc9cafbfd80e 100644
--- a/llvm/test/tools/llvm-cov/branch-templates.test
+++ b/llvm/test/tools/llvm-cov/branch-templates.test
@@ -26,6 +26,6 @@
// REPORTFILE: Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover
// REPORTFILE-NEXT: ---
-// REPORTFILE-NEXT: branch-templates.cpp 12 2 83.33% 2 0 100.00% 17 3 82.35% 12 6 50.00%
+// REPORTFILE-NEXT: branch-templates.cpp 12 2 83.33% 2 0 100.00% 17 3 82.35% 8 3 62.50%
// REPORTFILE-NEXT: ---
-// REPORTFILE-NEXT: TOTAL 12 2 83.33% 2 0 100.00% 17 3 82.35% 12 6 50.00%
+// REPORTFILE-NEXT: TOTAL 12 2 83.33% 2 0 100.00% 17 3 82.35% 8 3 62.50%
diff --git a/llvm/test/tools/llvm-cov/mcdc-templates-merge.test b/llvm/test/tools/llvm-cov/mcdc-templates-merge.test
new file mode 100644
index 00000000000000..21c5458edfa846
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/mcdc-templates-merge.test
@@ -0,0 +1,41 @@
+# Test `merge-instantiations=merge/any/all`
+
+RUN: yaml2obj %S/Inputs/mcdc-templates-merge.yaml -o %t.o
+RUN: llvm-profdata merge %S/Inputs/mcdc-templates-merge.proftext -o %t.profdata
+
+RUN: llvm-cov show -merge-instantiations=merge --show-mcdc -show-instantiations=true %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/mcdc-templates-merge.cpp --check-prefixes=CHECK,MERGE
+RUN: llvm-cov show -merge-instantiations=any --show-mcdc -show-instantiations=true %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/mcdc-templates-merge.cpp --check-prefixes=CHECK,ANY
+RUN: llvm-cov show -merge-instantiations=all --show-mcdc -show-instantiations=true %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/mcdc-templates-merge.cpp --check-prefixes=CHECK,ALL
+
+RUN: llvm-cov report -merge-instantiations=merge --show-mcdc-summary %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefixes=REPORT,MERGE
+RUN: llvm-cov report -merge-instantiations=any --show-mcdc-summary %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefixes=REPORT,ANY
+RUN: llvm-cov report -merge-instantiations=all --show-mcdc-summary %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %s -check-prefixes=REPORT,ALL
+
+REPORT: mcdc-templates-merge.cpp
+
+# Regions
+MERGE: 10 1 90.00%
+ANY: 10 1 90.00%
+ALL: 10 4 60.00%
+
+# Functions
+MERGE: 3 0 100.00%
+ANY: 3 0 100.00%
+ALL: 3 0 100.00%
+
+# Lines
+MERGE: 19 1 94.74%
+ANY: 19 1 94.74%
+ALL: 19 4 78.95%
+
+# Branches
+MERGE: 12 1 91.67%
+ANY: 11 1 90.91%
+ALL: 12 7 41.67%
+
+# MC/DC Conditions
+MERGE: 4 2 50.00%
+ANY: 4 2 50.00%
+ALL: 4 4 0.00%
+
+REPORT: TOTAL
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 2d6da7efc69798..4ae4fff64ad4bc 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -395,7 +395,8 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
auto SourceBuffer = getSourceFile(SourceFile);
if (!SourceBuffer)
return nullptr;
- auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+ auto FileCoverage =
+ Coverage.getCoverageForFile(SourceFile, ViewOpts.MergeStrategyOpts);
if (FileCoverage.empty())
return nullptr;
@@ -795,6 +796,14 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
"check-binary-ids", cl::desc("Fail if an object couldn't be found for a "
"binary ID in the profile"));
+ cl::opt<MergeStrategy> MergeStrategyOpts(
+ "merge-instantiations", cl::desc("Merge instantiations"),
+ cl::values(
+ clEnumValN(MergeStrategy::Merge, "merge", "Merge entries by adding"),
+ clEnumValN(MergeStrategy::Any, "any", "Pick up any better entries"),
+ clEnumValN(MergeStrategy::All, "all", "Pick up the worst entries")),
+ cl::init(MergeStrategy::Merge));
+
auto commandLineParser = [&, this](int argc, const char **argv) -> int {
cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
ViewOpts.Debug = DebugDump;
@@ -951,6 +960,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
ViewOpts.ExportSummaryOnly = SummaryOnly;
ViewOpts.NumThreads = NumThreads;
ViewOpts.CompilationDirectory = CompilationDirectory;
+ ViewOpts.MergeStrategyOpts = MergeStrategyOpts;
return 0;
};
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 0046b968756dd0..9215e2421f5145 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -480,8 +480,8 @@ void CoverageReport::prepareSingleFileReport(const StringRef Filename,
/*Covered=*/Group.getTotalExecutionCount() > 0);
}
- auto FileCoverage =
- Coverage->getCoverageForFile(Filename, FilteredOutFunctions);
+ auto FileCoverage = Coverage->getCoverageForFile(
+ Filename, Options.MergeStrategyOpts, FilteredOutFunctions);
if (FileCoverage.empty())
return;
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index 81e69c3814e306..d2135a19e11f69 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -11,6 +11,7 @@
#include "RenderingSupport.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include <vector>
namespace llvm {
@@ -48,6 +49,7 @@ struct CoverageViewOptions {
bool BinaryCounters;
OutputFormat Format;
BranchOutputType ShowBranches;
+ coverage::MergeStrategy MergeStrategyOpts;
std::string ShowOutputDirectory;
std::vector<std::string> DemanglerOpts;
uint32_t TabSize;
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp
index dfecddfaf4143f..1ef1952e691c9a 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -207,8 +207,8 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
// through them while we iterate lines.
llvm::stable_sort(ExpansionSubViews);
llvm::stable_sort(InstantiationSubViews);
- llvm::stable_sort(BranchSubViews);
- llvm::stable_sort(MCDCSubViews);
+ // BranchSubViews is sorted.
+ // MCDCSubViews is sorted.
auto NextESV = ExpansionSubViews.begin();
auto EndESV = ExpansionSubViews.end();
auto NextISV = InstantiationSubViews.begin();
More information about the llvm-branch-commits
mailing list