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