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));
444 std::vector<TVIdxTuple> ExecVectorIdxs;
445 std::vector<TVIdxTuple> NotExecVectorIdxs;
454 DenseSet<unsigned> TVIdxs;
460 MCDCRecordProcessor(
const BitVector &Bitmap,
461 const CounterMappingRegion &Region,
464 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
466 Branches(Branches), NumConditions(DecisionParams.NumConditions),
467 Folded{{BitVector(NumConditions), BitVector(NumConditions)}},
468 IndependencePairs(NumConditions), IsVersion11(IsVersion11) {}
479 TV.
set(
ID, MCDCCond);
480 auto NextID = NextIDs[
ID][MCDCCond];
481 auto NextTVIdx = TVIdx + Indices[
ID][MCDCCond];
482 assert(NextID == SavedNodes[
ID].NextIDs[MCDCCond]);
484 buildTestVector(TV, NextID, NextTVIdx);
488 assert(TVIdx < SavedNodes[
ID].Width);
489 assert(TVIdxs.insert(NextTVIdx).second &&
"Duplicate TVIdx");
494 : DecisionParams.
BitmapIdx - NumTestVectors + NextTVIdx];
496 ExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx, ExecVectors.size());
500 ExecVectors.push_back({TV, MCDCCond});
502 NotExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx,
503 NotExecVectors.size());
504 NotExecVectors.push_back({TV, MCDCCond});
515 void findTestVectors() {
520 MCDCRecord::TestVector TV(NumConditions);
521 buildTestVector(TV, 0, 0);
522 assert(TVIdxs.size() ==
unsigned(NumTestVectors) &&
523 "TVIdxs wasn't fulfilled");
527 for (
const auto &IdxTuple : ExecVectorIdxs)
528 NewExec.
push_back(std::move(ExecVectors[IdxTuple.Ord]));
529 ExecVectors = std::move(NewExec);
533 for (
const auto &IdxTuple : NotExecVectorIdxs)
534 NewNotExec.
push_back(std::move(NotExecVectors[IdxTuple.Ord]));
535 NotExecVectors = std::move(NewNotExec);
548 MCDCRecord processMCDCRecord() {
563 const auto &BranchParams =
B->getBranchParams();
564 PosToID[
I] = BranchParams.ID;
565 CondLoc[
I] =
B->startLoc();
566 Folded[
false][
I] =
B->FalseCount.isZero();
567 Folded[
true][
I] =
B->Count.isZero();
574 return MCDCRecord(Region, std::move(ExecVectors), std::move(NotExecVectors),
575 std::move(Folded), std::move(PosToID),
586 MCDCRecordProcessor MCDCProcessor(Bitmap,
Region, Branches, IsVersion11);
587 return MCDCProcessor.processMCDCRecord();
598 } VisitCount = KNeverVisited;
601 std::stack<StackElem> CounterStack;
602 CounterStack.push({
C});
604 int64_t LastPoppedValue;
606 while (!CounterStack.empty()) {
607 StackElem &Current = CounterStack.top();
609 switch (Current.ICounter.getKind()) {
615 LastPoppedValue = Current.ICounter.getCounterID();
619 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
623 const auto &E = Expressions[Current.ICounter.getExpressionID()];
624 if (Current.VisitCount == StackElem::KNeverVisited) {
625 CounterStack.push(StackElem{E.LHS});
626 Current.VisitCount = StackElem::KVisitedOnce;
627 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
628 Current.LHS = LastPoppedValue;
629 CounterStack.push(StackElem{E.RHS});
630 Current.VisitCount = StackElem::KVisitedTwice;
632 int64_t LHS = Current.LHS;
633 int64_t RHS = LastPoppedValue;
634 LastPoppedValue = std::max(LHS, RHS);
643 return LastPoppedValue;
646void FunctionRecordIterator::skipOtherFiles() {
647 while (Current != Records.
end() && !
Filename.empty() &&
650 if (Current == Records.
end())
657 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
658 if (RecordIt == FilenameHash2RecordIndices.end())
660 return RecordIt->second;
665 unsigned MaxCounterID = 0;
667 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(
Region.Count));
670 std::max(MaxCounterID, Ctx.getMaxCounterID(
Region.FalseCount));
678 unsigned MaxBitmapIdx = 0;
679 unsigned NumConditions = 0;
686 const auto &DecisionParams =
Region.getDecisionParams();
687 if (MaxBitmapIdx <= DecisionParams.
BitmapIdx) {
694 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
703struct CountedRegionEmitter {
705 struct DecisionRecord {
706 const CounterMappingRegion *DecisionRegion;
707 unsigned NumConditions;
714 DecisionRecord(
const CounterMappingRegion &Decision)
715 : DecisionRegion(&Decision),
716 NumConditions(Decision.getDecisionParams().NumConditions) {
720 bool pushBranch(
const CounterMappingRegion &
B) {
725 assert(MCDCBranches.
size() <= NumConditions &&
726 "MCDCBranch exceeds NumConds");
727 return (MCDCBranches.
size() == NumConditions);
731 const CoverageMappingRecord &
Record;
732 CounterMappingContext &Ctx;
737 std::map<Counter, uint64_t> CounterValues;
745 unsigned LastIndex = 0;
748 bool IsExpanded =
false;
752 std::vector<FileInfo>
Files;
754 DenseSet<unsigned> Visited;
757 CountedRegionEmitter(
const CoverageMappingRecord &Record,
758 CounterMappingContext &Ctx, FunctionRecord &Function,
764 if (Region.FileID >= Files.size()) {
766 Files.resize(Region.FileID + 1);
768 Files[
Region.FileID].LastIndex =
I + 1;
770 if (Region.ExpandedFileID >= Files.size()) {
772 Files.resize(Region.ExpandedFileID + 1);
774 Files[
Region.ExpandedFileID].IsExpanded =
true;
780 Error evaluateAndCacheCounter(Counter
C) {
781 if (CounterValues.count(
C) > 0)
786 return ValueOrErr.takeError();
787 CounterValues[
C] = *ValueOrErr;
791 Error walk(
unsigned Idx) {
793 unsigned B = (Idx == 0 ? 0 :
Files[Idx - 1].LastIndex);
794 unsigned E =
Files[Idx].LastIndex;
796 assert(Visited.
insert(Idx).second &&
"Duplicate Expansions");
797 for (
unsigned I =
B;
I !=
E; ++
I) {
803 if (
auto E = walk(
Region.ExpandedFileID))
806 if (
auto E = evaluateAndCacheCounter(
Region.Count))
813 assert(!DecisionStack.
empty() &&
"Orphan MCDCBranch");
814 auto &
D = DecisionStack.
back();
816 if (
D.pushBranch(Region)) {
819 *
D.DecisionRegion,
D.MCDCBranches, IsVersion11);
821 return RecordOrErr.takeError();
824 Function.pushMCDCRecord(std::move(*RecordOrErr));
831 if (
auto E = evaluateAndCacheCounter(
Region.FalseCount))
835 assert((Idx != 0 || DecisionStack.
empty()) &&
"Decision wasn't closed");
840 Error emitCountedRegions() {
846 if (
auto E = walk(
I))
852 for (
const auto &Region :
Record.MappingRegions) {
858 CounterValues[
Region.FalseCount]);
867Error CoverageMapping::loadFunctionRecord(
868 const CoverageMappingRecord &Record,
869 const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
871 StringRef OrigFuncName =
Record.FunctionName;
872 if (OrigFuncName.
empty())
874 "record function name is empty");
876 if (
Record.Filenames.empty())
881 CounterMappingContext Ctx(
Record.Expressions);
883 std::vector<uint64_t> Counts;
885 if (
Error E = ProfileReader.value().get().getFunctionCounts(
889 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
903 ProfileReader && ProfileReader.value().get().getVersion() <
908 if (
Error E = ProfileReader.value().get().getFunctionBitmap(
912 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
925 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
932 if (
Record.MappingRegions.size() == 1 &&
933 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
939 if (
auto E = CountedRegionEmitter(Record, Ctx, Function, IsVersion11)
940 .emitCountedRegions()) {
941 errs() <<
"warning: " <<
Record.FunctionName <<
": ";
948 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
951 Functions.push_back(std::move(Function));
956 unsigned RecordIndex = Functions.size() - 1;
962 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
963 RecordIndices.push_back(RecordIndex);
971Error CoverageMapping::loadFromReaders(
972 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
973 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
975 CoverageMapping &Coverage) {
978 ProfileReader.value().get().hasSingleByteCoverage());
980 !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
981 for (
const auto &CoverageReader : CoverageReaders) {
982 for (
auto RecordOrErr : *CoverageReader) {
983 if (
Error E = RecordOrErr.takeError())
985 const auto &
Record = *RecordOrErr;
994 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
995 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
997 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
998 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
1000 return std::move(Coverage);
1012Error CoverageMapping::loadFromFile(
1013 StringRef
Filename, StringRef Arch, StringRef CompilationDir,
1014 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1016 CoverageMapping &Coverage,
bool &DataFound,
1017 SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1020 if (std::error_code EC = CovMappingBufOrErr.getError())
1022 MemoryBufferRef CovMappingBufRef =
1023 CovMappingBufOrErr.get()->getMemBufferRef();
1028 CovMappingBufRef, Arch, Buffers, CompilationDir,
1029 FoundBinaryIDs ? &BinaryIDs :
nullptr);
1030 if (
Error E = CoverageReadersOrErr.takeError()) {
1038 for (
auto &Reader : CoverageReadersOrErr.get())
1040 if (FoundBinaryIDs && !Readers.
empty()) {
1046 DataFound |= !Readers.
empty();
1047 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1057 std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1058 if (ProfileFilename) {
1059 auto ProfileReaderOrErr =
1061 if (
Error E = ProfileReaderOrErr.takeError())
1063 ProfileReader = std::move(ProfileReaderOrErr.get());
1065 auto ProfileReaderRef =
1067 ? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1070 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1071 bool DataFound =
false;
1073 auto GetArch = [&](
size_t Idx) {
1076 if (Arches.
size() == 1)
1077 return Arches.
front();
1083 if (
Error E = loadFromFile(File.value(), GetArch(File.index()),
1084 CompilationDir, ProfileReaderRef, *Coverage,
1085 DataFound, &FoundBinaryIDs))
1086 return std::move(E);
1090 std::vector<object::BuildID> ProfileBinaryIDs;
1092 if (
Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1096 if (!ProfileBinaryIDs.empty()) {
1098 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1102 std::set_difference(
1103 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1104 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1105 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1111 if (
Error E = loadFromFile(*Path, Arch, CompilationDir,
1112 ProfileReaderRef, *Coverage, DataFound))
1113 return std::move(E);
1117 if (CheckBinaryIDs) {
1119 ProfileFilename.value(),
1121 "Missing binary ID: " +
1130 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1132 return std::move(Coverage);
1141class FunctionInstantiationSetCollector {
1142 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1143 MapT InstantiatedFunctions;
1148 while (
I != E &&
I->FileID != FileID)
1150 assert(
I != E &&
"function does not cover the given file");
1151 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1155 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1156 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1159class SegmentBuilder {
1160 std::vector<CoverageSegment> &
Segments;
1163 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1169 void startSegment(
const CountedRegion &Region,
LineColPair StartLoc,
1170 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1171 bool HasCount = !EmitSkippedRegion &&
1175 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1177 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1178 !
Last.IsRegionEntry)
1183 Segments.emplace_back(StartLoc.first, StartLoc.second,
1184 Region.ExecutionCount, IsRegionEntry,
1187 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1191 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1192 <<
" (count = " <<
Last.Count <<
")"
1193 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1194 << (!
Last.HasCount ?
", Skipped" :
"")
1195 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1204 void completeRegionsUntil(std::optional<LineColPair> Loc,
1205 unsigned FirstCompletedRegion) {
1208 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1209 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1210 [](
const CountedRegion *L,
const CountedRegion *R) {
1211 return L->endLoc() < R->endLoc();
1215 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1217 const auto *CompletedRegion = ActiveRegions[
I];
1218 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1219 "Completed region ends after start of new region");
1221 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1222 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1225 if (Loc && CompletedSegmentLoc == *Loc)
1230 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1234 for (
unsigned J =
I + 1; J <
E; ++J)
1235 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1236 CompletedRegion = ActiveRegions[J];
1238 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1242 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1245 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1247 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1250 startSegment(*
Last,
Last->endLoc(),
false,
true);
1254 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1258 for (
const auto &CR :
enumerate(Regions)) {
1259 auto CurStartLoc = CR.value().startLoc();
1262 auto CompletedRegions =
1263 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1264 [&](
const CountedRegion *Region) {
1265 return !(Region->endLoc() <= CurStartLoc);
1267 if (CompletedRegions != ActiveRegions.
end()) {
1268 unsigned FirstCompletedRegion =
1269 std::distance(ActiveRegions.
begin(), CompletedRegions);
1270 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1276 if (CurStartLoc == CR.value().endLoc()) {
1280 (CR.index() + 1) == Regions.
size() ||
1282 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1283 CurStartLoc, !GapRegion, Skipped);
1286 if (Skipped && !ActiveRegions.
empty())
1287 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1290 if (CR.index() + 1 == Regions.
size() ||
1291 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1294 startSegment(CR.value(), CurStartLoc, !GapRegion);
1302 if (!ActiveRegions.
empty())
1303 completeRegionsUntil(std::nullopt, 0);
1308 llvm::sort(Regions, [](
const CountedRegion &
LHS,
const CountedRegion &
RHS) {
1309 if (
LHS.startLoc() !=
RHS.startLoc())
1310 return LHS.startLoc() <
RHS.startLoc();
1311 if (
LHS.endLoc() !=
RHS.endLoc())
1313 return RHS.endLoc() <
LHS.endLoc();
1323 "Unexpected order of region kind values");
1324 return LHS.Kind <
RHS.Kind;
1331 if (Regions.
empty())
1334 auto End = Regions.
end();
1335 for (
auto I = Regions.
begin() + 1;
I != End; ++
I) {
1336 if (
Active->startLoc() !=
I->startLoc() ||
1337 Active->endLoc() !=
I->endLoc()) {
1357 Active->ExecutionCount +=
I->ExecutionCount;
1359 return Regions.
drop_back(std::distance(++Active, End));
1364 static std::vector<CoverageSegment>
1366 std::vector<CoverageSegment>
Segments;
1367 SegmentBuilder Builder(Segments);
1369 sortNestedRegions(Regions);
1373 dbgs() <<
"Combined regions:\n";
1374 for (
const auto &CR : CombinedRegions)
1375 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1376 << CR.LineEnd <<
":" << CR.ColumnEnd
1377 <<
" (count=" << CR.ExecutionCount <<
")\n";
1380 Builder.buildSegmentsImpl(CombinedRegions);
1386 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1387 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1390 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1391 assert(
false &&
"Coverage segments not unique or sorted");
1400struct MergeableCoverageData :
public CoverageData {
1401 std::vector<CountedRegion> CodeRegions;
1403 MergeableCoverageData(
bool Single, StringRef
Filename)
1406 void addFunctionRegions(
1407 const FunctionRecord &Function,
1408 std::function<
bool(
const CounterMappingRegion &CR)> shouldProcess,
1409 std::function<
bool(
const CountedRegion &CR)> shouldExpand) {
1410 for (
const auto &CR :
Function.CountedRegions)
1411 if (shouldProcess(CR)) {
1412 CodeRegions.push_back(CR);
1413 if (shouldExpand(CR))
1414 Expansions.emplace_back(CR, Function);
1417 for (
const auto &CR :
Function.CountedBranchRegions)
1418 if (shouldProcess(CR))
1419 BranchRegions.push_back(CR);
1421 for (
const auto &MR :
Function.MCDCRecords)
1422 if (shouldProcess(MR.getDecisionRegion()))
1423 MCDCRecords.push_back(MR);
1426 CoverageData buildSegments() {
1427 Segments = SegmentBuilder::buildSegments(CodeRegions);
1428 return CoverageData(std::move(*
this));
1434 std::vector<StringRef> Filenames;
1439 Filenames.erase(
Last, Filenames.end());
1447 if (SourceFile ==
Function.Filenames[
I])
1448 FilenameEquivalence[
I] =
true;
1449 return FilenameEquivalence;
1453static std::optional<unsigned>
1456 return std::nullopt;
1458 for (
const auto &CR :
Function.CountedRegions)
1463 return std::nullopt;
1470static std::optional<unsigned>
1473 if (
I && SourceFile ==
Function.Filenames[*
I])
1475 return std::nullopt;
1483 assert(SingleByteCoverage);
1484 MergeableCoverageData FileCoverage(*SingleByteCoverage,
Filename);
1489 getImpreciseRecordIndicesForFilename(
Filename);
1490 for (
unsigned RecordIndex : RecordIndices) {
1494 FileCoverage.addFunctionRegions(
1496 [&](
auto &CR) {
return (MainFileID &&
isExpansion(CR, *MainFileID)); });
1501 return FileCoverage.buildSegments();
1504std::vector<InstantiationGroup>
1506 FunctionInstantiationSetCollector InstantiationSetCollector;
1510 getImpreciseRecordIndicesForFilename(
Filename);
1511 for (
unsigned RecordIndex : RecordIndices) {
1516 InstantiationSetCollector.insert(
Function, *MainFileID);
1519 std::vector<InstantiationGroup> Result;
1520 for (
auto &InstantiationSet : InstantiationSetCollector) {
1522 InstantiationSet.first.second,
1523 std::move(InstantiationSet.second)};
1524 Result.emplace_back(std::move(IG));
1535 assert(SingleByteCoverage);
1536 MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
1538 FunctionCoverage.addFunctionRegions(
1540 [&](
auto &CR) {
return isExpansion(CR, *MainFileID); });
1545 return FunctionCoverage.buildSegments();
1550 assert(SingleByteCoverage);
1553 std::vector<CountedRegion> Regions;
1554 for (
const auto &CR :
Expansion.Function.CountedRegions)
1556 Regions.push_back(CR);
1560 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1567 ExpansionCoverage.
Segments = SegmentBuilder::buildSegments(Regions);
1569 return ExpansionCoverage;
1572LineCoverageStats::LineCoverageStats(
1575 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1576 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1578 unsigned MinRegionCount = 0;
1580 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1582 for (
unsigned I = 0;
I < LineSegments.size() && MinRegionCount < 2; ++
I)
1583 if (isStartOfRegion(LineSegments[
I]))
1586 bool StartOfSkippedRegion = !LineSegments.empty() &&
1587 !LineSegments.front()->HasCount &&
1588 LineSegments.front()->IsRegionEntry;
1590 HasMultipleRegions = MinRegionCount > 1;
1592 !StartOfSkippedRegion &&
1593 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1597 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1598 return Seq->IsRegionEntry && Seq->HasCount;
1608 ExecutionCount = WrappedSegment->Count;
1609 if (!MinRegionCount)
1611 for (
const auto *LS : LineSegments)
1612 if (isStartOfRegion(LS))
1613 ExecutionCount = std::max(ExecutionCount, LS->Count);
1617 if (Next == CD.end()) {
1622 if (Segments.size())
1623 WrappedSegment = Segments.back();
1625 while (Next != CD.end() && Next->Line == Line)
1626 Segments.push_back(&*Next++);
1633 const std::string &ErrMsg =
"") {
1642 OS <<
"end of File";
1645 OS <<
"no coverage data found";
1648 OS <<
"unsupported coverage format version";
1651 OS <<
"truncated coverage data";
1654 OS <<
"malformed coverage data";
1657 OS <<
"failed to decompress coverage data (zlib)";
1660 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1665 if (!ErrMsg.empty())
1666 OS <<
": " << ErrMsg;
1676class CoverageMappingErrorCategoryType :
public std::error_category {
1677 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1678 std::string message(
int IE)
const override {
1690 static CoverageMappingErrorCategoryType ErrorCategory;
1691 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 Expected< 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.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
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.
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.