42#include <system_error>
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,
59 SmallVectorImpl<Term> &Terms) {
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)
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()) {
190 OS <<
'[' << *
Value <<
']';
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)});
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();
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;
436 : MCDCCond(MCDCCond), BIdx(BIdx), Ord(Ord) {}
439 return (std::tie(this->MCDCCond, this->BIdx, this->Ord) <
440 std::tie(
RHS.MCDCCond,
RHS.BIdx,
RHS.Ord));
445 std::vector<TVIdxTuple> ExecVectorIdxs;
452 DenseSet<unsigned> TVIdxs;
458 MCDCRecordProcessor(
const BitVector &Bitmap,
459 const CounterMappingRegion &Region,
462 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
464 Branches(Branches), NumConditions(DecisionParams.NumConditions),
465 Folded{{BitVector(NumConditions), BitVector(NumConditions)}},
466 IndependencePairs(NumConditions), IsVersion11(IsVersion11) {}
477 TV.
set(
ID, MCDCCond);
478 auto NextID = NextIDs[
ID][MCDCCond];
479 auto NextTVIdx = TVIdx + Indices[
ID][MCDCCond];
480 assert(NextID == SavedNodes[
ID].NextIDs[MCDCCond]);
482 buildTestVector(TV, NextID, NextTVIdx);
486 assert(TVIdx < SavedNodes[
ID].Width);
487 assert(TVIdxs.insert(NextTVIdx).second &&
"Duplicate TVIdx");
489 if (!Bitmap[IsVersion11
491 : DecisionParams.
BitmapIdx - NumTestVectors + NextTVIdx])
494 ExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx, ExecVectors.size());
499 ExecVectors.push_back({TV, MCDCCond});
508 void findExecutedTestVectors() {
513 MCDCRecord::TestVector TV(NumConditions);
514 buildTestVector(TV, 0, 0);
515 assert(TVIdxs.size() ==
unsigned(NumTestVectors) &&
516 "TVIdxs wasn't fulfilled");
520 for (
const auto &IdxTuple : ExecVectorIdxs)
521 NewTestVectors.
push_back(std::move(ExecVectors[IdxTuple.Ord]));
522 ExecVectors = std::move(NewTestVectors);
535 MCDCRecord processMCDCRecord() {
550 const auto &BranchParams =
B->getBranchParams();
551 PosToID[
I] = BranchParams.ID;
552 CondLoc[
I] =
B->startLoc();
553 Folded[
false][
I] =
B->FalseCount.isZero();
554 Folded[
true][
I] =
B->Count.isZero();
558 findExecutedTestVectors();
561 return MCDCRecord(Region, std::move(ExecVectors), std::move(Folded),
562 std::move(PosToID), std::move(CondLoc));
572 MCDCRecordProcessor MCDCProcessor(Bitmap,
Region, Branches, IsVersion11);
573 return MCDCProcessor.processMCDCRecord();
584 } VisitCount = KNeverVisited;
587 std::stack<StackElem> CounterStack;
588 CounterStack.push({
C});
590 int64_t LastPoppedValue;
592 while (!CounterStack.empty()) {
593 StackElem &Current = CounterStack.top();
595 switch (Current.ICounter.getKind()) {
601 LastPoppedValue = Current.ICounter.getCounterID();
605 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
609 const auto &E = Expressions[Current.ICounter.getExpressionID()];
610 if (Current.VisitCount == StackElem::KNeverVisited) {
611 CounterStack.push(StackElem{E.LHS});
612 Current.VisitCount = StackElem::KVisitedOnce;
613 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
614 Current.LHS = LastPoppedValue;
615 CounterStack.push(StackElem{E.RHS});
616 Current.VisitCount = StackElem::KVisitedTwice;
618 int64_t LHS = Current.LHS;
619 int64_t RHS = LastPoppedValue;
620 LastPoppedValue = std::max(LHS, RHS);
629 return LastPoppedValue;
632void FunctionRecordIterator::skipOtherFiles() {
633 while (Current != Records.
end() && !Filename.empty() &&
634 Filename != Current->Filenames[0])
636 if (Current == Records.
end())
643 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
644 if (RecordIt == FilenameHash2RecordIndices.end())
646 return RecordIt->second;
651 unsigned MaxCounterID = 0;
653 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(
Region.Count));
656 std::max(MaxCounterID, Ctx.getMaxCounterID(
Region.FalseCount));
664 unsigned MaxBitmapIdx = 0;
665 unsigned NumConditions = 0;
672 const auto &DecisionParams =
Region.getDecisionParams();
673 if (MaxBitmapIdx <= DecisionParams.
BitmapIdx) {
680 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
689class MCDCDecisionRecorder {
695 struct DecisionRecord {
696 const CounterMappingRegion *DecisionRegion;
699 mcdc::DecisionParameters DecisionParams;
715 DenseSet<unsigned> ExpandedFileIDs;
717 DecisionRecord(
const CounterMappingRegion &Decision)
718 : DecisionRegion(&Decision),
719 DecisionParams(Decision.getDecisionParams()),
720 DecisionStartLoc(Decision.startLoc()),
721 DecisionEndLoc(Decision.endLoc()) {
726 bool dominates(
const CounterMappingRegion &R)
const {
728 if (
R.FileID == DecisionRegion->
FileID &&
729 R.startLoc() >= DecisionStartLoc &&
R.endLoc() <= DecisionEndLoc)
733 return ExpandedFileIDs.
contains(
R.FileID);
745 Result addBranch(
const CounterMappingRegion &Branch) {
761 if (ConditionID == 0)
762 MCDCBranches.
insert(MCDCBranches.
begin(), &Branch);
777 bool recordExpansion(
const CounterMappingRegion &
Expansion) {
793 ~MCDCDecisionRecorder() {
794 assert(Decisions.
empty() &&
"All Decisions have not been resolved");
798 void registerDecision(
const CounterMappingRegion &Decision) {
802 void recordExpansion(
const CounterMappingRegion &
Expansion) {
804 return Decision.recordExpansion(
Expansion);
808 using DecisionAndBranches =
809 std::pair<
const CounterMappingRegion *,
817 std::optional<DecisionAndBranches>
818 processBranch(
const CounterMappingRegion &Branch) {
820 for (
auto DecisionIter = Decisions.
begin(), DecisionEnd = Decisions.
end();
821 DecisionIter != DecisionEnd; ++DecisionIter)
822 switch (DecisionIter->addBranch(Branch)) {
823 case DecisionRecord::NotProcessed:
825 case DecisionRecord::Processed:
827 case DecisionRecord::Completed:
828 DecisionAndBranches
Result =
829 std::make_pair(DecisionIter->DecisionRegion,
830 std::move(DecisionIter->MCDCBranches));
831 Decisions.
erase(DecisionIter);
841Error CoverageMapping::loadFunctionRecord(
842 const CoverageMappingRecord &Record,
843 const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
845 StringRef OrigFuncName =
Record.FunctionName;
846 if (OrigFuncName.
empty())
848 "record function name is empty");
850 if (
Record.Filenames.empty())
855 CounterMappingContext Ctx(
Record.Expressions);
857 std::vector<uint64_t> Counts;
859 if (
Error E = ProfileReader.value().get().getFunctionCounts(
863 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
874 Ctx.setCounts(Counts);
877 ProfileReader && ProfileReader.value().get().getVersion() <
882 if (
Error E = ProfileReader.value().get().getFunctionBitmap(
886 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
897 Ctx.setBitmap(std::move(Bitmap));
899 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
906 if (
Record.MappingRegions.size() == 1 &&
907 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
910 MCDCDecisionRecorder MCDCDecisions;
912 for (
const auto &Region :
Record.MappingRegions) {
916 MCDCDecisions.registerDecision(Region);
919 Expected<int64_t> ExecutionCount = Ctx.evaluate(
Region.Count);
924 Expected<int64_t> AltExecutionCount = Ctx.evaluate(
Region.FalseCount);
929 Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
933 MCDCDecisions.recordExpansion(Region);
941 auto Result = MCDCDecisions.processBranch(Region);
945 auto MCDCDecision =
Result->first;
946 auto &MCDCBranches =
Result->second;
951 Expected<MCDCRecord>
Record =
952 Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
953 if (
auto E =
Record.takeError()) {
959 Function.pushMCDCRecord(std::move(*Record));
964 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
967 Functions.push_back(std::move(Function));
972 unsigned RecordIndex = Functions.size() - 1;
973 for (StringRef Filename :
Record.Filenames) {
974 auto &RecordIndices = FilenameHash2RecordIndices[
hash_value(Filename)];
978 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
979 RecordIndices.push_back(RecordIndex);
987Error CoverageMapping::loadFromReaders(
988 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
989 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
991 CoverageMapping &Coverage) {
994 ProfileReader.value().get().hasSingleByteCoverage());
996 !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
997 for (
const auto &CoverageReader : CoverageReaders) {
998 for (
auto RecordOrErr : *CoverageReader) {
999 if (
Error E = RecordOrErr.takeError())
1001 const auto &
Record = *RecordOrErr;
1002 if (
Error E =
Coverage.loadFunctionRecord(Record, ProfileReader))
1010 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
1011 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1013 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1014 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
1015 return std::move(E);
1016 return std::move(Coverage);
1028Error CoverageMapping::loadFromFile(
1029 StringRef Filename, StringRef Arch, StringRef CompilationDir,
1030 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1032 CoverageMapping &Coverage,
bool &DataFound,
1033 SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1035 Filename,
false,
false);
1036 if (std::error_code EC = CovMappingBufOrErr.getError())
1038 MemoryBufferRef CovMappingBufRef =
1039 CovMappingBufOrErr.get()->getMemBufferRef();
1044 CovMappingBufRef, Arch, Buffers, CompilationDir,
1045 FoundBinaryIDs ? &BinaryIDs :
nullptr);
1046 if (
Error E = CoverageReadersOrErr.takeError()) {
1054 for (
auto &Reader : CoverageReadersOrErr.get())
1056 if (FoundBinaryIDs && !Readers.
empty()) {
1062 DataFound |= !Readers.
empty();
1063 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1073 std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1074 if (ProfileFilename) {
1075 auto ProfileReaderOrErr =
1077 if (
Error E = ProfileReaderOrErr.takeError())
1079 ProfileReader = std::move(ProfileReaderOrErr.get());
1081 auto ProfileReaderRef =
1083 ? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1086 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1087 bool DataFound =
false;
1089 auto GetArch = [&](
size_t Idx) {
1092 if (Arches.
size() == 1)
1093 return Arches.
front();
1099 if (
Error E = loadFromFile(File.value(), GetArch(File.index()),
1100 CompilationDir, ProfileReaderRef, *Coverage,
1101 DataFound, &FoundBinaryIDs))
1102 return std::move(E);
1106 std::vector<object::BuildID> ProfileBinaryIDs;
1108 if (
Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1112 if (!ProfileBinaryIDs.empty()) {
1114 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1118 std::set_difference(
1119 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1120 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1121 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1125 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1127 std::string Path = std::move(*PathOpt);
1129 if (
Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
1130 *Coverage, DataFound))
1131 return std::move(E);
1132 }
else if (CheckBinaryIDs) {
1134 ProfileFilename.value(),
1136 "Missing binary ID: " +
1144 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1146 return std::move(Coverage);
1155class FunctionInstantiationSetCollector {
1156 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1157 MapT InstantiatedFunctions;
1162 while (
I != E &&
I->FileID != FileID)
1164 assert(
I != E &&
"function does not cover the given file");
1165 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1169 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1170 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1173class SegmentBuilder {
1174 std::vector<CoverageSegment> &
Segments;
1177 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1183 void startSegment(
const CountedRegion &Region,
LineColPair StartLoc,
1184 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1185 bool HasCount = !EmitSkippedRegion &&
1189 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1191 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1192 !
Last.IsRegionEntry)
1197 Segments.emplace_back(StartLoc.first, StartLoc.second,
1198 Region.ExecutionCount, IsRegionEntry,
1201 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1205 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1206 <<
" (count = " <<
Last.Count <<
")"
1207 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1208 << (!
Last.HasCount ?
", Skipped" :
"")
1209 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1218 void completeRegionsUntil(std::optional<LineColPair> Loc,
1219 unsigned FirstCompletedRegion) {
1222 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1223 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1224 [](
const CountedRegion *L,
const CountedRegion *R) {
1225 return L->endLoc() < R->endLoc();
1229 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1231 const auto *CompletedRegion = ActiveRegions[
I];
1232 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1233 "Completed region ends after start of new region");
1235 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1236 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1239 if (Loc && CompletedSegmentLoc == *Loc)
1244 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1248 for (
unsigned J =
I + 1; J <
E; ++J)
1249 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1250 CompletedRegion = ActiveRegions[J];
1252 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1256 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1259 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1261 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1264 startSegment(*
Last,
Last->endLoc(),
false,
true);
1268 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1272 for (
const auto &CR :
enumerate(Regions)) {
1273 auto CurStartLoc = CR.value().startLoc();
1276 auto CompletedRegions =
1277 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1278 [&](
const CountedRegion *Region) {
1279 return !(Region->endLoc() <= CurStartLoc);
1281 if (CompletedRegions != ActiveRegions.
end()) {
1282 unsigned FirstCompletedRegion =
1283 std::distance(ActiveRegions.
begin(), CompletedRegions);
1284 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1290 if (CurStartLoc == CR.value().endLoc()) {
1294 (CR.index() + 1) == Regions.
size() ||
1296 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1297 CurStartLoc, !GapRegion, Skipped);
1300 if (Skipped && !ActiveRegions.
empty())
1301 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1304 if (CR.index() + 1 == Regions.
size() ||
1305 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1308 startSegment(CR.value(), CurStartLoc, !GapRegion);
1316 if (!ActiveRegions.
empty())
1317 completeRegionsUntil(std::nullopt, 0);
1322 llvm::sort(Regions, [](
const CountedRegion &
LHS,
const CountedRegion &
RHS) {
1323 if (
LHS.startLoc() !=
RHS.startLoc())
1324 return LHS.startLoc() <
RHS.startLoc();
1325 if (
LHS.endLoc() !=
RHS.endLoc())
1327 return RHS.endLoc() <
LHS.endLoc();
1337 "Unexpected order of region kind values");
1338 return LHS.Kind <
RHS.Kind;
1345 if (Regions.
empty())
1348 auto End = Regions.
end();
1349 for (
auto I = Regions.
begin() + 1;
I != End; ++
I) {
1350 if (
Active->startLoc() !=
I->startLoc() ||
1351 Active->endLoc() !=
I->endLoc()) {
1371 Active->ExecutionCount +=
I->ExecutionCount;
1373 return Regions.
drop_back(std::distance(++Active, End));
1378 static std::vector<CoverageSegment>
1380 std::vector<CoverageSegment>
Segments;
1381 SegmentBuilder Builder(Segments);
1383 sortNestedRegions(Regions);
1387 dbgs() <<
"Combined regions:\n";
1388 for (
const auto &CR : CombinedRegions)
1389 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1390 << CR.LineEnd <<
":" << CR.ColumnEnd
1391 <<
" (count=" << CR.ExecutionCount <<
")\n";
1394 Builder.buildSegmentsImpl(CombinedRegions);
1400 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1401 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1404 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1405 assert(
false &&
"Coverage segments not unique or sorted");
1414struct MergeableCoverageData :
public CoverageData {
1415 std::vector<CountedRegion> CodeRegions;
1417 MergeableCoverageData(
bool Single, StringRef Filename)
1420 void addFunctionRegions(
1421 const FunctionRecord &Function,
1422 std::function<
bool(
const CounterMappingRegion &CR)> shouldProcess,
1423 std::function<
bool(
const CountedRegion &CR)> shouldExpand) {
1424 for (
const auto &CR :
Function.CountedRegions)
1425 if (shouldProcess(CR)) {
1426 CodeRegions.push_back(CR);
1427 if (shouldExpand(CR))
1428 Expansions.emplace_back(CR, Function);
1431 for (
const auto &CR :
Function.CountedBranchRegions)
1432 if (shouldProcess(CR))
1433 BranchRegions.push_back(CR);
1435 for (
const auto &MR :
Function.MCDCRecords)
1436 if (shouldProcess(MR.getDecisionRegion()))
1437 MCDCRecords.push_back(MR);
1440 CoverageData buildSegments() {
1441 Segments = SegmentBuilder::buildSegments(CodeRegions);
1442 return CoverageData(std::move(*
this));
1448 std::vector<StringRef> Filenames;
1453 Filenames.erase(
Last, Filenames.end());
1461 if (SourceFile ==
Function.Filenames[
I])
1462 FilenameEquivalence[
I] =
true;
1463 return FilenameEquivalence;
1467static std::optional<unsigned>
1470 for (
const auto &CR :
Function.CountedRegions)
1475 return std::nullopt;
1482static std::optional<unsigned>
1485 if (
I && SourceFile ==
Function.Filenames[*
I])
1487 return std::nullopt;
1495 assert(SingleByteCoverage);
1496 MergeableCoverageData FileCoverage(*SingleByteCoverage, Filename);
1501 getImpreciseRecordIndicesForFilename(Filename);
1502 for (
unsigned RecordIndex : RecordIndices) {
1506 FileCoverage.addFunctionRegions(
1508 [&](
auto &CR) {
return (MainFileID &&
isExpansion(CR, *MainFileID)); });
1511 LLVM_DEBUG(
dbgs() <<
"Emitting segments for file: " << Filename <<
"\n");
1513 return FileCoverage.buildSegments();
1516std::vector<InstantiationGroup>
1518 FunctionInstantiationSetCollector InstantiationSetCollector;
1522 getImpreciseRecordIndicesForFilename(Filename);
1523 for (
unsigned RecordIndex : RecordIndices) {
1528 InstantiationSetCollector.insert(
Function, *MainFileID);
1531 std::vector<InstantiationGroup> Result;
1532 for (
auto &InstantiationSet : InstantiationSetCollector) {
1534 InstantiationSet.first.second,
1535 std::move(InstantiationSet.second)};
1536 Result.emplace_back(std::move(IG));
1547 assert(SingleByteCoverage);
1548 MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
1550 FunctionCoverage.addFunctionRegions(
1552 [&](
auto &CR) {
return isExpansion(CR, *MainFileID); });
1557 return FunctionCoverage.buildSegments();
1562 assert(SingleByteCoverage);
1565 std::vector<CountedRegion> Regions;
1566 for (
const auto &CR :
Expansion.Function.CountedRegions)
1568 Regions.push_back(CR);
1572 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1579 ExpansionCoverage.
Segments = SegmentBuilder::buildSegments(Regions);
1581 return ExpansionCoverage;
1584LineCoverageStats::LineCoverageStats(
1587 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1588 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1590 unsigned MinRegionCount = 0;
1592 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1594 for (
unsigned I = 0;
I < LineSegments.size() && MinRegionCount < 2; ++
I)
1595 if (isStartOfRegion(LineSegments[
I]))
1598 bool StartOfSkippedRegion = !LineSegments.empty() &&
1599 !LineSegments.front()->HasCount &&
1600 LineSegments.front()->IsRegionEntry;
1602 HasMultipleRegions = MinRegionCount > 1;
1604 !StartOfSkippedRegion &&
1605 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1609 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1610 return Seq->IsRegionEntry && Seq->HasCount;
1620 ExecutionCount = WrappedSegment->Count;
1621 if (!MinRegionCount)
1623 for (
const auto *LS : LineSegments)
1624 if (isStartOfRegion(LS))
1625 ExecutionCount = std::max(ExecutionCount, LS->Count);
1629 if (Next == CD.end()) {
1634 if (Segments.size())
1635 WrappedSegment = Segments.back();
1637 while (Next != CD.end() && Next->Line == Line)
1638 Segments.push_back(&*Next++);
1645 const std::string &ErrMsg =
"") {
1654 OS <<
"end of File";
1657 OS <<
"no coverage data found";
1660 OS <<
"unsupported coverage format version";
1663 OS <<
"truncated coverage data";
1666 OS <<
"malformed coverage data";
1669 OS <<
"failed to decompress coverage data (zlib)";
1672 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1677 if (!ErrMsg.empty())
1678 OS <<
": " << ErrMsg;
1688class CoverageMappingErrorCategoryType :
public std::error_category {
1689 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1690 std::string message(
int IE)
const override {
1702 static CoverageMappingErrorCategoryType ErrorCategory;
1703 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< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-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)
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< 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< CountedRegion > BranchRegions
std::vector< CoverageSegment > Segments
std::vector< ExpansionRecord > Expansions
std::string message() const override
Return the error message as a string.
coveragemap_error get() const
const std::string & getMessage() const
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.
iterator_range< FunctionRecordIterator > getCoveredFunctions() const
Gets all of the functions covered by this profile.
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...
LineCoverageIterator(const CoverageData &CD)
LLVM_ABI LineCoverageIterator & operator++()
Coverage statistics for a single line.
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.
@ Skipped
Validation was skipped, as it was not needed.
int16_t ConditionID
The ID for MCDCBranch.
std::array< ConditionID, 2 > ConditionIDs
LLVM_ABI const std::error_category & coveragemap_category()
std::pair< unsigned, unsigned > LineColPair
@ invalid_or_missing_arch_specifier
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
ArrayRef< uint8_t > BuildIDRef
A reference to a BuildID in binary form.
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
ArrayRef(const T &OneElt) -> ArrayRef< T >
void toHex(ArrayRef< uint8_t > Input, bool LowerCase, SmallVectorImpl< char > &Output)
Convert buffer Input to its hexadecimal representation. The returned string is double the size of Inp...
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.
Coverage information for a macro expansion or included file.
Code coverage information for a single function.
llvm::SmallVector< std::pair< TestVector, CondState > > TestVectors
LLVM_ABI void findIndependencePairs()
llvm::DenseMap< unsigned, unsigned > CondIDMap
llvm::DenseMap< unsigned, LineColPair > LineColPairMap
CondState
CondState represents the evaluation of a condition in an executed test vector, which can be True or F...
std::array< BitVector, 2 > BoolVector
llvm::DenseMap< unsigned, TVRowPair > TVPairMap
unsigned BitmapIdx
Byte Index of Bitmap Coverage Object for a Decision Region.
uint16_t NumConditions
Number of Conditions used for a Decision Region.