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