41#include <system_error>
48#define DEBUG_TYPE "coverage-mapping"
51 auto [It, Inserted] = ExpressionIndices.try_emplace(
E, Expressions.size());
53 Expressions.push_back(
E);
57void CounterExpressionBuilder::extractTerms(
Counter C,
int Factor,
58 SmallVectorImpl<Term> &Terms) {
59 switch (
C.getKind()) {
66 const auto &
E = Expressions[
C.getExpressionID()];
67 extractTerms(
E.LHS, Factor, Terms);
74Counter CounterExpressionBuilder::simplify(
Counter ExpressionTree) {
77 extractTerms(ExpressionTree, +1, Terms);
81 if (Terms.
size() == 0)
86 return LHS.CounterID <
RHS.CounterID;
90 auto Prev = Terms.
begin();
91 for (
auto I = Prev + 1,
E = Terms.
end();
I !=
E; ++
I) {
92 if (
I->CounterID == Prev->CounterID) {
93 Prev->Factor +=
I->Factor;
104 for (
auto T : Terms) {
107 for (
int I = 0;
I <
T.Factor; ++
I)
116 for (
auto T : Terms) {
119 for (
int I = 0;
I < -
T.Factor; ++
I)
128 return Simplify ?
simplify(Cnt) : Cnt;
134 return Simplify ?
simplify(Cnt) : Cnt;
139 if (
auto I = Map.find(
C);
I != Map.end())
142 if (!
C.isExpression())
145 auto CE = Expressions[
C.getExpressionID()];
146 auto NewLHS =
subst(CE.LHS, Map);
147 auto NewRHS =
subst(CE.RHS, Map);
152 C =
add(NewLHS, NewRHS);
163 switch (
C.getKind()) {
168 OS <<
'#' <<
C.getCounterID();
171 if (
C.getExpressionID() >= Expressions.size())
173 const auto &E = Expressions[
C.getExpressionID()];
182 if (CounterValues.empty())
185 if (
auto E =
Value.takeError()) {
189 OS <<
'[' << *
Value <<
']';
200 } VisitCount = KNeverVisited;
203 std::stack<StackElem> CounterStack;
204 CounterStack.push({
C});
206 int64_t LastPoppedValue;
208 while (!CounterStack.empty()) {
209 StackElem &Current = CounterStack.top();
211 switch (Current.ICounter.getKind()) {
217 if (Current.ICounter.getCounterID() >= CounterValues.size())
219 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
223 if (Current.ICounter.getExpressionID() >= Expressions.size())
225 const auto &E = Expressions[Current.ICounter.getExpressionID()];
226 if (Current.VisitCount == StackElem::KNeverVisited) {
227 CounterStack.push(StackElem{E.LHS});
228 Current.VisitCount = StackElem::KVisitedOnce;
229 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
230 Current.LHS = LastPoppedValue;
231 CounterStack.push(StackElem{E.RHS});
232 Current.VisitCount = StackElem::KVisitedTwice;
234 int64_t LHS = Current.LHS;
235 int64_t RHS = LastPoppedValue;
245 return LastPoppedValue;
253 if (IndependencePairs)
256 IndependencePairs.emplace();
258 unsigned NumTVs = TV.size();
260 unsigned TVTrueIdx = std::distance(
263 [&](
auto I) { return (I.second == MCDCRecord::MCDC_True); })
266 for (
unsigned I = TVTrueIdx;
I < NumTVs; ++
I) {
267 const auto &[
A, ACond] = TV[
I];
269 for (
unsigned J = 0; J < TVTrueIdx; ++J) {
270 const auto &[
B, BCond] = TV[J];
274 auto AB =
A.getDifferences(
B);
276 IndependencePairs->insert(
277 {AB.find_first(), std::make_pair(J + 1,
I + 1)});
286 auto N = NextIDs.
size();
288 for (
unsigned ID = 0; ID <
N; ++ID) {
289 for (
unsigned C = 0;
C < 2; ++
C) {
293 auto NextID = NextIDs[ID][
C];
294 Nodes[ID].NextIDs[
C] = NextID;
296 ++Nodes[NextID].InCount;
310 assert(Nodes[0].InCount == 0);
316 auto IID = Q.
begin();
319 auto &
Node = Nodes[ID];
322 for (
unsigned I = 0;
I < 2; ++
I) {
323 auto NextID =
Node.NextIDs[
I];
324 assert(NextID != 0 &&
"NextID should not point to the top");
327 Decisions.emplace_back(-
Node.Width, Ord++, ID,
I);
328 assert(Ord == Decisions.size());
333 auto &NextNode = Nodes[NextID];
334 assert(NextNode.InCount > 0);
339 auto NextWidth = int64_t(NextNode.Width) +
Node.Width;
344 NextNode.Width = NextWidth;
348 if (--NextNode.InCount == 0)
357 for (
auto [NegWidth, Ord, ID,
C] : Decisions) {
358 int Width = -NegWidth;
359 assert(Nodes[ID].Width == Width);
360 assert(Nodes[ID].NextIDs[
C] < 0);
374 for (
const auto &Idxs :
Indices)
375 for (
auto Idx : Idxs)
385class NextIDsBuilder {
391 : NextIDs(Branches.
size()) {
395 for (
const auto *Branch : Branches) {
396 const auto &BranchParams = Branch->getBranchParams();
397 assert(SeenIDs.
insert(BranchParams.ID).second &&
"Duplicate CondID");
398 NextIDs[BranchParams.ID] = BranchParams.Conds;
420 unsigned NumConditions;
435 : MCDCCond(MCDCCond), BIdx(BIdx), Ord(Ord) {}
438 return (std::tie(this->MCDCCond, this->BIdx, this->Ord) <
439 std::tie(
RHS.MCDCCond,
RHS.BIdx,
RHS.Ord));
443 std::vector<TVIdxTuple> ExecVectorIdxs;
444 std::vector<TVIdxTuple> NotExecVectorIdxs;
453 DenseSet<unsigned> TVIdxs;
459 MCDCRecordProcessor(
const BitVector &Bitmap,
460 const CounterMappingRegion &Region,
463 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
465 Branches(Branches), NumConditions(DecisionParams.NumConditions),
466 Folded{{BitVector(NumConditions), BitVector(NumConditions)}},
467 IndependencePairs(NumConditions), IsVersion11(IsVersion11) {}
478 TV.
set(ID, MCDCCond);
479 auto NextID = NextIDs[
ID][MCDCCond];
480 auto NextTVIdx = TVIdx + Indices[
ID][MCDCCond];
481 assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
483 buildTestVector(TV, NextID, NextTVIdx);
487 assert(TVIdx < SavedNodes[ID].Width);
488 assert(TVIdxs.insert(NextTVIdx).second &&
"Duplicate TVIdx");
493 : DecisionParams.
BitmapIdx - NumTestVectors + NextTVIdx];
495 ExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx, ExecVectors.size());
499 ExecVectors.push_back({TV, MCDCCond});
501 NotExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx,
502 NotExecVectors.size());
503 NotExecVectors.push_back({TV, MCDCCond});
514 void findTestVectors() {
519 MCDCRecord::TestVector TV(NumConditions);
520 buildTestVector(TV, 0, 0);
521 assert(TVIdxs.size() ==
unsigned(NumTestVectors) &&
522 "TVIdxs wasn't fulfilled");
526 for (
const auto &IdxTuple : ExecVectorIdxs)
527 NewExec.
push_back(std::move(ExecVectors[IdxTuple.Ord]));
528 ExecVectors = std::move(NewExec);
532 for (
const auto &IdxTuple : NotExecVectorIdxs)
533 NewNotExec.
push_back(std::move(NotExecVectors[IdxTuple.Ord]));
534 NotExecVectors = std::move(NewNotExec);
547 MCDCRecord processMCDCRecord() {
562 const auto &BranchParams =
B->getBranchParams();
563 PosToID[
I] = BranchParams.ID;
564 CondLoc[
I] =
B->startLoc();
565 Folded[
false][
I] =
B->FalseCount.isZero();
566 Folded[
true][
I] =
B->Count.isZero();
573 return MCDCRecord(Region, std::move(ExecVectors), std::move(NotExecVectors),
574 std::move(Folded), std::move(PosToID),
585 MCDCRecordProcessor MCDCProcessor(Bitmap,
Region, Branches, IsVersion11);
586 return MCDCProcessor.processMCDCRecord();
597 } VisitCount = KNeverVisited;
600 std::stack<StackElem> CounterStack;
601 CounterStack.push({
C});
603 int64_t LastPoppedValue;
605 while (!CounterStack.empty()) {
606 StackElem &Current = CounterStack.top();
608 switch (Current.ICounter.getKind()) {
614 LastPoppedValue = Current.ICounter.getCounterID();
618 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
622 const auto &E = Expressions[Current.ICounter.getExpressionID()];
623 if (Current.VisitCount == StackElem::KNeverVisited) {
624 CounterStack.push(StackElem{E.LHS});
625 Current.VisitCount = StackElem::KVisitedOnce;
626 }
else if (Current.VisitCount == StackElem::KVisitedOnce) {
627 Current.LHS = LastPoppedValue;
628 CounterStack.push(StackElem{E.RHS});
629 Current.VisitCount = StackElem::KVisitedTwice;
631 int64_t LHS = Current.LHS;
632 int64_t RHS = LastPoppedValue;
633 LastPoppedValue = std::max(LHS, RHS);
642 return LastPoppedValue;
645void FunctionRecordIterator::skipOtherFiles() {
646 while (Current != Records.
end() && !
Filename.empty() &&
649 if (Current == Records.
end())
656 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
657 if (RecordIt == FilenameHash2RecordIndices.end())
659 return RecordIt->second;
664 unsigned MaxCounterID = 0;
666 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(
Region.Count));
669 std::max(MaxCounterID, Ctx.getMaxCounterID(
Region.FalseCount));
677 unsigned MaxBitmapIdx = 0;
678 unsigned NumConditions = 0;
685 const auto &DecisionParams =
Region.getDecisionParams();
686 if (MaxBitmapIdx <= DecisionParams.
BitmapIdx) {
693 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
702struct CountedRegionEmitter {
704 struct DecisionRecord {
705 const CounterMappingRegion *DecisionRegion;
706 unsigned NumConditions;
713 DecisionRecord(
const CounterMappingRegion &Decision)
714 : DecisionRegion(&Decision),
715 NumConditions(Decision.getDecisionParams().NumConditions) {
719 bool pushBranch(
const CounterMappingRegion &
B) {
724 assert(MCDCBranches.
size() <= NumConditions &&
725 "MCDCBranch exceeds NumConds");
726 return (MCDCBranches.
size() == NumConditions);
730 const CoverageMappingRecord &
Record;
731 CounterMappingContext &Ctx;
736 std::map<Counter, uint64_t> CounterValues;
744 unsigned LastIndex = 0;
747 bool IsExpanded =
false;
751 std::vector<FileInfo>
Files;
753 DenseSet<unsigned> Visited;
756 CountedRegionEmitter(
const CoverageMappingRecord &Record,
757 CounterMappingContext &Ctx, FunctionRecord &
Function,
763 if (Region.FileID >= Files.size()) {
765 Files.resize(Region.FileID + 1);
767 Files[
Region.FileID].LastIndex =
I + 1;
769 if (Region.ExpandedFileID >= Files.size()) {
771 Files.resize(Region.ExpandedFileID + 1);
773 Files[
Region.ExpandedFileID].IsExpanded =
true;
779 Error evaluateAndCacheCounter(Counter
C) {
780 if (CounterValues.count(
C) > 0)
785 return ValueOrErr.takeError();
786 CounterValues[
C] = *ValueOrErr;
790 Error walk(
unsigned Idx) {
792 unsigned B = (Idx == 0 ? 0 :
Files[Idx - 1].LastIndex);
793 unsigned E =
Files[Idx].LastIndex;
795 assert(Visited.
insert(Idx).second &&
"Duplicate Expansions");
796 for (
unsigned I =
B;
I !=
E; ++
I) {
802 if (
auto E = walk(
Region.ExpandedFileID))
805 if (
auto E = evaluateAndCacheCounter(
Region.Count))
812 assert(!DecisionStack.
empty() &&
"Orphan MCDCBranch");
813 auto &
D = DecisionStack.
back();
815 if (
D.pushBranch(Region)) {
818 *
D.DecisionRegion,
D.MCDCBranches, IsVersion11);
820 return RecordOrErr.takeError();
823 Function.pushMCDCRecord(std::move(*RecordOrErr));
830 if (
auto E = evaluateAndCacheCounter(
Region.FalseCount))
834 assert((Idx != 0 || DecisionStack.
empty()) &&
"Decision wasn't closed");
839 Error emitCountedRegions() {
845 if (
auto E = walk(
I))
851 for (
const auto &Region :
Record.MappingRegions) {
857 CounterValues[
Region.FalseCount]);
866Error CoverageMapping::loadFunctionRecord(
867 const CoverageMappingRecord &Record,
868 const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
870 StringRef OrigFuncName =
Record.FunctionName;
871 if (OrigFuncName.
empty())
873 "record function name is empty");
875 if (
Record.Filenames.empty())
880 CounterMappingContext Ctx(
Record.Expressions);
882 std::vector<uint64_t> Counts;
884 if (
Error E = ProfileReader.value().get().getFunctionCounts(
888 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
902 ProfileReader && ProfileReader.value().get().getVersion() <
907 if (
Error E = ProfileReader.value().get().getFunctionBitmap(
911 FuncHashMismatches.emplace_back(std::string(
Record.FunctionName),
924 assert(!
Record.MappingRegions.empty() &&
"Function has no regions");
931 if (
Record.MappingRegions.size() == 1 &&
932 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
938 if (
auto E = CountedRegionEmitter(Record, Ctx,
Function, IsVersion11)
939 .emitCountedRegions()) {
940 errs() <<
"warning: " <<
Record.FunctionName <<
": ";
947 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
950 Functions.push_back(std::move(
Function));
955 unsigned RecordIndex = Functions.size() - 1;
961 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
962 RecordIndices.push_back(RecordIndex);
970Error CoverageMapping::loadFromReaders(
971 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
972 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
974 CoverageMapping &Coverage) {
977 ProfileReader.value().get().hasSingleByteCoverage());
979 !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
980 for (
const auto &CoverageReader : CoverageReaders) {
981 for (
auto RecordOrErr : *CoverageReader) {
982 if (
Error E = RecordOrErr.takeError())
984 const auto &
Record = *RecordOrErr;
993 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
994 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
996 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
997 if (
Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
999 return std::move(Coverage);
1011Error CoverageMapping::loadFromFile(
1012 StringRef
Filename, StringRef Arch, StringRef CompilationDir,
1013 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1015 CoverageMapping &Coverage,
bool &DataFound,
1016 SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1019 if (std::error_code EC = CovMappingBufOrErr.getError())
1021 MemoryBufferRef CovMappingBufRef =
1022 CovMappingBufOrErr.get()->getMemBufferRef();
1027 CovMappingBufRef, Arch, Buffers, CompilationDir,
1028 FoundBinaryIDs ? &BinaryIDs :
nullptr);
1029 if (
Error E = CoverageReadersOrErr.takeError()) {
1037 for (
auto &Reader : CoverageReadersOrErr.get())
1039 if (FoundBinaryIDs && !Readers.
empty()) {
1045 DataFound |= !Readers.
empty();
1046 if (
Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1056 std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1057 if (ProfileFilename) {
1058 auto ProfileReaderOrErr =
1060 if (
Error E = ProfileReaderOrErr.takeError())
1062 ProfileReader = std::move(ProfileReaderOrErr.get());
1064 auto ProfileReaderRef =
1066 ? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1069 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
1070 bool DataFound =
false;
1072 auto GetArch = [&](
size_t Idx) {
1075 if (Arches.
size() == 1)
1076 return Arches.
front();
1082 if (
Error E = loadFromFile(File.value(), GetArch(File.index()),
1083 CompilationDir, ProfileReaderRef, *Coverage,
1084 DataFound, &FoundBinaryIDs))
1085 return std::move(E);
1089 std::vector<object::BuildID> ProfileBinaryIDs;
1091 if (
Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1095 if (!ProfileBinaryIDs.empty()) {
1097 return std::lexicographical_compare(
A.begin(),
A.end(),
B.begin(),
1101 std::set_difference(
1102 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1103 FoundBinaryIDs.
begin(), FoundBinaryIDs.
end(),
1104 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.
end()), Compare);
1110 if (
Error E = loadFromFile(*Path, Arch, CompilationDir,
1111 ProfileReaderRef, *Coverage, DataFound))
1112 return std::move(E);
1116 if (CheckBinaryIDs) {
1118 ProfileFilename.value(),
1120 "Missing binary ID: " +
1129 join(ObjectFilenames.
begin(), ObjectFilenames.
end(),
", "),
1131 return std::move(Coverage);
1140class FunctionInstantiationSetCollector {
1141 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1142 MapT InstantiatedFunctions;
1147 while (
I != E &&
I->FileID != FileID)
1149 assert(
I != E &&
"function does not cover the given file");
1150 auto &Functions = InstantiatedFunctions[
I->startLoc()];
1154 MapT::iterator begin() {
return InstantiatedFunctions.begin(); }
1155 MapT::iterator end() {
return InstantiatedFunctions.end(); }
1158class SegmentBuilder {
1159 std::vector<CoverageSegment> &
Segments;
1162 SegmentBuilder(std::vector<CoverageSegment> &Segments) :
Segments(
Segments) {}
1168 void startSegment(
const CountedRegion &Region,
LineColPair StartLoc,
1169 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
1170 bool HasCount = !EmitSkippedRegion &&
1174 if (!
Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1176 if (
Last.HasCount == HasCount &&
Last.Count ==
Region.ExecutionCount &&
1177 !
Last.IsRegionEntry)
1182 Segments.emplace_back(StartLoc.first, StartLoc.second,
1183 Region.ExecutionCount, IsRegionEntry,
1186 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1190 dbgs() <<
"Segment at " <<
Last.Line <<
":" <<
Last.Col
1191 <<
" (count = " <<
Last.Count <<
")"
1192 << (
Last.IsRegionEntry ?
", RegionEntry" :
"")
1193 << (!
Last.HasCount ?
", Skipped" :
"")
1194 << (
Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
1203 void completeRegionsUntil(std::optional<LineColPair> Loc,
1204 unsigned FirstCompletedRegion) {
1207 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
1208 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
1209 [](
const CountedRegion *L,
const CountedRegion *R) {
1210 return L->endLoc() < R->endLoc();
1214 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
1216 const auto *CompletedRegion = ActiveRegions[
I];
1217 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1218 "Completed region ends after start of new region");
1220 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
1221 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1224 if (Loc && CompletedSegmentLoc == *Loc)
1229 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1233 for (
unsigned J =
I + 1; J <
E; ++J)
1234 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1235 CompletedRegion = ActiveRegions[J];
1237 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
1241 if (FirstCompletedRegion &&
Last->endLoc() != *Loc) {
1244 startSegment(*ActiveRegions[FirstCompletedRegion - 1],
Last->endLoc(),
1246 }
else if (!FirstCompletedRegion && (!Loc || *Loc !=
Last->endLoc())) {
1249 startSegment(*
Last,
Last->endLoc(),
false,
true);
1253 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
1257 for (
const auto &CR :
enumerate(Regions)) {
1258 auto CurStartLoc = CR.value().startLoc();
1261 auto CompletedRegions =
1262 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
1263 [&](
const CountedRegion *Region) {
1264 return !(Region->endLoc() <= CurStartLoc);
1266 if (CompletedRegions != ActiveRegions.
end()) {
1267 unsigned FirstCompletedRegion =
1268 std::distance(ActiveRegions.
begin(), CompletedRegions);
1269 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1275 if (CurStartLoc == CR.value().endLoc()) {
1279 (CR.index() + 1) == Regions.
size() ||
1281 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
1282 CurStartLoc, !GapRegion, Skipped);
1285 if (Skipped && !ActiveRegions.
empty())
1286 startSegment(*ActiveRegions.
back(), CurStartLoc,
false);
1289 if (CR.index() + 1 == Regions.
size() ||
1290 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1293 startSegment(CR.value(), CurStartLoc, !GapRegion);
1301 if (!ActiveRegions.
empty())
1302 completeRegionsUntil(std::nullopt, 0);
1307 llvm::sort(Regions, [](
const CountedRegion &
LHS,
const CountedRegion &
RHS) {
1308 if (
LHS.startLoc() !=
RHS.startLoc())
1309 return LHS.startLoc() <
RHS.startLoc();
1310 if (
LHS.endLoc() !=
RHS.endLoc())
1312 return RHS.endLoc() <
LHS.endLoc();
1322 "Unexpected order of region kind values");
1323 return LHS.Kind <
RHS.Kind;
1330 if (Regions.
empty())
1333 auto End = Regions.
end();
1334 for (
auto I = Regions.
begin() + 1;
I != End; ++
I) {
1335 if (
Active->startLoc() !=
I->startLoc() ||
1336 Active->endLoc() !=
I->endLoc()) {
1356 Active->ExecutionCount +=
I->ExecutionCount;
1358 return Regions.
drop_back(std::distance(++Active, End));
1363 static std::vector<CoverageSegment>
1365 std::vector<CoverageSegment>
Segments;
1366 SegmentBuilder Builder(Segments);
1368 sortNestedRegions(Regions);
1372 dbgs() <<
"Combined regions:\n";
1373 for (
const auto &CR : CombinedRegions)
1374 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> "
1375 << CR.LineEnd <<
":" << CR.ColumnEnd
1376 <<
" (count=" << CR.ExecutionCount <<
")\n";
1379 Builder.buildSegmentsImpl(CombinedRegions);
1385 if (!(
L.Line <
R.Line) && !(
L.Line ==
R.Line &&
L.Col <
R.Col)) {
1386 if (
L.Line ==
R.Line &&
L.Col ==
R.Col && !
L.HasCount)
1389 <<
" followed by " <<
R.Line <<
":" <<
R.Col <<
"\n");
1390 assert(
false &&
"Coverage segments not unique or sorted");
1399struct MergeableCoverageData :
public CoverageData {
1400 std::vector<CountedRegion> CodeRegions;
1405 void addFunctionRegions(
1407 std::function<
bool(
const CounterMappingRegion &CR)> shouldProcess,
1408 std::function<
bool(
const CountedRegion &CR)> shouldExpand) {
1409 for (
const auto &CR :
Function.CountedRegions)
1410 if (shouldProcess(CR)) {
1411 CodeRegions.push_back(CR);
1412 if (shouldExpand(CR))
1413 Expansions.emplace_back(CR,
Function);
1416 for (
const auto &CR :
Function.CountedBranchRegions)
1417 if (shouldProcess(CR))
1418 BranchRegions.push_back(CR);
1420 for (
const auto &MR :
Function.MCDCRecords)
1421 if (shouldProcess(MR.getDecisionRegion()))
1422 MCDCRecords.push_back(MR);
1425 CoverageData buildSegments() {
1426 Segments = SegmentBuilder::buildSegments(CodeRegions);
1427 return CoverageData(std::move(*
this));
1433 std::vector<StringRef> Filenames;
1438 Filenames.erase(
Last, Filenames.end());
1446 if (SourceFile ==
Function.Filenames[
I])
1447 FilenameEquivalence[
I] =
true;
1448 return FilenameEquivalence;
1452static std::optional<unsigned>
1455 return std::nullopt;
1457 for (
const auto &CR :
Function.CountedRegions)
1462 return std::nullopt;
1469static std::optional<unsigned>
1472 if (
I && SourceFile ==
Function.Filenames[*
I])
1474 return std::nullopt;
1482 assert(SingleByteCoverage);
1483 MergeableCoverageData FileCoverage(*SingleByteCoverage,
Filename);
1488 getImpreciseRecordIndicesForFilename(
Filename);
1489 for (
unsigned RecordIndex : RecordIndices) {
1493 FileCoverage.addFunctionRegions(
1495 [&](
auto &CR) {
return (MainFileID &&
isExpansion(CR, *MainFileID)); });
1500 return FileCoverage.buildSegments();
1503std::vector<InstantiationGroup>
1505 FunctionInstantiationSetCollector InstantiationSetCollector;
1509 getImpreciseRecordIndicesForFilename(
Filename);
1510 for (
unsigned RecordIndex : RecordIndices) {
1515 InstantiationSetCollector.insert(
Function, *MainFileID);
1518 std::vector<InstantiationGroup> Result;
1519 for (
auto &InstantiationSet : InstantiationSetCollector) {
1521 InstantiationSet.first.second,
1522 std::move(InstantiationSet.second)};
1523 Result.emplace_back(std::move(IG));
1534 assert(SingleByteCoverage);
1535 MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
1537 FunctionCoverage.addFunctionRegions(
1539 [&](
auto &CR) {
return isExpansion(CR, *MainFileID); });
1544 return FunctionCoverage.buildSegments();
1549 assert(SingleByteCoverage);
1552 std::vector<CountedRegion> Regions;
1553 for (
const auto &CR :
Expansion.Function.CountedRegions)
1555 Regions.push_back(CR);
1559 for (
const auto &CR :
Expansion.Function.CountedBranchRegions)
1566 ExpansionCoverage.
Segments = SegmentBuilder::buildSegments(Regions);
1568 return ExpansionCoverage;
1571LineCoverageStats::LineCoverageStats(
1574 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
1575 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1577 unsigned MinRegionCount = 0;
1579 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1581 for (
unsigned I = 0;
I < LineSegments.size() && MinRegionCount < 2; ++
I)
1582 if (isStartOfRegion(LineSegments[
I]))
1585 bool StartOfSkippedRegion = !LineSegments.empty() &&
1586 !LineSegments.front()->HasCount &&
1587 LineSegments.front()->IsRegionEntry;
1589 HasMultipleRegions = MinRegionCount > 1;
1591 !StartOfSkippedRegion &&
1592 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1596 Mapped |=
any_of(LineSegments, [](
const auto *Seq) {
1597 return Seq->IsRegionEntry && Seq->HasCount;
1607 ExecutionCount = WrappedSegment->Count;
1608 if (!MinRegionCount)
1610 for (
const auto *LS : LineSegments)
1611 if (isStartOfRegion(LS))
1612 ExecutionCount = std::max(ExecutionCount, LS->Count);
1616 if (Next == CD.end()) {
1621 if (Segments.size())
1622 WrappedSegment = Segments.back();
1624 while (Next != CD.end() && Next->Line == Line)
1625 Segments.push_back(&*Next++);
1632 const std::string &ErrMsg =
"") {
1641 OS <<
"end of File";
1644 OS <<
"no coverage data found";
1647 OS <<
"unsupported coverage format version";
1650 OS <<
"truncated coverage data";
1653 OS <<
"malformed coverage data";
1656 OS <<
"failed to decompress coverage data (zlib)";
1659 OS <<
"`-arch` specifier is invalid or missing for universal binary";
1664 if (!ErrMsg.empty())
1665 OS <<
": " << ErrMsg;
1675class CoverageMappingErrorCategoryType :
public std::error_category {
1676 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
1677 std::string message(
int IE)
const override {
1689 static CoverageMappingErrorCategoryType ErrorCategory;
1690 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & front() const
Get the first element.
size_t size() const
Get the array size.
bool empty() const
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.
Represent a constant reference to a string, i.e.
constexpr bool empty() const
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.
@ 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.