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{{BitVector(NumConditions), BitVector(NumConditions)}},
396 IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false]),
397 IsVersion11(IsVersion11) {}
398
399private:
400 // Walk the binary decision diagram and try assigning both false and true to
401 // each node. When a terminal node (ID == 0) is reached, fill in the value in
402 // the truth table.
403 void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
404 int TVIdx) {
405 for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
406 static_assert(MCDCRecord::MCDC_False == 0);
407 static_assert(MCDCRecord::MCDC_True == 1);
408 TV.set(ID, MCDCCond);
409 auto NextID = NextIDs[ID][MCDCCond];
410 auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
411 assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
412 if (NextID >= 0) {
413 buildTestVector(TV, NextID, NextTVIdx);
414 continue;
415 }
416
417 assert(TVIdx < SavedNodes[ID].Width);
418 assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx");
419
420 if (!Bitmap[IsVersion11
421 ? DecisionParams.BitmapIdx * CHAR_BIT + TV.getIndex()
422 : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx])
423 continue;
424
425 // Copy the completed test vector to the vector of testvectors.
426 // The final value (T,F) is equal to the last non-dontcare state on the
427 // path (in a short-circuiting system).
428 ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
429 }
430
431 // Reset back to DontCare.
433 }
434
435 /// Walk the bits in the bitmap. A bit set to '1' indicates that the test
436 /// vector at the corresponding index was executed during a test run.
437 void findExecutedTestVectors() {
438 // Walk the binary decision diagram to enumerate all possible test vectors.
439 // We start at the root node (ID == 0) with all values being DontCare.
440 // `TVIdx` starts with 0 and is in the traversal.
441 // `Index` encodes the bitmask of true values and is initially 0.
442 MCDCRecord::TestVector TV(NumConditions);
443 buildTestVector(TV, 0, 0);
444 assert(TVIdxs.size() == unsigned(NumTestVectors) &&
445 "TVIdxs wasn't fulfilled");
446
447 // Fill ExecVectors order by False items and True items.
448 // ExecVectors is the alias of ExecVectorsByCond[false], so
449 // Append ExecVectorsByCond[true] on it.
450 NumExecVectorsF = ExecVectors.size();
451 auto &ExecVectorsT = ExecVectorsByCond[true];
452 ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
453 std::make_move_iterator(ExecVectorsT.end()));
454 }
455
456 // Find an independence pair for each condition:
457 // - The condition is true in one test and false in the other.
458 // - The decision outcome is true one test and false in the other.
459 // - All other conditions' values must be equal or marked as "don't care".
460 void findIndependencePairs() {
461 unsigned NumTVs = ExecVectors.size();
462 for (unsigned I = NumExecVectorsF; I < NumTVs; ++I) {
463 const auto &[A, ACond] = ExecVectors[I];
465 for (unsigned J = 0; J < NumExecVectorsF; ++J) {
466 const auto &[B, BCond] = ExecVectors[J];
468 // If the two vectors differ in exactly one condition, ignoring DontCare
469 // conditions, we have found an independence pair.
470 auto AB = A.getDifferences(B);
471 if (AB.count() == 1)
472 IndependencePairs.insert(
473 {AB.find_first(), std::make_pair(J + 1, I + 1)});
474 }
475 }
476 }
477
478public:
479 /// Process the MC/DC Record in order to produce a result for a boolean
480 /// expression. This process includes tracking the conditions that comprise
481 /// the decision region, calculating the list of all possible test vectors,
482 /// marking the executed test vectors, and then finding an Independence Pair
483 /// out of the executed test vectors for each condition in the boolean
484 /// expression. A condition is tracked to ensure that its ID can be mapped to
485 /// its ordinal position in the boolean expression. The condition's source
486 /// location is also tracked, as well as whether it is constant folded (in
487 /// which case it is excuded from the metric).
488 MCDCRecord processMCDCRecord() {
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 (auto [I, B] : enumerate(Branches)) {
503 const auto &BranchParams = B->getBranchParams();
504 PosToID[I] = BranchParams.ID;
505 CondLoc[I] = B->startLoc();
506 Folded[false][I] = B->FalseCount.isZero();
507 Folded[true][I] = B->Count.isZero();
508 }
509
510 // Using Profile Bitmap from runtime, mark the executed test vectors.
511 findExecutedTestVectors();
512
513 // Compare executed test vectors against each other to find an independence
514 // pairs for each condition. This processing takes the most time.
515 findIndependencePairs();
516
517 // Record Test vectors, executed vectors, and independence pairs.
518 return MCDCRecord(Region, std::move(ExecVectors),
519 std::move(IndependencePairs), std::move(Folded),
520 std::move(PosToID), std::move(CondLoc));
521 }
522};
523
524} // namespace
525
528 ArrayRef<const CounterMappingRegion *> Branches, bool IsVersion11) {
529
530 MCDCRecordProcessor MCDCProcessor(Bitmap, Region, Branches, IsVersion11);
531 return MCDCProcessor.processMCDCRecord();
532}
533
535 struct StackElem {
536 Counter ICounter;
537 int64_t LHS = 0;
538 enum {
539 KNeverVisited = 0,
540 KVisitedOnce = 1,
541 KVisitedTwice = 2,
542 } VisitCount = KNeverVisited;
543 };
544
545 std::stack<StackElem> CounterStack;
546 CounterStack.push({C});
547
548 int64_t LastPoppedValue;
549
550 while (!CounterStack.empty()) {
551 StackElem &Current = CounterStack.top();
552
553 switch (Current.ICounter.getKind()) {
554 case Counter::Zero:
555 LastPoppedValue = 0;
556 CounterStack.pop();
557 break;
559 LastPoppedValue = Current.ICounter.getCounterID();
560 CounterStack.pop();
561 break;
562 case Counter::Expression: {
563 if (Current.ICounter.getExpressionID() >= Expressions.size()) {
564 LastPoppedValue = 0;
565 CounterStack.pop();
566 } else {
567 const auto &E = Expressions[Current.ICounter.getExpressionID()];
568 if (Current.VisitCount == StackElem::KNeverVisited) {
569 CounterStack.push(StackElem{E.LHS});
570 Current.VisitCount = StackElem::KVisitedOnce;
571 } else if (Current.VisitCount == StackElem::KVisitedOnce) {
572 Current.LHS = LastPoppedValue;
573 CounterStack.push(StackElem{E.RHS});
574 Current.VisitCount = StackElem::KVisitedTwice;
575 } else {
576 int64_t LHS = Current.LHS;
577 int64_t RHS = LastPoppedValue;
578 LastPoppedValue = std::max(LHS, RHS);
579 CounterStack.pop();
580 }
581 }
582 break;
583 }
584 }
585 }
586
587 return LastPoppedValue;
588}
589
590void FunctionRecordIterator::skipOtherFiles() {
591 while (Current != Records.end() && !Filename.empty() &&
592 Filename != Current->Filenames[0])
593 ++Current;
594 if (Current == Records.end())
595 *this = FunctionRecordIterator();
596}
597
598ArrayRef<unsigned> CoverageMapping::getImpreciseRecordIndicesForFilename(
599 StringRef Filename) const {
600 size_t FilenameHash = hash_value(Filename);
601 auto RecordIt = FilenameHash2RecordIndices.find(FilenameHash);
602 if (RecordIt == FilenameHash2RecordIndices.end())
603 return {};
604 return RecordIt->second;
605}
606
607static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
609 unsigned MaxCounterID = 0;
610 for (const auto &Region : Record.MappingRegions) {
611 MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
612 }
613 return MaxCounterID;
614}
615
616/// Returns the bit count
618 bool IsVersion11) {
619 unsigned MaxBitmapIdx = 0;
620 unsigned NumConditions = 0;
621 // Scan max(BitmapIdx).
622 // Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
623 // and `MaxBitmapIdx is `unsigned`. `BitmapIdx` is unique in the record.
624 for (const auto &Region : reverse(Record.MappingRegions)) {
626 continue;
627 const auto &DecisionParams = Region.getDecisionParams();
628 if (MaxBitmapIdx <= DecisionParams.BitmapIdx) {
629 MaxBitmapIdx = DecisionParams.BitmapIdx;
630 NumConditions = DecisionParams.NumConditions;
631 }
632 }
633
634 if (IsVersion11)
635 MaxBitmapIdx = MaxBitmapIdx * CHAR_BIT +
636 llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
637
638 return MaxBitmapIdx;
639}
640
641namespace {
642
643/// Collect Decisions, Branchs, and Expansions and associate them.
644class MCDCDecisionRecorder {
645private:
646 /// This holds the DecisionRegion and MCDCBranches under it.
647 /// Also traverses Expansion(s).
648 /// The Decision has the number of MCDCBranches and will complete
649 /// when it is filled with unique ConditionID of MCDCBranches.
650 struct DecisionRecord {
651 const CounterMappingRegion *DecisionRegion;
652
653 /// They are reflected from DecisionRegion for convenience.
654 mcdc::DecisionParameters DecisionParams;
655 LineColPair DecisionStartLoc;
656 LineColPair DecisionEndLoc;
657
658 /// This is passed to `MCDCRecordProcessor`, so this should be compatible
659 /// to`ArrayRef<const CounterMappingRegion *>`.
661
662 /// IDs that are stored in MCDCBranches
663 /// Complete when all IDs (1 to NumConditions) are met.
665
666 /// Set of IDs of Expansion(s) that are relevant to DecisionRegion
667 /// and its children (via expansions).
668 /// FileID pointed by ExpandedFileID is dedicated to the expansion, so
669 /// the location in the expansion doesn't matter.
670 DenseSet<unsigned> ExpandedFileIDs;
671
672 DecisionRecord(const CounterMappingRegion &Decision)
673 : DecisionRegion(&Decision),
674 DecisionParams(Decision.getDecisionParams()),
675 DecisionStartLoc(Decision.startLoc()),
676 DecisionEndLoc(Decision.endLoc()) {
678 }
679
680 /// Determine whether DecisionRecord dominates `R`.
681 bool dominates(const CounterMappingRegion &R) const {
682 // Determine whether `R` is included in `DecisionRegion`.
683 if (R.FileID == DecisionRegion->FileID &&
684 R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc)
685 return true;
686
687 // Determine whether `R` is pointed by any of Expansions.
688 return ExpandedFileIDs.contains(R.FileID);
689 }
690
691 enum Result {
692 NotProcessed = 0, /// Irrelevant to this Decision
693 Processed, /// Added to this Decision
694 Completed, /// Added and filled this Decision
695 };
696
697 /// Add Branch into the Decision
698 /// \param Branch expects MCDCBranchRegion
699 /// \returns NotProcessed/Processed/Completed
700 Result addBranch(const CounterMappingRegion &Branch) {
702
703 auto ConditionID = Branch.getBranchParams().ID;
704
705 if (ConditionIDs.contains(ConditionID) ||
706 ConditionID >= DecisionParams.NumConditions)
707 return NotProcessed;
708
709 if (!this->dominates(Branch))
710 return NotProcessed;
711
712 assert(MCDCBranches.size() < DecisionParams.NumConditions);
713
714 // Put `ID=0` in front of `MCDCBranches` for convenience
715 // even if `MCDCBranches` is not topological.
716 if (ConditionID == 0)
717 MCDCBranches.insert(MCDCBranches.begin(), &Branch);
718 else
719 MCDCBranches.push_back(&Branch);
720
721 // Mark `ID` as `assigned`.
722 ConditionIDs.insert(ConditionID);
723
724 // `Completed` when `MCDCBranches` is full
725 return (MCDCBranches.size() == DecisionParams.NumConditions ? Completed
726 : Processed);
727 }
728
729 /// Record Expansion if it is relevant to this Decision.
730 /// Each `Expansion` may nest.
731 /// \returns true if recorded.
732 bool recordExpansion(const CounterMappingRegion &Expansion) {
733 if (!this->dominates(Expansion))
734 return false;
735
736 ExpandedFileIDs.insert(Expansion.ExpandedFileID);
737 return true;
738 }
739 };
740
741private:
742 /// Decisions in progress
743 /// DecisionRecord is added for each MCDCDecisionRegion.
744 /// DecisionRecord is removed when Decision is completed.
746
747public:
748 ~MCDCDecisionRecorder() {
749 assert(Decisions.empty() && "All Decisions have not been resolved");
750 }
751
752 /// Register Region and start recording.
753 void registerDecision(const CounterMappingRegion &Decision) {
754 Decisions.emplace_back(Decision);
755 }
756
757 void recordExpansion(const CounterMappingRegion &Expansion) {
758 any_of(Decisions, [&Expansion](auto &Decision) {
759 return Decision.recordExpansion(Expansion);
760 });
761 }
762
763 using DecisionAndBranches =
764 std::pair<const CounterMappingRegion *, /// Decision
766 >;
767
768 /// Add MCDCBranchRegion to DecisionRecord.
769 /// \param Branch to be processed
770 /// \returns DecisionsAndBranches if DecisionRecord completed.
771 /// Or returns nullopt.
772 std::optional<DecisionAndBranches>
773 processBranch(const CounterMappingRegion &Branch) {
774 // Seek each Decision and apply Region to it.
775 for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end();
776 DecisionIter != DecisionEnd; ++DecisionIter)
777 switch (DecisionIter->addBranch(Branch)) {
778 case DecisionRecord::NotProcessed:
779 continue;
780 case DecisionRecord::Processed:
781 return std::nullopt;
782 case DecisionRecord::Completed:
783 DecisionAndBranches Result =
784 std::make_pair(DecisionIter->DecisionRegion,
785 std::move(DecisionIter->MCDCBranches));
786 Decisions.erase(DecisionIter); // No longer used.
787 return Result;
788 }
789
790 llvm_unreachable("Branch not found in Decisions");
791 }
792};
793
794} // namespace
795
796Error CoverageMapping::loadFunctionRecord(
798 IndexedInstrProfReader &ProfileReader) {
799 StringRef OrigFuncName = Record.FunctionName;
800 if (OrigFuncName.empty())
801 return make_error<CoverageMapError>(coveragemap_error::malformed,
802 "record function name is empty");
803
804 if (Record.Filenames.empty())
805 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
806 else
807 OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
808
809 CounterMappingContext Ctx(Record.Expressions);
810
811 std::vector<uint64_t> Counts;
812 if (Error E = ProfileReader.getFunctionCounts(Record.FunctionName,
813 Record.FunctionHash, Counts)) {
814 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
816 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
817 Record.FunctionHash);
818 return Error::success();
819 }
821 return make_error<InstrProfError>(IPE);
822 Counts.assign(getMaxCounterID(Ctx, Record) + 1, 0);
823 }
824 Ctx.setCounts(Counts);
825
826 bool IsVersion11 =
828
829 BitVector Bitmap;
830 if (Error E = ProfileReader.getFunctionBitmap(Record.FunctionName,
831 Record.FunctionHash, Bitmap)) {
832 instrprof_error IPE = std::get<0>(InstrProfError::take(std::move(E)));
834 FuncHashMismatches.emplace_back(std::string(Record.FunctionName),
835 Record.FunctionHash);
836 return Error::success();
837 }
839 return make_error<InstrProfError>(IPE);
840 Bitmap = BitVector(getMaxBitmapSize(Record, IsVersion11));
841 }
842 Ctx.setBitmap(std::move(Bitmap));
843
844 assert(!Record.MappingRegions.empty() && "Function has no regions");
845
846 // This coverage record is a zero region for a function that's unused in
847 // some TU, but used in a different TU. Ignore it. The coverage maps from the
848 // the other TU will either be loaded (providing full region counts) or they
849 // won't (in which case we don't unintuitively report functions as uncovered
850 // when they have non-zero counts in the profile).
851 if (Record.MappingRegions.size() == 1 &&
852 Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
853 return Error::success();
854
855 MCDCDecisionRecorder MCDCDecisions;
856 FunctionRecord Function(OrigFuncName, Record.Filenames);
857 for (const auto &Region : Record.MappingRegions) {
858 // MCDCDecisionRegion should be handled first since it overlaps with
859 // others inside.
861 MCDCDecisions.registerDecision(Region);
862 continue;
863 }
864 Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
865 if (auto E = ExecutionCount.takeError()) {
866 consumeError(std::move(E));
867 return Error::success();
868 }
869 Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
870 if (auto E = AltExecutionCount.takeError()) {
871 consumeError(std::move(E));
872 return Error::success();
873 }
874 Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
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 assert(!Coverage.SingleByteCoverage ||
937 *Coverage.SingleByteCoverage == ProfileReader.hasSingleByteCoverage());
938 Coverage.SingleByteCoverage = ProfileReader.hasSingleByteCoverage();
939 for (const auto &CoverageReader : CoverageReaders) {
940 for (auto RecordOrErr : *CoverageReader) {
941 if (Error E = RecordOrErr.takeError())
942 return E;
943 const auto &Record = *RecordOrErr;
944 if (Error E = Coverage.loadFunctionRecord(Record, ProfileReader))
945 return E;
946 }
947 }
948 return Error::success();
949}
950
952 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
953 IndexedInstrProfReader &ProfileReader) {
954 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
955 if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
956 return std::move(E);
957 return std::move(Coverage);
958}
959
960// If E is a no_data_found error, returns success. Otherwise returns E.
962 return handleErrors(
963 std::move(E), [](const CoverageMapError &CME) {
965 return static_cast<Error>(Error::success());
966 return make_error<CoverageMapError>(CME.get(), CME.getMessage());
967 });
968}
969
970Error CoverageMapping::loadFromFile(
971 StringRef Filename, StringRef Arch, StringRef CompilationDir,
972 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
973 bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
974 auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
975 Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
976 if (std::error_code EC = CovMappingBufOrErr.getError())
977 return createFileError(Filename, errorCodeToError(EC));
978 MemoryBufferRef CovMappingBufRef =
979 CovMappingBufOrErr.get()->getMemBufferRef();
981
983 auto CoverageReadersOrErr = BinaryCoverageReader::create(
984 CovMappingBufRef, Arch, Buffers, CompilationDir,
985 FoundBinaryIDs ? &BinaryIDs : nullptr);
986 if (Error E = CoverageReadersOrErr.takeError()) {
987 E = handleMaybeNoDataFoundError(std::move(E));
988 if (E)
989 return createFileError(Filename, std::move(E));
990 return E;
991 }
992
994 for (auto &Reader : CoverageReadersOrErr.get())
995 Readers.push_back(std::move(Reader));
996 if (FoundBinaryIDs && !Readers.empty()) {
997 llvm::append_range(*FoundBinaryIDs,
998 llvm::map_range(BinaryIDs, [](object::BuildIDRef BID) {
999 return object::BuildID(BID);
1000 }));
1001 }
1002 DataFound |= !Readers.empty();
1003 if (Error E = loadFromReaders(Readers, ProfileReader, Coverage))
1004 return createFileError(Filename, std::move(E));
1005 return Error::success();
1006}
1007
1009 ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
1010 vfs::FileSystem &FS, ArrayRef<StringRef> Arches, StringRef CompilationDir,
1011 const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
1012 auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS);
1013 if (Error E = ProfileReaderOrErr.takeError())
1014 return createFileError(ProfileFilename, std::move(E));
1015 auto ProfileReader = std::move(ProfileReaderOrErr.get());
1016 auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
1017 bool DataFound = false;
1018
1019 auto GetArch = [&](size_t Idx) {
1020 if (Arches.empty())
1021 return StringRef();
1022 if (Arches.size() == 1)
1023 return Arches.front();
1024 return Arches[Idx];
1025 };
1026
1027 SmallVector<object::BuildID> FoundBinaryIDs;
1028 for (const auto &File : llvm::enumerate(ObjectFilenames)) {
1029 if (Error E =
1030 loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
1031 *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
1032 return std::move(E);
1033 }
1034
1035 if (BIDFetcher) {
1036 std::vector<object::BuildID> ProfileBinaryIDs;
1037 if (Error E = ProfileReader->readBinaryIds(ProfileBinaryIDs))
1038 return createFileError(ProfileFilename, std::move(E));
1039
1040 SmallVector<object::BuildIDRef> BinaryIDsToFetch;
1041 if (!ProfileBinaryIDs.empty()) {
1042 const auto &Compare = [](object::BuildIDRef A, object::BuildIDRef B) {
1043 return std::lexicographical_compare(A.begin(), A.end(), B.begin(),
1044 B.end());
1045 };
1046 llvm::sort(FoundBinaryIDs, Compare);
1047 std::set_difference(
1048 ProfileBinaryIDs.begin(), ProfileBinaryIDs.end(),
1049 FoundBinaryIDs.begin(), FoundBinaryIDs.end(),
1050 std::inserter(BinaryIDsToFetch, BinaryIDsToFetch.end()), Compare);
1051 }
1052
1053 for (object::BuildIDRef BinaryID : BinaryIDsToFetch) {
1054 std::optional<std::string> PathOpt = BIDFetcher->fetch(BinaryID);
1055 if (PathOpt) {
1056 std::string Path = std::move(*PathOpt);
1057 StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
1058 if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
1059 *Coverage, DataFound))
1060 return std::move(E);
1061 } else if (CheckBinaryIDs) {
1062 return createFileError(
1063 ProfileFilename,
1065 "Missing binary ID: " +
1066 llvm::toHex(BinaryID, /*LowerCase=*/true)));
1067 }
1068 }
1069 }
1070
1071 if (!DataFound)
1072 return createFileError(
1073 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "),
1074 make_error<CoverageMapError>(coveragemap_error::no_data_found));
1075 return std::move(Coverage);
1076}
1077
1078namespace {
1079
1080/// Distributes functions into instantiation sets.
1081///
1082/// An instantiation set is a collection of functions that have the same source
1083/// code, ie, template functions specializations.
1084class FunctionInstantiationSetCollector {
1085 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
1086 MapT InstantiatedFunctions;
1087
1088public:
1089 void insert(const FunctionRecord &Function, unsigned FileID) {
1090 auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
1091 while (I != E && I->FileID != FileID)
1092 ++I;
1093 assert(I != E && "function does not cover the given file");
1094 auto &Functions = InstantiatedFunctions[I->startLoc()];
1095 Functions.push_back(&Function);
1096 }
1097
1098 MapT::iterator begin() { return InstantiatedFunctions.begin(); }
1099 MapT::iterator end() { return InstantiatedFunctions.end(); }
1100};
1101
1102class SegmentBuilder {
1103 std::vector<CoverageSegment> &Segments;
1105
1106 SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
1107
1108 /// Emit a segment with the count from \p Region starting at \p StartLoc.
1109 //
1110 /// \p IsRegionEntry: The segment is at the start of a new non-gap region.
1111 /// \p EmitSkippedRegion: The segment must be emitted as a skipped region.
1112 void startSegment(const CountedRegion &Region, LineColPair StartLoc,
1113 bool IsRegionEntry, bool EmitSkippedRegion = false) {
1114 bool HasCount = !EmitSkippedRegion &&
1116
1117 // If the new segment wouldn't affect coverage rendering, skip it.
1118 if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
1119 const auto &Last = Segments.back();
1120 if (Last.HasCount == HasCount && Last.Count == Region.ExecutionCount &&
1121 !Last.IsRegionEntry)
1122 return;
1123 }
1124
1125 if (HasCount)
1126 Segments.emplace_back(StartLoc.first, StartLoc.second,
1127 Region.ExecutionCount, IsRegionEntry,
1129 else
1130 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
1131
1132 LLVM_DEBUG({
1133 const auto &Last = Segments.back();
1134 dbgs() << "Segment at " << Last.Line << ":" << Last.Col
1135 << " (count = " << Last.Count << ")"
1136 << (Last.IsRegionEntry ? ", RegionEntry" : "")
1137 << (!Last.HasCount ? ", Skipped" : "")
1138 << (Last.IsGapRegion ? ", Gap" : "") << "\n";
1139 });
1140 }
1141
1142 /// Emit segments for active regions which end before \p Loc.
1143 ///
1144 /// \p Loc: The start location of the next region. If std::nullopt, all active
1145 /// regions are completed.
1146 /// \p FirstCompletedRegion: Index of the first completed region.
1147 void completeRegionsUntil(std::optional<LineColPair> Loc,
1148 unsigned FirstCompletedRegion) {
1149 // Sort the completed regions by end location. This makes it simple to
1150 // emit closing segments in sorted order.
1151 auto CompletedRegionsIt = ActiveRegions.begin() + FirstCompletedRegion;
1152 std::stable_sort(CompletedRegionsIt, ActiveRegions.end(),
1153 [](const CountedRegion *L, const CountedRegion *R) {
1154 return L->endLoc() < R->endLoc();
1155 });
1156
1157 // Emit segments for all completed regions.
1158 for (unsigned I = FirstCompletedRegion + 1, E = ActiveRegions.size(); I < E;
1159 ++I) {
1160 const auto *CompletedRegion = ActiveRegions[I];
1161 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
1162 "Completed region ends after start of new region");
1163
1164 const auto *PrevCompletedRegion = ActiveRegions[I - 1];
1165 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
1166
1167 // Don't emit any more segments if they start where the new region begins.
1168 if (Loc && CompletedSegmentLoc == *Loc)
1169 break;
1170
1171 // Don't emit a segment if the next completed region ends at the same
1172 // location as this one.
1173 if (CompletedSegmentLoc == CompletedRegion->endLoc())
1174 continue;
1175
1176 // Use the count from the last completed region which ends at this loc.
1177 for (unsigned J = I + 1; J < E; ++J)
1178 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
1179 CompletedRegion = ActiveRegions[J];
1180
1181 startSegment(*CompletedRegion, CompletedSegmentLoc, false);
1182 }
1183
1184 auto Last = ActiveRegions.back();
1185 if (FirstCompletedRegion && Last->endLoc() != *Loc) {
1186 // If there's a gap after the end of the last completed region and the
1187 // start of the new region, use the last active region to fill the gap.
1188 startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
1189 false);
1190 } else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
1191 // Emit a skipped segment if there are no more active regions. This
1192 // ensures that gaps between functions are marked correctly.
1193 startSegment(*Last, Last->endLoc(), false, true);
1194 }
1195
1196 // Pop the completed regions.
1197 ActiveRegions.erase(CompletedRegionsIt, ActiveRegions.end());
1198 }
1199
1200 void buildSegmentsImpl(ArrayRef<CountedRegion> Regions) {
1201 for (const auto &CR : enumerate(Regions)) {
1202 auto CurStartLoc = CR.value().startLoc();
1203
1204 // Active regions which end before the current region need to be popped.
1205 auto CompletedRegions =
1206 std::stable_partition(ActiveRegions.begin(), ActiveRegions.end(),
1207 [&](const CountedRegion *Region) {
1208 return !(Region->endLoc() <= CurStartLoc);
1209 });
1210 if (CompletedRegions != ActiveRegions.end()) {
1211 unsigned FirstCompletedRegion =
1212 std::distance(ActiveRegions.begin(), CompletedRegions);
1213 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
1214 }
1215
1216 bool GapRegion = CR.value().Kind == CounterMappingRegion::GapRegion;
1217
1218 // Try to emit a segment for the current region.
1219 if (CurStartLoc == CR.value().endLoc()) {
1220 // Avoid making zero-length regions active. If it's the last region,
1221 // emit a skipped segment. Otherwise use its predecessor's count.
1222 const bool Skipped =
1223 (CR.index() + 1) == Regions.size() ||
1224 CR.value().Kind == CounterMappingRegion::SkippedRegion;
1225 startSegment(ActiveRegions.empty() ? CR.value() : *ActiveRegions.back(),
1226 CurStartLoc, !GapRegion, Skipped);
1227 // If it is skipped segment, create a segment with last pushed
1228 // regions's count at CurStartLoc.
1229 if (Skipped && !ActiveRegions.empty())
1230 startSegment(*ActiveRegions.back(), CurStartLoc, false);
1231 continue;
1232 }
1233 if (CR.index() + 1 == Regions.size() ||
1234 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
1235 // Emit a segment if the next region doesn't start at the same location
1236 // as this one.
1237 startSegment(CR.value(), CurStartLoc, !GapRegion);
1238 }
1239
1240 // This region is active (i.e not completed).
1241 ActiveRegions.push_back(&CR.value());
1242 }
1243
1244 // Complete any remaining active regions.
1245 if (!ActiveRegions.empty())
1246 completeRegionsUntil(std::nullopt, 0);
1247 }
1248
1249 /// Sort a nested sequence of regions from a single file.
1250 static void sortNestedRegions(MutableArrayRef<CountedRegion> Regions) {
1251 llvm::sort(Regions, [](const CountedRegion &LHS, const CountedRegion &RHS) {
1252 if (LHS.startLoc() != RHS.startLoc())
1253 return LHS.startLoc() < RHS.startLoc();
1254 if (LHS.endLoc() != RHS.endLoc())
1255 // When LHS completely contains RHS, we sort LHS first.
1256 return RHS.endLoc() < LHS.endLoc();
1257 // If LHS and RHS cover the same area, we need to sort them according
1258 // to their kinds so that the most suitable region will become "active"
1259 // in combineRegions(). Because we accumulate counter values only from
1260 // regions of the same kind as the first region of the area, prefer
1261 // CodeRegion to ExpansionRegion and ExpansionRegion to SkippedRegion.
1262 static_assert(CounterMappingRegion::CodeRegion <
1266 "Unexpected order of region kind values");
1267 return LHS.Kind < RHS.Kind;
1268 });
1269 }
1270
1271 /// Combine counts of regions which cover the same area.
1273 combineRegions(MutableArrayRef<CountedRegion> Regions) {
1274 if (Regions.empty())
1275 return Regions;
1276 auto Active = Regions.begin();
1277 auto End = Regions.end();
1278 for (auto I = Regions.begin() + 1; I != End; ++I) {
1279 if (Active->startLoc() != I->startLoc() ||
1280 Active->endLoc() != I->endLoc()) {
1281 // Shift to the next region.
1282 ++Active;
1283 if (Active != I)
1284 *Active = *I;
1285 continue;
1286 }
1287 // Merge duplicate region.
1288 // If CodeRegions and ExpansionRegions cover the same area, it's probably
1289 // a macro which is fully expanded to another macro. In that case, we need
1290 // to accumulate counts only from CodeRegions, or else the area will be
1291 // counted twice.
1292 // On the other hand, a macro may have a nested macro in its body. If the
1293 // outer macro is used several times, the ExpansionRegion for the nested
1294 // macro will also be added several times. These ExpansionRegions cover
1295 // the same source locations and have to be combined to reach the correct
1296 // value for that area.
1297 // We add counts of the regions of the same kind as the active region
1298 // to handle the both situations.
1299 if (I->Kind == Active->Kind)
1300 Active->ExecutionCount += I->ExecutionCount;
1301 }
1302 return Regions.drop_back(std::distance(++Active, End));
1303 }
1304
1305public:
1306 /// Build a sorted list of CoverageSegments from a list of Regions.
1307 static std::vector<CoverageSegment>
1308 buildSegments(MutableArrayRef<CountedRegion> Regions) {
1309 std::vector<CoverageSegment> Segments;
1310 SegmentBuilder Builder(Segments);
1311
1312 sortNestedRegions(Regions);
1313 ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
1314
1315 LLVM_DEBUG({
1316 dbgs() << "Combined regions:\n";
1317 for (const auto &CR : CombinedRegions)
1318 dbgs() << " " << CR.LineStart << ":" << CR.ColumnStart << " -> "
1319 << CR.LineEnd << ":" << CR.ColumnEnd
1320 << " (count=" << CR.ExecutionCount << ")\n";
1321 });
1322
1323 Builder.buildSegmentsImpl(CombinedRegions);
1324
1325#ifndef NDEBUG
1326 for (unsigned I = 1, E = Segments.size(); I < E; ++I) {
1327 const auto &L = Segments[I - 1];
1328 const auto &R = Segments[I];
1329 if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
1330 if (L.Line == R.Line && L.Col == R.Col && !L.HasCount)
1331 continue;
1332 LLVM_DEBUG(dbgs() << " ! Segment " << L.Line << ":" << L.Col
1333 << " followed by " << R.Line << ":" << R.Col << "\n");
1334 assert(false && "Coverage segments not unique or sorted");
1335 }
1336 }
1337#endif
1338
1339 return Segments;
1340 }
1341};
1342
1343} // end anonymous namespace
1344
1345std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
1346 std::vector<StringRef> Filenames;
1347 for (const auto &Function : getCoveredFunctions())
1348 llvm::append_range(Filenames, Function.Filenames);
1349 llvm::sort(Filenames);
1350 auto Last = llvm::unique(Filenames);
1351 Filenames.erase(Last, Filenames.end());
1352 return Filenames;
1353}
1354
1356 const FunctionRecord &Function) {
1357 SmallBitVector FilenameEquivalence(Function.Filenames.size(), false);
1358 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
1359 if (SourceFile == Function.Filenames[I])
1360 FilenameEquivalence[I] = true;
1361 return FilenameEquivalence;
1362}
1363
1364/// Return the ID of the file where the definition of the function is located.
1365static std::optional<unsigned>
1367 SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true);
1368 for (const auto &CR : Function.CountedRegions)
1370 IsNotExpandedFile[CR.ExpandedFileID] = false;
1371 int I = IsNotExpandedFile.find_first();
1372 if (I == -1)
1373 return std::nullopt;
1374 return I;
1375}
1376
1377/// Check if SourceFile is the file that contains the definition of
1378/// the Function. Return the ID of the file in that case or std::nullopt
1379/// otherwise.
1380static std::optional<unsigned>
1382 std::optional<unsigned> I = findMainViewFileID(Function);
1383 if (I && SourceFile == Function.Filenames[*I])
1384 return I;
1385 return std::nullopt;
1386}
1387
1388static bool isExpansion(const CountedRegion &R, unsigned FileID) {
1389 return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
1390}
1391
1394 CoverageData FileCoverage(*SingleByteCoverage, Filename);
1395 std::vector<CountedRegion> Regions;
1396
1397 // Look up the function records in the given file. Due to hash collisions on
1398 // the filename, we may get back some records that are not in the file.
1399 ArrayRef<unsigned> RecordIndices =
1400 getImpreciseRecordIndicesForFilename(Filename);
1401 for (unsigned RecordIndex : RecordIndices) {
1402 const FunctionRecord &Function = Functions[RecordIndex];
1403 auto MainFileID = findMainViewFileID(Filename, Function);
1404 auto FileIDs = gatherFileIDs(Filename, Function);
1405 for (const auto &CR : Function.CountedRegions)
1406 if (FileIDs.test(CR.FileID)) {
1407 Regions.push_back(CR);
1408 if (MainFileID && isExpansion(CR, *MainFileID))
1409 FileCoverage.Expansions.emplace_back(CR, Function);
1410 }
1411 // Capture branch regions specific to the function (excluding expansions).
1412 for (const auto &CR : Function.CountedBranchRegions)
1413 if (FileIDs.test(CR.FileID))
1414 FileCoverage.BranchRegions.push_back(CR);
1415 // Capture MCDC records specific to the function.
1416 for (const auto &MR : Function.MCDCRecords)
1417 if (FileIDs.test(MR.getDecisionRegion().FileID))
1418 FileCoverage.MCDCRecords.push_back(MR);
1419 }
1420
1421 LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
1422 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1423
1424 return FileCoverage;
1425}
1426
1427std::vector<InstantiationGroup>
1429 FunctionInstantiationSetCollector InstantiationSetCollector;
1430 // Look up the function records in the given file. Due to hash collisions on
1431 // the filename, we may get back some records that are not in the file.
1432 ArrayRef<unsigned> RecordIndices =
1433 getImpreciseRecordIndicesForFilename(Filename);
1434 for (unsigned RecordIndex : RecordIndices) {
1435 const FunctionRecord &Function = Functions[RecordIndex];
1436 auto MainFileID = findMainViewFileID(Filename, Function);
1437 if (!MainFileID)
1438 continue;
1439 InstantiationSetCollector.insert(Function, *MainFileID);
1440 }
1441
1442 std::vector<InstantiationGroup> Result;
1443 for (auto &InstantiationSet : InstantiationSetCollector) {
1444 InstantiationGroup IG{InstantiationSet.first.first,
1445 InstantiationSet.first.second,
1446 std::move(InstantiationSet.second)};
1447 Result.emplace_back(std::move(IG));
1448 }
1449 return Result;
1450}
1451
1454 auto MainFileID = findMainViewFileID(Function);
1455 if (!MainFileID)
1456 return CoverageData();
1457
1459 CoverageData FunctionCoverage(*SingleByteCoverage,
1460 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 {
1488 CoverageData ExpansionCoverage(
1489 *SingleByteCoverage, Expansion.Function.Filenames[Expansion.FileID]);
1490 std::vector<CountedRegion> Regions;
1491 for (const auto &CR : Expansion.Function.CountedRegions)
1492 if (CR.FileID == Expansion.FileID) {
1493 Regions.push_back(CR);
1494 if (isExpansion(CR, Expansion.FileID))
1495 ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
1496 }
1497 for (const auto &CR : Expansion.Function.CountedBranchRegions)
1498 // Capture branch regions that only pertain to the corresponding expansion.
1499 if (CR.FileID == Expansion.FileID)
1500 ExpansionCoverage.BranchRegions.push_back(CR);
1501
1502 LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
1503 << Expansion.FileID << "\n");
1504 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
1505
1506 return ExpansionCoverage;
1507}
1508
1509LineCoverageStats::LineCoverageStats(
1511 const CoverageSegment *WrappedSegment, unsigned Line)
1512 : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
1513 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
1514 // Find the minimum number of regions which start in this line.
1515 unsigned MinRegionCount = 0;
1516 auto isStartOfRegion = [](const CoverageSegment *S) {
1517 return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
1518 };
1519 for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
1520 if (isStartOfRegion(LineSegments[I]))
1521 ++MinRegionCount;
1522
1523 bool StartOfSkippedRegion = !LineSegments.empty() &&
1524 !LineSegments.front()->HasCount &&
1525 LineSegments.front()->IsRegionEntry;
1526
1527 HasMultipleRegions = MinRegionCount > 1;
1528 Mapped =
1529 !StartOfSkippedRegion &&
1530 ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
1531
1532 // if there is any starting segment at this line with a counter, it must be
1533 // mapped
1534 Mapped |= any_of(LineSegments, [](const auto *Seq) {
1535 return Seq->IsRegionEntry && Seq->HasCount;
1536 });
1537
1538 if (!Mapped) {
1539 return;
1540 }
1541
1542 // Pick the max count from the non-gap, region entry segments and the
1543 // wrapped count.
1544 if (WrappedSegment)
1545 ExecutionCount = WrappedSegment->Count;
1546 if (!MinRegionCount)
1547 return;
1548 for (const auto *LS : LineSegments)
1549 if (isStartOfRegion(LS))
1550 ExecutionCount = std::max(ExecutionCount, LS->Count);
1551}
1552
1554 if (Next == CD.end()) {
1555 Stats = LineCoverageStats();
1556 Ended = true;
1557 return *this;
1558 }
1559 if (Segments.size())
1560 WrappedSegment = Segments.back();
1561 Segments.clear();
1562 while (Next != CD.end() && Next->Line == Line)
1563 Segments.push_back(&*Next++);
1564 Stats = LineCoverageStats(Segments, WrappedSegment, Line);
1565 ++Line;
1566 return *this;
1567}
1568
1570 const std::string &ErrMsg = "") {
1571 std::string Msg;
1573
1574 switch (Err) {
1576 OS << "success";
1577 break;
1579 OS << "end of File";
1580 break;
1582 OS << "no coverage data found";
1583 break;
1585 OS << "unsupported coverage format version";
1586 break;
1588 OS << "truncated coverage data";
1589 break;
1591 OS << "malformed coverage data";
1592 break;
1594 OS << "failed to decompress coverage data (zlib)";
1595 break;
1597 OS << "`-arch` specifier is invalid or missing for universal binary";
1598 break;
1599 }
1600
1601 // If optional error message is not empty, append it to the message.
1602 if (!ErrMsg.empty())
1603 OS << ": " << ErrMsg;
1604
1605 return Msg;
1606}
1607
1608namespace {
1609
1610// FIXME: This class is only here to support the transition to llvm::Error. It
1611// will be removed once this transition is complete. Clients should prefer to
1612// deal with the Error value directly, rather than converting to error_code.
1613class CoverageMappingErrorCategoryType : public std::error_category {
1614 const char *name() const noexcept override { return "llvm.coveragemap"; }
1615 std::string message(int IE) const override {
1616 return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
1617 }
1618};
1619
1620} // end anonymous namespace
1621
1622std::string CoverageMapError::message() const {
1623 return getCoverageMapErrString(Err, Msg);
1624}
1625
1626const std::error_category &llvm::coverage::coveragemap_category() {
1627 static CoverageMappingErrorCategoryType ErrorCategory;
1628 return ErrorCategory;
1629}
1630
1631char 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
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
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.
std::array< BitVector, 2 > BoolVector
uint16_t NumConditions
Number of Conditions used for a Decision Region.
Definition: MCDCTypes.h:32