42#include <system_error>
47using namespace coverage;
49#define DEBUG_TYPE "coverage-mapping"
52 auto It = ExpressionIndices.find(E);
53 if (It != ExpressionIndices.end())
55 unsigned I = Expressions.size();
56 Expressions.push_back(E);
57 ExpressionIndices[E] =
I;
61void CounterExpressionBuilder::extractTerms(
Counter C,
int Factor,
63 switch (
C.getKind()) {
70 const auto &E = Expressions[
C.getExpressionID()];
71 extractTerms(E.LHS, Factor, Terms);
78Counter CounterExpressionBuilder::simplify(
Counter ExpressionTree) {
81 extractTerms(ExpressionTree, +1, Terms);
85 if (Terms.
size() == 0)
89 llvm::sort(Terms, [](
const Term &LHS,
const Term &RHS) {
90 return LHS.CounterID <
RHS.CounterID;
94 auto Prev = Terms.
begin();
95 for (
auto I = Prev + 1, E = Terms.
end();
I != E; ++
I) {
96 if (
I->CounterID == Prev->CounterID) {
97 Prev->Factor +=
I->Factor;
108 for (
auto T : Terms) {
111 for (
int I = 0;
I <
T.Factor; ++
I)
120 for (
auto T : Terms) {
123 for (
int I = 0;
I < -
T.Factor; ++
I)
132 return Simplify ?
simplify(Cnt) : Cnt;
138 return Simplify ?
simplify(Cnt) : Cnt;
142 switch (
C.getKind()) {
147 OS <<
'#' <<
C.getCounterID();
150 if (
C.getExpressionID() >= Expressions.size())
152 const auto &E = Expressions[
C.getExpressionID()];
161 if (CounterValues.
empty())
164 if (
auto E =
Value.takeError()) {
179 } VisitCount = KNeverVisited;
182 std::stack<StackElem> CounterStack;
183 CounterStack.push({
C});
185 int64_t LastPoppedValue;
187 while (!CounterStack.empty()) {
188 StackElem &Current = CounterStack.top();
190 switch (Current.ICounter.getKind()) {
196 if (Current.ICounter.getCounterID() >= CounterValues.
size())
198 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
202 if (Current.ICounter.getExpressionID() >= Expressions.size())
204 const auto &E = Expressions[Current.ICounter.getExpressionID()];
205 if (Current.VisitCount == StackElem::KNeverVisited) {
206 CounterStack.push(StackElem{E.LHS});
207 Current.VisitCount = StackElem::KVisitedOnce;
208 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
209 Current.LHS = LastPoppedValue;
210 CounterStack.push(StackElem{E.RHS});
211 Current.VisitCount = StackElem::KVisitedTwice;
213 int64_t
LHS = Current.LHS;
214 int64_t
RHS = LastPoppedValue;
224 return LastPoppedValue;
229 : Indices(NextIDs.
size()) {
231 auto N = NextIDs.
size();
233 for (
unsigned ID = 0;
ID <
N; ++
ID) {
234 for (
unsigned C = 0;
C < 2; ++
C) {
238 auto NextID = NextIDs[
ID][
C];
239 Nodes[
ID].NextIDs[
C] = NextID;
241 ++Nodes[NextID].InCount;
255 assert(Nodes[0].InCount == 0);
261 auto IID = Q.
begin();
264 auto &Node = Nodes[
ID];
267 for (
unsigned I = 0;
I < 2; ++
I) {
268 auto NextID = Node.NextIDs[
I];
269 assert(NextID != 0 &&
"NextID should not point to the top");
272 Decisions.emplace_back(-Node.Width, Ord++,
ID,
I);
273 assert(Ord == Decisions.size());
278 auto &NextNode = Nodes[NextID];
279 assert(NextNode.InCount > 0);
284 auto NextWidth = int64_t(NextNode.Width) + Node.Width;
289 NextNode.Width = NextWidth;
293 if (--NextNode.InCount == 0)
302 for (
auto [NegWidth, Ord,
ID,
C] : Decisions) {
303 int Width = -NegWidth;
319 for (
const auto &Idxs :
Indices)
320 for (
auto Idx : Idxs)
330class NextIDsBuilder {
336 : NextIDs(Branches.
size()) {
340 for (
const auto *Branch : Branches) {
341 const auto &BranchParams = Branch->getBranchParams();
342 assert(SeenIDs.
insert(BranchParams.ID).second &&
"Duplicate CondID");
343 NextIDs[BranchParams.ID] = BranchParams.Conds;
365 unsigned NumConditions;
375 std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
382 unsigned NumExecVectorsF;
391 MCDCRecordProcessor(
const BitVector &Bitmap,
395 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
397 Branches(Branches), NumConditions(DecisionParams.NumConditions),
398 Folded(NumConditions,
false), IndependencePairs(NumConditions),
399 ExecVectors(ExecVectorsByCond[
false]), IsVersion11(IsVersion11) {}
410 TV.
set(
ID, MCDCCond);
411 auto NextID = NextIDs[
ID][MCDCCond];
412 auto NextTVIdx = TVIdx + Indices[
ID][MCDCCond];
413 assert(NextID == SavedNodes[
ID].NextIDs[MCDCCond]);
415 buildTestVector(TV, NextID, NextTVIdx);
419 assert(TVIdx < SavedNodes[
ID].Width);
420 assert(TVIdxs.
insert(NextTVIdx).second &&
"Duplicate TVIdx");
422 if (!Bitmap[IsVersion11
424 : DecisionParams.
BitmapIdx - NumTestVectors + NextTVIdx])
430 ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
439 void findExecutedTestVectors() {
445 buildTestVector(TV, 0, 0);
446 assert(TVIdxs.
size() ==
unsigned(NumTestVectors) &&
447 "TVIdxs wasn't fulfilled");
452 NumExecVectorsF = ExecVectors.
size();
453 auto &ExecVectorsT = ExecVectorsByCond[
true];
454 ExecVectors.
append(std::make_move_iterator(ExecVectorsT.begin()),
455 std::make_move_iterator(ExecVectorsT.end()));
462 void findIndependencePairs() {
463 unsigned NumTVs = ExecVectors.
size();
464 for (
unsigned I = NumExecVectorsF;
I < NumTVs; ++
I) {
465 const auto &[
A, ACond] = ExecVectors[
I];
467 for (
unsigned J = 0; J < NumExecVectorsF; ++J) {
468 const auto &[
B, BCond] = ExecVectors[J];
472 auto AB =
A.getDifferences(
B);
475 {
AB.find_first(), std::make_pair(J + 1,
I + 1)});
505 for (
const auto *
B : Branches) {
506 const auto &BranchParams =
B->getBranchParams();
507 PosToID[
I] = BranchParams.ID;
508 CondLoc[
I] =
B->startLoc();
509 Folded[
I++] = (
B->Count.isZero() &&
B->FalseCount.isZero());
513 findExecutedTestVectors();
517 findIndependencePairs();
521 std::move(IndependencePairs), std::move(Folded),
522 std::move(PosToID), std::move(CondLoc));
532 MCDCRecordProcessor MCDCProcessor(Bitmap,
Region, Branches, IsVersion11);
533 return MCDCProcessor.processMCDCRecord();
544 } VisitCount = KNeverVisited;
547 std::stack<StackElem> CounterStack;
548 CounterStack.push({
C});
550 int64_t LastPoppedValue;
552 while (!CounterStack.empty()) {
553 StackElem &Current = CounterStack.top();
555 switch (Current.ICounter.getKind()) {
561 LastPoppedValue = Current.ICounter.getCounterID();
565 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
569 const auto &E = Expressions[Current.ICounter.getExpressionID()];
570 if (Current.VisitCount == StackElem::KNeverVisited) {
571 CounterStack.push(StackElem{E.LHS});
572 Current.VisitCount = StackElem::KVisitedOnce;
573 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
574 Current.LHS = LastPoppedValue;
575 CounterStack.push(StackElem{E.RHS});
576 Current.VisitCount = StackElem::KVisitedTwice;
578 int64_t
LHS = Current.LHS;
579 int64_t
RHS = LastPoppedValue;
580 LastPoppedValue = std::max(
LHS,
RHS);
589 return LastPoppedValue;
592void FunctionRecordIterator::skipOtherFiles() {
593 while (Current != Records.end() && !Filename.empty() &&
594 Filename != Current->Filenames[0])
596 if (Current == Records.end())
603 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
604 if (RecordIt == FilenameHash2RecordIndices.end())
606 return RecordIt->second;
611 unsigned MaxCounterID = 0;
621 unsigned MaxBitmapIdx = 0;
622 unsigned NumConditions = 0;
629 const auto &DecisionParams =
Region.getDecisionParams();
630 if (MaxBitmapIdx <= DecisionParams.
BitmapIdx) {
637 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
646class MCDCDecisionRecorder {
652 struct DecisionRecord {
675 : DecisionRegion(&Decision),
676 DecisionParams(Decision.getDecisionParams()),
677 DecisionStartLoc(Decision.startLoc()),
678 DecisionEndLoc(Decision.endLoc()) {
685 if (
R.FileID == DecisionRegion->
FileID &&
686 R.startLoc() >= DecisionStartLoc &&
R.endLoc() <= DecisionEndLoc)
690 return ExpandedFileIDs.
contains(
R.FileID);
718 if (ConditionID == 0)
719 MCDCBranches.
insert(MCDCBranches.
begin(), &Branch);
750 ~MCDCDecisionRecorder() {
751 assert(Decisions.
empty() &&
"All Decisions have not been resolved");
761 return Decision.recordExpansion(
Expansion);
765 using DecisionAndBranches =
774 std::optional<DecisionAndBranches>
777 for (
auto DecisionIter = Decisions.
begin(), DecisionEnd = Decisions.
end();
778 DecisionIter != DecisionEnd; ++DecisionIter)
779 switch (DecisionIter->addBranch(Branch)) {
780 case DecisionRecord::NotProcessed:
782 case DecisionRecord::Processed:
784 case DecisionRecord::Completed:
785 DecisionAndBranches
Result =
786 std::make_pair(DecisionIter->DecisionRegion,
787 std::move(DecisionIter->MCDCBranches));
788 Decisions.
erase(DecisionIter);
798Error CoverageMapping::loadFunctionRecord(
802 if (OrigFuncName.
empty())
804 "record function name is empty");
806 if (
Record.Filenames.empty())
813 std::vector<uint64_t> Counts;
815 Record.FunctionHash, Counts)) {
818 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
823 return make_error<InstrProfError>(IPE);
826 Ctx.setCounts(Counts);
833 Record.FunctionHash, Bitmap)) {
836 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
841 return make_error<InstrProfError>(IPE);
844 Ctx.setBitmap(std::move(Bitmap));
846 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
853 if (
Record.MappingRegions.size() == 1 &&
854 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
857 MCDCDecisionRecorder MCDCDecisions;
863 MCDCDecisions.registerDecision(
Region);
867 if (
auto E = ExecutionCount.
takeError()) {
872 if (
auto E = AltExecutionCount.
takeError()) {
881 MCDCDecisions.recordExpansion(
Region);
893 auto MCDCDecision =
Result->first;
894 auto &MCDCBranches =
Result->second;
900 Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
901 if (
auto E =
Record.takeError()) {
913 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
916 Functions.push_back(std::move(
Function));
921 unsigned RecordIndex = Functions.size() - 1;
923 auto &RecordIndices = FilenameHash2RecordIndices[
hash_value(Filename)];
927 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
928 RecordIndices.push_back(RecordIndex);
936Error CoverageMapping::loadFromReaders(
937 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
939 for (
const auto &CoverageReader : CoverageReaders) {
940 for (
auto RecordOrErr : *CoverageReader) {
941 if (
Error E = RecordOrErr.takeError())
943 const auto &
Record = *RecordOrErr;
952 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
954 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
955 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
957 return std::move(Coverage);
966 return make_error<CoverageMapError>(CME.
get(), CME.
getMessage());
970Error CoverageMapping::loadFromFile(
975 Filename,
false,
false);
976 if (std::error_code EC = CovMappingBufOrErr.getError())
979 CovMappingBufOrErr.get()->getMemBufferRef();
984 CovMappingBufRef, Arch, Buffers, CompilationDir,
985 FoundBinaryIDs ? &BinaryIDs :
nullptr);
986 if (
Error E = CoverageReadersOrErr.takeError()) {
994 for (
auto &Reader : CoverageReadersOrErr.get())
996 if (FoundBinaryIDs && !Readers.
empty()) {
1002 DataFound |= !Readers.
empty();
1003 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1013 if (
Error E = ProfileReaderOrErr.takeError())
1015 auto ProfileReader = std::move(ProfileReaderOrErr.get());
1016 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1017 bool DataFound =
false;
1019 auto GetArch = [&](
size_t Idx) {
1022 if (Arches.
size() == 1)
1023 return Arches.
front();
1030 loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
1031 *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
1032 return std::move(E);
1036 std::vector<object::BuildID> ProfileBinaryIDs;
1041 if (!ProfileBinaryIDs.empty()) {
1043 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1047 std::set_difference(
1048 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1049 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1050 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1054 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1056 std::string Path = std::move(*PathOpt);
1058 if (
Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
1059 *Coverage, DataFound))
1060 return std::move(E);
1061 }
else if (CheckBinaryIDs) {
1065 "Missing binary ID: " +
1066 llvm::toHex(BinaryID,
true)));
1073 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1075 return std::move(Coverage);
1084class FunctionInstantiationSetCollector {
1085 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1086 MapT InstantiatedFunctions;
1091 while (
I !=
E &&
I->FileID != FileID)
1093 assert(
I !=
E &&
"function does not cover the given file");
1094 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1098 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1099 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1102class SegmentBuilder {
1103 std::vector<CoverageSegment> &
Segments;
1106 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1113 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1114 bool HasCount = !EmitSkippedRegion &&
1118 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1120 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1121 !
Last.IsRegionEntry)
1126 Segments.emplace_back(StartLoc.first, StartLoc.second,
1127 Region.ExecutionCount, IsRegionEntry,
1130 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1134 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1135 <<
" (count = " <<
Last.Count <<
")"
1136 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1137 << (!
Last.HasCount ?
", Skipped" :
"")
1138 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1147 void completeRegionsUntil(std::optional<LineColPair> Loc,
1148 unsigned FirstCompletedRegion) {
1151 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1152 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1154 return L->endLoc() < R->endLoc();
1158 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1160 const auto *CompletedRegion = ActiveRegions[
I];
1161 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1162 "Completed region ends after start of new region");
1164 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1165 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1168 if (Loc && CompletedSegmentLoc == *Loc)
1173 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1177 for (
unsigned J =
I + 1; J <
E; ++J)
1178 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1179 CompletedRegion = ActiveRegions[J];
1181 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1185 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1188 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1190 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1193 startSegment(*
Last,
Last->endLoc(),
false,
true);
1197 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1201 for (
const auto &CR :
enumerate(Regions)) {
1202 auto CurStartLoc = CR.value().startLoc();
1205 auto CompletedRegions =
1206 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1208 return !(Region->endLoc() <= CurStartLoc);
1210 if (CompletedRegions != ActiveRegions.
end()) {
1211 unsigned FirstCompletedRegion =
1212 std::distance(ActiveRegions.
begin(), CompletedRegions);
1213 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1219 if (CurStartLoc == CR.value().endLoc()) {
1222 const bool Skipped =
1223 (CR.index() + 1) == Regions.
size() ||
1225 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1226 CurStartLoc, !GapRegion, Skipped);
1229 if (Skipped && !ActiveRegions.
empty())
1230 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1233 if (CR.index() + 1 == Regions.
size() ||
1234 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1237 startSegment(CR.value(), CurStartLoc, !GapRegion);
1245 if (!ActiveRegions.
empty())
1246 completeRegionsUntil(std::nullopt, 0);
1252 if (
LHS.startLoc() !=
RHS.startLoc())
1253 return LHS.startLoc() <
RHS.startLoc();
1256 return RHS.endLoc() <
LHS.endLoc();
1266 "Unexpected order of region kind values");
1267 return LHS.Kind <
RHS.Kind;
1274 if (Regions.
empty())
1276 auto Active = Regions.
begin();
1277 auto End = Regions.
end();
1278 for (
auto I = Regions.
begin() + 1;
I !=
End; ++
I) {
1279 if (Active->startLoc() !=
I->startLoc() ||
1280 Active->endLoc() !=
I->endLoc()) {
1299 if (
I->Kind == Active->Kind) {
1300 assert(
I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
1301 "Regions are generated in different coverage modes");
1302 if (
I->HasSingleByteCoverage)
1303 Active->ExecutionCount = Active->ExecutionCount ||
I->ExecutionCount;
1305 Active->ExecutionCount +=
I->ExecutionCount;
1308 return Regions.
drop_back(std::distance(++Active,
End));
1313 static std::vector<CoverageSegment>
1315 std::vector<CoverageSegment>
Segments;
1316 SegmentBuilder Builder(Segments);
1318 sortNestedRegions(Regions);
1322 dbgs() <<
"Combined regions:\n";
1323 for (
const auto &CR : CombinedRegions)
1324 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1325 << CR.LineEnd <<
":" << CR.ColumnEnd
1326 <<
" (count=" << CR.ExecutionCount <<
")\n";
1329 Builder.buildSegmentsImpl(CombinedRegions);
1335 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1336 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1339 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1340 assert(
false &&
"Coverage segments not unique or sorted");
1352 std::vector<StringRef> Filenames;
1353 for (
const auto &
Function : getCoveredFunctions())
1357 Filenames.erase(
Last, Filenames.end());
1365 if (SourceFile ==
Function.Filenames[
I])
1366 FilenameEquivalence[
I] =
true;
1367 return FilenameEquivalence;
1371static std::optional<unsigned>
1374 for (
const auto &CR :
Function.CountedRegions)
1376 IsNotExpandedFile[CR.ExpandedFileID] =
false;
1379 return std::nullopt;
1386static std::optional<unsigned>
1389 if (
I && SourceFile ==
Function.Filenames[*
I])
1391 return std::nullopt;
1400 std::vector<CountedRegion> Regions;
1405 getImpreciseRecordIndicesForFilename(Filename);
1406 for (
unsigned RecordIndex : RecordIndices) {
1410 for (
const auto &CR :
Function.CountedRegions)
1411 if (FileIDs.test(CR.FileID)) {
1412 Regions.push_back(CR);
1414 FileCoverage.Expansions.emplace_back(CR,
Function);
1417 for (
const auto &CR :
Function.CountedBranchRegions)
1418 if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
1419 FileCoverage.BranchRegions.push_back(CR);
1421 for (
const auto &MR :
Function.MCDCRecords)
1422 if (FileIDs.test(MR.getDecisionRegion().FileID))
1423 FileCoverage.MCDCRecords.push_back(MR);
1426 LLVM_DEBUG(
dbgs() <<
"Emitting segments for file: " << Filename <<
"\n");
1427 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1429 return FileCoverage;
1432std::vector<InstantiationGroup>
1434 FunctionInstantiationSetCollector InstantiationSetCollector;
1438 getImpreciseRecordIndicesForFilename(Filename);
1439 for (
unsigned RecordIndex : RecordIndices) {
1444 InstantiationSetCollector.insert(
Function, *MainFileID);
1447 std::vector<InstantiationGroup> Result;
1448 for (
auto &InstantiationSet : InstantiationSetCollector) {
1450 InstantiationSet.first.second,
1451 std::move(InstantiationSet.second)};
1452 Result.emplace_back(std::move(IG));
1464 std::vector<CountedRegion> Regions;
1465 for (
const auto &CR :
Function.CountedRegions)
1466 if (CR.FileID == *MainFileID) {
1467 Regions.push_back(CR);
1469 FunctionCoverage.Expansions.emplace_back(CR,
Function);
1472 for (
const auto &CR :
Function.CountedBranchRegions)
1473 if (CR.FileID == *MainFileID)
1474 FunctionCoverage.BranchRegions.push_back(CR);
1477 for (
const auto &MR :
Function.MCDCRecords)
1478 if (MR.getDecisionRegion().FileID == *MainFileID)
1479 FunctionCoverage.MCDCRecords.push_back(MR);
1483 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1485 return FunctionCoverage;
1492 std::vector<CountedRegion> Regions;
1493 for (
const auto &CR :
Expansion.Function.CountedRegions)
1495 Regions.push_back(CR);
1497 ExpansionCoverage.Expansions.emplace_back(CR,
Expansion.Function);
1499 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1502 ExpansionCoverage.BranchRegions.push_back(CR);
1506 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1508 return ExpansionCoverage;
1511LineCoverageStats::LineCoverageStats(
1514 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1515 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1517 unsigned MinRegionCount = 0;
1519 return !S->
IsGapRegion && S->HasCount && S->IsRegionEntry;
1521 for (
unsigned I = 0;
I < LineSegments.
size() && MinRegionCount < 2; ++
I)
1522 if (isStartOfRegion(LineSegments[
I]))
1525 bool StartOfSkippedRegion = !LineSegments.
empty() &&
1526 !LineSegments.
front()->HasCount &&
1527 LineSegments.
front()->IsRegionEntry;
1529 HasMultipleRegions = MinRegionCount > 1;
1531 !StartOfSkippedRegion &&
1532 ((WrappedSegment && WrappedSegment->
HasCount) || (MinRegionCount > 0));
1536 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1537 return Seq->IsRegionEntry && Seq->HasCount;
1547 ExecutionCount = WrappedSegment->
Count;
1548 if (!MinRegionCount)
1550 for (
const auto *LS : LineSegments)
1551 if (isStartOfRegion(LS))
1552 ExecutionCount = std::max(ExecutionCount, LS->Count);
1556 if (Next == CD.
end()) {
1561 if (Segments.size())
1562 WrappedSegment = Segments.back();
1564 while (Next != CD.
end() && Next->Line == Line)
1565 Segments.push_back(&*Next++);
1572 const std::string &ErrMsg =
"") {
1581 OS <<
"end of File";
1584 OS <<
"no coverage data found";
1587 OS <<
"unsupported coverage format version";
1590 OS <<
"truncated coverage data";
1593 OS <<
"malformed coverage data";
1596 OS <<
"failed to decompress coverage data (zlib)";
1599 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1604 if (!ErrMsg.empty())
1605 OS <<
": " << ErrMsg;
1615class CoverageMappingErrorCategoryType :
public std::error_category {
1616 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1617 std::string message(
int IE)
const override {
1629 static CoverageMappingErrorCategoryType ErrorCategory;
1630 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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
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.