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() &&
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 +
689struct CountedRegionEmitter {
691 struct DecisionRecord {
692 const CounterMappingRegion *DecisionRegion;
693 unsigned NumConditions;
700 DecisionRecord(
const CounterMappingRegion &Decision)
701 : DecisionRegion(&Decision),
702 NumConditions(Decision.getDecisionParams().NumConditions) {
706 bool pushBranch(
const CounterMappingRegion &
B) {
711 assert(MCDCBranches.
size() <= NumConditions &&
712 "MCDCBranch exceeds NumConds");
713 return (MCDCBranches.
size() == NumConditions);
717 const CoverageMappingRecord &
Record;
718 CounterMappingContext &Ctx;
723 std::map<Counter, uint64_t> CounterValues;
731 unsigned LastIndex = 0;
734 bool IsExpanded =
false;
738 std::vector<FileInfo>
Files;
740 DenseSet<unsigned> Visited;
743 CountedRegionEmitter(
const CoverageMappingRecord &Record,
744 CounterMappingContext &Ctx, FunctionRecord &Function,
750 if (Region.FileID >= Files.size()) {
752 Files.resize(Region.FileID + 1);
754 Files[
Region.FileID].LastIndex =
I + 1;
756 if (Region.ExpandedFileID >= Files.size()) {
758 Files.resize(Region.ExpandedFileID + 1);
760 Files[
Region.ExpandedFileID].IsExpanded =
true;
766 Error evaluateAndCacheCounter(Counter
C) {
767 if (CounterValues.count(
C) > 0)
772 return ValueOrErr.takeError();
773 CounterValues[
C] = *ValueOrErr;
777 Error walk(
unsigned Idx) {
779 unsigned B = (Idx == 0 ? 0 :
Files[Idx - 1].LastIndex);
780 unsigned E =
Files[Idx].LastIndex;
782 assert(Visited.
insert(Idx).second &&
"Duplicate Expansions");
783 for (
unsigned I =
B;
I !=
E; ++
I) {
789 if (
auto E = walk(
Region.ExpandedFileID))
792 if (
auto E = evaluateAndCacheCounter(
Region.Count))
799 assert(!DecisionStack.
empty() &&
"Orphan MCDCBranch");
800 auto &
D = DecisionStack.
back();
802 if (
D.pushBranch(Region)) {
805 *
D.DecisionRegion,
D.MCDCBranches, IsVersion11);
807 return RecordOrErr.takeError();
810 Function.pushMCDCRecord(std::move(*RecordOrErr));
817 if (
auto E = evaluateAndCacheCounter(
Region.FalseCount))
821 assert((Idx != 0 || DecisionStack.
empty()) &&
"Decision wasn't closed");
826 Error emitCountedRegions() {
832 if (
auto E = walk(
I))
838 for (
const auto &Region :
Record.MappingRegions) {
844 CounterValues[
Region.FalseCount]);
853Error CoverageMapping::loadFunctionRecord(
854 const CoverageMappingRecord &Record,
855 const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
857 StringRef OrigFuncName =
Record.FunctionName;
858 if (OrigFuncName.
empty())
860 "record function name is empty");
862 if (
Record.Filenames.empty())
867 CounterMappingContext Ctx(
Record.Expressions);
869 std::vector<uint64_t> Counts;
871 if (
Error E = ProfileReader.value().get().getFunctionCounts(
875 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
889 ProfileReader && ProfileReader.value().get().getVersion() <
894 if (
Error E = ProfileReader.value().get().getFunctionBitmap(
898 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
911 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
918 if (
Record.MappingRegions.size() == 1 &&
919 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
925 if (
auto E = CountedRegionEmitter(Record, Ctx, Function, IsVersion11)
926 .emitCountedRegions())
931 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
934 Functions.push_back(std::move(Function));
939 unsigned RecordIndex = Functions.size() - 1;
945 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
946 RecordIndices.push_back(RecordIndex);
954Error CoverageMapping::loadFromReaders(
955 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
956 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
958 CoverageMapping &Coverage) {
961 ProfileReader.value().get().hasSingleByteCoverage());
963 !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
964 for (
const auto &CoverageReader : CoverageReaders) {
965 for (
auto RecordOrErr : *CoverageReader) {
966 if (
Error E = RecordOrErr.takeError())
968 const auto &
Record = *RecordOrErr;
977 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
978 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
980 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
981 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
983 return std::move(Coverage);
995Error CoverageMapping::loadFromFile(
996 StringRef
Filename, StringRef Arch, StringRef CompilationDir,
997 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
999 CoverageMapping &Coverage,
bool &DataFound,
1000 SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1003 if (std::error_code EC = CovMappingBufOrErr.getError())
1005 MemoryBufferRef CovMappingBufRef =
1006 CovMappingBufOrErr.get()->getMemBufferRef();
1011 CovMappingBufRef, Arch, Buffers, CompilationDir,
1012 FoundBinaryIDs ? &BinaryIDs :
nullptr);
1013 if (
Error E = CoverageReadersOrErr.takeError()) {
1021 for (
auto &Reader : CoverageReadersOrErr.get())
1023 if (FoundBinaryIDs && !Readers.
empty()) {
1029 DataFound |= !Readers.
empty();
1030 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1040 std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1041 if (ProfileFilename) {
1042 auto ProfileReaderOrErr =
1044 if (
Error E = ProfileReaderOrErr.takeError())
1046 ProfileReader = std::move(ProfileReaderOrErr.get());
1048 auto ProfileReaderRef =
1050 ? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1053 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1054 bool DataFound =
false;
1056 auto GetArch = [&](
size_t Idx) {
1059 if (Arches.
size() == 1)
1060 return Arches.
front();
1066 if (
Error E = loadFromFile(File.value(), GetArch(File.index()),
1067 CompilationDir, ProfileReaderRef, *Coverage,
1068 DataFound, &FoundBinaryIDs))
1069 return std::move(E);
1073 std::vector<object::BuildID> ProfileBinaryIDs;
1075 if (
Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1079 if (!ProfileBinaryIDs.empty()) {
1081 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1085 std::set_difference(
1086 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1087 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1088 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1092 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1094 std::string Path = std::move(*PathOpt);
1096 if (
Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
1097 *Coverage, DataFound))
1098 return std::move(E);
1099 }
else if (CheckBinaryIDs) {
1101 ProfileFilename.value(),
1103 "Missing binary ID: " +
1111 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1113 return std::move(Coverage);
1122class FunctionInstantiationSetCollector {
1123 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1124 MapT InstantiatedFunctions;
1129 while (
I != E &&
I->FileID != FileID)
1131 assert(
I != E &&
"function does not cover the given file");
1132 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1136 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1137 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1140class SegmentBuilder {
1141 std::vector<CoverageSegment> &
Segments;
1144 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1150 void startSegment(
const CountedRegion &Region,
LineColPair StartLoc,
1151 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1152 bool HasCount = !EmitSkippedRegion &&
1156 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1158 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1159 !
Last.IsRegionEntry)
1164 Segments.emplace_back(StartLoc.first, StartLoc.second,
1165 Region.ExecutionCount, IsRegionEntry,
1168 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1172 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1173 <<
" (count = " <<
Last.Count <<
")"
1174 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1175 << (!
Last.HasCount ?
", Skipped" :
"")
1176 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1185 void completeRegionsUntil(std::optional<LineColPair> Loc,
1186 unsigned FirstCompletedRegion) {
1189 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1190 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1191 [](
const CountedRegion *L,
const CountedRegion *R) {
1192 return L->endLoc() < R->endLoc();
1196 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1198 const auto *CompletedRegion = ActiveRegions[
I];
1199 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1200 "Completed region ends after start of new region");
1202 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1203 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1206 if (Loc && CompletedSegmentLoc == *Loc)
1211 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1215 for (
unsigned J =
I + 1; J <
E; ++J)
1216 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1217 CompletedRegion = ActiveRegions[J];
1219 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1223 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1226 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1228 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1231 startSegment(*
Last,
Last->endLoc(),
false,
true);
1235 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1239 for (
const auto &CR :
enumerate(Regions)) {
1240 auto CurStartLoc = CR.value().startLoc();
1243 auto CompletedRegions =
1244 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1245 [&](
const CountedRegion *Region) {
1246 return !(Region->endLoc() <= CurStartLoc);
1248 if (CompletedRegions != ActiveRegions.
end()) {
1249 unsigned FirstCompletedRegion =
1250 std::distance(ActiveRegions.
begin(), CompletedRegions);
1251 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1257 if (CurStartLoc == CR.value().endLoc()) {
1261 (CR.index() + 1) == Regions.
size() ||
1263 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1264 CurStartLoc, !GapRegion, Skipped);
1267 if (Skipped && !ActiveRegions.
empty())
1268 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1271 if (CR.index() + 1 == Regions.
size() ||
1272 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1275 startSegment(CR.value(), CurStartLoc, !GapRegion);
1283 if (!ActiveRegions.
empty())
1284 completeRegionsUntil(std::nullopt, 0);
1289 llvm::sort(Regions, [](
const CountedRegion &
LHS,
const CountedRegion &
RHS) {
1290 if (
LHS.startLoc() !=
RHS.startLoc())
1291 return LHS.startLoc() <
RHS.startLoc();
1292 if (
LHS.endLoc() !=
RHS.endLoc())
1294 return RHS.endLoc() <
LHS.endLoc();
1304 "Unexpected order of region kind values");
1305 return LHS.Kind <
RHS.Kind;
1312 if (Regions.
empty())
1315 auto End = Regions.
end();
1316 for (
auto I = Regions.
begin() + 1;
I != End; ++
I) {
1317 if (
Active->startLoc() !=
I->startLoc() ||
1318 Active->endLoc() !=
I->endLoc()) {
1338 Active->ExecutionCount +=
I->ExecutionCount;
1340 return Regions.
drop_back(std::distance(++Active, End));
1345 static std::vector<CoverageSegment>
1347 std::vector<CoverageSegment>
Segments;
1348 SegmentBuilder Builder(Segments);
1350 sortNestedRegions(Regions);
1354 dbgs() <<
"Combined regions:\n";
1355 for (
const auto &CR : CombinedRegions)
1356 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1357 << CR.LineEnd <<
":" << CR.ColumnEnd
1358 <<
" (count=" << CR.ExecutionCount <<
")\n";
1361 Builder.buildSegmentsImpl(CombinedRegions);
1367 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1368 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1371 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1372 assert(
false &&
"Coverage segments not unique or sorted");
1381struct MergeableCoverageData :
public CoverageData {
1382 std::vector<CountedRegion> CodeRegions;
1384 MergeableCoverageData(
bool Single, StringRef
Filename)
1387 void addFunctionRegions(
1388 const FunctionRecord &Function,
1389 std::function<
bool(
const CounterMappingRegion &CR)> shouldProcess,
1390 std::function<
bool(
const CountedRegion &CR)> shouldExpand) {
1391 for (
const auto &CR :
Function.CountedRegions)
1392 if (shouldProcess(CR)) {
1393 CodeRegions.push_back(CR);
1394 if (shouldExpand(CR))
1395 Expansions.emplace_back(CR, Function);
1398 for (
const auto &CR :
Function.CountedBranchRegions)
1399 if (shouldProcess(CR))
1400 BranchRegions.push_back(CR);
1402 for (
const auto &MR :
Function.MCDCRecords)
1403 if (shouldProcess(MR.getDecisionRegion()))
1404 MCDCRecords.push_back(MR);
1407 CoverageData buildSegments() {
1408 Segments = SegmentBuilder::buildSegments(CodeRegions);
1409 return CoverageData(std::move(*
this));
1415 std::vector<StringRef> Filenames;
1420 Filenames.erase(
Last, Filenames.end());
1428 if (SourceFile ==
Function.Filenames[
I])
1429 FilenameEquivalence[
I] =
true;
1430 return FilenameEquivalence;
1434static std::optional<unsigned>
1437 for (
const auto &CR :
Function.CountedRegions)
1442 return std::nullopt;
1449static std::optional<unsigned>
1452 if (
I && SourceFile ==
Function.Filenames[*
I])
1454 return std::nullopt;
1462 assert(SingleByteCoverage);
1463 MergeableCoverageData FileCoverage(*SingleByteCoverage,
Filename);
1468 getImpreciseRecordIndicesForFilename(
Filename);
1469 for (
unsigned RecordIndex : RecordIndices) {
1473 FileCoverage.addFunctionRegions(
1475 [&](
auto &CR) {
return (MainFileID &&
isExpansion(CR, *MainFileID)); });
1480 return FileCoverage.buildSegments();
1483std::vector<InstantiationGroup>
1485 FunctionInstantiationSetCollector InstantiationSetCollector;
1489 getImpreciseRecordIndicesForFilename(
Filename);
1490 for (
unsigned RecordIndex : RecordIndices) {
1495 InstantiationSetCollector.insert(
Function, *MainFileID);
1498 std::vector<InstantiationGroup> Result;
1499 for (
auto &InstantiationSet : InstantiationSetCollector) {
1501 InstantiationSet.first.second,
1502 std::move(InstantiationSet.second)};
1503 Result.emplace_back(std::move(IG));
1514 assert(SingleByteCoverage);
1515 MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
1517 FunctionCoverage.addFunctionRegions(
1519 [&](
auto &CR) {
return isExpansion(CR, *MainFileID); });
1524 return FunctionCoverage.buildSegments();
1529 assert(SingleByteCoverage);
1532 std::vector<CountedRegion> Regions;
1533 for (
const auto &CR :
Expansion.Function.CountedRegions)
1535 Regions.push_back(CR);
1539 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1546 ExpansionCoverage.
Segments = SegmentBuilder::buildSegments(Regions);
1548 return ExpansionCoverage;
1551LineCoverageStats::LineCoverageStats(
1554 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1555 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1557 unsigned MinRegionCount = 0;
1559 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1561 for (
unsigned I = 0;
I < LineSegments.size() && MinRegionCount < 2; ++
I)
1562 if (isStartOfRegion(LineSegments[
I]))
1565 bool StartOfSkippedRegion = !LineSegments.empty() &&
1566 !LineSegments.front()->HasCount &&
1567 LineSegments.front()->IsRegionEntry;
1569 HasMultipleRegions = MinRegionCount > 1;
1571 !StartOfSkippedRegion &&
1572 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1576 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1577 return Seq->IsRegionEntry && Seq->HasCount;
1587 ExecutionCount = WrappedSegment->Count;
1588 if (!MinRegionCount)
1590 for (
const auto *LS : LineSegments)
1591 if (isStartOfRegion(LS))
1592 ExecutionCount = std::max(ExecutionCount, LS->Count);
1596 if (Next == CD.end()) {
1601 if (Segments.size())
1602 WrappedSegment = Segments.back();
1604 while (Next != CD.end() && Next->Line == Line)
1605 Segments.push_back(&*Next++);
1612 const std::string &ErrMsg =
"") {
1621 OS <<
"end of File";
1624 OS <<
"no coverage data found";
1627 OS <<
"unsupported coverage format version";
1630 OS <<
"truncated coverage data";
1633 OS <<
"malformed coverage data";
1636 OS <<
"failed to decompress coverage data (zlib)";
1639 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1644 if (!ErrMsg.empty())
1645 OS <<
": " << ErrMsg;
1655class CoverageMappingErrorCategoryType :
public std::error_category {
1656 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1657 std::string message(
int IE)
const override {
1669 static CoverageMappingErrorCategoryType ErrorCategory;
1670 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< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
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 constexpr StringLiteral Filename
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.
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)
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.
void setCounts(ArrayRef< uint64_t > Counts)
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.
void setBitmap(BitVector &&Bitmap_)
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)
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.
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.