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()) {
927 errs() <<
"warning: " <<
Record.FunctionName <<
": ";
934 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
937 Functions.push_back(std::move(Function));
942 unsigned RecordIndex = Functions.size() - 1;
948 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
949 RecordIndices.push_back(RecordIndex);
957Error CoverageMapping::loadFromReaders(
958 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
959 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
961 CoverageMapping &Coverage) {
964 ProfileReader.value().get().hasSingleByteCoverage());
966 !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
967 for (
const auto &CoverageReader : CoverageReaders) {
968 for (
auto RecordOrErr : *CoverageReader) {
969 if (
Error E = RecordOrErr.takeError())
971 const auto &
Record = *RecordOrErr;
980 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
981 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
983 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
984 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
986 return std::move(Coverage);
998Error CoverageMapping::loadFromFile(
999 StringRef
Filename, StringRef Arch, StringRef CompilationDir,
1000 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1002 CoverageMapping &Coverage,
bool &DataFound,
1003 SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1006 if (std::error_code EC = CovMappingBufOrErr.getError())
1008 MemoryBufferRef CovMappingBufRef =
1009 CovMappingBufOrErr.get()->getMemBufferRef();
1014 CovMappingBufRef, Arch, Buffers, CompilationDir,
1015 FoundBinaryIDs ? &BinaryIDs :
nullptr);
1016 if (
Error E = CoverageReadersOrErr.takeError()) {
1024 for (
auto &Reader : CoverageReadersOrErr.get())
1026 if (FoundBinaryIDs && !Readers.
empty()) {
1032 DataFound |= !Readers.
empty();
1033 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1043 std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1044 if (ProfileFilename) {
1045 auto ProfileReaderOrErr =
1047 if (
Error E = ProfileReaderOrErr.takeError())
1049 ProfileReader = std::move(ProfileReaderOrErr.get());
1051 auto ProfileReaderRef =
1053 ? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1056 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1057 bool DataFound =
false;
1059 auto GetArch = [&](
size_t Idx) {
1062 if (Arches.
size() == 1)
1063 return Arches.
front();
1069 if (
Error E = loadFromFile(File.value(), GetArch(File.index()),
1070 CompilationDir, ProfileReaderRef, *Coverage,
1071 DataFound, &FoundBinaryIDs))
1072 return std::move(E);
1076 std::vector<object::BuildID> ProfileBinaryIDs;
1078 if (
Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1082 if (!ProfileBinaryIDs.empty()) {
1084 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1088 std::set_difference(
1089 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1090 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1091 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1095 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1097 std::string Path = std::move(*PathOpt);
1099 if (
Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
1100 *Coverage, DataFound))
1101 return std::move(E);
1102 }
else if (CheckBinaryIDs) {
1104 ProfileFilename.value(),
1106 "Missing binary ID: " +
1114 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1116 return std::move(Coverage);
1125class FunctionInstantiationSetCollector {
1126 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1127 MapT InstantiatedFunctions;
1132 while (
I != E &&
I->FileID != FileID)
1134 assert(
I != E &&
"function does not cover the given file");
1135 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1139 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1140 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1143class SegmentBuilder {
1144 std::vector<CoverageSegment> &
Segments;
1147 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1153 void startSegment(
const CountedRegion &Region,
LineColPair StartLoc,
1154 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1155 bool HasCount = !EmitSkippedRegion &&
1159 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1161 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1162 !
Last.IsRegionEntry)
1167 Segments.emplace_back(StartLoc.first, StartLoc.second,
1168 Region.ExecutionCount, IsRegionEntry,
1171 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1175 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1176 <<
" (count = " <<
Last.Count <<
")"
1177 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1178 << (!
Last.HasCount ?
", Skipped" :
"")
1179 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1188 void completeRegionsUntil(std::optional<LineColPair> Loc,
1189 unsigned FirstCompletedRegion) {
1192 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1193 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1194 [](
const CountedRegion *L,
const CountedRegion *R) {
1195 return L->endLoc() < R->endLoc();
1199 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1201 const auto *CompletedRegion = ActiveRegions[
I];
1202 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1203 "Completed region ends after start of new region");
1205 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1206 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1209 if (Loc && CompletedSegmentLoc == *Loc)
1214 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1218 for (
unsigned J =
I + 1; J <
E; ++J)
1219 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1220 CompletedRegion = ActiveRegions[J];
1222 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1226 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1229 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1231 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1234 startSegment(*
Last,
Last->endLoc(),
false,
true);
1238 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1242 for (
const auto &CR :
enumerate(Regions)) {
1243 auto CurStartLoc = CR.value().startLoc();
1246 auto CompletedRegions =
1247 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1248 [&](
const CountedRegion *Region) {
1249 return !(Region->endLoc() <= CurStartLoc);
1251 if (CompletedRegions != ActiveRegions.
end()) {
1252 unsigned FirstCompletedRegion =
1253 std::distance(ActiveRegions.
begin(), CompletedRegions);
1254 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1260 if (CurStartLoc == CR.value().endLoc()) {
1264 (CR.index() + 1) == Regions.
size() ||
1266 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1267 CurStartLoc, !GapRegion, Skipped);
1270 if (Skipped && !ActiveRegions.
empty())
1271 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1274 if (CR.index() + 1 == Regions.
size() ||
1275 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1278 startSegment(CR.value(), CurStartLoc, !GapRegion);
1286 if (!ActiveRegions.
empty())
1287 completeRegionsUntil(std::nullopt, 0);
1292 llvm::sort(Regions, [](
const CountedRegion &
LHS,
const CountedRegion &
RHS) {
1293 if (
LHS.startLoc() !=
RHS.startLoc())
1294 return LHS.startLoc() <
RHS.startLoc();
1295 if (
LHS.endLoc() !=
RHS.endLoc())
1297 return RHS.endLoc() <
LHS.endLoc();
1307 "Unexpected order of region kind values");
1308 return LHS.Kind <
RHS.Kind;
1315 if (Regions.
empty())
1318 auto End = Regions.
end();
1319 for (
auto I = Regions.
begin() + 1;
I != End; ++
I) {
1320 if (
Active->startLoc() !=
I->startLoc() ||
1321 Active->endLoc() !=
I->endLoc()) {
1341 Active->ExecutionCount +=
I->ExecutionCount;
1343 return Regions.
drop_back(std::distance(++Active, End));
1348 static std::vector<CoverageSegment>
1350 std::vector<CoverageSegment>
Segments;
1351 SegmentBuilder Builder(Segments);
1353 sortNestedRegions(Regions);
1357 dbgs() <<
"Combined regions:\n";
1358 for (
const auto &CR : CombinedRegions)
1359 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1360 << CR.LineEnd <<
":" << CR.ColumnEnd
1361 <<
" (count=" << CR.ExecutionCount <<
")\n";
1364 Builder.buildSegmentsImpl(CombinedRegions);
1370 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1371 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1374 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1375 assert(
false &&
"Coverage segments not unique or sorted");
1384struct MergeableCoverageData :
public CoverageData {
1385 std::vector<CountedRegion> CodeRegions;
1387 MergeableCoverageData(
bool Single, StringRef
Filename)
1390 void addFunctionRegions(
1391 const FunctionRecord &Function,
1392 std::function<
bool(
const CounterMappingRegion &CR)> shouldProcess,
1393 std::function<
bool(
const CountedRegion &CR)> shouldExpand) {
1394 for (
const auto &CR :
Function.CountedRegions)
1395 if (shouldProcess(CR)) {
1396 CodeRegions.push_back(CR);
1397 if (shouldExpand(CR))
1398 Expansions.emplace_back(CR, Function);
1401 for (
const auto &CR :
Function.CountedBranchRegions)
1402 if (shouldProcess(CR))
1403 BranchRegions.push_back(CR);
1405 for (
const auto &MR :
Function.MCDCRecords)
1406 if (shouldProcess(MR.getDecisionRegion()))
1407 MCDCRecords.push_back(MR);
1410 CoverageData buildSegments() {
1411 Segments = SegmentBuilder::buildSegments(CodeRegions);
1412 return CoverageData(std::move(*
this));
1418 std::vector<StringRef> Filenames;
1423 Filenames.erase(
Last, Filenames.end());
1431 if (SourceFile ==
Function.Filenames[
I])
1432 FilenameEquivalence[
I] =
true;
1433 return FilenameEquivalence;
1437static std::optional<unsigned>
1440 for (
const auto &CR :
Function.CountedRegions)
1445 return std::nullopt;
1452static std::optional<unsigned>
1455 if (
I && SourceFile ==
Function.Filenames[*
I])
1457 return std::nullopt;
1465 assert(SingleByteCoverage);
1466 MergeableCoverageData FileCoverage(*SingleByteCoverage,
Filename);
1471 getImpreciseRecordIndicesForFilename(
Filename);
1472 for (
unsigned RecordIndex : RecordIndices) {
1476 FileCoverage.addFunctionRegions(
1478 [&](
auto &CR) {
return (MainFileID &&
isExpansion(CR, *MainFileID)); });
1483 return FileCoverage.buildSegments();
1486std::vector<InstantiationGroup>
1488 FunctionInstantiationSetCollector InstantiationSetCollector;
1492 getImpreciseRecordIndicesForFilename(
Filename);
1493 for (
unsigned RecordIndex : RecordIndices) {
1498 InstantiationSetCollector.insert(
Function, *MainFileID);
1501 std::vector<InstantiationGroup> Result;
1502 for (
auto &InstantiationSet : InstantiationSetCollector) {
1504 InstantiationSet.first.second,
1505 std::move(InstantiationSet.second)};
1506 Result.emplace_back(std::move(IG));
1517 assert(SingleByteCoverage);
1518 MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
1520 FunctionCoverage.addFunctionRegions(
1522 [&](
auto &CR) {
return isExpansion(CR, *MainFileID); });
1527 return FunctionCoverage.buildSegments();
1532 assert(SingleByteCoverage);
1535 std::vector<CountedRegion> Regions;
1536 for (
const auto &CR :
Expansion.Function.CountedRegions)
1538 Regions.push_back(CR);
1542 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1549 ExpansionCoverage.
Segments = SegmentBuilder::buildSegments(Regions);
1551 return ExpansionCoverage;
1554LineCoverageStats::LineCoverageStats(
1557 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1558 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1560 unsigned MinRegionCount = 0;
1562 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1564 for (
unsigned I = 0;
I < LineSegments.size() && MinRegionCount < 2; ++
I)
1565 if (isStartOfRegion(LineSegments[
I]))
1568 bool StartOfSkippedRegion = !LineSegments.empty() &&
1569 !LineSegments.front()->HasCount &&
1570 LineSegments.front()->IsRegionEntry;
1572 HasMultipleRegions = MinRegionCount > 1;
1574 !StartOfSkippedRegion &&
1575 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1579 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1580 return Seq->IsRegionEntry && Seq->HasCount;
1590 ExecutionCount = WrappedSegment->Count;
1591 if (!MinRegionCount)
1593 for (
const auto *LS : LineSegments)
1594 if (isStartOfRegion(LS))
1595 ExecutionCount = std::max(ExecutionCount, LS->Count);
1599 if (Next == CD.end()) {
1604 if (Segments.size())
1605 WrappedSegment = Segments.back();
1607 while (Next != CD.end() && Next->Line == Line)
1608 Segments.push_back(&*Next++);
1615 const std::string &ErrMsg =
"") {
1624 OS <<
"end of File";
1627 OS <<
"no coverage data found";
1630 OS <<
"unsupported coverage format version";
1633 OS <<
"truncated coverage data";
1636 OS <<
"malformed coverage data";
1639 OS <<
"failed to decompress coverage data (zlib)";
1642 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1647 if (!ErrMsg.empty())
1648 OS <<
": " << ErrMsg;
1658class CoverageMappingErrorCategoryType :
public std::error_category {
1659 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1660 std::string message(
int IE)
const override {
1672 static CoverageMappingErrorCategoryType ErrorCategory;
1673 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)
LLVM_ABI void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
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)
Return a range that applies F to the elements of C.
@ 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.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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.