LLVM 23.0.0git
CoverageMapping.cpp
Go to the documentation of this file.
1//===- CoverageMapping.cpp - Code coverage mapping support ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains support for clang's and llvm's instrumentation based
10// code coverage.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/ArrayRef.h"
16#include "llvm/ADT/DenseMap.h"
17#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Object/BuildID.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/Errc.h"
27#include "llvm/Support/Error.h"
32#include <algorithm>
33#include <cassert>
34#include <cmath>
35#include <cstdint>
36#include <iterator>
37#include <map>
38#include <memory>
39#include <optional>
40#include <stack>
41#include <string>
42#include <system_error>
43#include <utility>
44#include <vector>
45
46using namespace llvm;
47using namespace coverage;
48
49#define DEBUG_TYPE "coverage-mapping"
50
51Counter CounterExpressionBuilder::get(const CounterExpression &E) {
52 auto [It, Inserted] = ExpressionIndices.try_emplace(E, Expressions.size());
53 if (Inserted)
54 Expressions.push_back(E);
55 return Counter::getExpression(It->second);
56}
57
58void CounterExpressionBuilder::extractTerms(Counter C, int Factor,
59 SmallVectorImpl<Term> &Terms) {
60 switch (C.getKind()) {
61 case Counter::Zero:
62 break;
64 Terms.emplace_back(C.getCounterID(), Factor);
65 break;
67 const auto &E = Expressions[C.getExpressionID()];
68 extractTerms(E.LHS, Factor, Terms);
69 extractTerms(
70 E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms);
71 break;
72 }
73}
74
75Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
76 // Gather constant terms.
78 extractTerms(ExpressionTree, +1, Terms);
79
80 // If there are no terms, this is just a zero. The algorithm below assumes at
81 // least one term.
82 if (Terms.size() == 0)
83 return Counter::getZero();
84
85 // Group the terms by counter ID.
86 llvm::sort(Terms, [](const Term &LHS, const Term &RHS) {
87 return LHS.CounterID < RHS.CounterID;
88 });
89
90 // Combine terms by counter ID to eliminate counters that sum to zero.
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;
95 continue;
96 }
97 ++Prev;
98 *Prev = *I;
99 }
100 Terms.erase(++Prev, Terms.end());
101
102 Counter C;
103 // Create additions. We do this before subtractions to avoid constructs like
104 // ((0 - X) + Y), as opposed to (Y - X).
105 for (auto T : Terms) {
106 if (T.Factor <= 0)
107 continue;
108 for (int I = 0; I < T.Factor; ++I)
109 if (C.isZero())
110 C = Counter::getCounter(T.CounterID);
111 else
112 C = get(CounterExpression(CounterExpression::Add, C,
113 Counter::getCounter(T.CounterID)));
114 }
115
116 // Create subtractions.
117 for (auto T : Terms) {
118 if (T.Factor >= 0)
119 continue;
120 for (int I = 0; I < -T.Factor; ++I)
121 C = get(CounterExpression(CounterExpression::Subtract, C,
122 Counter::getCounter(T.CounterID)));
123 }
124 return C;
125}
126
128 auto Cnt = get(CounterExpression(CounterExpression::Add, LHS, RHS));
129 return Simplify ? simplify(Cnt) : Cnt;
130}
131
133 bool Simplify) {
134 auto Cnt = get(CounterExpression(CounterExpression::Subtract, LHS, RHS));
135 return Simplify ? simplify(Cnt) : Cnt;
136}
137
139 // Replace C with the value found in Map even if C is Expression.
140 if (auto I = Map.find(C); I != Map.end())
141 return I->second;
142
143 if (!C.isExpression())
144 return C;
145
146 auto CE = Expressions[C.getExpressionID()];
147 auto NewLHS = subst(CE.LHS, Map);
148 auto NewRHS = subst(CE.RHS, Map);
149
150 // Reconstruct Expression with induced subexpressions.
151 switch (CE.Kind) {
153 C = add(NewLHS, NewRHS);
154 break;
156 C = subtract(NewLHS, NewRHS);
157 break;
158 }
159
160 return C;
161}
162
164 switch (C.getKind()) {
165 case Counter::Zero:
166 OS << '0';
167 return;
169 OS << '#' << C.getCounterID();
170 break;
171 case Counter::Expression: {
172 if (C.getExpressionID() >= Expressions.size())
173 return;
174 const auto &E = Expressions[C.getExpressionID()];
175 OS << '(';
176 dump(E.LHS, OS);
177 OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
178 dump(E.RHS, OS);
179 OS << ')';
180 break;
181 }
182 }
183 if (CounterValues.empty())
184 return;
186 if (auto E = Value.takeError()) {
187 consumeError(std::move(E));
188 return;
189 }
190 OS << '[' << *Value << ']';
191}
192
194 struct StackElem {
195 Counter ICounter;
196 int64_t LHS = 0;
197 enum {
198 KNeverVisited = 0,
199 KVisitedOnce = 1,
200 KVisitedTwice = 2,
201 } VisitCount = KNeverVisited;
202 };
203
204 std::stack<StackElem> CounterStack;
205 CounterStack.push({C});
206
207 int64_t LastPoppedValue;
208
209 while (!CounterStack.empty()) {
210 StackElem &Current = CounterStack.top();
211
212 switch (Current.ICounter.getKind()) {
213 case Counter::Zero:
214 LastPoppedValue = 0;
215 CounterStack.pop();
216 break;
218 if (Current.ICounter.getCounterID() >= CounterValues.size())
220 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
221 CounterStack.pop();
222 break;
223 case Counter::Expression: {
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;
234 } else {
235 int64_t LHS = Current.LHS;
236 int64_t RHS = LastPoppedValue;
237 LastPoppedValue =
238 E.Kind == CounterExpression::Subtract ? LHS - RHS : LHS + RHS;
239 CounterStack.pop();
240 }
241 break;
242 }
243 }
244 }
245
246 return LastPoppedValue;
247}
248
249// Find an independence pair for each condition:
250// - The condition is true in one test and false in the other.
251// - The decision outcome is true one test and false in the other.
252// - All other conditions' values must be equal or marked as "don't care".
254 if (IndependencePairs)
255 return;
256
257 IndependencePairs.emplace();
258
259 unsigned NumTVs = TV.size();
260 // Will be replaced to shorter expr.
261 unsigned TVTrueIdx = std::distance(
262 TV.begin(),
263 llvm::find_if(TV,
264 [&](auto I) { return (I.second == MCDCRecord::MCDC_True); })
265
266 );
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];
273 // If the two vectors differ in exactly one condition, ignoring DontCare
274 // conditions, we have found an independence pair.
275 auto AB = A.getDifferences(B);
276 if (AB.count() == 1)
277 IndependencePairs->insert(
278 {AB.find_first(), std::make_pair(J + 1, I + 1)});
279 }
280 }
281}
282
284 int Offset)
285 : Indices(NextIDs.size()) {
286 // Construct Nodes and set up each InCount
287 auto N = NextIDs.size();
289 for (unsigned ID = 0; ID < N; ++ID) {
290 for (unsigned C = 0; C < 2; ++C) {
291#ifndef NDEBUG
292 Indices[ID][C] = INT_MIN;
293#endif
294 auto NextID = NextIDs[ID][C];
295 Nodes[ID].NextIDs[C] = NextID;
296 if (NextID >= 0)
297 ++Nodes[NextID].InCount;
298 }
299 }
300
301 // Sort key ordered by <-Width, Ord>
302 SmallVector<std::tuple<int, /// -Width
303 unsigned, /// Ord
304 int, /// ID
305 unsigned /// Cond (0 or 1)
306 >>
307 Decisions;
308
309 // Traverse Nodes to assign Idx
311 assert(Nodes[0].InCount == 0);
312 Nodes[0].Width = 1;
313 Q.push_back(0);
314
315 unsigned Ord = 0;
316 while (!Q.empty()) {
317 auto IID = Q.begin();
318 int ID = *IID;
319 Q.erase(IID);
320 auto &Node = Nodes[ID];
321 assert(Node.Width > 0);
322
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");
326 if (NextID < 0) {
327 // Decision
328 Decisions.emplace_back(-Node.Width, Ord++, ID, I);
329 assert(Ord == Decisions.size());
330 continue;
331 }
332
333 // Inter Node
334 auto &NextNode = Nodes[NextID];
335 assert(NextNode.InCount > 0);
336
337 // Assign Idx
338 assert(Indices[ID][I] == INT_MIN);
339 Indices[ID][I] = NextNode.Width;
340 auto NextWidth = int64_t(NextNode.Width) + Node.Width;
341 if (NextWidth > HardMaxTVs) {
342 NumTestVectors = HardMaxTVs; // Overflow
343 return;
344 }
345 NextNode.Width = NextWidth;
346
347 // Ready if all incomings are processed.
348 // Or NextNode.Width hasn't been confirmed yet.
349 if (--NextNode.InCount == 0)
350 Q.push_back(NextID);
351 }
352 }
353
354 llvm::sort(Decisions);
355
356 // Assign TestVector Indices in Decision Nodes
357 int64_t CurIdx = 0;
358 for (auto [NegWidth, Ord, ID, C] : Decisions) {
359 int Width = -NegWidth;
360 assert(Nodes[ID].Width == Width);
361 assert(Nodes[ID].NextIDs[C] < 0);
362 assert(Indices[ID][C] == INT_MIN);
363 Indices[ID][C] = Offset + CurIdx;
364 CurIdx += Width;
365 if (CurIdx > HardMaxTVs) {
366 NumTestVectors = HardMaxTVs; // Overflow
367 return;
368 }
369 }
370
371 assert(CurIdx < HardMaxTVs);
372 NumTestVectors = CurIdx;
373
374#ifndef NDEBUG
375 for (const auto &Idxs : Indices)
376 for (auto Idx : Idxs)
377 assert(Idx != INT_MIN);
378 SavedNodes = std::move(Nodes);
379#endif
380}
381
382namespace {
383
384/// Construct this->NextIDs with Branches for TVIdxBuilder to use it
385/// before MCDCRecordProcessor().
386class NextIDsBuilder {
387protected:
389
390public:
391 NextIDsBuilder(const ArrayRef<const CounterMappingRegion *> Branches)
392 : NextIDs(Branches.size()) {
393#ifndef NDEBUG
395#endif
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;
400 }
401 assert(SeenIDs.size() == Branches.size());
402 }
403};
404
405class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
406 /// A bitmap representing the executed test vectors for a boolean expression.
407 /// Each index of the bitmap corresponds to a possible test vector. An index
408 /// with a bit value of '1' indicates that the corresponding Test Vector
409 /// identified by that index was executed.
410 const BitVector &Bitmap;
411
412 /// Decision Region to which the ExecutedTestVectorBitmap applies.
414 const mcdc::DecisionParameters &DecisionParams;
415
416 /// Array of branch regions corresponding each conditions in the boolean
417 /// expression.
419
420 /// Total number of conditions in the boolean expression.
421 unsigned NumConditions;
422
423 /// Vector used to track whether a condition is constant folded.
425
426 /// Mapping of calculated MC/DC Independence Pairs for each condition.
427 MCDCRecord::TVPairMap IndependencePairs;
428
429 /// Helper for sorting ExecVectors / NotExecVectors.
430 struct TVIdxTuple {
431 MCDCRecord::CondState MCDCCond; /// True/False
432 unsigned BIdx; /// Bitmap Index
433 unsigned Ord; /// Last position in exec / not-exec TVs
434
435 TVIdxTuple(MCDCRecord::CondState MCDCCond, unsigned BIdx, unsigned Ord)
436 : MCDCCond(MCDCCond), BIdx(BIdx), Ord(Ord) {}
437
438 bool operator<(const TVIdxTuple &RHS) const {
439 return (std::tie(this->MCDCCond, this->BIdx, this->Ord) <
440 std::tie(RHS.MCDCCond, RHS.BIdx, RHS.Ord));
441 }
442 };
443
444 std::vector<TVIdxTuple> ExecVectorIdxs;
445 std::vector<TVIdxTuple> NotExecVectorIdxs;
446
447 /// Actual executed Test Vectors for the boolean expression, based on
448 /// ExecutedTestVectorBitmap.
449 MCDCRecord::TestVectors ExecVectors;
450 /// Never-executed test vectors
451 MCDCRecord::TestVectors NotExecVectors;
452
453#ifndef NDEBUG
454 DenseSet<unsigned> TVIdxs;
455#endif
456
457 bool IsVersion11;
458
459public:
460 MCDCRecordProcessor(const BitVector &Bitmap,
461 const CounterMappingRegion &Region,
463 bool IsVersion11)
464 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
465 Region(Region), DecisionParams(Region.getDecisionParams()),
466 Branches(Branches), NumConditions(DecisionParams.NumConditions),
467 Folded{{BitVector(NumConditions), BitVector(NumConditions)}},
468 IndependencePairs(NumConditions), IsVersion11(IsVersion11) {}
469
470private:
471 // Walk the binary decision diagram and try assigning both false and true to
472 // each node. When a terminal node (ID == 0) is reached, fill in the value in
473 // the truth table.
474 void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
475 int TVIdx) {
476 for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
477 static_assert(MCDCRecord::MCDC_False == 0);
478 static_assert(MCDCRecord::MCDC_True == 1);
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]);
483 if (NextID >= 0) {
484 buildTestVector(TV, NextID, NextTVIdx);
485 continue;
486 }
487
488 assert(TVIdx < SavedNodes[ID].Width);
489 assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx");
490
491 bool Executed =
492 Bitmap[IsVersion11
493 ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()
494 : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx];
495 if (Executed) {
496 ExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx, ExecVectors.size());
497 // Copy the completed test vector to the vector of testvectors.
498 // The final value (T,F) is equal to the last non-dontcare state on the
499 // path (in a short-circuiting system).
500 ExecVectors.push_back({TV, MCDCCond});
501 } else {
502 NotExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx,
503 NotExecVectors.size());
504 NotExecVectors.push_back({TV, MCDCCond});
505 }
506 }
507
508 // Reset back to DontCare.
510 }
511
512 /// Walk the bits in the bitmap. A bit set to '1' indicates that the test
513 /// vector at the corresponding index was executed during a test run.
514 /// Vectors with '0' bit are collected separately for UI.
515 void findTestVectors() {
516 // Walk the binary decision diagram to enumerate all possible test vectors.
517 // We start at the root node (ID == 0) with all values being DontCare.
518 // `TVIdx` starts with 0 and is in the traversal.
519 // `Index` encodes the bitmask of true values and is initially 0.
520 MCDCRecord::TestVector TV(NumConditions);
521 buildTestVector(TV, 0, 0);
522 assert(TVIdxs.size() == unsigned(NumTestVectors) &&
523 "TVIdxs wasn't fulfilled");
524
525 llvm::sort(ExecVectorIdxs);
527 for (const auto &IdxTuple : ExecVectorIdxs)
528 NewExec.push_back(std::move(ExecVectors[IdxTuple.Ord]));
529 ExecVectors = std::move(NewExec);
530
531 llvm::sort(NotExecVectorIdxs);
532 MCDCRecord::TestVectors NewNotExec;
533 for (const auto &IdxTuple : NotExecVectorIdxs)
534 NewNotExec.push_back(std::move(NotExecVectors[IdxTuple.Ord]));
535 NotExecVectors = std::move(NewNotExec);
536 }
537
538public:
539 /// Process the MC/DC Record in order to produce a result for a boolean
540 /// expression. This process includes tracking the conditions that comprise
541 /// the decision region, calculating the list of all possible test vectors,
542 /// marking the executed test vectors, and then finding an Independence Pair
543 /// out of the executed test vectors for each condition in the boolean
544 /// expression. A condition is tracked to ensure that its ID can be mapped to
545 /// its ordinal position in the boolean expression. The condition's source
546 /// location is also tracked, as well as whether it is constant folded (in
547 /// which case it is excuded from the metric).
548 MCDCRecord processMCDCRecord() {
549 MCDCRecord::CondIDMap PosToID;
551
552 // Walk the Record's BranchRegions (representing Conditions) in order to:
553 // - Hash the condition based on its corresponding ID. This will be used to
554 // calculate the test vectors.
555 // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
556 // actual ID. This will be used to visualize the conditions in the
557 // correct order.
558 // - Keep track of the condition source location. This will be used to
559 // visualize where the condition is.
560 // - Record whether the condition is constant folded so that we exclude it
561 // from being measured.
562 for (auto [I, B] : enumerate(Branches)) {
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();
568 }
569
570 // Using Profile Bitmap from runtime, mark the test vectors.
571 findTestVectors();
572
573 // Record executed vectors, not-executed vectors, and independence pairs.
574 return MCDCRecord(Region, std::move(ExecVectors), std::move(NotExecVectors),
575 std::move(Folded), std::move(PosToID),
576 std::move(CondLoc));
577 }
578};
579
580} // namespace
581
584 ArrayRef<const CounterMappingRegion *> Branches, bool IsVersion11) {
585
586 MCDCRecordProcessor MCDCProcessor(Bitmap, Region, Branches, IsVersion11);
587 return MCDCProcessor.processMCDCRecord();
588}
589
591 struct StackElem {
592 Counter ICounter;
593 int64_t LHS = 0;
594 enum {
595 KNeverVisited = 0,
596 KVisitedOnce = 1,
597 KVisitedTwice = 2,
598 } VisitCount = KNeverVisited;
599 };
600
601 std::stack<StackElem> CounterStack;
602 CounterStack.push({C});
603
604 int64_t LastPoppedValue;
605
606 while (!CounterStack.empty()) {
607 StackElem &Current = CounterStack.top();
608
609 switch (Current.ICounter.getKind()) {
610 case Counter::Zero:
611 LastPoppedValue = 0;
612 CounterStack.pop();
613 break;
615 LastPoppedValue = Current.ICounter.getCounterID();
616 CounterStack.pop();
617 break;
618 case Counter::Expression: {
619 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
620 LastPoppedValue = 0;
621 CounterStack.pop();
622 } else {
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;
631 } else {
632 int64_t LHS = Current.LHS;
633 int64_t RHS = LastPoppedValue;
634 LastPoppedValue = std::max(LHS, RHS);
635 CounterStack.pop();
636 }
637 }
638 break;
639 }
640 }
641 }
642
643 return LastPoppedValue;
644}
645
646void FunctionRecordIterator::skipOtherFiles() {
647 while (Current != Records.end() && !Filename.empty() &&
648 Filename != Current->Filenames[0])
649 advanceOne();
650 if (Current == Records.end())
651 *this = FunctionRecordIterator();
652}
653
654ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
655 StringRef Filename) const {
656 size_t FilenameHash = hash_value(Filename);
657 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
658 if (RecordIt == FilenameHash2RecordIndices.end())
659 return {};
660 return RecordIt->second;
661}
662
663static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
665 unsigned MaxCounterID = 0;
666 for (const auto &Region : Record.MappingRegions) {
667 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
668 if (Region.isBranch())
669 MaxCounterID =
670 std::max(MaxCounterID, Ctx.getMaxCounterID(Region.FalseCount));
671 }
672 return MaxCounterID;
673}
674
675/// Returns the bit count
677 bool IsVersion11) {
678 unsigned MaxBitmapIdx = 0;
679 unsigned NumConditions = 0;
680 // Scan max(BitmapIdx).
681 // Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
682 // and `MaxBitmapIdx is `unsigned`. `BitmapIdx` is unique in the record.
683 for (const auto &Region : reverse(Record.MappingRegions)) {
685 continue;
686 const auto &DecisionParams = Region.getDecisionParams();
687 if (MaxBitmapIdx <= DecisionParams.BitmapIdx) {
688 MaxBitmapIdx = DecisionParams.BitmapIdx;
689 NumConditions = DecisionParams.NumConditions;
690 }
691 }
692
693 if (IsVersion11)
694 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
695 llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
696
697 return MaxBitmapIdx;
698}
699
700namespace {
701
702/// Walk MappingRegions along Expansions and emit CountedRegions.
703struct CountedRegionEmitter {
704 /// A nestable Decision.
705 struct DecisionRecord {
706 const CounterMappingRegion *DecisionRegion;
707 unsigned NumConditions; ///< Copy of DecisionRegion.NumConditions
708 /// Pushed by traversal order.
710#ifndef NDEBUG
711 DenseSet<mcdc::ConditionID> ConditionIDs;
712#endif
713
714 DecisionRecord(const CounterMappingRegion &Decision)
715 : DecisionRegion(&Decision),
716 NumConditions(Decision.getDecisionParams().NumConditions) {
718 }
719
720 bool pushBranch(const CounterMappingRegion &B) {
722 assert(ConditionIDs.insert(B.getBranchParams().ID).second &&
723 "Duplicate CondID");
724 MCDCBranches.push_back(&B);
725 assert(MCDCBranches.size() <= NumConditions &&
726 "MCDCBranch exceeds NumConds");
727 return (MCDCBranches.size() == NumConditions);
728 }
729 };
730
731 const CoverageMappingRecord &Record;
732 CounterMappingContext &Ctx;
733 FunctionRecord &Function;
734 bool IsVersion11;
735
736 /// Evaluated Counters.
737 std::map<Counter, uint64_t> CounterValues;
738
739 /// Decisions are nestable.
740 SmallVector<DecisionRecord, 1> DecisionStack;
741
742 /// A File pointed by Expansion
743 struct FileInfo {
744 /// The last index(+1) for each FileID in MappingRegions.
745 unsigned LastIndex = 0;
746 /// Mark Files pointed by Expansions.
747 /// Non-marked Files are root Files.
748 bool IsExpanded = false;
749 };
750
751 /// The last element is a sentinel with Index=NumRegions.
752 std::vector<FileInfo> Files;
753#ifndef NDEBUG
754 DenseSet<unsigned> Visited;
755#endif
756
757 CountedRegionEmitter(const CoverageMappingRecord &Record,
758 CounterMappingContext &Ctx, FunctionRecord &Function,
759 bool IsVersion11)
760 : Record(Record), Ctx(Ctx), Function(Function), IsVersion11(IsVersion11),
761 Files(Record.Filenames.size()) {
762 // Scan MappingRegions and mark each last index by FileID.
763 for (auto [I, Region] : enumerate(Record.MappingRegions)) {
764 if (Region.FileID >= Files.size()) {
765 // Extend (only possible in CoverageMappingTests)
766 Files.resize(Region.FileID + 1);
767 }
768 Files[Region.FileID].LastIndex = I + 1;
770 if (Region.ExpandedFileID >= Files.size()) {
771 // Extend (only possible in CoverageMappingTests)
772 Files.resize(Region.ExpandedFileID + 1);
773 }
774 Files[Region.ExpandedFileID].IsExpanded = true;
775 }
776 }
777 }
778
779 /// Evaluate C and store its evaluated Value into CounterValues.
780 Error evaluateAndCacheCounter(Counter C) {
781 if (CounterValues.count(C) > 0)
782 return Error::success();
783
784 auto ValueOrErr = Ctx.evaluate(C);
785 if (!ValueOrErr)
786 return ValueOrErr.takeError();
787 CounterValues[C] = *ValueOrErr;
788 return Error::success();
789 }
790
791 Error walk(unsigned Idx) {
792 assert(Idx < Files.size());
793 unsigned B = (Idx == 0 ? 0 : Files[Idx - 1].LastIndex);
794 unsigned E = Files[Idx].LastIndex;
795 assert(B != E && "Empty FileID");
796 assert(Visited.insert(Idx).second && "Duplicate Expansions");
797 for (unsigned I = B; I != E; ++I) {
798 const auto &Region = Record.MappingRegions[I];
799 if (Region.FileID != Idx)
800 break;
801
803 if (auto E = walk(Region.ExpandedFileID))
804 return E;
805
806 if (auto E = evaluateAndCacheCounter(Region.Count))
807 return E;
808
810 // Start the new Decision on the stack.
811 DecisionStack.emplace_back(Region);
813 assert(!DecisionStack.empty() && "Orphan MCDCBranch");
814 auto &D = DecisionStack.back();
815
816 if (D.pushBranch(Region)) {
817 // All Branches have been found in the Decision.
818 auto RecordOrErr = Ctx.evaluateMCDCRegion(
819 *D.DecisionRegion, D.MCDCBranches, IsVersion11);
820 if (!RecordOrErr)
821 return RecordOrErr.takeError();
822
823 // Finish the stack.
824 Function.pushMCDCRecord(std::move(*RecordOrErr));
825 DecisionStack.pop_back();
826 }
827 }
828
829 // Evaluate FalseCount
830 // It may have the Counter in Branches, or Zero.
831 if (auto E = evaluateAndCacheCounter(Region.FalseCount))
832 return E;
833 }
834
835 assert((Idx != 0 || DecisionStack.empty()) && "Decision wasn't closed");
836
837 return Error::success();
838 }
839
840 Error emitCountedRegions() {
841 // Walk MappingRegions along Expansions.
842 // - Evaluate Counters
843 // - Emit MCDCRecords
844 for (auto [I, F] : enumerate(Files)) {
845 if (!F.IsExpanded)
846 if (auto E = walk(I))
847 return E;
848 }
849 assert(Visited.size() == Files.size() && "Dangling FileID");
850
851 // Emit CountedRegions in the same order as MappingRegions.
852 for (const auto &Region : Record.MappingRegions) {
854 continue; // Don't emit.
855 // Adopt values from the CounterValues.
856 // FalseCount may be Zero unless Branches.
857 Function.pushRegion(Region, CounterValues[Region.Count],
858 CounterValues[Region.FalseCount]);
859 }
860
861 return Error::success();
862 }
863};
864
865} // namespace
866
867Error CoverageMapping::loadFunctionRecord(
868 const CoverageMappingRecord &Record,
869 const std::optional<std::reference_wrapper<IndexedInstrProfReader>>
870 &ProfileReader) {
871 StringRef OrigFuncName = Record.FunctionName;
872 if (OrigFuncName.empty())
874 "record function name is empty");
875
876 if (Record.Filenames.empty())
877 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
878 else
879 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
880
881 CounterMappingContext Ctx(Record.Expressions);
882
883 std::vector<uint64_t> Counts;
884 if (ProfileReader) {
885 if (Error E = ProfileReader.value().get().getFunctionCounts(
886 Record.FunctionName, Record.FunctionHash, Counts)) {
887 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
889 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
890 Record.FunctionHash);
891 return Error::success();
892 }
894 return make_error<InstrProfError>(IPE);
895 Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
896 }
897 } else {
898 Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
899 }
900 Ctx.setCounts(Counts);
901
902 bool IsVersion11 =
903 ProfileReader && ProfileReader.value().get().getVersion() <
905
906 BitVector Bitmap;
907 if (ProfileReader) {
908 if (Error E = ProfileReader.value().get().getFunctionBitmap(
909 Record.FunctionName, Record.FunctionHash, Bitmap)) {
910 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
912 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
913 Record.FunctionHash);
914 return Error::success();
915 }
917 return make_error<InstrProfError>(IPE);
918 Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
919 }
920 } else {
921 Bitmap = BitVector(getMaxBitmapSize(Record, false));
922 }
923 Ctx.setBitmap(std::move(Bitmap));
924
925 assert(!Record.MappingRegions.empty() && "Function has no regions");
926
927 // This coverage record is a zero region for a function that's unused in
928 // some TU, but used in a different TU. Ignore it. The coverage maps from the
929 // the other TU will either be loaded (providing full region counts) or they
930 // won't (in which case we don't unintuitively report functions as uncovered
931 // when they have non-zero counts in the profile).
932 if (Record.MappingRegions.size() == 1 &&
933 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
934 return Error::success();
935
936 FunctionRecord Function(OrigFuncName, Record.Filenames);
937
938 // Emit CountedRegions into FunctionRecord.
939 if (auto E = CountedRegionEmitter(Record, Ctx, Function, IsVersion11)
940 .emitCountedRegions()) {
941 errs() << "warning: " << Record.FunctionName << ": ";
942 logAllUnhandledErrors(std::move(E), errs());
943 return Error::success();
944 }
945
946 // Don't create records for (filenames, function) pairs we've already seen.
947 auto FilenamesHash = hash_combine_range(Record.Filenames);
948 if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
949 return Error::success();
950
951 Functions.push_back(std::move(Function));
952
953 // Performance optimization: keep track of the indices of the function records
954 // which correspond to each filename. This can be used to substantially speed
955 // up queries for coverage info in a file.
956 unsigned RecordIndex = Functions.size() - 1;
957 for (StringRef Filename : Record.Filenames) {
958 auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
959 // Note that there may be duplicates in the filename set for a function
960 // record, because of e.g. macro expansions in the function in which both
961 // the macro and the function are defined in the same file.
962 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
963 RecordIndices.push_back(RecordIndex);
964 }
965
966 return Error::success();
967}
968
969// This function is for memory optimization by shortening the lifetimes
970// of CoverageMappingReader instances.
971Error CoverageMapping::loadFromReaders(
972 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
973 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
974 &ProfileReader,
975 CoverageMapping &Coverage) {
976 assert(!Coverage.SingleByteCoverage || !ProfileReader ||
977 *Coverage.SingleByteCoverage ==
978 ProfileReader.value().get().hasSingleByteCoverage());
979 Coverage.SingleByteCoverage =
980 !ProfileReader || ProfileReader.value().get().hasSingleByteCoverage();
981 for (const auto &CoverageReader : CoverageReaders) {
982 for (auto RecordOrErr : *CoverageReader) {
983 if (Error E = RecordOrErr.takeError())
984 return E;
985 const auto &Record = *RecordOrErr;
986 if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
987 return E;
988 }
989 }
990 return Error::success();
991}
992
994 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
995 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
996 &ProfileReader) {
997 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
998 if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
999 return std::move(E);
1000 return std::move(Coverage);
1001}
1002
1003// If E is a no_data_found error, returns success. Otherwise returns E.
1005 return handleErrors(std::move(E), [](const CoverageMapError &CME) {
1007 return static_cast<Error>(Error::success());
1008 return make_error<CoverageMapError>(CME.get(), CME.getMessage());
1009 });
1010}
1011
1012Error CoverageMapping::loadFromFile(
1013 StringRef Filename, StringRef Arch, StringRef CompilationDir,
1014 std::optional<std::reference_wrapper<IndexedInstrProfReader>>
1015 &ProfileReader,
1016 CoverageMapping &Coverage, bool &DataFound,
1017 SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
1018 auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
1019 Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
1020 if (std::error_code EC = CovMappingBufOrErr.getError())
1022 MemoryBufferRef CovMappingBufRef =
1023 CovMappingBufOrErr.get()->getMemBufferRef();
1025
1027 auto CoverageReadersOrErr = BinaryCoverageReader::create(
1028 CovMappingBufRef, Arch, Buffers, CompilationDir,
1029 FoundBinaryIDs ? &BinaryIDs : nullptr);
1030 if (Error E = CoverageReadersOrErr.takeError()) {
1031 E = handleMaybeNoDataFoundError(std::move(E));
1032 if (E)
1033 return createFileError(Filename, std::move(E));
1034 return E;
1035 }
1036
1038 for (auto &Reader : CoverageReadersOrErr.get())
1039 Readers.push_back(std::move(Reader));
1040 if (FoundBinaryIDs && !Readers.empty()) {
1041 llvm::append_range(*FoundBinaryIDs,
1042 llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) {
1043 return object::BuildID(BID);
1044 }));
1045 }
1046 DataFound |= !Readers.empty();
1047 if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1048 return createFileError(Filename, std::move(E));
1049 return Error::success();
1050}
1051
1053 ArrayRef<StringRef> ObjectFilenames,
1054 std::optional<StringRef> ProfileFilename, vfs::FileSystem &FS,
1055 ArrayRef<StringRef> Arches, StringRef CompilationDir,
1056 const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
1057 std::unique_ptr<IndexedInstrProfReader> ProfileReader;
1058 if (ProfileFilename) {
1059 auto ProfileReaderOrErr =
1060 IndexedInstrProfReader::create(ProfileFilename.value(), FS);
1061 if (Error E = ProfileReaderOrErr.takeError())
1062 return createFileError(ProfileFilename.value(), std::move(E));
1063 ProfileReader = std::move(ProfileReaderOrErr.get());
1064 }
1065 auto ProfileReaderRef =
1066 ProfileReader
1067 ? std::optional<std::reference_wrapper<IndexedInstrProfReader>>(
1068 *ProfileReader)
1069 : std::nullopt;
1070 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
1071 bool DataFound = false;
1072
1073 auto GetArch = [&](size_t Idx) {
1074 if (Arches.empty())
1075 return StringRef();
1076 if (Arches.size() == 1)
1077 return Arches.front();
1078 return Arches[Idx];
1079 };
1080
1081 SmallVector<object::BuildID> FoundBinaryIDs;
1082 for (const auto &File : llvm::enumerate(ObjectFilenames)) {
1083 if (Error E = loadFromFile(File.value(), GetArch(File.index()),
1084 CompilationDir, ProfileReaderRef, *Coverage,
1085 DataFound, &FoundBinaryIDs))
1086 return std::move(E);
1087 }
1088
1089 if (BIDFetcher) {
1090 std::vector<object::BuildID> ProfileBinaryIDs;
1091 if (ProfileReader)
1092 if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1093 return createFileError(ProfileFilename.value(), std::move(E));
1094
1095 SmallVector<object::BuildIDRef> BinaryIDsToFetch;
1096 if (!ProfileBinaryIDs.empty()) {
1097 const auto &Compare = [](object::BuildIDRef A, object::BuildIDRef B) {
1098 return std::lexicographical_compare(A.begin(), A.end(), B.begin(),
1099 B.end());
1100 };
1101 llvm::sort(FoundBinaryIDs, Compare);
1102 std::set_difference(
1103 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1104 FoundBinaryIDs.begin(), FoundBinaryIDs.end(),
1105 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare);
1106 }
1107
1108 for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
1109 if (Expected<std::string> Path = BIDFetcher->fetch(BinaryID)) {
1110 StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
1111 if (Error E = loadFromFile(*Path, Arch, CompilationDir,
1112 ProfileReaderRef, *Coverage, DataFound))
1113 return std::move(E);
1114 } else {
1115 // Conditionally propagate as new error.
1116 consumeError(Path.takeError());
1117 if (CheckBinaryIDs) {
1118 return createFileError(
1119 ProfileFilename.value(),
1121 "Missing binary ID: " +
1122 llvm::toHex(BinaryID, /*LowerCase=*/true)));
1123 }
1124 }
1125 }
1126 }
1127
1128 if (!DataFound)
1129 return createFileError(
1130 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "),
1132 return std::move(Coverage);
1133}
1134
1135namespace {
1136
1137/// Distributes functions into instantiation sets.
1138///
1139/// An instantiation set is a collection of functions that have the same source
1140/// code, ie, template functions specializations.
1141class FunctionInstantiationSetCollector {
1142 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1143 MapT InstantiatedFunctions;
1144
1145public:
1146 void insert(const FunctionRecord &Function, unsigned FileID) {
1147 auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
1148 while (I != E && I->FileID != FileID)
1149 ++I;
1150 assert(I != E && "function does not cover the given file");
1151 auto &Functions = InstantiatedFunctions[I->startLoc()];
1152 Functions.push_back(&Function);
1153 }
1154
1155 MapT::iterator begin() { return InstantiatedFunctions.begin(); }
1156 MapT::iterator end() { return InstantiatedFunctions.end(); }
1157};
1158
1159class SegmentBuilder {
1160 std::vector<CoverageSegment> &Segments;
1162
1163 SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
1164
1165 /// Emit a segment with the count from \p Region starting at \p StartLoc.
1166 //
1167 /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
1168 /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
1169 void startSegment(const CountedRegion &Region, LineColPair StartLoc,
1170 bool IsRegionEntry, bool EmitSkippedRegion = false) {
1171 bool HasCount = !EmitSkippedRegion &&
1173
1174 // If the new segment wouldn't affect coverage rendering, skip it.
1175 if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1176 const auto &Last = Segments.back();
1177 if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
1178 !Last.IsRegionEntry)
1179 return;
1180 }
1181
1182 if (HasCount)
1183 Segments.emplace_back(StartLoc.first, StartLoc.second,
1184 Region.ExecutionCount, IsRegionEntry,
1186 else
1187 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1188
1189 LLVM_DEBUG({
1190 const auto &Last = Segments.back();
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";
1196 });
1197 }
1198
1199 /// Emit segments for active regions which end before \p Loc.
1200 ///
1201 /// \p Loc: The start location of the next region. If std::nullopt, all active
1202 /// regions are completed.
1203 /// \p FirstCompletedRegion: Index of the first completed region.
1204 void completeRegionsUntil(std::optional<LineColPair> Loc,
1205 unsigned FirstCompletedRegion) {
1206 // Sort the completed regions by end location. This makes it simple to
1207 // emit closing segments in sorted order.
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();
1212 });
1213
1214 // Emit segments for all completed regions.
1215 for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
1216 ++I) {
1217 const auto *CompletedRegion = ActiveRegions[I];
1218 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1219 "Completed region ends after start of new region");
1220
1221 const auto *PrevCompletedRegion = ActiveRegions[I - 1];
1222 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1223
1224 // Don't emit any more segments if they start where the new region begins.
1225 if (Loc && CompletedSegmentLoc == *Loc)
1226 break;
1227
1228 // Don't emit a segment if the next completed region ends at the same
1229 // location as this one.
1230 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1231 continue;
1232
1233 // Use the count from the last completed region which ends at this loc.
1234 for (unsigned J = I + 1; J < E; ++J)
1235 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1236 CompletedRegion = ActiveRegions[J];
1237
1238 startSegment(*CompletedRegion, CompletedSegmentLoc, false);
1239 }
1240
1241 auto Last = ActiveRegions.back();
1242 if (FirstCompletedRegion && Last->endLoc() != *Loc) {
1243 // If there's a gap after the end of the last completed region and the
1244 // start of the new region, use the last active region to fill the gap.
1245 startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
1246 false);
1247 } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
1248 // Emit a skipped segment if there are no more active regions. This
1249 // ensures that gaps between functions are marked correctly.
1250 startSegment(*Last, Last->endLoc(), false, true);
1251 }
1252
1253 // Pop the completed regions.
1254 ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
1255 }
1256
1257 void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
1258 for (const auto &CR : enumerate(Regions)) {
1259 auto CurStartLoc = CR.value().startLoc();
1260
1261 // Active regions which end before the current region need to be popped.
1262 auto CompletedRegions =
1263 std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
1264 [&](const CountedRegion *Region) {
1265 return !(Region->endLoc() <= CurStartLoc);
1266 });
1267 if (CompletedRegions != ActiveRegions.end()) {
1268 unsigned FirstCompletedRegion =
1269 std::distance(ActiveRegions.begin(), CompletedRegions);
1270 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1271 }
1272
1273 bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
1274
1275 // Try to emit a segment for the current region.
1276 if (CurStartLoc == CR.value().endLoc()) {
1277 // Avoid making zero-length regions active. If it's the last region,
1278 // emit a skipped segment. Otherwise use its predecessor's count.
1279 const bool Skipped =
1280 (CR.index() + 1) == Regions.size() ||
1281 CR.value().Kind == CounterMappingRegion::SkippedRegion;
1282 startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
1283 CurStartLoc, !GapRegion, Skipped);
1284 // If it is skipped segment, create a segment with last pushed
1285 // regions's count at CurStartLoc.
1286 if (Skipped && !ActiveRegions.empty())
1287 startSegment(*ActiveRegions.back(), CurStartLoc, false);
1288 continue;
1289 }
1290 if (CR.index() + 1 == Regions.size() ||
1291 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1292 // Emit a segment if the next region doesn't start at the same location
1293 // as this one.
1294 startSegment(CR.value(), CurStartLoc, !GapRegion);
1295 }
1296
1297 // This region is active (i.e not completed).
1298 ActiveRegions.push_back(&CR.value());
1299 }
1300
1301 // Complete any remaining active regions.
1302 if (!ActiveRegions.empty())
1303 completeRegionsUntil(std::nullopt, 0);
1304 }
1305
1306 /// Sort a nested sequence of regions from a single file.
1307 static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
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())
1312 // When LHS completely contains RHS, we sort LHS first.
1313 return RHS.endLoc() < LHS.endLoc();
1314 // If LHS and RHS cover the same area, we need to sort them according
1315 // to their kinds so that the most suitable region will become "active"
1316 // in combineRegions(). Because we accumulate counter values only from
1317 // regions of the same kind as the first region of the area, prefer
1318 // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
1319 static_assert(CounterMappingRegion::CodeRegion <
1323 "Unexpected order of region kind values");
1324 return LHS.Kind < RHS.Kind;
1325 });
1326 }
1327
1328 /// Combine counts of regions which cover the same area.
1330 combineRegions(MutableArrayRef<CountedRegion> Regions) {
1331 if (Regions.empty())
1332 return Regions;
1333 auto Active = Regions.begin();
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()) {
1338 // Shift to the next region.
1339 ++Active;
1340 if (Active != I)
1341 *Active = *I;
1342 continue;
1343 }
1344 // Merge duplicate region.
1345 // If CodeRegions and ExpansionRegions cover the same area, it's probably
1346 // a macro which is fully expanded to another macro. In that case, we need
1347 // to accumulate counts only from CodeRegions, or else the area will be
1348 // counted twice.
1349 // On the other hand, a macro may have a nested macro in its body. If the
1350 // outer macro is used several times, the ExpansionRegion for the nested
1351 // macro will also be added several times. These ExpansionRegions cover
1352 // the same source locations and have to be combined to reach the correct
1353 // value for that area.
1354 // We add counts of the regions of the same kind as the active region
1355 // to handle the both situations.
1356 if (I->Kind == Active->Kind)
1357 Active->ExecutionCount += I->ExecutionCount;
1358 }
1359 return Regions.drop_back(std::distance(++Active, End));
1360 }
1361
1362public:
1363 /// Build a sorted list of CoverageSegments from a list of Regions.
1364 static std::vector<CoverageSegment>
1365 buildSegments(MutableArrayRef<CountedRegion> Regions) {
1366 std::vector<CoverageSegment> Segments;
1367 SegmentBuilder Builder(Segments);
1368
1369 sortNestedRegions(Regions);
1370 ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
1371
1372 LLVM_DEBUG({
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";
1378 });
1379
1380 Builder.buildSegmentsImpl(CombinedRegions);
1381
1382#ifndef NDEBUG
1383 for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
1384 const auto &L = Segments[I - 1];
1385 const auto &R = Segments[I];
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)
1388 continue;
1389 LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
1390 << " followed by " << R.Line << ":" << R.Col << "\n");
1391 assert(false && "Coverage segments not unique or sorted");
1392 }
1393 }
1394#endif
1395
1396 return Segments;
1397 }
1398};
1399
1400struct MergeableCoverageData : public CoverageData {
1401 std::vector<CountedRegion> CodeRegions;
1402
1403 MergeableCoverageData(bool Single, StringRef Filename)
1404 : CoverageData(Single, Filename) {}
1405
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);
1415 }
1416 // Capture branch regions specific to the function (excluding expansions).
1417 for (const auto &CR : Function.CountedBranchRegions)
1418 if (shouldProcess(CR))
1419 BranchRegions.push_back(CR);
1420 // Capture MCDC records specific to the function.
1421 for (const auto &MR : Function.MCDCRecords)
1422 if (shouldProcess(MR.getDecisionRegion()))
1423 MCDCRecords.push_back(MR);
1424 }
1425
1426 CoverageData buildSegments() {
1427 Segments = SegmentBuilder::buildSegments(CodeRegions);
1428 return CoverageData(std::move(*this));
1429 }
1430};
1431} // end anonymous namespace
1432
1433std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
1434 std::vector<StringRef> Filenames;
1435 for (const auto &Function : getCoveredFunctions())
1436 llvm::append_range(Filenames, Function.Filenames);
1437 llvm::sort(Filenames);
1438 auto Last = llvm::unique(Filenames);
1439 Filenames.erase(Last, Filenames.end());
1440 return Filenames;
1441}
1442
1444 const FunctionRecord &Function) {
1445 SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
1446 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
1447 if (SourceFile == Function.Filenames[I])
1448 FilenameEquivalence[I] = true;
1449 return FilenameEquivalence;
1450}
1451
1452/// Return the ID of the file where the definition of the function is located.
1453static std::optional<unsigned>
1455 if (Function.CountedRegions.empty())
1456 return std::nullopt;
1457 SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
1458 for (const auto &CR : Function.CountedRegions)
1460 IsNotExpandedFile[CR.ExpandedFileID] = false;
1461 int I = IsNotExpandedFile.find_first();
1462 if (I == -1)
1463 return std::nullopt;
1464 return I;
1465}
1466
1467/// Check if SourceFile is the file that contains the definition of
1468/// the Function. Return the ID of the file in that case or std::nullopt
1469/// otherwise.
1470static std::optional<unsigned>
1472 std::optional<unsigned> I = findMainViewFileID(Function);
1473 if (I && SourceFile == Function.Filenames[*I])
1474 return I;
1475 return std::nullopt;
1476}
1477
1478static bool isExpansion(const CountedRegion &R, unsigned FileID) {
1479 return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
1480}
1481
1483 assert(SingleByteCoverage);
1484 MergeableCoverageData FileCoverage(*SingleByteCoverage, Filename);
1485
1486 // Look up the function records in the given file. Due to hash collisions on
1487 // the filename, we may get back some records that are not in the file.
1488 ArrayRef<unsigned> RecordIndices =
1489 getImpreciseRecordIndicesForFilename(Filename);
1490 for (unsigned RecordIndex : RecordIndices) {
1491 const FunctionRecord &Function = Functions[RecordIndex];
1492 auto MainFileID = findMainViewFileID(Filename, Function);
1493 auto FileIDs = gatherFileIDs(Filename, Function);
1494 FileCoverage.addFunctionRegions(
1495 Function, [&](auto &CR) { return FileIDs.test(CR.FileID); },
1496 [&](auto &CR) { return (MainFileID && isExpansion(CR, *MainFileID)); });
1497 }
1498
1499 LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
1500
1501 return FileCoverage.buildSegments();
1502}
1503
1504std::vector<InstantiationGroup>
1506 FunctionInstantiationSetCollector InstantiationSetCollector;
1507 // Look up the function records in the given file. Due to hash collisions on
1508 // the filename, we may get back some records that are not in the file.
1509 ArrayRef<unsigned> RecordIndices =
1510 getImpreciseRecordIndicesForFilename(Filename);
1511 for (unsigned RecordIndex : RecordIndices) {
1512 const FunctionRecord &Function = Functions[RecordIndex];
1513 auto MainFileID = findMainViewFileID(Filename, Function);
1514 if (!MainFileID)
1515 continue;
1516 InstantiationSetCollector.insert(Function, *MainFileID);
1517 }
1518
1519 std::vector<InstantiationGroup> Result;
1520 for (auto &InstantiationSet : InstantiationSetCollector) {
1521 InstantiationGroup IG{InstantiationSet.first.first,
1522 InstantiationSet.first.second,
1523 std::move(InstantiationSet.second)};
1524 Result.emplace_back(std::move(IG));
1525 }
1526 return Result;
1527}
1528
1531 auto MainFileID = findMainViewFileID(Function);
1532 if (!MainFileID)
1533 return CoverageData();
1534
1535 assert(SingleByteCoverage);
1536 MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
1537 Function.Filenames[*MainFileID]);
1538 FunctionCoverage.addFunctionRegions(
1539 Function, [&](auto &CR) { return (CR.FileID == *MainFileID); },
1540 [&](auto &CR) { return isExpansion(CR, *MainFileID); });
1541
1542 LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
1543 << "\n");
1544
1545 return FunctionCoverage.buildSegments();
1546}
1547
1549 const ExpansionRecord &Expansion) const {
1550 assert(SingleByteCoverage);
1551 CoverageData ExpansionCoverage(
1552 *SingleByteCoverage, Expansion.Function.Filenames[Expansion.FileID]);
1553 std::vector<CountedRegion> Regions;
1554 for (const auto &CR : Expansion.Function.CountedRegions)
1555 if (CR.FileID == Expansion.FileID) {
1556 Regions.push_back(CR);
1557 if (isExpansion(CR, Expansion.FileID))
1558 ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
1559 }
1560 for (const auto &CR : Expansion.Function.CountedBranchRegions)
1561 // Capture branch regions that only pertain to the corresponding expansion.
1562 if (CR.FileID == Expansion.FileID)
1563 ExpansionCoverage.BranchRegions.push_back(CR);
1564
1565 LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
1566 << Expansion.FileID << "\n");
1567 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1568
1569 return ExpansionCoverage;
1570}
1571
1572LineCoverageStats::LineCoverageStats(
1574 const CoverageSegment *WrappedSegment, unsigned Line)
1575 : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
1576 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1577 // Find the minimum number of regions which start in this line.
1578 unsigned MinRegionCount = 0;
1579 auto isStartOfRegion = [](const CoverageSegment *S) {
1580 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1581 };
1582 for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
1583 if (isStartOfRegion(LineSegments[I]))
1584 ++MinRegionCount;
1585
1586 bool StartOfSkippedRegion = !LineSegments.empty() &&
1587 !LineSegments.front()->HasCount &&
1588 LineSegments.front()->IsRegionEntry;
1589
1590 HasMultipleRegions = MinRegionCount > 1;
1591 Mapped =
1592 !StartOfSkippedRegion &&
1593 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1594
1595 // if there is any starting segment at this line with a counter, it must be
1596 // mapped
1597 Mapped |= any_of(LineSegments, [](const auto *Seq) {
1598 return Seq->IsRegionEntry && Seq->HasCount;
1599 });
1600
1601 if (!Mapped) {
1602 return;
1603 }
1604
1605 // Pick the max count from the non-gap, region entry segments and the
1606 // wrapped count.
1607 if (WrappedSegment)
1608 ExecutionCount = WrappedSegment->Count;
1609 if (!MinRegionCount)
1610 return;
1611 for (const auto *LS : LineSegments)
1612 if (isStartOfRegion(LS))
1613 ExecutionCount = std::max(ExecutionCount, LS->Count);
1614}
1615
1617 if (Next == CD.end()) {
1618 Stats = LineCoverageStats();
1619 Ended = true;
1620 return *this;
1621 }
1622 if (Segments.size())
1623 WrappedSegment = Segments.back();
1624 Segments.clear();
1625 while (Next != CD.end() && Next->Line == Line)
1626 Segments.push_back(&*Next++);
1627 Stats = LineCoverageStats(Segments, WrappedSegment, Line);
1628 ++Line;
1629 return *this;
1630}
1631
1633 const std::string &ErrMsg = "") {
1634 std::string Msg;
1635 raw_string_ostream OS(Msg);
1636
1637 switch (Err) {
1639 OS << "success";
1640 break;
1642 OS << "end of File";
1643 break;
1645 OS << "no coverage data found";
1646 break;
1648 OS << "unsupported coverage format version";
1649 break;
1651 OS << "truncated coverage data";
1652 break;
1654 OS << "malformed coverage data";
1655 break;
1657 OS << "failed to decompress coverage data (zlib)";
1658 break;
1660 OS << "`-arch` specifier is invalid or missing for universal binary";
1661 break;
1662 }
1663
1664 // If optional error message is not empty, append it to the message.
1665 if (!ErrMsg.empty())
1666 OS << ": " << ErrMsg;
1667
1668 return Msg;
1669}
1670
1671namespace {
1672
1673// FIXME: This class is only here to support the transition to llvm::Error. It
1674// will be removed once this transition is complete. Clients should prefer to
1675// deal with the Error value directly, rather than converting to error_code.
1676class CoverageMappingErrorCategoryType : public std::error_category {
1677 const char *name() const noexcept override { return "llvm.coveragemap"; }
1678 std::string message(int IE) const override {
1679 return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
1680 }
1681};
1682
1683} // end anonymous namespace
1684
1685std::string CoverageMapError::message() const {
1686 return getCoverageMapErrString(Err, Msg);
1687}
1688
1689const std::error_category &llvm::coverage::coveragemap_category() {
1690 static CoverageMappingErrorCategoryType ErrorCategory;
1691 return ErrorCategory;
1692}
1693
1694char CoverageMapError::ID = 0;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
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)
DXIL Intrinsic Expansion
This file defines the DenseMap class.
hexagon bit simplify
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
static constexpr StringLiteral Filename
if(PassOpts->AAPipeline)
This file contains some templates that are useful if you are working with the STL at all.
static const char * name
This file implements the SmallBitVector class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:114
Defines the virtual file system interface vfs::FileSystem.
Value * RHS
Value * LHS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
front - Get the first element.
Definition ArrayRef.h:145
iterator end() const
Definition ArrayRef.h:131
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
iterator begin() const
Definition ArrayRef.h:130
bool empty() const
empty - Check if the array is empty.
Definition ArrayRef.h:137
Implements a dense probed hash-table based set.
Definition DenseSet.h:279
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
bool empty() const
Definition Function.h:859
iterator begin()
Definition Function.h:853
size_t size() const
Definition Function.h:858
iterator end()
Definition Function.h:855
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.
Definition InstrProf.h:470
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 "-".
iterator end() const
Definition ArrayRef.h:343
iterator begin() const
Definition ArrayRef.h:342
MutableArrayRef< T > drop_back(size_t N=1) const
Definition ArrayRef.h:392
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.
Definition StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:140
LLVM Value Representation.
Definition Value.h:75
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)
Definition DenseSet.h:202
size_type size() const
Definition DenseSet.h:87
BuildIDFetcher searches local cache directories for debug info.
Definition BuildID.h:41
virtual Expected< std::string > fetch(BuildIDRef BuildID) const
Returns the path to the debug file with the given build ID.
Definition BuildID.cpp:83
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
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.
Definition CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
@ Skipped
Validation was skipped, as it was not needed.
int16_t ConditionID
The ID for MCDCBranch.
Definition MCDCTypes.h:25
std::array< ConditionID, 2 > ConditionIDs
Definition MCDCTypes.h:26
LLVM_ABI const std::error_category & coveragemap_category()
std::pair< unsigned, unsigned > LineColPair
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
Definition BuildID.h:27
ArrayRef< uint8_t > BuildIDRef
A reference to a BuildID in binary form.
Definition BuildID.h:30
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:532
bool operator<(int64_t V1, const APSInt &V2)
Definition APSInt.h:360
LLVM_ABI void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Definition Error.cpp:61
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.
Definition Error.h:1415
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.
Definition STLExtras.h:1669
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
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.
Definition Error.h:990
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2134
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
Definition STLExtras.h:366
@ no_such_file_or_directory
Definition Errc.h:65
@ argument_out_of_domain
Definition Errc.h:37
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
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.
Definition Error.h:340
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.
instrprof_error
Definition InstrProf.h:398
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.
Definition STLExtras.h:1772
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition Error.cpp:107
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition Hashing.h:466
#define N
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.
Definition MCDCTypes.h:30
uint16_t NumConditions
Number of Conditions used for a Decision Region.
Definition MCDCTypes.h:33