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);
1109 std::optional<std::string> PathOpt = BIDFetcher->
fetch(BinaryID);
1111 std::string Path = std::move(*PathOpt);
1113 if (
Error E = loadFromFile(Path, Arch, CompilationDir, ProfileReaderRef,
1114 *Coverage, DataFound))
1115 return std::move(E);
1116 }
else if (CheckBinaryIDs) {
1118 ProfileFilename.value(),
1120 "Missing binary ID: " +
1128 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1130 return std::move(Coverage);
1139class FunctionInstantiationSetCollector {
1140 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1141 MapT InstantiatedFunctions;
1146 while (
I != E &&
I->FileID != FileID)
1148 assert(
I != E &&
"function does not cover the given file");
1149 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1153 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1154 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1157class SegmentBuilder {
1158 std::vector<CoverageSegment> &
Segments;
1161 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1167 void startSegment(
const CountedRegion &Region,
LineColPair StartLoc,
1168 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1169 bool HasCount = !EmitSkippedRegion &&
1173 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1175 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1176 !
Last.IsRegionEntry)
1181 Segments.emplace_back(StartLoc.first, StartLoc.second,
1182 Region.ExecutionCount, IsRegionEntry,
1185 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1189 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1190 <<
" (count = " <<
Last.Count <<
")"
1191 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1192 << (!
Last.HasCount ?
", Skipped" :
"")
1193 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1202 void completeRegionsUntil(std::optional<LineColPair> Loc,
1203 unsigned FirstCompletedRegion) {
1206 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1207 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1208 [](
const CountedRegion *L,
const CountedRegion *R) {
1209 return L->endLoc() < R->endLoc();
1213 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1215 const auto *CompletedRegion = ActiveRegions[
I];
1216 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1217 "Completed region ends after start of new region");
1219 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1220 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1223 if (Loc && CompletedSegmentLoc == *Loc)
1228 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1232 for (
unsigned J =
I + 1; J <
E; ++J)
1233 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1234 CompletedRegion = ActiveRegions[J];
1236 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1240 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1243 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1245 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1248 startSegment(*
Last,
Last->endLoc(),
false,
true);
1252 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1256 for (
const auto &CR :
enumerate(Regions)) {
1257 auto CurStartLoc = CR.value().startLoc();
1260 auto CompletedRegions =
1261 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1262 [&](
const CountedRegion *Region) {
1263 return !(Region->endLoc() <= CurStartLoc);
1265 if (CompletedRegions != ActiveRegions.
end()) {
1266 unsigned FirstCompletedRegion =
1267 std::distance(ActiveRegions.
begin(), CompletedRegions);
1268 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1274 if (CurStartLoc == CR.value().endLoc()) {
1278 (CR.index() + 1) == Regions.
size() ||
1280 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1281 CurStartLoc, !GapRegion, Skipped);
1284 if (Skipped && !ActiveRegions.
empty())
1285 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1288 if (CR.index() + 1 == Regions.
size() ||
1289 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1292 startSegment(CR.value(), CurStartLoc, !GapRegion);
1300 if (!ActiveRegions.
empty())
1301 completeRegionsUntil(std::nullopt, 0);
1306 llvm::sort(Regions, [](
const CountedRegion &
LHS,
const CountedRegion &
RHS) {
1307 if (
LHS.startLoc() !=
RHS.startLoc())
1308 return LHS.startLoc() <
RHS.startLoc();
1309 if (
LHS.endLoc() !=
RHS.endLoc())
1311 return RHS.endLoc() <
LHS.endLoc();
1321 "Unexpected order of region kind values");
1322 return LHS.Kind <
RHS.Kind;
1329 if (Regions.
empty())
1332 auto End = Regions.
end();
1333 for (
auto I = Regions.
begin() + 1;
I != End; ++
I) {
1334 if (
Active->startLoc() !=
I->startLoc() ||
1335 Active->endLoc() !=
I->endLoc()) {
1355 Active->ExecutionCount +=
I->ExecutionCount;
1357 return Regions.
drop_back(std::distance(++Active, End));
1362 static std::vector<CoverageSegment>
1364 std::vector<CoverageSegment>
Segments;
1365 SegmentBuilder Builder(Segments);
1367 sortNestedRegions(Regions);
1371 dbgs() <<
"Combined regions:\n";
1372 for (
const auto &CR : CombinedRegions)
1373 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1374 << CR.LineEnd <<
":" << CR.ColumnEnd
1375 <<
" (count=" << CR.ExecutionCount <<
")\n";
1378 Builder.buildSegmentsImpl(CombinedRegions);
1384 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1385 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1388 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1389 assert(
false &&
"Coverage segments not unique or sorted");
1398struct MergeableCoverageData :
public CoverageData {
1399 std::vector<CountedRegion> CodeRegions;
1401 MergeableCoverageData(
bool Single, StringRef
Filename)
1404 void addFunctionRegions(
1405 const FunctionRecord &Function,
1406 std::function<
bool(
const CounterMappingRegion &CR)> shouldProcess,
1407 std::function<
bool(
const CountedRegion &CR)> shouldExpand) {
1408 for (
const auto &CR :
Function.CountedRegions)
1409 if (shouldProcess(CR)) {
1410 CodeRegions.push_back(CR);
1411 if (shouldExpand(CR))
1412 Expansions.emplace_back(CR, Function);
1415 for (
const auto &CR :
Function.CountedBranchRegions)
1416 if (shouldProcess(CR))
1417 BranchRegions.push_back(CR);
1419 for (
const auto &MR :
Function.MCDCRecords)
1420 if (shouldProcess(MR.getDecisionRegion()))
1421 MCDCRecords.push_back(MR);
1424 CoverageData buildSegments() {
1425 Segments = SegmentBuilder::buildSegments(CodeRegions);
1426 return CoverageData(std::move(*
this));
1432 std::vector<StringRef> Filenames;
1437 Filenames.erase(
Last, Filenames.end());
1445 if (SourceFile ==
Function.Filenames[
I])
1446 FilenameEquivalence[
I] =
true;
1447 return FilenameEquivalence;
1451static std::optional<unsigned>
1454 return std::nullopt;
1456 for (
const auto &CR :
Function.CountedRegions)
1461 return std::nullopt;
1468static std::optional<unsigned>
1471 if (
I && SourceFile ==
Function.Filenames[*
I])
1473 return std::nullopt;
1481 assert(SingleByteCoverage);
1482 MergeableCoverageData FileCoverage(*SingleByteCoverage,
Filename);
1487 getImpreciseRecordIndicesForFilename(
Filename);
1488 for (
unsigned RecordIndex : RecordIndices) {
1492 FileCoverage.addFunctionRegions(
1494 [&](
auto &CR) {
return (MainFileID &&
isExpansion(CR, *MainFileID)); });
1499 return FileCoverage.buildSegments();
1502std::vector<InstantiationGroup>
1504 FunctionInstantiationSetCollector InstantiationSetCollector;
1508 getImpreciseRecordIndicesForFilename(
Filename);
1509 for (
unsigned RecordIndex : RecordIndices) {
1514 InstantiationSetCollector.insert(
Function, *MainFileID);
1517 std::vector<InstantiationGroup> Result;
1518 for (
auto &InstantiationSet : InstantiationSetCollector) {
1520 InstantiationSet.first.second,
1521 std::move(InstantiationSet.second)};
1522 Result.emplace_back(std::move(IG));
1533 assert(SingleByteCoverage);
1534 MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
1536 FunctionCoverage.addFunctionRegions(
1538 [&](
auto &CR) {
return isExpansion(CR, *MainFileID); });
1543 return FunctionCoverage.buildSegments();
1548 assert(SingleByteCoverage);
1551 std::vector<CountedRegion> Regions;
1552 for (
const auto &CR :
Expansion.Function.CountedRegions)
1554 Regions.push_back(CR);
1558 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1565 ExpansionCoverage.
Segments = SegmentBuilder::buildSegments(Regions);
1567 return ExpansionCoverage;
1570LineCoverageStats::LineCoverageStats(
1573 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1574 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1576 unsigned MinRegionCount = 0;
1578 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1580 for (
unsigned I = 0;
I < LineSegments.size() && MinRegionCount < 2; ++
I)
1581 if (isStartOfRegion(LineSegments[
I]))
1584 bool StartOfSkippedRegion = !LineSegments.empty() &&
1585 !LineSegments.front()->HasCount &&
1586 LineSegments.front()->IsRegionEntry;
1588 HasMultipleRegions = MinRegionCount > 1;
1590 !StartOfSkippedRegion &&
1591 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1595 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1596 return Seq->IsRegionEntry && Seq->HasCount;
1606 ExecutionCount = WrappedSegment->Count;
1607 if (!MinRegionCount)
1609 for (
const auto *LS : LineSegments)
1610 if (isStartOfRegion(LS))
1611 ExecutionCount = std::max(ExecutionCount, LS->Count);
1615 if (Next == CD.end()) {
1620 if (Segments.size())
1621 WrappedSegment = Segments.back();
1623 while (Next != CD.end() && Next->Line == Line)
1624 Segments.push_back(&*Next++);
1631 const std::string &ErrMsg =
"") {
1640 OS <<
"end of File";
1643 OS <<
"no coverage data found";
1646 OS <<
"unsupported coverage format version";
1649 OS <<
"truncated coverage data";
1652 OS <<
"malformed coverage data";
1655 OS <<
"failed to decompress coverage data (zlib)";
1658 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1663 if (!ErrMsg.empty())
1664 OS <<
": " << ErrMsg;
1674class CoverageMappingErrorCategoryType :
public std::error_category {
1675 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1676 std::string message(
int IE)
const override {
1688 static CoverageMappingErrorCategoryType ErrorCategory;
1689 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.
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.