42#include <system_error>
47using namespace coverage;
49#define DEBUG_TYPE "coverage-mapping"
52 auto [It, Inserted] = ExpressionIndices.try_emplace(E, Expressions.size());
54 Expressions.push_back(E);
58void CounterExpressionBuilder::extractTerms(
Counter C,
int Factor,
60 switch (
C.getKind()) {
67 const auto &E = Expressions[
C.getExpressionID()];
68 extractTerms(E.LHS, Factor, Terms);
75Counter CounterExpressionBuilder::simplify(
Counter ExpressionTree) {
78 extractTerms(ExpressionTree, +1, Terms);
82 if (Terms.
size() == 0)
86 llvm::sort(Terms, [](
const Term &LHS,
const Term &RHS) {
87 return LHS.CounterID <
RHS.CounterID;
91 auto Prev = Terms.
begin();
92 for (
auto I = Prev + 1, E = Terms.
end();
I != E; ++
I) {
93 if (
I->CounterID == Prev->CounterID) {
94 Prev->Factor +=
I->Factor;
105 for (
auto T : Terms) {
108 for (
int I = 0;
I <
T.Factor; ++
I)
117 for (
auto T : Terms) {
120 for (
int I = 0;
I < -
T.Factor; ++
I)
129 return Simplify ?
simplify(Cnt) : Cnt;
135 return Simplify ?
simplify(Cnt) : Cnt;
139 switch (
C.getKind()) {
144 OS <<
'#' <<
C.getCounterID();
147 if (
C.getExpressionID() >= Expressions.size())
149 const auto &E = Expressions[
C.getExpressionID()];
158 if (CounterValues.
empty())
161 if (
auto E =
Value.takeError()) {
176 } VisitCount = KNeverVisited;
179 std::stack<StackElem> CounterStack;
180 CounterStack.push({
C});
182 int64_t LastPoppedValue;
184 while (!CounterStack.empty()) {
185 StackElem &Current = CounterStack.top();
187 switch (Current.ICounter.getKind()) {
193 if (Current.ICounter.getCounterID() >= CounterValues.
size())
195 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
199 if (Current.ICounter.getExpressionID() >= Expressions.size())
201 const auto &E = Expressions[Current.ICounter.getExpressionID()];
202 if (Current.VisitCount == StackElem::KNeverVisited) {
203 CounterStack.push(StackElem{E.LHS});
204 Current.VisitCount = StackElem::KVisitedOnce;
205 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
206 Current.LHS = LastPoppedValue;
207 CounterStack.push(StackElem{E.RHS});
208 Current.VisitCount = StackElem::KVisitedTwice;
210 int64_t
LHS = Current.LHS;
211 int64_t
RHS = LastPoppedValue;
221 return LastPoppedValue;
226 : Indices(NextIDs.
size()) {
228 auto N = NextIDs.
size();
230 for (
unsigned ID = 0;
ID <
N; ++
ID) {
231 for (
unsigned C = 0;
C < 2; ++
C) {
235 auto NextID = NextIDs[
ID][
C];
236 Nodes[
ID].NextIDs[
C] = NextID;
238 ++Nodes[NextID].InCount;
252 assert(Nodes[0].InCount == 0);
258 auto IID = Q.
begin();
261 auto &Node = Nodes[
ID];
264 for (
unsigned I = 0;
I < 2; ++
I) {
265 auto NextID = Node.NextIDs[
I];
266 assert(NextID != 0 &&
"NextID should not point to the top");
269 Decisions.emplace_back(-Node.Width, Ord++,
ID,
I);
270 assert(Ord == Decisions.size());
275 auto &NextNode = Nodes[NextID];
276 assert(NextNode.InCount > 0);
281 auto NextWidth = int64_t(NextNode.Width) + Node.Width;
286 NextNode.Width = NextWidth;
290 if (--NextNode.InCount == 0)
299 for (
auto [NegWidth, Ord,
ID,
C] : Decisions) {
300 int Width = -NegWidth;
316 for (
const auto &Idxs :
Indices)
317 for (
auto Idx : Idxs)
327class NextIDsBuilder {
333 : NextIDs(Branches.
size()) {
337 for (
const auto *Branch : Branches) {
338 const auto &BranchParams = Branch->getBranchParams();
339 assert(SeenIDs.
insert(BranchParams.ID).second &&
"Duplicate CondID");
340 NextIDs[BranchParams.ID] = BranchParams.Conds;
362 unsigned NumConditions;
372 std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
379 unsigned NumExecVectorsF;
388 MCDCRecordProcessor(
const BitVector &Bitmap,
392 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
394 Branches(Branches), NumConditions(DecisionParams.NumConditions),
395 Folded(NumConditions,
false), IndependencePairs(NumConditions),
396 ExecVectors(ExecVectorsByCond[
false]), IsVersion11(IsVersion11) {}
407 TV.
set(
ID, MCDCCond);
408 auto NextID = NextIDs[
ID][MCDCCond];
409 auto NextTVIdx = TVIdx + Indices[
ID][MCDCCond];
410 assert(NextID == SavedNodes[
ID].NextIDs[MCDCCond]);
412 buildTestVector(TV, NextID, NextTVIdx);
416 assert(TVIdx < SavedNodes[
ID].Width);
417 assert(TVIdxs.
insert(NextTVIdx).second &&
"Duplicate TVIdx");
419 if (!Bitmap[IsVersion11
421 : DecisionParams.
BitmapIdx - NumTestVectors + NextTVIdx])
427 ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
436 void findExecutedTestVectors() {
442 buildTestVector(TV, 0, 0);
443 assert(TVIdxs.
size() ==
unsigned(NumTestVectors) &&
444 "TVIdxs wasn't fulfilled");
449 NumExecVectorsF = ExecVectors.
size();
450 auto &ExecVectorsT = ExecVectorsByCond[
true];
451 ExecVectors.
append(std::make_move_iterator(ExecVectorsT.begin()),
452 std::make_move_iterator(ExecVectorsT.end()));
459 void findIndependencePairs() {
460 unsigned NumTVs = ExecVectors.
size();
461 for (
unsigned I = NumExecVectorsF;
I < NumTVs; ++
I) {
462 const auto &[
A, ACond] = ExecVectors[
I];
464 for (
unsigned J = 0; J < NumExecVectorsF; ++J) {
465 const auto &[
B, BCond] = ExecVectors[J];
469 auto AB =
A.getDifferences(
B);
472 {
AB.find_first(), std::make_pair(J + 1,
I + 1)});
502 for (
const auto *
B : Branches) {
503 const auto &BranchParams =
B->getBranchParams();
504 PosToID[
I] = BranchParams.ID;
505 CondLoc[
I] =
B->startLoc();
506 Folded[
I++] = (
B->Count.isZero() ||
B->FalseCount.isZero());
510 findExecutedTestVectors();
514 findIndependencePairs();
518 std::move(IndependencePairs), std::move(Folded),
519 std::move(PosToID), std::move(CondLoc));
529 MCDCRecordProcessor MCDCProcessor(Bitmap,
Region, Branches, IsVersion11);
530 return MCDCProcessor.processMCDCRecord();
541 } VisitCount = KNeverVisited;
544 std::stack<StackElem> CounterStack;
545 CounterStack.push({
C});
547 int64_t LastPoppedValue;
549 while (!CounterStack.empty()) {
550 StackElem &Current = CounterStack.top();
552 switch (Current.ICounter.getKind()) {
558 LastPoppedValue = Current.ICounter.getCounterID();
562 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
566 const auto &E = Expressions[Current.ICounter.getExpressionID()];
567 if (Current.VisitCount == StackElem::KNeverVisited) {
568 CounterStack.push(StackElem{E.LHS});
569 Current.VisitCount = StackElem::KVisitedOnce;
570 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
571 Current.LHS = LastPoppedValue;
572 CounterStack.push(StackElem{E.RHS});
573 Current.VisitCount = StackElem::KVisitedTwice;
575 int64_t
LHS = Current.LHS;
576 int64_t
RHS = LastPoppedValue;
577 LastPoppedValue = std::max(
LHS,
RHS);
586 return LastPoppedValue;
589void FunctionRecordIterator::skipOtherFiles() {
590 while (Current != Records.end() && !Filename.empty() &&
591 Filename != Current->Filenames[0])
593 if (Current == Records.end())
600 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
601 if (RecordIt == FilenameHash2RecordIndices.end())
603 return RecordIt->second;
608 unsigned MaxCounterID = 0;
618 unsigned MaxBitmapIdx = 0;
619 unsigned NumConditions = 0;
626 const auto &DecisionParams =
Region.getDecisionParams();
627 if (MaxBitmapIdx <= DecisionParams.
BitmapIdx) {
634 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
643class MCDCDecisionRecorder {
649 struct DecisionRecord {
672 : DecisionRegion(&Decision),
673 DecisionParams(Decision.getDecisionParams()),
674 DecisionStartLoc(Decision.startLoc()),
675 DecisionEndLoc(Decision.endLoc()) {
682 if (
R.FileID == DecisionRegion->
FileID &&
683 R.startLoc() >= DecisionStartLoc &&
R.endLoc() <= DecisionEndLoc)
687 return ExpandedFileIDs.
contains(
R.FileID);
715 if (ConditionID == 0)
716 MCDCBranches.
insert(MCDCBranches.
begin(), &Branch);
747 ~MCDCDecisionRecorder() {
748 assert(Decisions.
empty() &&
"All Decisions have not been resolved");
758 return Decision.recordExpansion(
Expansion);
762 using DecisionAndBranches =
771 std::optional<DecisionAndBranches>
774 for (
auto DecisionIter = Decisions.
begin(), DecisionEnd = Decisions.
end();
775 DecisionIter != DecisionEnd; ++DecisionIter)
776 switch (DecisionIter->addBranch(Branch)) {
777 case DecisionRecord::NotProcessed:
779 case DecisionRecord::Processed:
781 case DecisionRecord::Completed:
782 DecisionAndBranches
Result =
783 std::make_pair(DecisionIter->DecisionRegion,
784 std::move(DecisionIter->MCDCBranches));
785 Decisions.
erase(DecisionIter);
795Error CoverageMapping::loadFunctionRecord(
799 if (OrigFuncName.
empty())
801 "record function name is empty");
803 if (
Record.Filenames.empty())
810 std::vector<uint64_t> Counts;
812 Record.FunctionHash, Counts)) {
815 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
820 return make_error<InstrProfError>(IPE);
823 Ctx.setCounts(Counts);
830 Record.FunctionHash, Bitmap)) {
833 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
838 return make_error<InstrProfError>(IPE);
841 Ctx.setBitmap(std::move(Bitmap));
843 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
850 if (
Record.MappingRegions.size() == 1 &&
851 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
854 MCDCDecisionRecorder MCDCDecisions;
860 MCDCDecisions.registerDecision(
Region);
864 if (
auto E = ExecutionCount.
takeError()) {
869 if (
auto E = AltExecutionCount.
takeError()) {
878 MCDCDecisions.recordExpansion(
Region);
890 auto MCDCDecision =
Result->first;
891 auto &MCDCBranches =
Result->second;
897 Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
898 if (
auto E =
Record.takeError()) {
910 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
913 Functions.push_back(std::move(
Function));
918 unsigned RecordIndex = Functions.size() - 1;
920 auto &RecordIndices = FilenameHash2RecordIndices[
hash_value(Filename)];
924 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
925 RecordIndices.push_back(RecordIndex);
933Error CoverageMapping::loadFromReaders(
934 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
936 for (
const auto &CoverageReader : CoverageReaders) {
937 for (
auto RecordOrErr : *CoverageReader) {
938 if (
Error E = RecordOrErr.takeError())
940 const auto &
Record = *RecordOrErr;
949 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
951 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
952 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
954 return std::move(Coverage);
963 return make_error<CoverageMapError>(CME.
get(), CME.
getMessage());
967Error CoverageMapping::loadFromFile(
972 Filename,
false,
false);
973 if (std::error_code EC = CovMappingBufOrErr.getError())
976 CovMappingBufOrErr.get()->getMemBufferRef();
981 CovMappingBufRef, Arch, Buffers, CompilationDir,
982 FoundBinaryIDs ? &BinaryIDs :
nullptr);
983 if (
Error E = CoverageReadersOrErr.takeError()) {
991 for (
auto &Reader : CoverageReadersOrErr.get())
993 if (FoundBinaryIDs && !Readers.
empty()) {
999 DataFound |= !Readers.
empty();
1000 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1010 if (
Error E = ProfileReaderOrErr.takeError())
1012 auto ProfileReader = std::move(ProfileReaderOrErr.get());
1013 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1014 bool DataFound =
false;
1016 auto GetArch = [&](
size_t Idx) {
1019 if (Arches.
size() == 1)
1020 return Arches.
front();
1027 loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
1028 *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
1029 return std::move(E);
1033 std::vector<object::BuildID> ProfileBinaryIDs;
1038 if (!ProfileBinaryIDs.empty()) {
1040 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1044 std::set_difference(
1045 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1046 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1047 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1051 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1053 std::string Path = std::move(*PathOpt);
1055 if (
Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
1056 *Coverage, DataFound))
1057 return std::move(E);
1058 }
else if (CheckBinaryIDs) {
1062 "Missing binary ID: " +
1063 llvm::toHex(BinaryID,
true)));
1070 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1072 return std::move(Coverage);
1081class FunctionInstantiationSetCollector {
1082 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1083 MapT InstantiatedFunctions;
1088 while (
I !=
E &&
I->FileID != FileID)
1090 assert(
I !=
E &&
"function does not cover the given file");
1091 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1095 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1096 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1099class SegmentBuilder {
1100 std::vector<CoverageSegment> &
Segments;
1103 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1110 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1111 bool HasCount = !EmitSkippedRegion &&
1115 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1117 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1118 !
Last.IsRegionEntry)
1123 Segments.emplace_back(StartLoc.first, StartLoc.second,
1124 Region.ExecutionCount, IsRegionEntry,
1127 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1131 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1132 <<
" (count = " <<
Last.Count <<
")"
1133 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1134 << (!
Last.HasCount ?
", Skipped" :
"")
1135 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1144 void completeRegionsUntil(std::optional<LineColPair> Loc,
1145 unsigned FirstCompletedRegion) {
1148 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1149 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1151 return L->endLoc() < R->endLoc();
1155 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1157 const auto *CompletedRegion = ActiveRegions[
I];
1158 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1159 "Completed region ends after start of new region");
1161 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1162 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1165 if (Loc && CompletedSegmentLoc == *Loc)
1170 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1174 for (
unsigned J =
I + 1; J <
E; ++J)
1175 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1176 CompletedRegion = ActiveRegions[J];
1178 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1182 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1185 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1187 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1190 startSegment(*
Last,
Last->endLoc(),
false,
true);
1194 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1198 for (
const auto &CR :
enumerate(Regions)) {
1199 auto CurStartLoc = CR.value().startLoc();
1202 auto CompletedRegions =
1203 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1205 return !(Region->endLoc() <= CurStartLoc);
1207 if (CompletedRegions != ActiveRegions.
end()) {
1208 unsigned FirstCompletedRegion =
1209 std::distance(ActiveRegions.
begin(), CompletedRegions);
1210 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1216 if (CurStartLoc == CR.value().endLoc()) {
1219 const bool Skipped =
1220 (CR.index() + 1) == Regions.
size() ||
1222 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1223 CurStartLoc, !GapRegion, Skipped);
1226 if (Skipped && !ActiveRegions.
empty())
1227 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1230 if (CR.index() + 1 == Regions.
size() ||
1231 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1234 startSegment(CR.value(), CurStartLoc, !GapRegion);
1242 if (!ActiveRegions.
empty())
1243 completeRegionsUntil(std::nullopt, 0);
1249 if (
LHS.startLoc() !=
RHS.startLoc())
1250 return LHS.startLoc() <
RHS.startLoc();
1253 return RHS.endLoc() <
LHS.endLoc();
1263 "Unexpected order of region kind values");
1264 return LHS.Kind <
RHS.Kind;
1271 if (Regions.
empty())
1273 auto Active = Regions.
begin();
1274 auto End = Regions.
end();
1275 for (
auto I = Regions.
begin() + 1;
I !=
End; ++
I) {
1276 if (Active->startLoc() !=
I->startLoc() ||
1277 Active->endLoc() !=
I->endLoc()) {
1296 if (
I->Kind == Active->Kind) {
1297 assert(
I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
1298 "Regions are generated in different coverage modes");
1299 if (
I->HasSingleByteCoverage)
1300 Active->ExecutionCount = Active->ExecutionCount ||
I->ExecutionCount;
1302 Active->ExecutionCount +=
I->ExecutionCount;
1305 return Regions.
drop_back(std::distance(++Active,
End));
1310 static std::vector<CoverageSegment>
1312 std::vector<CoverageSegment>
Segments;
1313 SegmentBuilder Builder(Segments);
1315 sortNestedRegions(Regions);
1319 dbgs() <<
"Combined regions:\n";
1320 for (
const auto &CR : CombinedRegions)
1321 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1322 << CR.LineEnd <<
":" << CR.ColumnEnd
1323 <<
" (count=" << CR.ExecutionCount <<
")\n";
1326 Builder.buildSegmentsImpl(CombinedRegions);
1332 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1333 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1336 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1337 assert(
false &&
"Coverage segments not unique or sorted");
1349 std::vector<StringRef> Filenames;
1350 for (
const auto &
Function : getCoveredFunctions())
1354 Filenames.erase(
Last, Filenames.end());
1362 if (SourceFile ==
Function.Filenames[
I])
1363 FilenameEquivalence[
I] =
true;
1364 return FilenameEquivalence;
1368static std::optional<unsigned>
1371 for (
const auto &CR :
Function.CountedRegions)
1373 IsNotExpandedFile[CR.ExpandedFileID] =
false;
1376 return std::nullopt;
1383static std::optional<unsigned>
1386 if (
I && SourceFile ==
Function.Filenames[*
I])
1388 return std::nullopt;
1397 std::vector<CountedRegion> Regions;
1402 getImpreciseRecordIndicesForFilename(Filename);
1403 for (
unsigned RecordIndex : RecordIndices) {
1407 for (
const auto &CR :
Function.CountedRegions)
1408 if (FileIDs.test(CR.FileID)) {
1409 Regions.push_back(CR);
1411 FileCoverage.Expansions.emplace_back(CR,
Function);
1414 for (
const auto &CR :
Function.CountedBranchRegions)
1415 if (FileIDs.test(CR.FileID))
1416 FileCoverage.BranchRegions.push_back(CR);
1418 for (
const auto &MR :
Function.MCDCRecords)
1419 if (FileIDs.test(MR.getDecisionRegion().FileID))
1420 FileCoverage.MCDCRecords.push_back(MR);
1423 LLVM_DEBUG(
dbgs() <<
"Emitting segments for file: " << Filename <<
"\n");
1424 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1426 return FileCoverage;
1429std::vector<InstantiationGroup>
1431 FunctionInstantiationSetCollector InstantiationSetCollector;
1435 getImpreciseRecordIndicesForFilename(Filename);
1436 for (
unsigned RecordIndex : RecordIndices) {
1441 InstantiationSetCollector.insert(
Function, *MainFileID);
1444 std::vector<InstantiationGroup> Result;
1445 for (
auto &InstantiationSet : InstantiationSetCollector) {
1447 InstantiationSet.first.second,
1448 std::move(InstantiationSet.second)};
1449 Result.emplace_back(std::move(IG));
1461 std::vector<CountedRegion> Regions;
1462 for (
const auto &CR :
Function.CountedRegions)
1463 if (CR.FileID == *MainFileID) {
1464 Regions.push_back(CR);
1466 FunctionCoverage.Expansions.emplace_back(CR,
Function);
1469 for (
const auto &CR :
Function.CountedBranchRegions)
1470 if (CR.FileID == *MainFileID)
1471 FunctionCoverage.BranchRegions.push_back(CR);
1474 for (
const auto &MR :
Function.MCDCRecords)
1475 if (MR.getDecisionRegion().FileID == *MainFileID)
1476 FunctionCoverage.MCDCRecords.push_back(MR);
1480 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1482 return FunctionCoverage;
1489 std::vector<CountedRegion> Regions;
1490 for (
const auto &CR :
Expansion.Function.CountedRegions)
1492 Regions.push_back(CR);
1494 ExpansionCoverage.Expansions.emplace_back(CR,
Expansion.Function);
1496 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1499 ExpansionCoverage.BranchRegions.push_back(CR);
1503 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1505 return ExpansionCoverage;
1508LineCoverageStats::LineCoverageStats(
1511 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1512 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1514 unsigned MinRegionCount = 0;
1516 return !S->
IsGapRegion && S->HasCount && S->IsRegionEntry;
1518 for (
unsigned I = 0;
I < LineSegments.
size() && MinRegionCount < 2; ++
I)
1519 if (isStartOfRegion(LineSegments[
I]))
1522 bool StartOfSkippedRegion = !LineSegments.
empty() &&
1523 !LineSegments.
front()->HasCount &&
1524 LineSegments.
front()->IsRegionEntry;
1526 HasMultipleRegions = MinRegionCount > 1;
1528 !StartOfSkippedRegion &&
1529 ((WrappedSegment && WrappedSegment->
HasCount) || (MinRegionCount > 0));
1533 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1534 return Seq->IsRegionEntry && Seq->HasCount;
1544 ExecutionCount = WrappedSegment->
Count;
1545 if (!MinRegionCount)
1547 for (
const auto *LS : LineSegments)
1548 if (isStartOfRegion(LS))
1549 ExecutionCount = std::max(ExecutionCount, LS->Count);
1553 if (Next == CD.
end()) {
1558 if (Segments.size())
1559 WrappedSegment = Segments.back();
1561 while (Next != CD.
end() && Next->Line == Line)
1562 Segments.push_back(&*Next++);
1569 const std::string &ErrMsg =
"") {
1578 OS <<
"end of File";
1581 OS <<
"no coverage data found";
1584 OS <<
"unsupported coverage format version";
1587 OS <<
"truncated coverage data";
1590 OS <<
"malformed coverage data";
1593 OS <<
"failed to decompress coverage data (zlib)";
1596 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1601 if (!ErrMsg.empty())
1602 OS <<
": " << ErrMsg;
1612class CoverageMappingErrorCategoryType :
public std::error_category {
1613 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1614 std::string message(
int IE)
const override {
1626 static CoverageMappingErrorCategoryType ErrorCategory;
1627 return ErrorCategory;
This file declares a library for handling Build IDs and using them to find debug info.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static SmallBitVector gatherFileIDs(StringRef SourceFile, const FunctionRecord &Function)
static std::optional< unsigned > findMainViewFileID(const FunctionRecord &Function)
Return the ID of the file where the definition of the function is located.
static bool isExpansion(const CountedRegion &R, unsigned FileID)
static Error handleMaybeNoDataFoundError(Error E)
static unsigned getMaxBitmapSize(const CoverageMappingRecord &Record, bool IsVersion11)
Returns the bit count.
static std::string getCoverageMapErrString(coveragemap_error Err, const std::string &ErrMsg="")
static unsigned getMaxCounterID(const CounterMappingContext &Ctx, const CoverageMappingRecord &Record)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseMap class.
static bool dominates(InstrPosIndexes &PosIndexes, const MachineInstr &A, const MachineInstr &B)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements the SmallBitVector class.
This file defines the SmallVector class.
Defines the virtual file system interface vfs::FileSystem.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
front - Get the first element.
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
Reader for the indexed binary instrprof format.
uint64_t getVersion() const override
Return the profile version.
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const Twine &RemappingPath="")
Factory method to create an indexed reader.
Error getFunctionBitmap(StringRef FuncName, uint64_t FuncHash, BitVector &Bitmap)
Fill Bitmap with the profile data for the given function name.
bool hasSingleByteCoverage() const override
Return true if the profile has single byte counters representing coverage.
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector< uint64_t > &Counts)
Fill Counts with the profile data for the given function name.
Error readBinaryIds(std::vector< llvm::object::BuildID > &BinaryIds) override
Read a list of binary ids.
static std::pair< instrprof_error, std::string > take(Error E)
Consume an Error and return the raw enum value contained within it, and the optional error message.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
MutableArrayRef< T > drop_back(size_t N=1) const
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
int find_first() const
Returns the index of the first set bit, -1 if none of the bits are set.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
iterator erase(const_iterator CI)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
LLVM Value Representation.
static Expected< std::vector< std::unique_ptr< BinaryCoverageReader > > > create(MemoryBufferRef ObjectBuffer, StringRef Arch, SmallVectorImpl< std::unique_ptr< MemoryBuffer > > &ObjectFileBuffers, StringRef CompilationDir="", SmallVectorImpl< object::BuildIDRef > *BinaryIDs=nullptr)
Counter subtract(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that subtracts RHS from LHS.
Counter add(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that adds LHS and RHS.
A Counter mapping context is used to connect the counters, expressions and the obtained counter value...
Expected< MCDCRecord > evaluateMCDCRegion(const CounterMappingRegion &Region, ArrayRef< const CounterMappingRegion * > Branches, bool IsVersion11)
Return an MCDC record that indicates executed test vectors and condition pairs.
Expected< int64_t > evaluate(const Counter &C) const
Return the number of times that a region of code associated with this counter was executed.
unsigned getMaxCounterID(const Counter &C) const
void dump(const Counter &C, raw_ostream &OS) const
Coverage information to be processed or displayed.
std::vector< CoverageSegment >::const_iterator end() const
std::string message() const override
Return the error message as a string.
coveragemap_error get() const
const std::string & getMessage() const
The mapping of profile information to coverage data.
std::vector< StringRef > getUniqueSourceFiles() const
Returns a lexicographically sorted, unique list of files that are covered.
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const
Get the coverage for an expansion within a coverage set.
CoverageData getCoverageForFunction(const FunctionRecord &Function) const
Get the coverage for a particular function.
std::vector< InstantiationGroup > getInstantiationGroups(StringRef Filename) const
Get the list of function instantiation groups in a particular file.
CoverageData getCoverageForFile(StringRef Filename) const
Get the coverage for a particular file.
static Expected< std::unique_ptr< CoverageMapping > > load(ArrayRef< std::unique_ptr< CoverageMappingReader > > CoverageReaders, IndexedInstrProfReader &ProfileReader)
Load the coverage mapping using the given readers.
Iterator over Functions, optionally filtered to a single file.
An instantiation group contains a FunctionRecord list, such that each record corresponds to a distinc...
An iterator over the LineCoverageStats objects for lines described by a CoverageData instance.
LineCoverageIterator & operator++()
Coverage statistics for a single line.
Emulate SmallVector<CondState> with a pair of BitVector.
auto getIndex() const
Equivalent to buildTestVector's Index.
void set(int I, CondState Val)
Set the condition Val at position I.
Compute TestVector Indices "TVIdx" from the Conds graph.
static constexpr auto HardMaxTVs
Hard limit of test vectors.
TVIdxBuilder(const SmallVectorImpl< ConditionIDs > &NextIDs, int Offset=0)
Calculate and assign Indices.
SmallVector< std::array< int, 2 > > Indices
Output: Index for TestVectors bitmap (These are not CondIDs)
int NumTestVectors
Output: The number of test vectors.
SmallVector< MCDCNode > SavedNodes
This is no longer needed after the assignment.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
BuildIDFetcher searches local cache directories for debug info.
virtual std::optional< std::string > fetch(BuildIDRef BuildID) const
Returns the path to the debug file with the given build ID.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
The virtual file system interface.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
int16_t ConditionID
The ID for MCDCBranch.
std::array< ConditionID, 2 > ConditionIDs
const std::error_category & coveragemap_category()
@ invalid_or_missing_arch_specifier
std::pair< unsigned, unsigned > LineColPair
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
This is an optimization pass for GlobalISel generic memory operations.
hash_code hash_value(const FixedPointSemantics &Val)
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName="<unknown>")
Given a PGO function name, remove the filename prefix and return the original (static) function name.
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
auto unique(Range &&R, Predicate P)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
auto map_range(ContainerTy &&C, FuncTy F)
@ no_such_file_or_directory
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
void consumeError(Error Err)
Consume a Error without doing anything.
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Associates a source range with an execution count.
A Counter expression is a value that represents an arithmetic operation with two counters.
A Counter mapping region associates a source range with a specific counter.
@ ExpansionRegion
An ExpansionRegion represents a file expansion region that associates a source range with the expansi...
@ MCDCDecisionRegion
A DecisionRegion represents a top-level boolean expression and is associated with a variable length b...
@ MCDCBranchRegion
A Branch Region can be extended to include IDs to facilitate MC/DC.
@ SkippedRegion
A SkippedRegion represents a source range with code that was skipped by a preprocessor or similar mea...
@ GapRegion
A GapRegion is like a CodeRegion, but its count is only set as the line execution count when its the ...
@ CodeRegion
A CodeRegion associates some code with a counter.
A Counter is an abstract value that describes how to compute the execution count for a region of code...
static Counter getZero()
Return the counter that represents the number zero.
static Counter getCounter(unsigned CounterId)
Return the counter that corresponds to a specific profile counter.
static Counter getExpression(unsigned ExpressionId)
Return the counter that corresponds to a specific addition counter expression.
Coverage mapping information for a single function.
The execution count information starting at a point in a file.
bool HasCount
When false, the segment was uninstrumented or skipped.
uint64_t Count
The execution count, or zero if no count was recorded.
bool IsGapRegion
Whether this enters a gap region.
Coverage information for a macro expansion or #included file.
Code coverage information for a single function.
MCDC Record grouping all information together.
unsigned BitmapIdx
Byte Index of Bitmap Coverage Object for a Decision Region.
uint16_t NumConditions
Number of Conditions used for a Decision Region.