41#include <system_error>
46using namespace coverage;
48#define DEBUG_TYPE "coverage-mapping"
51 auto It = ExpressionIndices.find(
E);
52 if (It != ExpressionIndices.end())
54 unsigned I = Expressions.size();
55 Expressions.push_back(
E);
56 ExpressionIndices[
E] =
I;
60void CounterExpressionBuilder::extractTerms(
Counter C,
int Factor,
62 switch (
C.getKind()) {
69 const auto &
E = Expressions[
C.getExpressionID()];
70 extractTerms(
E.LHS, Factor, Terms);
77Counter CounterExpressionBuilder::simplify(
Counter ExpressionTree) {
80 extractTerms(ExpressionTree, +1, Terms);
84 if (Terms.
size() == 0)
88 llvm::sort(Terms, [](
const Term &LHS,
const Term &RHS) {
89 return LHS.CounterID <
RHS.CounterID;
93 auto Prev = Terms.
begin();
94 for (
auto I = Prev + 1,
E = Terms.
end();
I !=
E; ++
I) {
95 if (
I->CounterID == Prev->CounterID) {
96 Prev->Factor +=
I->Factor;
107 for (
auto T : Terms) {
110 for (
int I = 0;
I <
T.Factor; ++
I)
119 for (
auto T : Terms) {
122 for (
int I = 0;
I < -
T.Factor; ++
I)
131 return Simplify ?
simplify(Cnt) : Cnt;
137 return Simplify ?
simplify(Cnt) : Cnt;
141 switch (
C.getKind()) {
146 OS <<
'#' <<
C.getCounterID();
149 if (
C.getExpressionID() >= Expressions.size())
151 const auto &
E = Expressions[
C.getExpressionID()];
160 if (CounterValues.
empty())
163 if (
auto E =
Value.takeError()) {
178 } VisitCount = KNeverVisited;
181 std::stack<StackElem> CounterStack;
182 CounterStack.push({
C});
184 int64_t LastPoppedValue;
186 while (!CounterStack.empty()) {
187 StackElem &Current = CounterStack.top();
189 switch (Current.ICounter.getKind()) {
195 if (Current.ICounter.getCounterID() >= CounterValues.
size())
197 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
201 if (Current.ICounter.getExpressionID() >= Expressions.size())
203 const auto &
E = Expressions[Current.ICounter.getExpressionID()];
204 if (Current.VisitCount == StackElem::KNeverVisited) {
205 CounterStack.push(StackElem{
E.LHS});
206 Current.VisitCount = StackElem::KVisitedOnce;
207 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
208 Current.LHS = LastPoppedValue;
209 CounterStack.push(StackElem{
E.RHS});
210 Current.VisitCount = StackElem::KVisitedTwice;
212 int64_t
LHS = Current.LHS;
213 int64_t
RHS = LastPoppedValue;
223 return LastPoppedValue;
228 : Indices(NextIDs.
size()) {
230 auto N = NextIDs.
size();
232 for (
unsigned ID = 0;
ID <
N; ++
ID) {
233 for (
unsigned C = 0;
C < 2; ++
C) {
237 auto NextID = NextIDs[
ID][
C];
238 Nodes[
ID].NextIDs[
C] = NextID;
240 ++Nodes[NextID].InCount;
254 assert(Nodes[0].InCount == 0);
260 auto IID = Q.
begin();
263 auto &Node = Nodes[
ID];
266 for (
unsigned I = 0;
I < 2; ++
I) {
267 auto NextID = Node.NextIDs[
I];
268 assert(NextID != 0 &&
"NextID should not point to the top");
271 Decisions.emplace_back(-Node.Width, Ord++,
ID,
I);
272 assert(Ord == Decisions.size());
277 auto &NextNode = Nodes[NextID];
278 assert(NextNode.InCount > 0);
283 auto NextWidth = int64_t(NextNode.Width) + Node.Width;
288 NextNode.Width = NextWidth;
292 if (--NextNode.InCount == 0)
301 for (
auto [NegWidth, Ord,
ID,
C] : Decisions) {
302 int Width = -NegWidth;
318 for (
const auto &Idxs :
Indices)
319 for (
auto Idx : Idxs)
329class NextIDsBuilder {
335 : NextIDs(Branches.
size()) {
339 for (
const auto *Branch : Branches) {
340 const auto &BranchParams = Branch->getBranchParams();
341 assert(BranchParams.ID >= 0 &&
"CondID isn't set");
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;
389 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]) {}
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");
425 ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
434 void findExecutedTestVectors() {
440 buildTestVector(TV, 0, 0);
441 assert(TVIdxs.
size() ==
unsigned(NumTestVectors) &&
442 "TVIdxs wasn't fulfilled");
447 NumExecVectorsF = ExecVectors.
size();
448 auto &ExecVectorsT = ExecVectorsByCond[
true];
449 ExecVectors.
append(std::make_move_iterator(ExecVectorsT.begin()),
450 std::make_move_iterator(ExecVectorsT.end()));
457 void findIndependencePairs() {
458 unsigned NumTVs = ExecVectors.
size();
459 for (
unsigned I = NumExecVectorsF;
I < NumTVs; ++
I) {
460 const auto &[
A, ACond] = ExecVectors[
I];
462 for (
unsigned J = 0; J < NumExecVectorsF; ++J) {
463 const auto &[
B, BCond] = ExecVectors[J];
467 auto AB =
A.getDifferences(
B);
470 {
AB.find_first(), std::make_pair(J + 1,
I + 1)});
500 for (
const auto *
B : Branches) {
501 const auto &BranchParams =
B->getBranchParams();
502 PosToID[
I] = BranchParams.ID;
503 CondLoc[
I] =
B->startLoc();
504 Folded[
I++] = (
B->Count.isZero() &&
B->FalseCount.isZero());
508 findExecutedTestVectors();
512 findIndependencePairs();
516 std::move(IndependencePairs), std::move(Folded),
517 std::move(PosToID), std::move(CondLoc));
527 MCDCRecordProcessor MCDCProcessor(Bitmap,
Region, Branches);
528 return MCDCProcessor.processMCDCRecord();
539 } VisitCount = KNeverVisited;
542 std::stack<StackElem> CounterStack;
543 CounterStack.push({
C});
545 int64_t LastPoppedValue;
547 while (!CounterStack.empty()) {
548 StackElem &Current = CounterStack.top();
550 switch (Current.ICounter.getKind()) {
556 LastPoppedValue = Current.ICounter.getCounterID();
560 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
564 const auto &
E = Expressions[Current.ICounter.getExpressionID()];
565 if (Current.VisitCount == StackElem::KNeverVisited) {
566 CounterStack.push(StackElem{
E.LHS});
567 Current.VisitCount = StackElem::KVisitedOnce;
568 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
569 Current.LHS = LastPoppedValue;
570 CounterStack.push(StackElem{
E.RHS});
571 Current.VisitCount = StackElem::KVisitedTwice;
573 int64_t
LHS = Current.LHS;
574 int64_t
RHS = LastPoppedValue;
575 LastPoppedValue = std::max(
LHS,
RHS);
584 return LastPoppedValue;
587void FunctionRecordIterator::skipOtherFiles() {
588 while (Current != Records.end() && !Filename.empty() &&
589 Filename != Current->Filenames[0])
591 if (Current == Records.end())
598 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
599 if (RecordIt == FilenameHash2RecordIndices.end())
601 return RecordIt->second;
606 unsigned MaxCounterID = 0;
616 unsigned MaxBitmapIdx = 0;
617 unsigned NumConditions = 0;
624 const auto &DecisionParams =
Region.getDecisionParams();
625 if (MaxBitmapIdx <= DecisionParams.
BitmapIdx) {
631 return MaxBitmapIdx * CHAR_BIT + SizeInBits;
637class MCDCDecisionRecorder {
643 struct DecisionRecord {
666 : DecisionRegion(&Decision),
667 DecisionParams(Decision.getDecisionParams()),
668 DecisionStartLoc(Decision.startLoc()),
669 DecisionEndLoc(Decision.endLoc()) {
676 if (
R.FileID == DecisionRegion->
FileID &&
677 R.startLoc() >= DecisionStartLoc &&
R.endLoc() <= DecisionEndLoc)
681 return ExpandedFileIDs.
contains(
R.FileID);
697 assert(ConditionID >= 0 &&
"ConditionID should be positive");
710 if (ConditionID == 0)
711 MCDCBranches.
insert(MCDCBranches.
begin(), &Branch);
742 ~MCDCDecisionRecorder() {
743 assert(Decisions.
empty() &&
"All Decisions have not been resolved");
753 return Decision.recordExpansion(
Expansion);
757 using DecisionAndBranches =
766 std::optional<DecisionAndBranches>
769 for (
auto DecisionIter = Decisions.
begin(), DecisionEnd = Decisions.
end();
770 DecisionIter != DecisionEnd; ++DecisionIter)
771 switch (DecisionIter->addBranch(Branch)) {
772 case DecisionRecord::NotProcessed:
774 case DecisionRecord::Processed:
776 case DecisionRecord::Completed:
777 DecisionAndBranches
Result =
778 std::make_pair(DecisionIter->DecisionRegion,
779 std::move(DecisionIter->MCDCBranches));
780 Decisions.
erase(DecisionIter);
790Error CoverageMapping::loadFunctionRecord(
794 if (OrigFuncName.
empty())
796 "record function name is empty");
798 if (
Record.Filenames.empty())
805 std::vector<uint64_t> Counts;
807 Record.FunctionHash, Counts)) {
810 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
815 return make_error<InstrProfError>(IPE);
818 Ctx.setCounts(Counts);
822 Record.FunctionHash, Bitmap)) {
825 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
830 return make_error<InstrProfError>(IPE);
833 Ctx.setBitmap(std::move(Bitmap));
835 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
842 if (
Record.MappingRegions.size() == 1 &&
843 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
846 MCDCDecisionRecorder MCDCDecisions;
852 MCDCDecisions.registerDecision(
Region);
870 MCDCDecisions.recordExpansion(
Region);
882 auto MCDCDecision =
Result->first;
883 auto &MCDCBranches =
Result->second;
889 Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches);
890 if (
auto E =
Record.takeError()) {
902 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
905 Functions.push_back(std::move(
Function));
910 unsigned RecordIndex = Functions.size() - 1;
912 auto &RecordIndices = FilenameHash2RecordIndices[
hash_value(Filename)];
916 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
917 RecordIndices.push_back(RecordIndex);
925Error CoverageMapping::loadFromReaders(
926 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
928 for (
const auto &CoverageReader : CoverageReaders) {
929 for (
auto RecordOrErr : *CoverageReader) {
930 if (
Error E = RecordOrErr.takeError())
932 const auto &
Record = *RecordOrErr;
941 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
943 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
944 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
946 return std::move(Coverage);
955 return make_error<CoverageMapError>(CME.
get(), CME.
getMessage());
959Error CoverageMapping::loadFromFile(
964 Filename,
false,
false);
965 if (std::error_code EC = CovMappingBufOrErr.getError())
968 CovMappingBufOrErr.get()->getMemBufferRef();
973 CovMappingBufRef, Arch, Buffers, CompilationDir,
974 FoundBinaryIDs ? &BinaryIDs :
nullptr);
975 if (
Error E = CoverageReadersOrErr.takeError()) {
983 for (
auto &Reader : CoverageReadersOrErr.get())
985 if (FoundBinaryIDs && !Readers.
empty()) {
991 DataFound |= !Readers.
empty();
992 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1002 if (
Error E = ProfileReaderOrErr.takeError())
1004 auto ProfileReader = std::move(ProfileReaderOrErr.get());
1005 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1006 bool DataFound =
false;
1008 auto GetArch = [&](
size_t Idx) {
1011 if (Arches.
size() == 1)
1012 return Arches.
front();
1019 loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
1020 *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
1021 return std::move(
E);
1025 std::vector<object::BuildID> ProfileBinaryIDs;
1030 if (!ProfileBinaryIDs.empty()) {
1032 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1036 std::set_difference(
1037 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1038 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1039 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1043 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1045 std::string Path = std::move(*PathOpt);
1047 if (
Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
1048 *Coverage, DataFound))
1049 return std::move(
E);
1050 }
else if (CheckBinaryIDs) {
1054 "Missing binary ID: " +
1055 llvm::toHex(BinaryID,
true)));
1062 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1064 return std::move(Coverage);
1073class FunctionInstantiationSetCollector {
1074 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1075 MapT InstantiatedFunctions;
1080 while (
I !=
E &&
I->FileID != FileID)
1082 assert(
I !=
E &&
"function does not cover the given file");
1083 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1087 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1088 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1091class SegmentBuilder {
1092 std::vector<CoverageSegment> &
Segments;
1095 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1102 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1103 bool HasCount = !EmitSkippedRegion &&
1107 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1109 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1110 !
Last.IsRegionEntry)
1115 Segments.emplace_back(StartLoc.first, StartLoc.second,
1116 Region.ExecutionCount, IsRegionEntry,
1119 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1123 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1124 <<
" (count = " <<
Last.Count <<
")"
1125 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1126 << (!
Last.HasCount ?
", Skipped" :
"")
1127 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1136 void completeRegionsUntil(std::optional<LineColPair> Loc,
1137 unsigned FirstCompletedRegion) {
1140 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1141 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1143 return L->endLoc() < R->endLoc();
1147 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1149 const auto *CompletedRegion = ActiveRegions[
I];
1150 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1151 "Completed region ends after start of new region");
1153 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1154 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1157 if (Loc && CompletedSegmentLoc == *Loc)
1162 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1166 for (
unsigned J =
I + 1; J <
E; ++J)
1167 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1168 CompletedRegion = ActiveRegions[J];
1170 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1174 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1177 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1179 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1182 startSegment(*
Last,
Last->endLoc(),
false,
true);
1186 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1190 for (
const auto &CR :
enumerate(Regions)) {
1191 auto CurStartLoc = CR.value().startLoc();
1194 auto CompletedRegions =
1195 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1197 return !(Region->endLoc() <= CurStartLoc);
1199 if (CompletedRegions != ActiveRegions.
end()) {
1200 unsigned FirstCompletedRegion =
1201 std::distance(ActiveRegions.
begin(), CompletedRegions);
1202 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1208 if (CurStartLoc == CR.value().endLoc()) {
1211 const bool Skipped =
1212 (CR.index() + 1) == Regions.
size() ||
1214 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1215 CurStartLoc, !GapRegion, Skipped);
1218 if (Skipped && !ActiveRegions.
empty())
1219 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1222 if (CR.index() + 1 == Regions.
size() ||
1223 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1226 startSegment(CR.value(), CurStartLoc, !GapRegion);
1234 if (!ActiveRegions.
empty())
1235 completeRegionsUntil(std::nullopt, 0);
1241 if (
LHS.startLoc() !=
RHS.startLoc())
1242 return LHS.startLoc() <
RHS.startLoc();
1245 return RHS.endLoc() <
LHS.endLoc();
1255 "Unexpected order of region kind values");
1256 return LHS.Kind <
RHS.Kind;
1263 if (Regions.
empty())
1265 auto Active = Regions.
begin();
1266 auto End = Regions.
end();
1267 for (
auto I = Regions.
begin() + 1;
I !=
End; ++
I) {
1268 if (Active->startLoc() !=
I->startLoc() ||
1269 Active->endLoc() !=
I->endLoc()) {
1288 if (
I->Kind == Active->Kind) {
1289 assert(
I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
1290 "Regions are generated in different coverage modes");
1291 if (
I->HasSingleByteCoverage)
1292 Active->ExecutionCount = Active->ExecutionCount ||
I->ExecutionCount;
1294 Active->ExecutionCount +=
I->ExecutionCount;
1297 return Regions.
drop_back(std::distance(++Active,
End));
1302 static std::vector<CoverageSegment>
1304 std::vector<CoverageSegment>
Segments;
1305 SegmentBuilder Builder(Segments);
1307 sortNestedRegions(Regions);
1311 dbgs() <<
"Combined regions:\n";
1312 for (
const auto &CR : CombinedRegions)
1313 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1314 << CR.LineEnd <<
":" << CR.ColumnEnd
1315 <<
" (count=" << CR.ExecutionCount <<
")\n";
1318 Builder.buildSegmentsImpl(CombinedRegions);
1324 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1325 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1328 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1329 assert(
false &&
"Coverage segments not unique or sorted");
1341 std::vector<StringRef> Filenames;
1342 for (
const auto &
Function : getCoveredFunctions())
1345 auto Last = std::unique(Filenames.begin(), Filenames.end());
1346 Filenames.erase(
Last, Filenames.end());
1354 if (SourceFile ==
Function.Filenames[
I])
1355 FilenameEquivalence[
I] =
true;
1356 return FilenameEquivalence;
1360static std::optional<unsigned>
1363 for (
const auto &CR :
Function.CountedRegions)
1365 IsNotExpandedFile[CR.ExpandedFileID] =
false;
1368 return std::nullopt;
1375static std::optional<unsigned>
1378 if (
I && SourceFile ==
Function.Filenames[*
I])
1380 return std::nullopt;
1389 std::vector<CountedRegion> Regions;
1394 getImpreciseRecordIndicesForFilename(Filename);
1395 for (
unsigned RecordIndex : RecordIndices) {
1399 for (
const auto &CR :
Function.CountedRegions)
1400 if (FileIDs.test(CR.FileID)) {
1401 Regions.push_back(CR);
1403 FileCoverage.Expansions.emplace_back(CR,
Function);
1406 for (
const auto &CR :
Function.CountedBranchRegions)
1407 if (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
1408 FileCoverage.BranchRegions.push_back(CR);
1410 for (
const auto &MR :
Function.MCDCRecords)
1411 if (FileIDs.test(MR.getDecisionRegion().FileID))
1412 FileCoverage.MCDCRecords.push_back(MR);
1415 LLVM_DEBUG(
dbgs() <<
"Emitting segments for file: " << Filename <<
"\n");
1416 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1418 return FileCoverage;
1421std::vector<InstantiationGroup>
1423 FunctionInstantiationSetCollector InstantiationSetCollector;
1427 getImpreciseRecordIndicesForFilename(Filename);
1428 for (
unsigned RecordIndex : RecordIndices) {
1433 InstantiationSetCollector.insert(
Function, *MainFileID);
1436 std::vector<InstantiationGroup> Result;
1437 for (
auto &InstantiationSet : InstantiationSetCollector) {
1439 InstantiationSet.first.second,
1440 std::move(InstantiationSet.second)};
1441 Result.emplace_back(std::move(IG));
1453 std::vector<CountedRegion> Regions;
1454 for (
const auto &CR :
Function.CountedRegions)
1455 if (CR.FileID == *MainFileID) {
1456 Regions.push_back(CR);
1458 FunctionCoverage.Expansions.emplace_back(CR,
Function);
1461 for (
const auto &CR :
Function.CountedBranchRegions)
1462 if (CR.FileID == *MainFileID)
1463 FunctionCoverage.BranchRegions.push_back(CR);
1466 for (
const auto &MR :
Function.MCDCRecords)
1467 if (MR.getDecisionRegion().FileID == *MainFileID)
1468 FunctionCoverage.MCDCRecords.push_back(MR);
1472 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1474 return FunctionCoverage;
1481 std::vector<CountedRegion> Regions;
1482 for (
const auto &CR :
Expansion.Function.CountedRegions)
1484 Regions.push_back(CR);
1486 ExpansionCoverage.Expansions.emplace_back(CR,
Expansion.Function);
1488 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1491 ExpansionCoverage.BranchRegions.push_back(CR);
1495 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1497 return ExpansionCoverage;
1500LineCoverageStats::LineCoverageStats(
1503 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1504 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1506 unsigned MinRegionCount = 0;
1508 return !S->
IsGapRegion && S->HasCount && S->IsRegionEntry;
1510 for (
unsigned I = 0;
I < LineSegments.
size() && MinRegionCount < 2; ++
I)
1511 if (isStartOfRegion(LineSegments[
I]))
1514 bool StartOfSkippedRegion = !LineSegments.
empty() &&
1515 !LineSegments.
front()->HasCount &&
1516 LineSegments.
front()->IsRegionEntry;
1518 HasMultipleRegions = MinRegionCount > 1;
1520 !StartOfSkippedRegion &&
1521 ((WrappedSegment && WrappedSegment->
HasCount) || (MinRegionCount > 0));
1525 Mapped |= std::any_of(
1526 LineSegments.
begin(), LineSegments.
end(),
1527 [](
const auto *Seq) { return Seq->IsRegionEntry && Seq->HasCount; });
1536 ExecutionCount = WrappedSegment->
Count;
1537 if (!MinRegionCount)
1539 for (
const auto *LS : LineSegments)
1540 if (isStartOfRegion(LS))
1541 ExecutionCount = std::max(ExecutionCount, LS->Count);
1545 if (Next == CD.
end()) {
1550 if (Segments.size())
1551 WrappedSegment = Segments.back();
1553 while (Next != CD.
end() && Next->Line == Line)
1554 Segments.push_back(&*Next++);
1561 const std::string &ErrMsg =
"") {
1570 OS <<
"end of File";
1573 OS <<
"no coverage data found";
1576 OS <<
"unsupported coverage format version";
1579 OS <<
"truncated coverage data";
1582 OS <<
"malformed coverage data";
1585 OS <<
"failed to decompress coverage data (zlib)";
1588 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1593 if (!ErrMsg.empty())
1594 OS <<
": " << ErrMsg;
1604class CoverageMappingErrorCategoryType :
public std::error_category {
1605 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1606 std::string message(
int IE)
const override {
1618 static CoverageMappingErrorCategoryType ErrorCategory;
1619 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 std::string getCoverageMapErrString(coveragemap_error Err, const std::string &ErrMsg="")
static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx, const CoverageMappingRecord &Record)
Returns the bit count.
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.
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)
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 are tuples (A,...
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.
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.