Skip to content

Commit fe73cf9

Browse files
authored
Revert "Revert "[llvm-cov] Add support for baseline coverage" (llvm#144121)"
This reverts commit 65d88d3.
1 parent ecdb549 commit fe73cf9

File tree

6 files changed

+195
-86
lines changed

6 files changed

+195
-86
lines changed

llvm/docs/CommandGuide/llvm-cov.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@ OPTIONS
380380
Fail if an object file cannot be found for a binary ID present in the profile,
381381
neither on the command line nor via binary ID lookup.
382382

383+
.. option:: -empty-profile
384+
385+
Display the baseline coverage of the binaries with all zero execution counts.
386+
Mutually exclusive with -instr-profile.
387+
383388
.. program:: llvm-cov report
384389

385390
.. _llvm-cov-report:
@@ -470,6 +475,11 @@ OPTIONS
470475
Fail if an object file cannot be found for a binary ID present in the profile,
471476
neither on the command line nor via binary ID lookup.
472477

478+
.. option:: -empty-profile
479+
480+
Display the baseline coverage of the binaries with all zero execution counts.
481+
Mutually exclusive with -instr-profile.
482+
473483
.. program:: llvm-cov export
474484

475485
.. _llvm-cov-export:
@@ -562,6 +572,11 @@ OPTIONS
562572
Fail if an object file cannot be found for a binary ID present in the profile,
563573
neither on the command line nor via binary ID lookup.
564574

575+
.. option:: -empty-profile
576+
577+
Export the baseline coverage of the binaries with all zero execution counts.
578+
Mutually exclusive with -instr-profile.
579+
565580
CONVERT-FOR-TESTING COMMAND
566581
---------------------------
567582

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -991,18 +991,23 @@ class CoverageMapping {
991991
// Load coverage records from readers.
992992
static Error loadFromReaders(
993993
ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
994-
IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage);
994+
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
995+
&ProfileReader,
996+
CoverageMapping &Coverage);
995997

996998
// Load coverage records from file.
997999
static Error
9981000
loadFromFile(StringRef Filename, StringRef Arch, StringRef CompilationDir,
999-
IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
1000-
bool &DataFound,
1001+
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1002+
&ProfileReader,
1003+
CoverageMapping &Coverage, bool &DataFound,
10011004
SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr);
10021005

10031006
/// Add a function record corresponding to \p Record.
1004-
Error loadFunctionRecord(const CoverageMappingRecord &Record,
1005-
IndexedInstrProfReader &ProfileReader);
1007+
Error loadFunctionRecord(
1008+
const CoverageMappingRecord &Record,
1009+
const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1010+
&ProfileReader);
10061011

10071012
/// Look up the indices for function records which are at least partially
10081013
/// defined in the specified file. This is guaranteed to return a superset of
@@ -1018,15 +1023,16 @@ class CoverageMapping {
10181023
/// Load the coverage mapping using the given readers.
10191024
LLVM_ABI static Expected<std::unique_ptr<CoverageMapping>>
10201025
load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
1021-
IndexedInstrProfReader &ProfileReader);
1026+
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1027+
&ProfileReader);
10221028

10231029
/// Load the coverage mapping from the given object files and profile. If
10241030
/// \p Arches is non-empty, it must specify an architecture for each object.
10251031
/// Ignores non-instrumented object files unless all are not instrumented.
10261032
LLVM_ABI static Expected<std::unique_ptr<CoverageMapping>>
1027-
load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
1028-
vfs::FileSystem &FS, ArrayRef<StringRef> Arches = {},
1029-
StringRef CompilationDir = "",
1033+
load(ArrayRef<StringRef> ObjectFilenames,
1034+
std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
1035+
ArrayRef<StringRef> Arches = {}, StringRef CompilationDir = "",
10301036
const object::BuildIDFetcher *BIDFetcher = nullptr,
10311037
bool CheckBinaryIDs = false);
10321038

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp

Lines changed: 75 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,8 @@ class MCDCDecisionRecorder {
823823

824824
Error CoverageMapping::loadFunctionRecord(
825825
const CoverageMappingRecord &Record,
826-
IndexedInstrProfReader &ProfileReader) {
826+
const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
827+
&ProfileReader) {
827828
StringRef OrigFuncName = Record.FunctionName;
828829
if (OrigFuncName.empty())
829830
return make_error<CoverageMapError>(coveragemap_error::malformed,
@@ -837,35 +838,44 @@ Error CoverageMapping::loadFunctionRecord(
837838
CounterMappingContext Ctx(Record.Expressions);
838839

839840
std::vector<uint64_t> Counts;
840-
if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
841-
Record.FunctionHash, Counts)) {
842-
instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
843-
if (IPE == instrprof_error::hash_mismatch) {
844-
FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
845-
Record.FunctionHash);
846-
return Error::success();
841+
if (ProfileReader) {
842+
if (Error E = ProfileReader.value().get().getFunctionCounts(
843+
Record.FunctionName, Record.FunctionHash, Counts)) {
844+
instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
845+
if (IPE == instrprof_error::hash_mismatch) {
846+
FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
847+
Record.FunctionHash);
848+
return Error::success();
849+
}
850+
if (IPE != instrprof_error::unknown_function)
851+
return make_error<InstrProfError>(IPE);
852+
Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
847853
}
848-
if (IPE != instrprof_error::unknown_function)
849-
return make_error<InstrProfError>(IPE);
854+
} else {
850855
Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
851856
}
852857
Ctx.setCounts(Counts);
853858

854859
bool IsVersion11 =
855-
ProfileReader.getVersion() < IndexedInstrProf::ProfVersion::Version12;
860+
ProfileReader && ProfileReader.value().get().getVersion() <
861+
IndexedInstrProf::ProfVersion::Version12;
856862

857863
BitVector Bitmap;
858-
if (Error E = ProfileReader.getFunctionBitmap(Record.FunctionName,
859-
Record.FunctionHash, Bitmap)) {
860-
instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
861-
if (IPE == instrprof_error::hash_mismatch) {
862-
FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
863-
Record.FunctionHash);
864-
return Error::success();
864+
if (ProfileReader) {
865+
if (Error E = ProfileReader.value().get().getFunctionBitmap(
866+
Record.FunctionName, Record.FunctionHash, Bitmap)) {
867+
instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
868+
if (IPE == instrprof_error::hash_mismatch) {
869+
FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
870+
Record.FunctionHash);
871+
return Error::success();
872+
}
873+
if (IPE != instrprof_error::unknown_function)
874+
return make_error<InstrProfError>(IPE);
875+
Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
865876
}
866-
if (IPE != instrprof_error::unknown_function)
867-
return make_error<InstrProfError>(IPE);
868-
Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
877+
} else {
878+
Bitmap = BitVector(getMaxBitmapSize(Record, false));
869879
}
870880
Ctx.setBitmap(std::move(Bitmap));
871881

@@ -959,10 +969,14 @@ Error CoverageMapping::loadFunctionRecord(
959969
// of CoverageMappingReader instances.
960970
Error CoverageMapping::loadFromReaders(
961971
ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
962-
IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) {
963-
assert(!Coverage.SingleByteCoverage ||
964-
*Coverage.SingleByteCoverage == ProfileReader.hasSingleByteCoverage());
965-
Coverage.SingleByteCoverage = ProfileReader.hasSingleByteCoverage();
972+
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
973+
&ProfileReader,
974+
CoverageMapping &Coverage) {
975+
assert(!Coverage.SingleByteCoverage || !ProfileReader ||
976+
*Coverage.SingleByteCoverage ==
977+
ProfileReader.value().get().hasSingleByteCoverage());
978+
Coverage.SingleByteCoverage =
979+
!ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
966980
for (const auto &CoverageReader : CoverageReaders) {
967981
for (auto RecordOrErr : *CoverageReader) {
968982
if (Error E = RecordOrErr.takeError())
@@ -977,7 +991,8 @@ Error CoverageMapping::loadFromReaders(
977991

978992
Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
979993
ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
980-
IndexedInstrProfReader &ProfileReader) {
994+
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
995+
&ProfileReader) {
981996
auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
982997
if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
983998
return std::move(E);
@@ -986,18 +1001,19 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
9861001

9871002
// If E is a no_data_found error, returns success. Otherwise returns E.
9881003
static Error handleMaybeNoDataFoundError(Error E) {
989-
return handleErrors(
990-
std::move(E), [](const CoverageMapError &CME) {
991-
if (CME.get() == coveragemap_error::no_data_found)
992-
return static_cast<Error>(Error::success());
993-
return make_error<CoverageMapError>(CME.get(), CME.getMessage());
994-
});
1004+
return handleErrors(std::move(E), [](const CoverageMapError &CME) {
1005+
if (CME.get() == coveragemap_error::no_data_found)
1006+
return static_cast<Error>(Error::success());
1007+
return make_error<CoverageMapError>(CME.get(), CME.getMessage());
1008+
});
9951009
}
9961010

9971011
Error CoverageMapping::loadFromFile(
9981012
StringRef Filename, StringRef Arch, StringRef CompilationDir,
999-
IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
1000-
bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1013+
std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1014+
&ProfileReader,
1015+
CoverageMapping &Coverage, bool &DataFound,
1016+
SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
10011017
auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
10021018
Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
10031019
if (std::error_code EC = CovMappingBufOrErr.getError())
@@ -1033,13 +1049,23 @@ Error CoverageMapping::loadFromFile(
10331049
}
10341050

10351051
Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
1036-
ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
1037-
vfs::FileSystem &FS, ArrayRef<StringRef> Arches, StringRef CompilationDir,
1052+
ArrayRef<StringRef> ObjectFilenames,
1053+
std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
1054+
ArrayRef<StringRef> Arches, StringRef CompilationDir,
10381055
const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
1039-
auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS);
1040-
if (Error E = ProfileReaderOrErr.takeError())
1041-
return createFileError(ProfileFilename, std::move(E));
1042-
auto ProfileReader = std::move(ProfileReaderOrErr.get());
1056+
std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1057+
if (ProfileFilename) {
1058+
auto ProfileReaderOrErr =
1059+
IndexedInstrProfReader::create(ProfileFilename.value(), FS);
1060+
if (Error E = ProfileReaderOrErr.takeError())
1061+
return createFileError(ProfileFilename.value(), std::move(E));
1062+
ProfileReader = std::move(ProfileReaderOrErr.get());
1063+
}
1064+
auto ProfileReaderRef =
1065+
ProfileReader
1066+
? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1067+
*ProfileReader)
1068+
: std::nullopt;
10431069
auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
10441070
bool DataFound = false;
10451071

@@ -1053,16 +1079,17 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
10531079

10541080
SmallVector<object::BuildID> FoundBinaryIDs;
10551081
for (const auto &File : llvm::enumerate(ObjectFilenames)) {
1056-
if (Error E =
1057-
loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
1058-
*ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
1082+
if (Error E = loadFromFile(File.value(), GetArch(File.index()),
1083+
CompilationDir, ProfileReaderRef, *Coverage,
1084+
DataFound, &FoundBinaryIDs))
10591085
return std::move(E);
10601086
}
10611087

10621088
if (BIDFetcher) {
10631089
std::vector<object::BuildID> ProfileBinaryIDs;
1064-
if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1065-
return createFileError(ProfileFilename, std::move(E));
1090+
if (ProfileReader)
1091+
if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1092+
return createFileError(ProfileFilename.value(), std::move(E));
10661093

10671094
SmallVector<object::BuildIDRef> BinaryIDsToFetch;
10681095
if (!ProfileBinaryIDs.empty()) {
@@ -1082,12 +1109,12 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
10821109
if (PathOpt) {
10831110
std::string Path = std::move(*PathOpt);
10841111
StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
1085-
if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
1086-
*Coverage, DataFound))
1112+
if (Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
1113+
*Coverage, DataFound))
10871114
return std::move(E);
10881115
} else if (CheckBinaryIDs) {
10891116
return createFileError(
1090-
ProfileFilename,
1117+
ProfileFilename.value(),
10911118
createStringError(errc::no_such_file_or_directory,
10921119
"Missing binary ID: " +
10931120
llvm::toHex(BinaryID, /*LowerCase=*/true)));
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// FULL: SF:{{.*}}showLineExecutionCounts.cpp
2+
// FULL: FN:6,main
3+
// FULL: FNDA:0,main
4+
// FULL: FNF:1
5+
// FULL: FNH:0
6+
int main() { // FULL: DA:[[@LINE]],0
7+
int x = 0; // FULL: DA:[[@LINE]],0
8+
// FULL: DA:[[@LINE]],0
9+
if (x) { // FULL: DA:[[@LINE]],0
10+
x = 0; // FULL: DA:[[@LINE]],0
11+
} else { // FULL: DA:[[@LINE]],0
12+
x = 1; // FULL: DA:[[@LINE]],0
13+
} // FULL: DA:[[@LINE]],0
14+
// FULL: DA:[[@LINE]],0
15+
for (int i = 0; i < 100; ++i) { // FULL: DA:[[@LINE]],0
16+
x = 1; // FULL: DA:[[@LINE]],0
17+
} // FULL: DA:[[@LINE]],0
18+
// FULL: DA:[[@LINE]],0
19+
x = x < 10 ? x + 1 : x - 1; // FULL: DA:[[@LINE]],0
20+
x = x > 10 ? // FULL: DA:[[@LINE]],0
21+
x - 1: // FULL: DA:[[@LINE]],0
22+
x + 1; // FULL: DA:[[@LINE]],0
23+
// FULL: DA:[[@LINE]],0
24+
return 0; // FULL: DA:[[@LINE]],0
25+
} // FULL: DA:[[@LINE]],0
26+
// FULL: LF:20
27+
// FULL: LH:0
28+
// FULL: end_of_record
29+
// RUN: llvm-cov export -format=lcov %S/Inputs/lineExecutionCounts.covmapping -empty-profile %s | FileCheck -check-prefixes=FULL %s
30+
31+
// RUN: llvm-cov export -format=lcov -summary-only %S/Inputs/lineExecutionCounts.covmapping -empty-profile %s | FileCheck -check-prefixes=SUMMARYONLY %s
32+
// SUMMARYONLY: SF:{{.*}}showLineExecutionCounts.cpp
33+
// SUMMARYONLY: FNF:1
34+
// SUMMARYONLY: FNH:0
35+
// SUMMARYONLY: LF:20
36+
// SUMMARYONLY: LH:0
37+
// SUMMARYONLY: end_of_record

0 commit comments

Comments
 (0)