LLVM 20.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 = ExpressionIndices.find(E);
53 if (It != ExpressionIndices.end())
54 return Counter::getExpression(It->second);
55 unsigned I = Expressions.size();
56 Expressions.push_back(E);
57 ExpressionIndices[E] = I;
59}
60
61void CounterExpressionBuilder::extractTerms(Counter C, int Factor,
62 SmallVectorImpl<Term> &Terms) {
63 switch (C.getKind()) {
64 case Counter::Zero:
65 break;
67 Terms.emplace_back(C.getCounterID(), Factor);
68 break;
70 const auto &E = Expressions[C.getExpressionID()];
71 extractTerms(E.LHS, Factor, Terms);
72 extractTerms(
73 E.RHS, E.Kind == CounterExpression::Subtract ? -Factor : Factor, Terms);
74 break;
75 }
76}
77
78Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) {
79 // Gather constant terms.
81 extractTerms(ExpressionTree, +1, Terms);
82
83 // If there are no terms, this is just a zero. The algorithm below assumes at
84 // least one term.
85 if (Terms.size() == 0)
86 return Counter::getZero();
87
88 // Group the terms by counter ID.
89 llvm::sort(Terms, [](const Term &LHS, const Term &RHS) {
90 return LHS.CounterID < RHS.CounterID;
91 });
92
93 // Combine terms by counter ID to eliminate counters that sum to zero.
94 auto Prev = Terms.begin();
95 for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) {
96 if (I->CounterID == Prev->CounterID) {
97 Prev->Factor += I->Factor;
98 continue;
99 }
100 ++Prev;
101 *Prev = *I;
102 }
103 Terms.erase(++Prev, Terms.end());
104
105 Counter C;
106 // Create additions. We do this before subtractions to avoid constructs like
107 // ((0 - X) + Y), as opposed to (Y - X).
108 for (auto T : Terms) {
109 if (T.Factor <= 0)
110 continue;
111 for (int I = 0; I < T.Factor; ++I)
112 if (C.isZero())
113 C = Counter::getCounter(T.CounterID);
114 else
116 Counter::getCounter(T.CounterID)));
117 }
118
119 // Create subtractions.
120 for (auto T : Terms) {
121 if (T.Factor >= 0)
122 continue;
123 for (int I = 0; I < -T.Factor; ++I)
125 Counter::getCounter(T.CounterID)));
126 }
127 return C;
128}
129
132 return Simplify ? simplify(Cnt) : Cnt;
133}
134
136 bool Simplify) {
138 return Simplify ? simplify(Cnt) : Cnt;
139}
140
142 switch (C.getKind()) {
143 case Counter::Zero:
144 OS << '0';
145 return;
147 OS << '#' << C.getCounterID();
148 break;
149 case Counter::Expression: {
150 if (C.getExpressionID() >= Expressions.size())
151 return;
152 const auto &E = Expressions[C.getExpressionID()];
153 OS << '(';
154 dump(E.LHS, OS);
155 OS << (E.Kind == CounterExpression::Subtract ? " - " : " + ");
156 dump(E.RHS, OS);
157 OS << ')';
158 break;
159 }
160 }
161 if (CounterValues.empty())
162 return;
164 if (auto E = Value.takeError()) {
165 consumeError(std::move(E));
166 return;
167 }
168 OS << '[' << *Value << ']';
169}
170
172 struct StackElem {
173 Counter ICounter;
174 int64_t LHS = 0;
175 enum {
176 KNeverVisited = 0,
177 KVisitedOnce = 1,
178 KVisitedTwice = 2,
179 } VisitCount = KNeverVisited;
180 };
181
182 std::stack<StackElem> CounterStack;
183 CounterStack.push({C});
184
185 int64_t LastPoppedValue;
186
187 while (!CounterStack.empty()) {
188 StackElem &Current = CounterStack.top();
189
190 switch (Current.ICounter.getKind()) {
191 case Counter::Zero:
192 LastPoppedValue = 0;
193 CounterStack.pop();
194 break;
196 if (Current.ICounter.getCounterID() >= CounterValues.size())
198 LastPoppedValue = CounterValues[Current.ICounter.getCounterID()];
199 CounterStack.pop();
200 break;
201 case Counter::Expression: {
202 if (Current.ICounter.getExpressionID() >= Expressions.size())
204 const auto &E = Expressions[Current.ICounter.getExpressionID()];
205 if (Current.VisitCount == StackElem::KNeverVisited) {
206 CounterStack.push(StackElem{E.LHS});
207 Current.VisitCount = StackElem::KVisitedOnce;
208 } else if (Current.VisitCount == StackElem::KVisitedOnce) {
209 Current.LHS = LastPoppedValue;
210 CounterStack.push(StackElem{E.RHS});
211 Current.VisitCount = StackElem::KVisitedTwice;
212 } else {
213 int64_t LHS = Current.LHS;
214 int64_t RHS = LastPoppedValue;
215 LastPoppedValue =
216 E.Kind == CounterExpression::Subtract ? LHS - RHS : LHS + RHS;
217 CounterStack.pop();
218 }
219 break;
220 }
221 }
222 }
223
224 return LastPoppedValue;
225}
226
228 int Offset)
229 : Indices(NextIDs.size()) {
230 // Construct Nodes and set up each InCount
231 auto N = NextIDs.size();
233 for (unsigned ID = 0; ID < N; ++ID) {
234 for (unsigned C = 0; C < 2; ++C) {
235#ifndef NDEBUG
236 Indices[ID][C] = INT_MIN;
237#endif
238 auto NextID = NextIDs[ID][C];
239 Nodes[ID].NextIDs[C] = NextID;
240 if (NextID >= 0)
241 ++Nodes[NextID].InCount;
242 }
243 }
244
245 // Sort key ordered by <-Width, Ord>
246 SmallVector<std::tuple<int, /// -Width
247 unsigned, /// Ord
248 int, /// ID
249 unsigned /// Cond (0 or 1)
250 >>
251 Decisions;
252
253 // Traverse Nodes to assign Idx
255 assert(Nodes[0].InCount == 0);
256 Nodes[0].Width = 1;
257 Q.push_back(0);
258
259 unsigned Ord = 0;
260 while (!Q.empty()) {
261 auto IID = Q.begin();
262 int ID = *IID;
263 Q.erase(IID);
264 auto &Node = Nodes[ID];
265 assert(Node.Width > 0);
266
267 for (unsigned I = 0; I < 2; ++I) {
268 auto NextID = Node.NextIDs[I];
269 assert(NextID != 0 && "NextID should not point to the top");
270 if (NextID < 0) {
271 // Decision
272 Decisions.emplace_back(-Node.Width, Ord++, ID, I);
273 assert(Ord == Decisions.size());
274 continue;
275 }
276
277 // Inter Node
278 auto &NextNode = Nodes[NextID];
279 assert(NextNode.InCount > 0);
280
281 // Assign Idx
282 assert(Indices[ID][I] == INT_MIN);
283 Indices[ID][I] = NextNode.Width;
284 auto NextWidth = int64_t(NextNode.Width) + Node.Width;
285 if (NextWidth > HardMaxTVs) {
286 NumTestVectors = HardMaxTVs; // Overflow
287 return;
288 }
289 NextNode.Width = NextWidth;
290
291 // Ready if all incomings are processed.
292 // Or NextNode.Width hasn't been confirmed yet.
293 if (--NextNode.InCount == 0)
294 Q.push_back(NextID);
295 }
296 }
297
298 llvm::sort(Decisions);
299
300 // Assign TestVector Indices in Decision Nodes
301 int64_t CurIdx = 0;
302 for (auto [NegWidth, Ord, ID, C] : Decisions) {
303 int Width = -NegWidth;
304 assert(Nodes[ID].Width == Width);
305 assert(Nodes[ID].NextIDs[C] < 0);
306 assert(Indices[ID][C] == INT_MIN);
307 Indices[ID][C] = Offset + CurIdx;
308 CurIdx += Width;
309 if (CurIdx > HardMaxTVs) {
310 NumTestVectors = HardMaxTVs; // Overflow
311 return;
312 }
313 }
314
315 assert(CurIdx < HardMaxTVs);
316 NumTestVectors = CurIdx;
317
318#ifndef NDEBUG
319 for (const auto &Idxs : Indices)
320 for (auto Idx : Idxs)
321 assert(Idx != INT_MIN);
322 SavedNodes = std::move(Nodes);
323#endif
324}
325
326namespace {
327
328/// Construct this->NextIDs with Branches for TVIdxBuilder to use it
329/// before MCDCRecordProcessor().
330class NextIDsBuilder {
331protected:
333
334public:
335 NextIDsBuilder(const ArrayRef<const CounterMappingRegion *> Branches)
336 : NextIDs(Branches.size()) {
337#ifndef NDEBUG
339#endif
340 for (const auto *Branch : Branches) {
341 const auto &BranchParams = Branch->getBranchParams();
342 assert(SeenIDs.insert(BranchParams.ID).second && "Duplicate CondID");
343 NextIDs[BranchParams.ID] = BranchParams.Conds;
344 }
345 assert(SeenIDs.size() == Branches.size());
346 }
347};
348
349class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
350 /// A bitmap representing the executed test vectors for a boolean expression.
351 /// Each index of the bitmap corresponds to a possible test vector. An index
352 /// with a bit value of '1' indicates that the corresponding Test Vector
353 /// identified by that index was executed.
354 const BitVector &Bitmap;
355
356 /// Decision Region to which the ExecutedTestVectorBitmap applies.
358 const mcdc::DecisionParameters &DecisionParams;
359
360 /// Array of branch regions corresponding each conditions in the boolean
361 /// expression.
363
364 /// Total number of conditions in the boolean expression.
365 unsigned NumConditions;
366
367 /// Vector used to track whether a condition is constant folded.
369
370 /// Mapping of calculated MC/DC Independence Pairs for each condition.
371 MCDCRecord::TVPairMap IndependencePairs;
372
373 /// Storage for ExecVectors
374 /// ExecVectors is the alias of its 0th element.
375 std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
376
377 /// Actual executed Test Vectors for the boolean expression, based on
378 /// ExecutedTestVectorBitmap.
379 MCDCRecord::TestVectors &ExecVectors;
380
381 /// Number of False items in ExecVectors
382 unsigned NumExecVectorsF;
383
384#ifndef NDEBUG
385 DenseSet<unsigned> TVIdxs;
386#endif
387
388 bool IsVersion11;
389
390public:
391 MCDCRecordProcessor(const BitVector &Bitmap,
394 bool IsVersion11)
395 : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
396 Region(Region), DecisionParams(Region.getDecisionParams()),
397 Branches(Branches), NumConditions(DecisionParams.NumConditions),
398 Folded(NumConditions, false), IndependencePairs(NumConditions),
399 ExecVectors(ExecVectorsByCond[false]), IsVersion11(IsVersion11) {}
400
401private:
402 // Walk the binary decision diagram and try assigning both false and true to
403 // each node. When a terminal node (ID == 0) is reached, fill in the value in
404 // the truth table.
405 void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
406 int TVIdx) {
407 for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
408 static_assert(MCDCRecord::MCDC_False == 0);
409 static_assert(MCDCRecord::MCDC_True == 1);
410 TV.set(ID, MCDCCond);
411 auto NextID = NextIDs[ID][MCDCCond];
412 auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
413 assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
414 if (NextID >= 0) {
415 buildTestVector(TV, NextID, NextTVIdx);
416 continue;
417 }
418
419 assert(TVIdx < SavedNodes[ID].Width);
420 assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx");
421
422 if (!Bitmap[IsVersion11
423 ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()
424 : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx])
425 continue;
426
427 // Copy the completed test vector to the vector of testvectors.
428 // The final value (T,F) is equal to the last non-dontcare state on the
429 // path (in a short-circuiting system).
430 ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
431 }
432
433 // Reset back to DontCare.
435 }
436
437 /// Walk the bits in the bitmap. A bit set to '1' indicates that the test
438 /// vector at the corresponding index was executed during a test run.
439 void findExecutedTestVectors() {
440 // Walk the binary decision diagram to enumerate all possible test vectors.
441 // We start at the root node (ID == 0) with all values being DontCare.
442 // `TVIdx` starts with 0 and is in the traversal.
443 // `Index` encodes the bitmask of true values and is initially 0.
444 MCDCRecord::TestVector TV(NumConditions);
445 buildTestVector(TV, 0, 0);
446 assert(TVIdxs.size() == unsigned(NumTestVectors) &&
447 "TVIdxs wasn't fulfilled");
448
449 // Fill ExecVectors order by False items and True items.
450 // ExecVectors is the alias of ExecVectorsByCond[false], so
451 // Append ExecVectorsByCond[true] on it.
452 NumExecVectorsF = ExecVectors.size();
453 auto &ExecVectorsT = ExecVectorsByCond[true];
454 ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
455 std::make_move_iterator(ExecVectorsT.end()));
456 }
457
458 // Find an independence pair for each condition:
459 // - The condition is true in one test and false in the other.
460 // - The decision outcome is true one test and false in the other.
461 // - All other conditions' values must be equal or marked as "don't care".
462 void findIndependencePairs() {
463 unsigned NumTVs = ExecVectors.size();
464 for (unsigned I = NumExecVectorsF; I < NumTVs; ++I) {
465 const auto &[A, ACond] = ExecVectors[I];
467 for (unsigned J = 0; J < NumExecVectorsF; ++J) {
468 const auto &[B, BCond] = ExecVectors[J];
470 // If the two vectors differ in exactly one condition, ignoring DontCare
471 // conditions, we have found an independence pair.
472 auto AB = A.getDifferences(B);
473 if (AB.count() == 1)
474 IndependencePairs.insert(
475 {AB.find_first(), std::make_pair(J + 1, I + 1)});
476 }
477 }
478 }
479
480public:
481 /// Process the MC/DC Record in order to produce a result for a boolean
482 /// expression. This process includes tracking the conditions that comprise
483 /// the decision region, calculating the list of all possible test vectors,
484 /// marking the executed test vectors, and then finding an Independence Pair
485 /// out of the executed test vectors for each condition in the boolean
486 /// expression. A condition is tracked to ensure that its ID can be mapped to
487 /// its ordinal position in the boolean expression. The condition's source
488 /// location is also tracked, as well as whether it is constant folded (in
489 /// which case it is excuded from the metric).
490 MCDCRecord processMCDCRecord() {
491 unsigned I = 0;
492 MCDCRecord::CondIDMap PosToID;
494
495 // Walk the Record's BranchRegions (representing Conditions) in order to:
496 // - Hash the condition based on its corresponding ID. This will be used to
497 // calculate the test vectors.
498 // - Keep a map of the condition's ordinal position (1, 2, 3, 4) to its
499 // actual ID. This will be used to visualize the conditions in the
500 // correct order.
501 // - Keep track of the condition source location. This will be used to
502 // visualize where the condition is.
503 // - Record whether the condition is constant folded so that we exclude it
504 // from being measured.
505 for (const auto *B : Branches) {
506 const auto &BranchParams = B->getBranchParams();
507 PosToID[I] = BranchParams.ID;
508 CondLoc[I] = B->startLoc();
509 Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero());
510 }
511
512 // Using Profile Bitmap from runtime, mark the executed test vectors.
513 findExecutedTestVectors();
514
515 // Compare executed test vectors against each other to find an independence
516 // pairs for each condition. This processing takes the most time.
517 findIndependencePairs();
518
519 // Record Test vectors, executed vectors, and independence pairs.
520 return MCDCRecord(Region, std::move(ExecVectors),
521 std::move(IndependencePairs), std::move(Folded),
522 std::move(PosToID), std::move(CondLoc));
523 }
524};
525
526} // namespace
527
530 ArrayRef<const CounterMappingRegion *> Branches, bool IsVersion11) {
531
532 MCDCRecordProcessor MCDCProcessor(Bitmap, Region, Branches, IsVersion11);
533 return MCDCProcessor.processMCDCRecord();
534}
535
537 struct StackElem {
538 Counter ICounter;
539 int64_t LHS = 0;
540 enum {
541 KNeverVisited = 0,
542 KVisitedOnce = 1,
543 KVisitedTwice = 2,
544 } VisitCount = KNeverVisited;
545 };
546
547 std::stack<StackElem> CounterStack;
548 CounterStack.push({C});
549
550 int64_t LastPoppedValue;
551
552 while (!CounterStack.empty()) {
553 StackElem &Current = CounterStack.top();
554
555 switch (Current.ICounter.getKind()) {
556 case Counter::Zero:
557 LastPoppedValue = 0;
558 CounterStack.pop();
559 break;
561 LastPoppedValue = Current.ICounter.getCounterID();
562 CounterStack.pop();
563 break;
564 case Counter::Expression: {
565 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
566 LastPoppedValue = 0;
567 CounterStack.pop();
568 } else {
569 const auto &E = Expressions[Current.ICounter.getExpressionID()];
570 if (Current.VisitCount == StackElem::KNeverVisited) {
571 CounterStack.push(StackElem{E.LHS});
572 Current.VisitCount = StackElem::KVisitedOnce;
573 } else if (Current.VisitCount == StackElem::KVisitedOnce) {
574 Current.LHS = LastPoppedValue;
575 CounterStack.push(StackElem{E.RHS});
576 Current.VisitCount = StackElem::KVisitedTwice;
577 } else {
578 int64_t LHS = Current.LHS;
579 int64_t RHS = LastPoppedValue;
580 LastPoppedValue = std::max(LHS, RHS);
581 CounterStack.pop();
582 }
583 }
584 break;
585 }
586 }
587 }
588
589 return LastPoppedValue;
590}
591
592void FunctionRecordIterator::skipOtherFiles() {
593 while (Current != Records.end() && !Filename.empty() &&
594 Filename != Current->Filenames[0])
595 ++Current;
596 if (Current == Records.end())
597 *this = FunctionRecordIterator();
598}
599
600ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
601 StringRef Filename) const {
602 size_t FilenameHash = hash_value(Filename);
603 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
604 if (RecordIt == FilenameHash2RecordIndices.end())
605 return {};
606 return RecordIt->second;
607}
608
609static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
611 unsigned MaxCounterID = 0;
612 for (const auto &Region : Record.MappingRegions) {
613 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
614 }
615 return MaxCounterID;
616}
617
618/// Returns the bit count
620 bool IsVersion11) {
621 unsigned MaxBitmapIdx = 0;
622 unsigned NumConditions = 0;
623 // Scan max(BitmapIdx).
624 // Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
625 // and `MaxBitmapIdx is `unsigned`. `BitmapIdx` is unique in the record.
626 for (const auto &Region : reverse(Record.MappingRegions)) {
628 continue;
629 const auto &DecisionParams = Region.getDecisionParams();
630 if (MaxBitmapIdx <= DecisionParams.BitmapIdx) {
631 MaxBitmapIdx = DecisionParams.BitmapIdx;
632 NumConditions = DecisionParams.NumConditions;
633 }
634 }
635
636 if (IsVersion11)
637 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
638 llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
639
640 return MaxBitmapIdx;
641}
642
643namespace {
644
645/// Collect Decisions, Branchs, and Expansions and associate them.
646class MCDCDecisionRecorder {
647private:
648 /// This holds the DecisionRegion and MCDCBranches under it.
649 /// Also traverses Expansion(s).
650 /// The Decision has the number of MCDCBranches and will complete
651 /// when it is filled with unique ConditionID of MCDCBranches.
652 struct DecisionRecord {
653 const CounterMappingRegion *DecisionRegion;
654
655 /// They are reflected from DecisionRegion for convenience.
656 mcdc::DecisionParameters DecisionParams;
657 LineColPair DecisionStartLoc;
658 LineColPair DecisionEndLoc;
659
660 /// This is passed to `MCDCRecordProcessor`, so this should be compatible
661 /// to`ArrayRef<const CounterMappingRegion *>`.
663
664 /// IDs that are stored in MCDCBranches
665 /// Complete when all IDs (1 to NumConditions) are met.
667
668 /// Set of IDs of Expansion(s) that are relevant to DecisionRegion
669 /// and its children (via expansions).
670 /// FileID pointed by ExpandedFileID is dedicated to the expansion, so
671 /// the location in the expansion doesn't matter.
672 DenseSet<unsigned> ExpandedFileIDs;
673
674 DecisionRecord(const CounterMappingRegion &Decision)
675 : DecisionRegion(&Decision),
676 DecisionParams(Decision.getDecisionParams()),
677 DecisionStartLoc(Decision.startLoc()),
678 DecisionEndLoc(Decision.endLoc()) {
680 }
681
682 /// Determine whether DecisionRecord dominates `R`.
683 bool dominates(const CounterMappingRegion &R) const {
684 // Determine whether `R` is included in `DecisionRegion`.
685 if (R.FileID == DecisionRegion->FileID &&
686 R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc)
687 return true;
688
689 // Determine whether `R` is pointed by any of Expansions.
690 return ExpandedFileIDs.contains(R.FileID);
691 }
692
693 enum Result {
694 NotProcessed = 0, /// Irrelevant to this Decision
695 Processed, /// Added to this Decision
696 Completed, /// Added and filled this Decision
697 };
698
699 /// Add Branch into the Decision
700 /// \param Branch expects MCDCBranchRegion
701 /// \returns NotProcessed/Processed/Completed
702 Result addBranch(const CounterMappingRegion &Branch) {
704
705 auto ConditionID = Branch.getBranchParams().ID;
706
707 if (ConditionIDs.contains(ConditionID) ||
708 ConditionID >= DecisionParams.NumConditions)
709 return NotProcessed;
710
711 if (!this->dominates(Branch))
712 return NotProcessed;
713
714 assert(MCDCBranches.size() < DecisionParams.NumConditions);
715
716 // Put `ID=0` in front of `MCDCBranches` for convenience
717 // even if `MCDCBranches` is not topological.
718 if (ConditionID == 0)
719 MCDCBranches.insert(MCDCBranches.begin(), &Branch);
720 else
721 MCDCBranches.push_back(&Branch);
722
723 // Mark `ID` as `assigned`.
724 ConditionIDs.insert(ConditionID);
725
726 // `Completed` when `MCDCBranches` is full
727 return (MCDCBranches.size() == DecisionParams.NumConditions ? Completed
728 : Processed);
729 }
730
731 /// Record Expansion if it is relevant to this Decision.
732 /// Each `Expansion` may nest.
733 /// \returns true if recorded.
734 bool recordExpansion(const CounterMappingRegion &Expansion) {
735 if (!this->dominates(Expansion))
736 return false;
737
738 ExpandedFileIDs.insert(Expansion.ExpandedFileID);
739 return true;
740 }
741 };
742
743private:
744 /// Decisions in progress
745 /// DecisionRecord is added for each MCDCDecisionRegion.
746 /// DecisionRecord is removed when Decision is completed.
748
749public:
750 ~MCDCDecisionRecorder() {
751 assert(Decisions.empty() && "All Decisions have not been resolved");
752 }
753
754 /// Register Region and start recording.
755 void registerDecision(const CounterMappingRegion &Decision) {
756 Decisions.emplace_back(Decision);
757 }
758
759 void recordExpansion(const CounterMappingRegion &Expansion) {
760 any_of(Decisions, [&Expansion](auto &Decision) {
761 return Decision.recordExpansion(Expansion);
762 });
763 }
764
765 using DecisionAndBranches =
766 std::pair<const CounterMappingRegion *, /// Decision
768 >;
769
770 /// Add MCDCBranchRegion to DecisionRecord.
771 /// \param Branch to be processed
772 /// \returns DecisionsAndBranches if DecisionRecord completed.
773 /// Or returns nullopt.
774 std::optional<DecisionAndBranches>
775 processBranch(const CounterMappingRegion &Branch) {
776 // Seek each Decision and apply Region to it.
777 for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end();
778 DecisionIter != DecisionEnd; ++DecisionIter)
779 switch (DecisionIter->addBranch(Branch)) {
780 case DecisionRecord::NotProcessed:
781 continue;
782 case DecisionRecord::Processed:
783 return std::nullopt;
784 case DecisionRecord::Completed:
785 DecisionAndBranches Result =
786 std::make_pair(DecisionIter->DecisionRegion,
787 std::move(DecisionIter->MCDCBranches));
788 Decisions.erase(DecisionIter); // No longer used.
789 return Result;
790 }
791
792 llvm_unreachable("Branch not found in Decisions");
793 }
794};
795
796} // namespace
797
798Error CoverageMapping::loadFunctionRecord(
800 IndexedInstrProfReader &ProfileReader) {
801 StringRef OrigFuncName = Record.FunctionName;
802 if (OrigFuncName.empty())
803 return make_error<CoverageMapError>(coveragemap_error::malformed,
804 "record function name is empty");
805
806 if (Record.Filenames.empty())
807 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
808 else
809 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
810
811 CounterMappingContext Ctx(Record.Expressions);
812
813 std::vector<uint64_t> Counts;
814 if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
815 Record.FunctionHash, Counts)) {
816 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
818 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
819 Record.FunctionHash);
820 return Error::success();
821 }
823 return make_error<InstrProfError>(IPE);
824 Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
825 }
826 Ctx.setCounts(Counts);
827
828 bool IsVersion11 =
830
831 BitVector Bitmap;
832 if (Error E = ProfileReader.getFunctionBitmap(Record.FunctionName,
833 Record.FunctionHash, Bitmap)) {
834 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
836 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
837 Record.FunctionHash);
838 return Error::success();
839 }
841 return make_error<InstrProfError>(IPE);
842 Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
843 }
844 Ctx.setBitmap(std::move(Bitmap));
845
846 assert(!Record.MappingRegions.empty() && "Function has no regions");
847
848 // This coverage record is a zero region for a function that's unused in
849 // some TU, but used in a different TU. Ignore it. The coverage maps from the
850 // the other TU will either be loaded (providing full region counts) or they
851 // won't (in which case we don't unintuitively report functions as uncovered
852 // when they have non-zero counts in the profile).
853 if (Record.MappingRegions.size() == 1 &&
854 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
855 return Error::success();
856
857 MCDCDecisionRecorder MCDCDecisions;
858 FunctionRecord Function(OrigFuncName, Record.Filenames);
859 for (const auto &Region : Record.MappingRegions) {
860 // MCDCDecisionRegion should be handled first since it overlaps with
861 // others inside.
863 MCDCDecisions.registerDecision(Region);
864 continue;
865 }
866 Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
867 if (auto E = ExecutionCount.takeError()) {
868 consumeError(std::move(E));
869 return Error::success();
870 }
871 Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
872 if (auto E = AltExecutionCount.takeError()) {
873 consumeError(std::move(E));
874 return Error::success();
875 }
876 Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount,
877 ProfileReader.hasSingleByteCoverage());
878
879 // Record ExpansionRegion.
881 MCDCDecisions.recordExpansion(Region);
882 continue;
883 }
884
885 // Do nothing unless MCDCBranchRegion.
887 continue;
888
889 auto Result = MCDCDecisions.processBranch(Region);
890 if (!Result) // Any Decision doesn't complete.
891 continue;
892
893 auto MCDCDecision = Result->first;
894 auto &MCDCBranches = Result->second;
895
896 // Since the bitmap identifies the executed test vectors for an MC/DC
897 // DecisionRegion, all of the information is now available to process.
898 // This is where the bulk of the MC/DC progressing takes place.
900 Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
901 if (auto E = Record.takeError()) {
902 consumeError(std::move(E));
903 return Error::success();
904 }
905
906 // Save the MC/DC Record so that it can be visualized later.
907 Function.pushMCDCRecord(std::move(*Record));
908 }
909
910 // Don't create records for (filenames, function) pairs we've already seen.
911 auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
912 Record.Filenames.end());
913 if (!RecordProvenance[FilenamesHash].insert(hash_value(OrigFuncName)).second)
914 return Error::success();
915
916 Functions.push_back(std::move(Function));
917
918 // Performance optimization: keep track of the indices of the function records
919 // which correspond to each filename. This can be used to substantially speed
920 // up queries for coverage info in a file.
921 unsigned RecordIndex = Functions.size() - 1;
922 for (StringRef Filename : Record.Filenames) {
923 auto &RecordIndices = FilenameHash2RecordIndices[hash_value(Filename)];
924 // Note that there may be duplicates in the filename set for a function
925 // record, because of e.g. macro expansions in the function in which both
926 // the macro and the function are defined in the same file.
927 if (RecordIndices.empty() || RecordIndices.back() != RecordIndex)
928 RecordIndices.push_back(RecordIndex);
929 }
930
931 return Error::success();
932}
933
934// This function is for memory optimization by shortening the lifetimes
935// of CoverageMappingReader instances.
936Error CoverageMapping::loadFromReaders(
937 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
938 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) {
939 for (const auto &CoverageReader : CoverageReaders) {
940 for (auto RecordOrErr : *CoverageReader) {
941 if (Error E = RecordOrErr.takeError())
942 return E;
943 const auto &Record = *RecordOrErr;
944 if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
945 return E;
946 }
947 }
948 return Error::success();
949}
950
952 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
953 IndexedInstrProfReader &ProfileReader) {
954 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
955 if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
956 return std::move(E);
957 return std::move(Coverage);
958}
959
960// If E is a no_data_found error, returns success. Otherwise returns E.
962 return handleErrors(
963 std::move(E), [](const CoverageMapError &CME) {
965 return static_cast<Error>(Error::success());
966 return make_error<CoverageMapError>(CME.get(), CME.getMessage());
967 });
968}
969
970Error CoverageMapping::loadFromFile(
971 StringRef Filename, StringRef Arch, StringRef CompilationDir,
972 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
973 bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
974 auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
975 Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
976 if (std::error_code EC = CovMappingBufOrErr.getError())
977 return createFileError(Filename, errorCodeToError(EC));
978 MemoryBufferRef CovMappingBufRef =
979 CovMappingBufOrErr.get()->getMemBufferRef();
981
983 auto CoverageReadersOrErr = BinaryCoverageReader::create(
984 CovMappingBufRef, Arch, Buffers, CompilationDir,
985 FoundBinaryIDs ? &BinaryIDs : nullptr);
986 if (Error E = CoverageReadersOrErr.takeError()) {
987 E = handleMaybeNoDataFoundError(std::move(E));
988 if (E)
989 return createFileError(Filename, std::move(E));
990 return E;
991 }
992
994 for (auto &Reader : CoverageReadersOrErr.get())
995 Readers.push_back(std::move(Reader));
996 if (FoundBinaryIDs && !Readers.empty()) {
997 llvm::append_range(*FoundBinaryIDs,
998 llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) {
999 return object::BuildID(BID);
1000 }));
1001 }
1002 DataFound |= !Readers.empty();
1003 if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1004 return createFileError(Filename, std::move(E));
1005 return Error::success();
1006}
1007
1009 ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
1010 vfs::FileSystem &FS, ArrayRef<StringRef> Arches, StringRef CompilationDir,
1011 const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
1012 auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS);
1013 if (Error E = ProfileReaderOrErr.takeError())
1014 return createFileError(ProfileFilename, std::move(E));
1015 auto ProfileReader = std::move(ProfileReaderOrErr.get());
1016 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
1017 bool DataFound = false;
1018
1019 auto GetArch = [&](size_t Idx) {
1020 if (Arches.empty())
1021 return StringRef();
1022 if (Arches.size() == 1)
1023 return Arches.front();
1024 return Arches[Idx];
1025 };
1026
1027 SmallVector<object::BuildID> FoundBinaryIDs;
1028 for (const auto &File : llvm::enumerate(ObjectFilenames)) {
1029 if (Error E =
1030 loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
1031 *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
1032 return std::move(E);
1033 }
1034
1035 if (BIDFetcher) {
1036 std::vector<object::BuildID> ProfileBinaryIDs;
1037 if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1038 return createFileError(ProfileFilename, std::move(E));
1039
1040 SmallVector<object::BuildIDRef> BinaryIDsToFetch;
1041 if (!ProfileBinaryIDs.empty()) {
1042 const auto &Compare = [](object::BuildIDRef A, object::BuildIDRef B) {
1043 return std::lexicographical_compare(A.begin(), A.end(), B.begin(),
1044 B.end());
1045 };
1046 llvm::sort(FoundBinaryIDs, Compare);
1047 std::set_difference(
1048 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1049 FoundBinaryIDs.begin(), FoundBinaryIDs.end(),
1050 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare);
1051 }
1052
1053 for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
1054 std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID);
1055 if (PathOpt) {
1056 std::string Path = std::move(*PathOpt);
1057 StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
1058 if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
1059 *Coverage, DataFound))
1060 return std::move(E);
1061 } else if (CheckBinaryIDs) {
1062 return createFileError(
1063 ProfileFilename,
1065 "Missing binary ID: " +
1066 llvm::toHex(BinaryID, /*LowerCase=*/true)));
1067 }
1068 }
1069 }
1070
1071 if (!DataFound)
1072 return createFileError(
1073 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "),
1074 make_error<CoverageMapError>(coveragemap_error::no_data_found));
1075 return std::move(Coverage);
1076}
1077
1078namespace {
1079
1080/// Distributes functions into instantiation sets.
1081///
1082/// An instantiation set is a collection of functions that have the same source
1083/// code, ie, template functions specializations.
1084class FunctionInstantiationSetCollector {
1085 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1086 MapT InstantiatedFunctions;
1087
1088public:
1089 void insert(const FunctionRecord &Function, unsigned FileID) {
1090 auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
1091 while (I != E && I->FileID != FileID)
1092 ++I;
1093 assert(I != E && "function does not cover the given file");
1094 auto &Functions = InstantiatedFunctions[I->startLoc()];
1095 Functions.push_back(&Function);
1096 }
1097
1098 MapT::iterator begin() { return InstantiatedFunctions.begin(); }
1099 MapT::iterator end() { return InstantiatedFunctions.end(); }
1100};
1101
1102class SegmentBuilder {
1103 std::vector<CoverageSegment> &Segments;
1105
1106 SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
1107
1108 /// Emit a segment with the count from \p Region starting at \p StartLoc.
1109 //
1110 /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
1111 /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
1112 void startSegment(const CountedRegion &Region, LineColPair StartLoc,
1113 bool IsRegionEntry, bool EmitSkippedRegion = false) {
1114 bool HasCount = !EmitSkippedRegion &&
1116
1117 // If the new segment wouldn't affect coverage rendering, skip it.
1118 if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1119 const auto &Last = Segments.back();
1120 if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
1121 !Last.IsRegionEntry)
1122 return;
1123 }
1124
1125 if (HasCount)
1126 Segments.emplace_back(StartLoc.first, StartLoc.second,
1127 Region.ExecutionCount, IsRegionEntry,
1129 else
1130 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1131
1132 LLVM_DEBUG({
1133 const auto &Last = Segments.back();
1134 dbgs() << "Segment at " << Last.Line << ":" << Last.Col
1135 << " (count = " << Last.Count << ")"
1136 << (Last.IsRegionEntry ? ", RegionEntry" : "")
1137 << (!Last.HasCount ? ", Skipped" : "")
1138 << (Last.IsGapRegion ? ", Gap" : "") << "\n";
1139 });
1140 }
1141
1142 /// Emit segments for active regions which end before \p Loc.
1143 ///
1144 /// \p Loc: The start location of the next region. If std::nullopt, all active
1145 /// regions are completed.
1146 /// \p FirstCompletedRegion: Index of the first completed region.
1147 void completeRegionsUntil(std::optional<LineColPair> Loc,
1148 unsigned FirstCompletedRegion) {
1149 // Sort the completed regions by end location. This makes it simple to
1150 // emit closing segments in sorted order.
1151 auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
1152 std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
1153 [](const CountedRegion *L, const CountedRegion *R) {
1154 return L->endLoc() < R->endLoc();
1155 });
1156
1157 // Emit segments for all completed regions.
1158 for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
1159 ++I) {
1160 const auto *CompletedRegion = ActiveRegions[I];
1161 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1162 "Completed region ends after start of new region");
1163
1164 const auto *PrevCompletedRegion = ActiveRegions[I - 1];
1165 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1166
1167 // Don't emit any more segments if they start where the new region begins.
1168 if (Loc && CompletedSegmentLoc == *Loc)
1169 break;
1170
1171 // Don't emit a segment if the next completed region ends at the same
1172 // location as this one.
1173 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1174 continue;
1175
1176 // Use the count from the last completed region which ends at this loc.
1177 for (unsigned J = I + 1; J < E; ++J)
1178 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1179 CompletedRegion = ActiveRegions[J];
1180
1181 startSegment(*CompletedRegion, CompletedSegmentLoc, false);
1182 }
1183
1184 auto Last = ActiveRegions.back();
1185 if (FirstCompletedRegion && Last->endLoc() != *Loc) {
1186 // If there's a gap after the end of the last completed region and the
1187 // start of the new region, use the last active region to fill the gap.
1188 startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
1189 false);
1190 } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
1191 // Emit a skipped segment if there are no more active regions. This
1192 // ensures that gaps between functions are marked correctly.
1193 startSegment(*Last, Last->endLoc(), false, true);
1194 }
1195
1196 // Pop the completed regions.
1197 ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
1198 }
1199
1200 void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
1201 for (const auto &CR : enumerate(Regions)) {
1202 auto CurStartLoc = CR.value().startLoc();
1203
1204 // Active regions which end before the current region need to be popped.
1205 auto CompletedRegions =
1206 std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
1207 [&](const CountedRegion *Region) {
1208 return !(Region->endLoc() <= CurStartLoc);
1209 });
1210 if (CompletedRegions != ActiveRegions.end()) {
1211 unsigned FirstCompletedRegion =
1212 std::distance(ActiveRegions.begin(), CompletedRegions);
1213 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1214 }
1215
1216 bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
1217
1218 // Try to emit a segment for the current region.
1219 if (CurStartLoc == CR.value().endLoc()) {
1220 // Avoid making zero-length regions active. If it's the last region,
1221 // emit a skipped segment. Otherwise use its predecessor's count.
1222 const bool Skipped =
1223 (CR.index() + 1) == Regions.size() ||
1224 CR.value().Kind == CounterMappingRegion::SkippedRegion;
1225 startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
1226 CurStartLoc, !GapRegion, Skipped);
1227 // If it is skipped segment, create a segment with last pushed
1228 // regions's count at CurStartLoc.
1229 if (Skipped && !ActiveRegions.empty())
1230 startSegment(*ActiveRegions.back(), CurStartLoc, false);
1231 continue;
1232 }
1233 if (CR.index() + 1 == Regions.size() ||
1234 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1235 // Emit a segment if the next region doesn't start at the same location
1236 // as this one.
1237 startSegment(CR.value(), CurStartLoc, !GapRegion);
1238 }
1239
1240 // This region is active (i.e not completed).
1241 ActiveRegions.push_back(&CR.value());
1242 }
1243
1244 // Complete any remaining active regions.
1245 if (!ActiveRegions.empty())
1246 completeRegionsUntil(std::nullopt, 0);
1247 }
1248
1249 /// Sort a nested sequence of regions from a single file.
1250 static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
1251 llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) {
1252 if (LHS.startLoc() != RHS.startLoc())
1253 return LHS.startLoc() < RHS.startLoc();
1254 if (LHS.endLoc() != RHS.endLoc())
1255 // When LHS completely contains RHS, we sort LHS first.
1256 return RHS.endLoc() < LHS.endLoc();
1257 // If LHS and RHS cover the same area, we need to sort them according
1258 // to their kinds so that the most suitable region will become "active"
1259 // in combineRegions(). Because we accumulate counter values only from
1260 // regions of the same kind as the first region of the area, prefer
1261 // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
1262 static_assert(CounterMappingRegion::CodeRegion <
1266 "Unexpected order of region kind values");
1267 return LHS.Kind < RHS.Kind;
1268 });
1269 }
1270
1271 /// Combine counts of regions which cover the same area.
1273 combineRegions(MutableArrayRef<CountedRegion> Regions) {
1274 if (Regions.empty())
1275 return Regions;
1276 auto Active = Regions.begin();
1277 auto End = Regions.end();
1278 for (auto I = Regions.begin() + 1; I != End; ++I) {
1279 if (Active->startLoc() != I->startLoc() ||
1280 Active->endLoc() != I->endLoc()) {
1281 // Shift to the next region.
1282 ++Active;
1283 if (Active != I)
1284 *Active = *I;
1285 continue;
1286 }
1287 // Merge duplicate region.
1288 // If CodeRegions and ExpansionRegions cover the same area, it's probably
1289 // a macro which is fully expanded to another macro. In that case, we need
1290 // to accumulate counts only from CodeRegions, or else the area will be
1291 // counted twice.
1292 // On the other hand, a macro may have a nested macro in its body. If the
1293 // outer macro is used several times, the ExpansionRegion for the nested
1294 // macro will also be added several times. These ExpansionRegions cover
1295 // the same source locations and have to be combined to reach the correct
1296 // value for that area.
1297 // We add counts of the regions of the same kind as the active region
1298 // to handle the both situations.
1299 if (I->Kind == Active->Kind) {
1300 assert(I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
1301 "Regions are generated in different coverage modes");
1302 if (I->HasSingleByteCoverage)
1303 Active->ExecutionCount = Active->ExecutionCount || I->ExecutionCount;
1304 else
1305 Active->ExecutionCount += I->ExecutionCount;
1306 }
1307 }
1308 return Regions.drop_back(std::distance(++Active, End));
1309 }
1310
1311public:
1312 /// Build a sorted list of CoverageSegments from a list of Regions.
1313 static std::vector<CoverageSegment>
1314 buildSegments(MutableArrayRef<CountedRegion> Regions) {
1315 std::vector<CoverageSegment> Segments;
1316 SegmentBuilder Builder(Segments);
1317
1318 sortNestedRegions(Regions);
1319 ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
1320
1321 LLVM_DEBUG({
1322 dbgs() << "Combined regions:\n";
1323 for (const auto &CR : CombinedRegions)
1324 dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> "
1325 << CR.LineEnd << ":" << CR.ColumnEnd
1326 << " (count=" << CR.ExecutionCount << ")\n";
1327 });
1328
1329 Builder.buildSegmentsImpl(CombinedRegions);
1330
1331#ifndef NDEBUG
1332 for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
1333 const auto &L = Segments[I - 1];
1334 const auto &R = Segments[I];
1335 if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
1336 if (L.Line == R.Line && L.Col == R.Col && !L.HasCount)
1337 continue;
1338 LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
1339 << " followed by " << R.Line << ":" << R.Col << "\n");
1340 assert(false && "Coverage segments not unique or sorted");
1341 }
1342 }
1343#endif
1344
1345 return Segments;
1346 }
1347};
1348
1349} // end anonymous namespace
1350
1351std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
1352 std::vector<StringRef> Filenames;
1353 for (const auto &Function : getCoveredFunctions())
1354 llvm::append_range(Filenames, Function.Filenames);
1355 llvm::sort(Filenames);
1356 auto Last = llvm::unique(Filenames);
1357 Filenames.erase(Last, Filenames.end());
1358 return Filenames;
1359}
1360
1362 const FunctionRecord &Function) {
1363 SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
1364 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
1365 if (SourceFile == Function.Filenames[I])
1366 FilenameEquivalence[I] = true;
1367 return FilenameEquivalence;
1368}
1369
1370/// Return the ID of the file where the definition of the function is located.
1371static std::optional<unsigned>
1373 SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
1374 for (const auto &CR : Function.CountedRegions)
1376 IsNotExpandedFile[CR.ExpandedFileID] = false;
1377 int I = IsNotExpandedFile.find_first();
1378 if (I == -1)
1379 return std::nullopt;
1380 return I;
1381}
1382
1383/// Check if SourceFile is the file that contains the definition of
1384/// the Function. Return the ID of the file in that case or std::nullopt
1385/// otherwise.
1386static std::optional<unsigned>
1388 std::optional<unsigned> I = findMainViewFileID(Function);
1389 if (I && SourceFile == Function.Filenames[*I])
1390 return I;
1391 return std::nullopt;
1392}
1393
1394static bool isExpansion(const CountedRegion &R, unsigned FileID) {
1395 return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
1396}
1397
1399 CoverageData FileCoverage(Filename);
1400 std::vector<CountedRegion> Regions;
1401
1402 // Look up the function records in the given file. Due to hash collisions on
1403 // the filename, we may get back some records that are not in the file.
1404 ArrayRef<unsigned> RecordIndices =
1405 getImpreciseRecordIndicesForFilename(Filename);
1406 for (unsigned RecordIndex : RecordIndices) {
1407 const FunctionRecord &Function = Functions[RecordIndex];
1408 auto MainFileID = findMainViewFileID(Filename, Function);
1409 auto FileIDs = gatherFileIDs(Filename, Function);
1410 for (const auto &CR : Function.CountedRegions)
1411 if (FileIDs.test(CR.FileID)) {
1412 Regions.push_back(CR);
1413 if (MainFileID && isExpansion(CR, *MainFileID))
1414 FileCoverage.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 (FileIDs.test(CR.FileID) && (CR.FileID == CR.ExpandedFileID))
1419 FileCoverage.BranchRegions.push_back(CR);
1420 // Capture MCDC records specific to the function.
1421 for (const auto &MR : Function.MCDCRecords)
1422 if (FileIDs.test(MR.getDecisionRegion().FileID))
1423 FileCoverage.MCDCRecords.push_back(MR);
1424 }
1425
1426 LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
1427 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1428
1429 return FileCoverage;
1430}
1431
1432std::vector<InstantiationGroup>
1434 FunctionInstantiationSetCollector InstantiationSetCollector;
1435 // Look up the function records in the given file. Due to hash collisions on
1436 // the filename, we may get back some records that are not in the file.
1437 ArrayRef<unsigned> RecordIndices =
1438 getImpreciseRecordIndicesForFilename(Filename);
1439 for (unsigned RecordIndex : RecordIndices) {
1440 const FunctionRecord &Function = Functions[RecordIndex];
1441 auto MainFileID = findMainViewFileID(Filename, Function);
1442 if (!MainFileID)
1443 continue;
1444 InstantiationSetCollector.insert(Function, *MainFileID);
1445 }
1446
1447 std::vector<InstantiationGroup> Result;
1448 for (auto &InstantiationSet : InstantiationSetCollector) {
1449 InstantiationGroup IG{InstantiationSet.first.first,
1450 InstantiationSet.first.second,
1451 std::move(InstantiationSet.second)};
1452 Result.emplace_back(std::move(IG));
1453 }
1454 return Result;
1455}
1456
1459 auto MainFileID = findMainViewFileID(Function);
1460 if (!MainFileID)
1461 return CoverageData();
1462
1463 CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
1464 std::vector<CountedRegion> Regions;
1465 for (const auto &CR : Function.CountedRegions)
1466 if (CR.FileID == *MainFileID) {
1467 Regions.push_back(CR);
1468 if (isExpansion(CR, *MainFileID))
1469 FunctionCoverage.Expansions.emplace_back(CR, Function);
1470 }
1471 // Capture branch regions specific to the function (excluding expansions).
1472 for (const auto &CR : Function.CountedBranchRegions)
1473 if (CR.FileID == *MainFileID)
1474 FunctionCoverage.BranchRegions.push_back(CR);
1475
1476 // Capture MCDC records specific to the function.
1477 for (const auto &MR : Function.MCDCRecords)
1478 if (MR.getDecisionRegion().FileID == *MainFileID)
1479 FunctionCoverage.MCDCRecords.push_back(MR);
1480
1481 LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
1482 << "\n");
1483 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1484
1485 return FunctionCoverage;
1486}
1487
1489 const ExpansionRecord &Expansion) const {
1490 CoverageData ExpansionCoverage(
1491 Expansion.Function.Filenames[Expansion.FileID]);
1492 std::vector<CountedRegion> Regions;
1493 for (const auto &CR : Expansion.Function.CountedRegions)
1494 if (CR.FileID == Expansion.FileID) {
1495 Regions.push_back(CR);
1496 if (isExpansion(CR, Expansion.FileID))
1497 ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
1498 }
1499 for (const auto &CR : Expansion.Function.CountedBranchRegions)
1500 // Capture branch regions that only pertain to the corresponding expansion.
1501 if (CR.FileID == Expansion.FileID)
1502 ExpansionCoverage.BranchRegions.push_back(CR);
1503
1504 LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
1505 << Expansion.FileID << "\n");
1506 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1507
1508 return ExpansionCoverage;
1509}
1510
1511LineCoverageStats::LineCoverageStats(
1513 const CoverageSegment *WrappedSegment, unsigned Line)
1514 : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
1515 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1516 // Find the minimum number of regions which start in this line.
1517 unsigned MinRegionCount = 0;
1518 auto isStartOfRegion = [](const CoverageSegment *S) {
1519 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1520 };
1521 for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
1522 if (isStartOfRegion(LineSegments[I]))
1523 ++MinRegionCount;
1524
1525 bool StartOfSkippedRegion = !LineSegments.empty() &&
1526 !LineSegments.front()->HasCount &&
1527 LineSegments.front()->IsRegionEntry;
1528
1529 HasMultipleRegions = MinRegionCount > 1;
1530 Mapped =
1531 !StartOfSkippedRegion &&
1532 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1533
1534 // if there is any starting segment at this line with a counter, it must be
1535 // mapped
1536 Mapped |= any_of(LineSegments, [](const auto *Seq) {
1537 return Seq->IsRegionEntry && Seq->HasCount;
1538 });
1539
1540 if (!Mapped) {
1541 return;
1542 }
1543
1544 // Pick the max count from the non-gap, region entry segments and the
1545 // wrapped count.
1546 if (WrappedSegment)
1547 ExecutionCount = WrappedSegment->Count;
1548 if (!MinRegionCount)
1549 return;
1550 for (const auto *LS : LineSegments)
1551 if (isStartOfRegion(LS))
1552 ExecutionCount = std::max(ExecutionCount, LS->Count);
1553}
1554
1556 if (Next == CD.end()) {
1557 Stats = LineCoverageStats();
1558 Ended = true;
1559 return *this;
1560 }
1561 if (Segments.size())
1562 WrappedSegment = Segments.back();
1563 Segments.clear();
1564 while (Next != CD.end() && Next->Line == Line)
1565 Segments.push_back(&*Next++);
1566 Stats = LineCoverageStats(Segments, WrappedSegment, Line);
1567 ++Line;
1568 return *this;
1569}
1570
1572 const std::string &ErrMsg = "") {
1573 std::string Msg;
1575
1576 switch (Err) {
1578 OS << "success";
1579 break;
1581 OS << "end of File";
1582 break;
1584 OS << "no coverage data found";
1585 break;
1587 OS << "unsupported coverage format version";
1588 break;
1590 OS << "truncated coverage data";
1591 break;
1593 OS << "malformed coverage data";
1594 break;
1596 OS << "failed to decompress coverage data (zlib)";
1597 break;
1599 OS << "`-arch` specifier is invalid or missing for universal binary";
1600 break;
1601 }
1602
1603 // If optional error message is not empty, append it to the message.
1604 if (!ErrMsg.empty())
1605 OS << ": " << ErrMsg;
1606
1607 return Msg;
1608}
1609
1610namespace {
1611
1612// FIXME: This class is only here to support the transition to llvm::Error. It
1613// will be removed once this transition is complete. Clients should prefer to
1614// deal with the Error value directly, rather than converting to error_code.
1615class CoverageMappingErrorCategoryType : public std::error_category {
1616 const char *name() const noexcept override { return "llvm.coveragemap"; }
1617 std::string message(int IE) const override {
1618 return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
1619 }
1620};
1621
1622} // end anonymous namespace
1623
1624std::string CoverageMapError::message() const {
1625 return getCoverageMapErrString(Err, Msg);
1626}
1627
1628const std::error_category &llvm::coverage::coveragemap_category() {
1629 static CoverageMappingErrorCategoryType ErrorCategory;
1630 return ErrorCategory;
1631}
1632
1633char CoverageMapError::ID = 0;
aarch64 promote const
This file declares a library for handling Build IDs and using them to find debug info.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-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
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(X)
Definition: Debug.h:101
This file defines the DenseMap class.
bool End
Definition: ELF_riscv.cpp:480
hexagon bit simplify
#define I(x, y, z)
Definition: MD5.cpp:58
if(PassOpts->AAPipeline)
static bool dominates(InstrPosIndexes &PosIndexes, const MachineInstr &A, const MachineInstr &B)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static const char * name
Definition: SMEABIPass.cpp:50
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This file implements the SmallBitVector class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
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:41
const T & front() const
front - Get the first element.
Definition: ArrayRef.h:168
iterator end() const
Definition: ArrayRef.h:154
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
iterator begin() const
Definition: ArrayRef.h:153
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:160
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:211
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
Error takeError()
Take ownership of the stored error.
Definition: Error.h:608
iterator begin()
Definition: Function.h:851
size_t size() const
Definition: Function.h:856
iterator end()
Definition: Function.h:853
Reader for the indexed binary instrprof format.
uint64_t getVersion() const override
Return the profile version.
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const Twine &RemappingPath="")
Factory method to create an indexed reader.
Error getFunctionBitmap(StringRef FuncName, uint64_t FuncHash, BitVector &Bitmap)
Fill Bitmap with the profile data for the given function name.
bool hasSingleByteCoverage() const override
Return true if the profile has single byte counters representing coverage.
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector< uint64_t > &Counts)
Fill Counts with the profile data for the given function name.
Error readBinaryIds(std::vector< llvm::object::BuildID > &BinaryIds) override
Read a list of binary ids.
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:419
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:307
iterator end() const
Definition: ArrayRef.h:357
iterator begin() const
Definition: ArrayRef.h:356
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.
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:950
iterator erase(const_iterator CI)
Definition: SmallVector.h:750
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:696
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:818
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
LLVM Value Representation.
Definition: Value.h:74
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)
Counter subtract(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that subtracts RHS from LHS.
Counter add(Counter LHS, Counter RHS, bool Simplify=true)
Return a counter that represents the expression that adds LHS and RHS.
A Counter mapping context is used to connect the counters, expressions and the obtained counter value...
Expected< MCDCRecord > evaluateMCDCRegion(const CounterMappingRegion &Region, ArrayRef< const CounterMappingRegion * > Branches, bool IsVersion11)
Return an MCDC record that indicates executed test vectors and condition pairs.
Expected< int64_t > evaluate(const Counter &C) const
Return the number of times that a region of code associated with this counter was executed.
unsigned getMaxCounterID(const Counter &C) const
void dump(const Counter &C, raw_ostream &OS) const
Coverage information to be processed or displayed.
std::vector< CoverageSegment >::const_iterator end() const
std::string message() const override
Return the error message as a string.
coveragemap_error get() const
const std::string & getMessage() const
The mapping of profile information to coverage data.
std::vector< StringRef > getUniqueSourceFiles() const
Returns a lexicographically sorted, unique list of files that are covered.
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const
Get the coverage for an expansion within a coverage set.
CoverageData getCoverageForFunction(const FunctionRecord &Function) const
Get the coverage for a particular function.
std::vector< InstantiationGroup > getInstantiationGroups(StringRef Filename) const
Get the list of function instantiation groups in a particular file.
CoverageData getCoverageForFile(StringRef Filename) const
Get the coverage for a particular file.
static Expected< std::unique_ptr< CoverageMapping > > load(ArrayRef< std::unique_ptr< CoverageMappingReader > > CoverageReaders, IndexedInstrProfReader &ProfileReader)
Load the coverage mapping using the given readers.
Iterator over Functions, optionally filtered to a single file.
An instantiation group contains a FunctionRecord list, such that each record corresponds to a distinc...
An iterator over the LineCoverageStats objects for lines described by a CoverageData instance.
Coverage statistics for a single line.
Emulate SmallVector<CondState> with a pair of BitVector.
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.
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:206
size_type size() const
Definition: DenseSet.h:81
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition: DenseSet.h:185
BuildIDFetcher searches local cache directories for debug info.
Definition: BuildID.h:39
virtual std::optional< std::string > fetch(BuildIDRef BuildID) const
Returns the path to the debug file with the given build ID.
Definition: BuildID.cpp:68
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
The virtual file system interface.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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
int16_t ConditionID
The ID for MCDCBranch.
Definition: MCDCTypes.h:24
std::array< ConditionID, 2 > ConditionIDs
Definition: MCDCTypes.h:25
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:25
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
hash_code hash_value(const FixedPointSemantics &Val)
Definition: APFixedPoint.h:127
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition: Error.h:1380
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:1680
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:2431
StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName="<unknown>")
Given a PGO function name, remove the filename prefix and return the original (static) function name.
Definition: InstrProf.cpp:410
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Definition: Error.h:954
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition: STLExtras.h:2098
auto unique(Range &&R, Predicate P)
Definition: STLExtras.h:2038
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1286
auto map_range(ContainerTy &&C, FuncTy F)
Definition: STLExtras.h:377
@ no_such_file_or_directory
@ argument_out_of_domain
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:1729
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:419
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1647
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
instrprof_error
Definition: InstrProf.h:348
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:111
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1069
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition: Hashing.h:471
#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.
bool HasCount
When false, the segment was uninstrumented or skipped.
uint64_t Count
The execution count, or zero if no count was recorded.
bool IsGapRegion
Whether this enters a gap region.
Coverage information for a macro expansion or #included file.
Code coverage information for a single function.
MCDC Record grouping all information together.
unsigned BitmapIdx
Byte Index of Bitmap Coverage Object for a Decision Region.
Definition: MCDCTypes.h:29
uint16_t NumConditions
Number of Conditions used for a Decision Region.
Definition: MCDCTypes.h:32