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;
140 if (
auto I = Map.find(
C);
I != Map.end())
143 if (!
C.isExpression())
146 auto CE = Expressions[
C.getExpressionID()];
147 auto NewLHS =
subst(CE.LHS, Map);
148 auto NewRHS =
subst(CE.RHS, Map);
153 C =
add(NewLHS, NewRHS);
164 switch (
C.getKind()) {
169 OS <<
'#' <<
C.getCounterID();
172 if (
C.getExpressionID() >= Expressions.size())
174 const auto &E = Expressions[
C.getExpressionID()];
183 if (CounterValues.
empty())
186 if (
auto E =
Value.takeError()) {
201 } VisitCount = KNeverVisited;
204 std::stack<StackElem> CounterStack;
205 CounterStack.push({
C});
207 int64_t LastPoppedValue;
209 while (!CounterStack.empty()) {
210 StackElem &Current = CounterStack.top();
212 switch (Current.ICounter.getKind()) {
218 if (Current.ICounter.getCounterID() >= CounterValues.
size())
220 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
224 if (Current.ICounter.getExpressionID() >= Expressions.size())
226 const auto &E = Expressions[Current.ICounter.getExpressionID()];
227 if (Current.VisitCount == StackElem::KNeverVisited) {
228 CounterStack.push(StackElem{E.LHS});
229 Current.VisitCount = StackElem::KVisitedOnce;
230 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
231 Current.LHS = LastPoppedValue;
232 CounterStack.push(StackElem{E.RHS});
233 Current.VisitCount = StackElem::KVisitedTwice;
235 int64_t
LHS = Current.LHS;
236 int64_t
RHS = LastPoppedValue;
246 return LastPoppedValue;
254 if (IndependencePairs)
257 IndependencePairs.emplace();
259 unsigned NumTVs = TV.
size();
261 unsigned TVTrueIdx = std::distance(
264 [&](
auto I) { return (I.second == MCDCRecord::MCDC_True); })
267 for (
unsigned I = TVTrueIdx;
I < NumTVs; ++
I) {
268 const auto &[
A, ACond] = TV[
I];
270 for (
unsigned J = 0; J < TVTrueIdx; ++J) {
271 const auto &[
B, BCond] = TV[J];
275 auto AB =
A.getDifferences(
B);
277 IndependencePairs->insert(
278 {AB.find_first(), std::make_pair(J + 1,
I + 1)});
285 : Indices(NextIDs.
size()) {
287 auto N = NextIDs.
size();
289 for (
unsigned ID = 0;
ID <
N; ++
ID) {
290 for (
unsigned C = 0;
C < 2; ++
C) {
294 auto NextID = NextIDs[
ID][
C];
295 Nodes[
ID].NextIDs[
C] = NextID;
297 ++Nodes[NextID].InCount;
311 assert(Nodes[0].InCount == 0);
317 auto IID = Q.
begin();
320 auto &Node = Nodes[
ID];
323 for (
unsigned I = 0;
I < 2; ++
I) {
324 auto NextID = Node.NextIDs[
I];
325 assert(NextID != 0 &&
"NextID should not point to the top");
328 Decisions.emplace_back(-Node.Width, Ord++,
ID,
I);
329 assert(Ord == Decisions.size());
334 auto &NextNode = Nodes[NextID];
335 assert(NextNode.InCount > 0);
340 auto NextWidth = int64_t(NextNode.Width) + Node.Width;
345 NextNode.Width = NextWidth;
349 if (--NextNode.InCount == 0)
358 for (
auto [NegWidth, Ord,
ID,
C] : Decisions) {
359 int Width = -NegWidth;
375 for (
const auto &Idxs :
Indices)
376 for (
auto Idx : Idxs)
386class NextIDsBuilder {
392 : NextIDs(Branches.
size()) {
396 for (
const auto *Branch : Branches) {
397 const auto &BranchParams = Branch->getBranchParams();
398 assert(SeenIDs.
insert(BranchParams.ID).second &&
"Duplicate CondID");
399 NextIDs[BranchParams.ID] = BranchParams.Conds;
421 unsigned NumConditions;
431 std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
444 MCDCRecordProcessor(
const BitVector &Bitmap,
448 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
450 Branches(Branches), NumConditions(DecisionParams.NumConditions),
452 IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[
false]),
453 IsVersion11(IsVersion11) {}
464 TV.
set(
ID, MCDCCond);
465 auto NextID = NextIDs[
ID][MCDCCond];
466 auto NextTVIdx = TVIdx + Indices[
ID][MCDCCond];
467 assert(NextID == SavedNodes[
ID].NextIDs[MCDCCond]);
469 buildTestVector(TV, NextID, NextTVIdx);
473 assert(TVIdx < SavedNodes[
ID].Width);
474 assert(TVIdxs.insert(NextTVIdx).second &&
"Duplicate TVIdx");
476 if (!Bitmap[IsVersion11
477 ? DecisionParams.BitmapIdx * CHAR_BIT + TV.
getIndex()
478 : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx])
484 ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
493 void findExecutedTestVectors() {
499 buildTestVector(TV, 0, 0);
500 assert(TVIdxs.size() ==
unsigned(NumTestVectors) &&
501 "TVIdxs wasn't fulfilled");
506 auto &ExecVectorsT = ExecVectorsByCond[
true];
507 ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
508 std::make_move_iterator(ExecVectorsT.end()));
536 const auto &BranchParams =
B->getBranchParams();
537 PosToID[
I] = BranchParams.ID;
538 CondLoc[
I] =
B->startLoc();
539 Folded[
false][
I] =
B->FalseCount.isZero();
540 Folded[
true][
I] =
B->Count.isZero();
544 findExecutedTestVectors();
548 std::move(PosToID), std::move(CondLoc));
558 MCDCRecordProcessor MCDCProcessor(Bitmap,
Region, Branches, IsVersion11);
559 return MCDCProcessor.processMCDCRecord();
570 } VisitCount = KNeverVisited;
573 std::stack<StackElem> CounterStack;
574 CounterStack.push({
C});
576 int64_t LastPoppedValue;
578 while (!CounterStack.empty()) {
579 StackElem &Current = CounterStack.top();
581 switch (Current.ICounter.getKind()) {
587 LastPoppedValue = Current.ICounter.getCounterID();
591 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
595 const auto &E = Expressions[Current.ICounter.getExpressionID()];
596 if (Current.VisitCount == StackElem::KNeverVisited) {
597 CounterStack.push(StackElem{E.LHS});
598 Current.VisitCount = StackElem::KVisitedOnce;
599 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
600 Current.LHS = LastPoppedValue;
601 CounterStack.push(StackElem{E.RHS});
602 Current.VisitCount = StackElem::KVisitedTwice;
604 int64_t
LHS = Current.LHS;
605 int64_t
RHS = LastPoppedValue;
606 LastPoppedValue = std::max(
LHS,
RHS);
615 return LastPoppedValue;
618void FunctionRecordIterator::skipOtherFiles() {
619 while (Current != Records.end() && !Filename.empty() &&
620 Filename != Current->Filenames[0])
622 if (Current == Records.end())
629 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
630 if (RecordIt == FilenameHash2RecordIndices.end())
632 return RecordIt->second;
637 unsigned MaxCounterID = 0;
647 unsigned MaxBitmapIdx = 0;
648 unsigned NumConditions = 0;
655 const auto &DecisionParams =
Region.getDecisionParams();
656 if (MaxBitmapIdx <= DecisionParams.BitmapIdx) {
657 MaxBitmapIdx = DecisionParams.BitmapIdx;
658 NumConditions = DecisionParams.NumConditions;
663 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
672class MCDCDecisionRecorder {
678 struct DecisionRecord {
701 : DecisionRegion(&Decision),
702 DecisionParams(Decision.getDecisionParams()),
703 DecisionStartLoc(Decision.startLoc()),
704 DecisionEndLoc(Decision.endLoc()) {
711 if (
R.FileID == DecisionRegion->
FileID &&
712 R.startLoc() >= DecisionStartLoc &&
R.endLoc() <= DecisionEndLoc)
716 return ExpandedFileIDs.
contains(
R.FileID);
744 if (ConditionID == 0)
745 MCDCBranches.
insert(MCDCBranches.
begin(), &Branch);
776 ~MCDCDecisionRecorder() {
777 assert(Decisions.
empty() &&
"All Decisions have not been resolved");
787 return Decision.recordExpansion(
Expansion);
791 using DecisionAndBranches =
800 std::optional<DecisionAndBranches>
803 for (
auto DecisionIter = Decisions.
begin(), DecisionEnd = Decisions.
end();
804 DecisionIter != DecisionEnd; ++DecisionIter)
805 switch (DecisionIter->addBranch(Branch)) {
806 case DecisionRecord::NotProcessed:
808 case DecisionRecord::Processed:
810 case DecisionRecord::Completed:
811 DecisionAndBranches
Result =
812 std::make_pair(DecisionIter->DecisionRegion,
813 std::move(DecisionIter->MCDCBranches));
814 Decisions.
erase(DecisionIter);
824Error CoverageMapping::loadFunctionRecord(
826 const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
829 if (OrigFuncName.
empty())
831 "record function name is empty");
833 if (
Record.Filenames.empty())
840 std::vector<uint64_t> Counts;
842 if (
Error E = ProfileReader.value().get().getFunctionCounts(
846 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
851 return make_error<InstrProfError>(IPE);
857 Ctx.setCounts(Counts);
860 ProfileReader && ProfileReader.value().get().getVersion() <
865 if (
Error E = ProfileReader.value().get().getFunctionBitmap(
869 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
874 return make_error<InstrProfError>(IPE);
880 Ctx.setBitmap(std::move(Bitmap));
882 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
889 if (
Record.MappingRegions.size() == 1 &&
890 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
893 MCDCDecisionRecorder MCDCDecisions;
899 MCDCDecisions.registerDecision(
Region);
903 if (
auto E = ExecutionCount.
takeError()) {
908 if (
auto E = AltExecutionCount.
takeError()) {
916 MCDCDecisions.recordExpansion(
Region);
928 auto MCDCDecision =
Result->first;
929 auto &MCDCBranches =
Result->second;
935 Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
936 if (
auto E =
Record.takeError()) {
947 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
950 Functions.push_back(std::move(
Function));
955 unsigned RecordIndex = Functions.size() - 1;
957 auto &RecordIndices = FilenameHash2RecordIndices[
hash_value(Filename)];
961 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
962 RecordIndices.push_back(RecordIndex);
970Error CoverageMapping::loadFromReaders(
971 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
972 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
977 ProfileReader.value().get().hasSingleByteCoverage());
979 !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
980 for (
const auto &CoverageReader : CoverageReaders) {
981 for (
auto RecordOrErr : *CoverageReader) {
982 if (
Error E = RecordOrErr.takeError())
984 const auto &
Record = *RecordOrErr;
993 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
994 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
996 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
997 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
999 return std::move(Coverage);
1007 return make_error<CoverageMapError>(CME.
get(), CME.
getMessage());
1011Error CoverageMapping::loadFromFile(
1013 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1018 Filename,
false,
false);
1019 if (std::error_code EC = CovMappingBufOrErr.getError())
1022 CovMappingBufOrErr.get()->getMemBufferRef();
1027 CovMappingBufRef, Arch, Buffers, CompilationDir,
1028 FoundBinaryIDs ? &BinaryIDs :
nullptr);
1029 if (
Error E = CoverageReadersOrErr.takeError()) {
1037 for (
auto &Reader : CoverageReadersOrErr.get())
1039 if (FoundBinaryIDs && !Readers.
empty()) {
1045 DataFound |= !Readers.
empty();
1046 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1056 std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1057 if (ProfileFilename) {
1058 auto ProfileReaderOrErr =
1060 if (
Error E = ProfileReaderOrErr.takeError())
1062 ProfileReader = std::move(ProfileReaderOrErr.get());
1064 auto ProfileReaderRef =
1066 ? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1069 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1070 bool DataFound =
false;
1072 auto GetArch = [&](
size_t Idx) {
1075 if (Arches.
size() == 1)
1076 return Arches.
front();
1082 if (
Error E = loadFromFile(File.value(), GetArch(File.index()),
1083 CompilationDir, ProfileReaderRef, *Coverage,
1084 DataFound, &FoundBinaryIDs))
1085 return std::move(E);
1089 std::vector<object::BuildID> ProfileBinaryIDs;
1091 if (
Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1095 if (!ProfileBinaryIDs.empty()) {
1097 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1101 std::set_difference(
1102 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1103 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1104 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1108 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1110 std::string Path = std::move(*PathOpt);
1112 if (
Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
1113 *Coverage, DataFound))
1114 return std::move(E);
1115 }
else if (CheckBinaryIDs) {
1117 ProfileFilename.value(),
1119 "Missing binary ID: " +
1120 llvm::toHex(BinaryID,
true)));
1127 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1129 return std::move(Coverage);
1138class FunctionInstantiationSetCollector {
1139 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1140 MapT InstantiatedFunctions;
1145 while (
I !=
E &&
I->FileID != FileID)
1147 assert(
I !=
E &&
"function does not cover the given file");
1148 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1152 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1153 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1156class SegmentBuilder {
1157 std::vector<CoverageSegment> &
Segments;
1160 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1167 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1168 bool HasCount = !EmitSkippedRegion &&
1172 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1174 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1175 !
Last.IsRegionEntry)
1180 Segments.emplace_back(StartLoc.first, StartLoc.second,
1181 Region.ExecutionCount, IsRegionEntry,
1184 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1188 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1189 <<
" (count = " <<
Last.Count <<
")"
1190 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1191 << (!
Last.HasCount ?
", Skipped" :
"")
1192 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1201 void completeRegionsUntil(std::optional<LineColPair> Loc,
1202 unsigned FirstCompletedRegion) {
1205 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1206 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1208 return L->endLoc() < R->endLoc();
1212 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1214 const auto *CompletedRegion = ActiveRegions[
I];
1215 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1216 "Completed region ends after start of new region");
1218 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1219 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1222 if (Loc && CompletedSegmentLoc == *Loc)
1227 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1231 for (
unsigned J =
I + 1; J <
E; ++J)
1232 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1233 CompletedRegion = ActiveRegions[J];
1235 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1239 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1242 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1244 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1247 startSegment(*
Last,
Last->endLoc(),
false,
true);
1251 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1255 for (
const auto &CR :
enumerate(Regions)) {
1256 auto CurStartLoc = CR.value().startLoc();
1259 auto CompletedRegions =
1260 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1262 return !(Region->endLoc() <= CurStartLoc);
1264 if (CompletedRegions != ActiveRegions.
end()) {
1265 unsigned FirstCompletedRegion =
1266 std::distance(ActiveRegions.
begin(), CompletedRegions);
1267 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1273 if (CurStartLoc == CR.value().endLoc()) {
1276 const bool Skipped =
1277 (CR.index() + 1) == Regions.
size() ||
1279 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1280 CurStartLoc, !GapRegion, Skipped);
1283 if (Skipped && !ActiveRegions.
empty())
1284 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1287 if (CR.index() + 1 == Regions.
size() ||
1288 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1291 startSegment(CR.value(), CurStartLoc, !GapRegion);
1299 if (!ActiveRegions.
empty())
1300 completeRegionsUntil(std::nullopt, 0);
1306 if (
LHS.startLoc() !=
RHS.startLoc())
1307 return LHS.startLoc() <
RHS.startLoc();
1310 return RHS.endLoc() <
LHS.endLoc();
1320 "Unexpected order of region kind values");
1321 return LHS.Kind <
RHS.Kind;
1328 if (Regions.
empty())
1331 auto End = Regions.
end();
1332 for (
auto I = Regions.
begin() + 1;
I !=
End; ++
I) {
1333 if (
Active->startLoc() !=
I->startLoc() ||
1334 Active->endLoc() !=
I->endLoc()) {
1354 Active->ExecutionCount +=
I->ExecutionCount;
1356 return Regions.
drop_back(std::distance(++Active,
End));
1361 static std::vector<CoverageSegment>
1363 std::vector<CoverageSegment>
Segments;
1364 SegmentBuilder Builder(Segments);
1366 sortNestedRegions(Regions);
1370 dbgs() <<
"Combined regions:\n";
1371 for (
const auto &CR : CombinedRegions)
1372 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1373 << CR.LineEnd <<
":" << CR.ColumnEnd
1374 <<
" (count=" << CR.ExecutionCount <<
")\n";
1377 Builder.buildSegmentsImpl(CombinedRegions);
1383 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1384 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1387 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1388 assert(
false &&
"Coverage segments not unique or sorted");
1400 std::vector<StringRef> Filenames;
1401 for (
const auto &
Function : getCoveredFunctions())
1405 Filenames.erase(
Last, Filenames.end());
1413 if (SourceFile ==
Function.Filenames[
I])
1414 FilenameEquivalence[
I] =
true;
1415 return FilenameEquivalence;
1419static std::optional<unsigned>
1422 for (
const auto &CR :
Function.CountedRegions)
1424 IsNotExpandedFile[CR.ExpandedFileID] =
false;
1427 return std::nullopt;
1434static std::optional<unsigned>
1437 if (
I && SourceFile ==
Function.Filenames[*
I])
1439 return std::nullopt;
1449 std::vector<CountedRegion> Regions;
1454 getImpreciseRecordIndicesForFilename(Filename);
1455 for (
unsigned RecordIndex : RecordIndices) {
1459 for (
const auto &CR :
Function.CountedRegions)
1460 if (FileIDs.test(CR.FileID)) {
1461 Regions.push_back(CR);
1463 FileCoverage.Expansions.emplace_back(CR,
Function);
1466 for (
const auto &CR :
Function.CountedBranchRegions)
1467 if (FileIDs.test(CR.FileID))
1468 FileCoverage.BranchRegions.push_back(CR);
1470 for (
const auto &MR :
Function.MCDCRecords)
1471 if (FileIDs.test(MR.getDecisionRegion().FileID))
1472 FileCoverage.MCDCRecords.push_back(MR);
1475 LLVM_DEBUG(
dbgs() <<
"Emitting segments for file: " << Filename <<
"\n");
1476 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1478 return FileCoverage;
1481std::vector<InstantiationGroup>
1483 FunctionInstantiationSetCollector InstantiationSetCollector;
1487 getImpreciseRecordIndicesForFilename(Filename);
1488 for (
unsigned RecordIndex : RecordIndices) {
1493 InstantiationSetCollector.insert(
Function, *MainFileID);
1496 std::vector<InstantiationGroup> Result;
1497 for (
auto &InstantiationSet : InstantiationSetCollector) {
1499 InstantiationSet.first.second,
1500 std::move(InstantiationSet.second)};
1501 Result.emplace_back(std::move(IG));
1515 std::vector<CountedRegion> Regions;
1516 for (
const auto &CR :
Function.CountedRegions)
1517 if (CR.FileID == *MainFileID) {
1518 Regions.push_back(CR);
1520 FunctionCoverage.Expansions.emplace_back(CR,
Function);
1523 for (
const auto &CR :
Function.CountedBranchRegions)
1524 if (CR.FileID == *MainFileID)
1525 FunctionCoverage.BranchRegions.push_back(CR);
1528 for (
const auto &MR :
Function.MCDCRecords)
1529 if (MR.getDecisionRegion().FileID == *MainFileID)
1530 FunctionCoverage.MCDCRecords.push_back(MR);
1534 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1536 return FunctionCoverage;
1544 std::vector<CountedRegion> Regions;
1545 for (
const auto &CR :
Expansion.Function.CountedRegions)
1547 Regions.push_back(CR);
1549 ExpansionCoverage.Expansions.emplace_back(CR,
Expansion.Function);
1551 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1554 ExpansionCoverage.BranchRegions.push_back(CR);
1558 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1560 return ExpansionCoverage;
1563LineCoverageStats::LineCoverageStats(
1566 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1567 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1569 unsigned MinRegionCount = 0;
1571 return !S->
IsGapRegion && S->HasCount && S->IsRegionEntry;
1573 for (
unsigned I = 0;
I < LineSegments.
size() && MinRegionCount < 2; ++
I)
1574 if (isStartOfRegion(LineSegments[
I]))
1577 bool StartOfSkippedRegion = !LineSegments.
empty() &&
1578 !LineSegments.
front()->HasCount &&
1579 LineSegments.
front()->IsRegionEntry;
1581 HasMultipleRegions = MinRegionCount > 1;
1583 !StartOfSkippedRegion &&
1584 ((WrappedSegment && WrappedSegment->
HasCount) || (MinRegionCount > 0));
1588 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1589 return Seq->IsRegionEntry && Seq->HasCount;
1599 ExecutionCount = WrappedSegment->
Count;
1600 if (!MinRegionCount)
1602 for (
const auto *LS : LineSegments)
1603 if (isStartOfRegion(LS))
1604 ExecutionCount = std::max(ExecutionCount, LS->Count);
1608 if (Next == CD.
end()) {
1613 if (Segments.size())
1614 WrappedSegment = Segments.back();
1616 while (Next != CD.
end() && Next->Line == Line)
1617 Segments.push_back(&*Next++);
1624 const std::string &ErrMsg =
"") {
1633 OS <<
"end of File";
1636 OS <<
"no coverage data found";
1639 OS <<
"unsupported coverage format version";
1642 OS <<
"truncated coverage data";
1645 OS <<
"malformed coverage data";
1648 OS <<
"failed to decompress coverage data (zlib)";
1651 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1656 if (!ErrMsg.empty())
1657 OS <<
": " << ErrMsg;
1667class CoverageMappingErrorCategoryType :
public std::error_category {
1668 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1669 std::string message(
int IE)
const override {
1681 static CoverageMappingErrorCategoryType ErrorCategory;
1682 return ErrorCategory;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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)
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.
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.
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const Twine &RemappingPath="")
Factory method to create an indexed reader.
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)
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)
LLVM_ABI Counter subtract(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that subtracts RHS from LHS.
LLVM_ABI Counter add(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that adds LHS and RHS.
LLVM_ABI Counter subst(Counter C, const SubstMap &Map)
std::map< Counter, Counter > SubstMap
K to V map.
A Counter mapping context is used to connect the counters, expressions and the obtained counter value...
LLVM_ABI Expected< MCDCRecord > evaluateMCDCRegion(const CounterMappingRegion &Region, ArrayRef< const CounterMappingRegion * > Branches, bool IsVersion11)
Return an MCDC record that indicates executed test vectors and condition pairs.
LLVM_ABI Expected< int64_t > evaluate(const Counter &C) const
Return the number of times that a region of code associated with this counter was executed.
LLVM_ABI unsigned getMaxCounterID(const Counter &C) const
LLVM_ABI 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.
static LLVM_ABI Expected< std::unique_ptr< CoverageMapping > > load(ArrayRef< std::unique_ptr< CoverageMappingReader > > CoverageReaders, std::optional< std::reference_wrapper< IndexedInstrProfReader > > &ProfileReader)
Load the coverage mapping using the given readers.
LLVM_ABI std::vector< StringRef > getUniqueSourceFiles() const
Returns a lexicographically sorted, unique list of files that are covered.
LLVM_ABI CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const
Get the coverage for an expansion within a coverage set.
LLVM_ABI CoverageData getCoverageForFunction(const FunctionRecord &Function) const
Get the coverage for a particular function.
LLVM_ABI std::vector< InstantiationGroup > getInstantiationGroups(StringRef Filename) const
Get the list of function instantiation groups in a particular file.
LLVM_ABI CoverageData getCoverageForFile(StringRef Filename) const
Get the coverage for a particular file.
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.
LLVM_ABI 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.
LLVM_ABI 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
LLVM_ABI 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,...
LLVM_ABI 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)
LLVM_ABI 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.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI 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.
LLVM_ABI void findIndependencePairs()
std::array< BitVector, 2 > BoolVector
uint16_t NumConditions
Number of Conditions used for a Decision Region.