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