1//===- CoverageMapping.h - Code coverage mapping support --------*- C++ -*-===//
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// Code coverage mapping data is generated by clang and read by
10// llvm-cov to show code coverage statistics for a file.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
15#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
16
17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/ADT/BitVector.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/DenseSet.h"
21#include "llvm/ADT/Hashing.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/ADT/iterator.h"
24#include "llvm/ADT/iterator_range.h"
25#include "llvm/Object/BuildID.h"
26#include "llvm/ProfileData/Coverage/MCDCTypes.h"
27#include "llvm/ProfileData/InstrProf.h"
28#include "llvm/Support/Alignment.h"
29#include "llvm/Support/Compiler.h"
30#include "llvm/Support/Debug.h"
31#include "llvm/Support/Endian.h"
32#include "llvm/Support/Error.h"
33#include "llvm/Support/raw_ostream.h"
34#include <cassert>
35#include <cstdint>
36#include <iterator>
37#include <memory>
38#include <sstream>
39#include <string>
40#include <system_error>
41#include <utility>
42#include <vector>
43
44namespace llvm {
45
46class IndexedInstrProfReader;
47
48namespace object {
49class BuildIDFetcher;
50} // namespace object
51
52namespace vfs {
53class FileSystem;
54} // namespace vfs
55
56namespace coverage {
57
58class CoverageMappingReader;
59struct CoverageMappingRecord;
60
61enum class coveragemap_error {
62 success = 0,
63 eof,
64 no_data_found,
65 unsupported_version,
66 truncated,
67 malformed,
68 decompression_failed,
69 invalid_or_missing_arch_specifier
70};
71
72const std::error_category &coveragemap_category();
73
74inline std::error_code make_error_code(coveragemap_error E) {
75 return std::error_code(static_cast<int>(E), coveragemap_category());
76}
77
78class CoverageMapError : public ErrorInfo<CoverageMapError> {
79public:
80 CoverageMapError(coveragemap_error Err, const Twine &ErrStr = Twine())
81 : Err(Err), Msg(ErrStr.str()) {
82 assert(Err != coveragemap_error::success && "Not an error");
83 }
84
85 std::string message() const override;
86
87 void log(raw_ostream &OS) const override { OS << message(); }
88
89 std::error_code convertToErrorCode() const override {
90 return make_error_code(E: Err);
91 }
92
93 coveragemap_error get() const { return Err; }
94 const std::string &getMessage() const { return Msg; }
95
96 static char ID;
97
98private:
99 coveragemap_error Err;
100 std::string Msg;
101};
102
103/// A Counter is an abstract value that describes how to compute the
104/// execution count for a region of code using the collected profile count data.
105struct Counter {
106 /// The CounterExpression kind (Add or Subtract) is encoded in bit 0 next to
107 /// the CounterKind. This means CounterKind has to leave bit 0 free.
108 enum CounterKind { Zero, CounterValueReference, Expression };
109 static const unsigned EncodingTagBits = 2;
110 static const unsigned EncodingTagMask = 0x3;
111 static const unsigned EncodingCounterTagAndExpansionRegionTagBits =
112 EncodingTagBits + 1;
113
114private:
115 CounterKind Kind = Zero;
116 unsigned ID = 0;
117
118 Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {}
119
120public:
121 Counter() = default;
122
123 CounterKind getKind() const { return Kind; }
124
125 bool isZero() const { return Kind == Zero; }
126
127 bool isExpression() const { return Kind == Expression; }
128
129 unsigned getCounterID() const { return ID; }
130
131 unsigned getExpressionID() const { return ID; }
132
133 friend bool operator==(const Counter &LHS, const Counter &RHS) {
134 return LHS.Kind == RHS.Kind && LHS.ID == RHS.ID;
135 }
136
137 friend bool operator!=(const Counter &LHS, const Counter &RHS) {
138 return !(LHS == RHS);
139 }
140
141 friend bool operator<(const Counter &LHS, const Counter &RHS) {
142 return std::tie(args: LHS.Kind, args: LHS.ID) < std::tie(args: RHS.Kind, args: RHS.ID);
143 }
144
145 /// Return the counter that represents the number zero.
146 static Counter getZero() { return Counter(); }
147
148 /// Return the counter that corresponds to a specific profile counter.
149 static Counter getCounter(unsigned CounterId) {
150 return Counter(CounterValueReference, CounterId);
151 }
152
153 /// Return the counter that corresponds to a specific addition counter
154 /// expression.
155 static Counter getExpression(unsigned ExpressionId) {
156 return Counter(Expression, ExpressionId);
157 }
158};
159
160/// A Counter expression is a value that represents an arithmetic operation
161/// with two counters.
162struct CounterExpression {
163 enum ExprKind { Subtract, Add };
164 ExprKind Kind;
165 Counter LHS, RHS;
166
167 CounterExpression(ExprKind Kind, Counter LHS, Counter RHS)
168 : Kind(Kind), LHS(LHS), RHS(RHS) {}
169};
170
171/// A Counter expression builder is used to construct the counter expressions.
172/// It avoids unnecessary duplication and simplifies algebraic expressions.
173class CounterExpressionBuilder {
174 /// A list of all the counter expressions
175 std::vector<CounterExpression> Expressions;
176
177 /// A lookup table for the index of a given expression.
178 DenseMap<CounterExpression, unsigned> ExpressionIndices;
179
180 /// Return the counter which corresponds to the given expression.
181 ///
182 /// If the given expression is already stored in the builder, a counter
183 /// that references that expression is returned. Otherwise, the given
184 /// expression is added to the builder's collection of expressions.
185 Counter get(const CounterExpression &E);
186
187 /// Represents a term in a counter expression tree.
188 struct Term {
189 unsigned CounterID;
190 int Factor;
191
192 Term(unsigned CounterID, int Factor)
193 : CounterID(CounterID), Factor(Factor) {}
194 };
195
196 /// Gather the terms of the expression tree for processing.
197 ///
198 /// This collects each addition and subtraction referenced by the counter into
199 /// a sequence that can be sorted and combined to build a simplified counter
200 /// expression.
201 void extractTerms(Counter C, int Sign, SmallVectorImpl<Term> &Terms);
202
203 /// Simplifies the given expression tree
204 /// by getting rid of algebraically redundant operations.
205 Counter simplify(Counter ExpressionTree);
206
207public:
208 ArrayRef<CounterExpression> getExpressions() const { return Expressions; }
209
210 /// Return a counter that represents the expression that adds LHS and RHS.
211 Counter add(Counter LHS, Counter RHS, bool Simplify = true);
212
213 /// Return a counter that represents the expression that subtracts RHS from
214 /// LHS.
215 Counter subtract(Counter LHS, Counter RHS, bool Simplify = true);
216};
217
218using LineColPair = std::pair<unsigned, unsigned>;
219
220/// A Counter mapping region associates a source range with a specific counter.
221struct CounterMappingRegion {
222 enum RegionKind {
223 /// A CodeRegion associates some code with a counter
224 CodeRegion,
225
226 /// An ExpansionRegion represents a file expansion region that associates
227 /// a source range with the expansion of a virtual source file, such as
228 /// for a macro instantiation or #include file.
229 ExpansionRegion,
230
231 /// A SkippedRegion represents a source range with code that was skipped
232 /// by a preprocessor or similar means.
233 SkippedRegion,
234
235 /// A GapRegion is like a CodeRegion, but its count is only set as the
236 /// line execution count when its the only region in the line.
237 GapRegion,
238
239 /// A BranchRegion represents leaf-level boolean expressions and is
240 /// associated with two counters, each representing the number of times the
241 /// expression evaluates to true or false.
242 BranchRegion,
243
244 /// A DecisionRegion represents a top-level boolean expression and is
245 /// associated with a variable length bitmap index and condition number.
246 MCDCDecisionRegion,
247
248 /// A Branch Region can be extended to include IDs to facilitate MC/DC.
249 MCDCBranchRegion
250 };
251
252 /// Primary Counter that is also used for Branch Regions (TrueCount).
253 Counter Count;
254
255 /// Secondary Counter used for Branch Regions (FalseCount).
256 Counter FalseCount;
257
258 /// Parameters used for Modified Condition/Decision Coverage
259 mcdc::Parameters MCDCParams;
260
261 template <class MaybeConstInnerParameters, class MaybeConstMCDCParameters>
262 static auto &getParams(MaybeConstMCDCParameters &MCDCParams) {
263 using InnerParameters =
264 typename std::remove_const<MaybeConstInnerParameters>::type;
265 MaybeConstInnerParameters *Params =
266 std::get_if<InnerParameters>(&MCDCParams);
267 assert(Params && "InnerParameters unavailable");
268 return *Params;
269 }
270
271 const auto &getDecisionParams() const {
272 return getParams<const mcdc::DecisionParameters>(MCDCParams);
273 }
274
275 const auto &getBranchParams() const {
276 return getParams<const mcdc::BranchParameters>(MCDCParams);
277 }
278
279 unsigned FileID = 0;
280 unsigned ExpandedFileID = 0;
281 unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
282
283 RegionKind Kind;
284
285 CounterMappingRegion(Counter Count, unsigned FileID, unsigned ExpandedFileID,
286 unsigned LineStart, unsigned ColumnStart,
287 unsigned LineEnd, unsigned ColumnEnd, RegionKind Kind)
288 : Count(Count), FileID(FileID), ExpandedFileID(ExpandedFileID),
289 LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
290 ColumnEnd(ColumnEnd), Kind(Kind) {}
291
292 CounterMappingRegion(Counter Count, Counter FalseCount, unsigned FileID,
293 unsigned ExpandedFileID, unsigned LineStart,
294 unsigned ColumnStart, unsigned LineEnd,
295 unsigned ColumnEnd, RegionKind Kind,
296 const mcdc::Parameters &MCDCParams = std::monostate())
297 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
298 FileID(FileID), ExpandedFileID(ExpandedFileID), LineStart(LineStart),
299 ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
300 Kind(Kind) {}
301
302 CounterMappingRegion(const mcdc::DecisionParameters &MCDCParams,
303 unsigned FileID, unsigned LineStart,
304 unsigned ColumnStart, unsigned LineEnd,
305 unsigned ColumnEnd, RegionKind Kind)
306 : MCDCParams(MCDCParams), FileID(FileID), LineStart(LineStart),
307 ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
308 Kind(Kind) {}
309
310 static CounterMappingRegion
311 makeRegion(Counter Count, unsigned FileID, unsigned LineStart,
312 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
313 return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart,
314 LineEnd, ColumnEnd, CodeRegion);
315 }
316
317 static CounterMappingRegion
318 makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart,
319 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
320 return CounterMappingRegion(Counter(), FileID, ExpandedFileID, LineStart,
321 ColumnStart, LineEnd, ColumnEnd,
322 ExpansionRegion);
323 }
324
325 static CounterMappingRegion
326 makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart,
327 unsigned LineEnd, unsigned ColumnEnd) {
328 return CounterMappingRegion(Counter(), FileID, 0, LineStart, ColumnStart,
329 LineEnd, ColumnEnd, SkippedRegion);
330 }
331
332 static CounterMappingRegion
333 makeGapRegion(Counter Count, unsigned FileID, unsigned LineStart,
334 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
335 return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart,
336 LineEnd, (1U << 31) | ColumnEnd, GapRegion);
337 }
338
339 static CounterMappingRegion
340 makeBranchRegion(Counter Count, Counter FalseCount, unsigned FileID,
341 unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
342 unsigned ColumnEnd,
343 const mcdc::Parameters &MCDCParams = std::monostate()) {
344 return CounterMappingRegion(
345 Count, FalseCount, FileID, 0, LineStart, ColumnStart, LineEnd,
346 ColumnEnd,
347 (std::get_if<mcdc::BranchParameters>(ptr: &MCDCParams) ? MCDCBranchRegion
348 : BranchRegion),
349 MCDCParams);
350 }
351
352 static CounterMappingRegion
353 makeDecisionRegion(const mcdc::DecisionParameters &MCDCParams,
354 unsigned FileID, unsigned LineStart, unsigned ColumnStart,
355 unsigned LineEnd, unsigned ColumnEnd) {
356 return CounterMappingRegion(MCDCParams, FileID, LineStart, ColumnStart,
357 LineEnd, ColumnEnd, MCDCDecisionRegion);
358 }
359
360 inline LineColPair startLoc() const {
361 return LineColPair(LineStart, ColumnStart);
362 }
363
364 inline LineColPair endLoc() const { return LineColPair(LineEnd, ColumnEnd); }
365};
366
367/// Associates a source range with an execution count.
368struct CountedRegion : public CounterMappingRegion {
369 uint64_t ExecutionCount;
370 uint64_t FalseExecutionCount;
371 bool Folded;
372
373 CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
374 : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
375 FalseExecutionCount(0), Folded(false) {}
376
377 CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
378 uint64_t FalseExecutionCount)
379 : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
380 FalseExecutionCount(FalseExecutionCount), Folded(false) {}
381};
382
383/// MCDC Record grouping all information together.
384struct MCDCRecord {
385 /// CondState represents the evaluation of a condition in an executed test
386 /// vector, which can be True or False. A DontCare is used to mask an
387 /// unevaluatable condition resulting from short-circuit behavior of logical
388 /// operators in languages like C/C++. When comparing the evaluation of a
389 /// condition across executed test vectors, comparisons against a DontCare
390 /// are effectively ignored.
391 enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
392
393 using TestVector = llvm::SmallVector<CondState>;
394 using TestVectors = llvm::SmallVector<TestVector>;
395 using BoolVector = llvm::SmallVector<bool>;
396 using TVRowPair = std::pair<unsigned, unsigned>;
397 using TVPairMap = llvm::DenseMap<unsigned, TVRowPair>;
398 using CondIDMap = llvm::DenseMap<unsigned, unsigned>;
399 using LineColPairMap = llvm::DenseMap<unsigned, LineColPair>;
400
401private:
402 CounterMappingRegion Region;
403 TestVectors TV;
404 TVPairMap IndependencePairs;
405 BoolVector Folded;
406 CondIDMap PosToID;
407 LineColPairMap CondLoc;
408
409public:
410 MCDCRecord(const CounterMappingRegion &Region, TestVectors &&TV,
411 TVPairMap &&IndependencePairs, BoolVector &&Folded,
412 CondIDMap &&PosToID, LineColPairMap &&CondLoc)
413 : Region(Region), TV(std::move(TV)),
414 IndependencePairs(std::move(IndependencePairs)),
415 Folded(std::move(Folded)), PosToID(std::move(PosToID)),
416 CondLoc(std::move(CondLoc)){};
417
418 CounterMappingRegion getDecisionRegion() const { return Region; }
419 unsigned getNumConditions() const {
420 unsigned NumConditions = Region.getDecisionParams().NumConditions;
421 assert(NumConditions != 0 &&
422 "In MC/DC, NumConditions should never be zero!");
423 return NumConditions;
424 }
425 unsigned getNumTestVectors() const { return TV.size(); }
426 bool isCondFolded(unsigned Condition) const { return Folded[Condition]; }
427
428 /// Return the evaluation of a condition (indicated by Condition) in an
429 /// executed test vector (indicated by TestVectorIndex), which will be True,
430 /// False, or DontCare if the condition is unevaluatable. Because condition
431 /// IDs are not associated based on their position in the expression,
432 /// accessing conditions in the TestVectors requires a translation from a
433 /// ordinal position to actual condition ID. This is done via PosToID[].
434 CondState getTVCondition(unsigned TestVectorIndex, unsigned Condition) {
435 return TV[TestVectorIndex][PosToID[Condition]];
436 }
437
438 /// Return the Result evaluation for an executed test vector.
439 /// See MCDCRecordProcessor::RecordTestVector().
440 CondState getTVResult(unsigned TestVectorIndex) {
441 return TV[TestVectorIndex][getNumConditions()];
442 }
443
444 /// Determine whether a given condition (indicated by Condition) is covered
445 /// by an Independence Pair. Because condition IDs are not associated based
446 /// on their position in the expression, accessing conditions in the
447 /// TestVectors requires a translation from a ordinal position to actual
448 /// condition ID. This is done via PosToID[].
449 bool isConditionIndependencePairCovered(unsigned Condition) const {
450 auto It = PosToID.find(Val: Condition);
451 if (It != PosToID.end())
452 return IndependencePairs.contains(Val: It->second);
453 llvm_unreachable("Condition ID without an Ordinal mapping");
454 }
455
456 /// Return the Independence Pair that covers the given condition. Because
457 /// condition IDs are not associated based on their position in the
458 /// expression, accessing conditions in the TestVectors requires a
459 /// translation from a ordinal position to actual condition ID. This is done
460 /// via PosToID[].
461 TVRowPair getConditionIndependencePair(unsigned Condition) {
462 assert(isConditionIndependencePairCovered(Condition));
463 return IndependencePairs[PosToID[Condition]];
464 }
465
466 float getPercentCovered() const {
467 unsigned Folded = 0;
468 unsigned Covered = 0;
469 for (unsigned C = 0; C < getNumConditions(); C++) {
470 if (isCondFolded(Condition: C))
471 Folded++;
472 else if (isConditionIndependencePairCovered(Condition: C))
473 Covered++;
474 }
475
476 unsigned Total = getNumConditions() - Folded;
477 if (Total == 0)
478 return 0.0;
479 return (static_cast<double>(Covered) / static_cast<double>(Total)) * 100.0;
480 }
481
482 std::string getConditionHeaderString(unsigned Condition) {
483 std::ostringstream OS;
484 OS << "Condition C" << Condition + 1 << " --> (";
485 OS << CondLoc[Condition].first << ":" << CondLoc[Condition].second;
486 OS << ")\n";
487 return OS.str();
488 }
489
490 std::string getTestVectorHeaderString() const {
491 std::ostringstream OS;
492 if (getNumTestVectors() == 0) {
493 OS << "None.\n";
494 return OS.str();
495 }
496 const auto NumConditions = getNumConditions();
497 for (unsigned I = 0; I < NumConditions; I++) {
498 OS << "C" << I + 1;
499 if (I != NumConditions - 1)
500 OS << ", ";
501 }
502 OS << " Result\n";
503 return OS.str();
504 }
505
506 std::string getTestVectorString(unsigned TestVectorIndex) {
507 assert(TestVectorIndex < getNumTestVectors() &&
508 "TestVector index out of bounds!");
509 std::ostringstream OS;
510 const auto NumConditions = getNumConditions();
511 // Add individual condition values to the string.
512 OS << " " << TestVectorIndex + 1 << " { ";
513 for (unsigned Condition = 0; Condition < NumConditions; Condition++) {
514 if (isCondFolded(Condition))
515 OS << "C";
516 else {
517 switch (getTVCondition(TestVectorIndex, Condition)) {
518 case MCDCRecord::MCDC_DontCare:
519 OS << "-";
520 break;
521 case MCDCRecord::MCDC_True:
522 OS << "T";
523 break;
524 case MCDCRecord::MCDC_False:
525 OS << "F";
526 break;
527 }
528 }
529 if (Condition != NumConditions - 1)
530 OS << ", ";
531 }
532
533 // Add result value to the string.
534 OS << " = ";
535 if (getTVResult(TestVectorIndex) == MCDC_True)
536 OS << "T";
537 else
538 OS << "F";
539 OS << " }\n";
540
541 return OS.str();
542 }
543
544 std::string getConditionCoverageString(unsigned Condition) {
545 assert(Condition < getNumConditions() &&
546 "Condition index is out of bounds!");
547 std::ostringstream OS;
548
549 OS << " C" << Condition + 1 << "-Pair: ";
550 if (isCondFolded(Condition)) {
551 OS << "constant folded\n";
552 } else if (isConditionIndependencePairCovered(Condition)) {
553 TVRowPair rows = getConditionIndependencePair(Condition);
554 OS << "covered: (" << rows.first << ",";
555 OS << rows.second << ")\n";
556 } else
557 OS << "not covered\n";
558
559 return OS.str();
560 }
561};
562
563/// A Counter mapping context is used to connect the counters, expressions
564/// and the obtained counter values.
565class CounterMappingContext {
566 ArrayRef<CounterExpression> Expressions;
567 ArrayRef<uint64_t> CounterValues;
568 BitVector Bitmap;
569
570public:
571 CounterMappingContext(ArrayRef<CounterExpression> Expressions,
572 ArrayRef<uint64_t> CounterValues = std::nullopt)
573 : Expressions(Expressions), CounterValues(CounterValues) {}
574
575 void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; }
576 void setBitmap(BitVector &&Bitmap_) { Bitmap = std::move(Bitmap_); }
577
578 void dump(const Counter &C, raw_ostream &OS) const;
579 void dump(const Counter &C) const { dump(C, OS&: dbgs()); }
580
581 /// Return the number of times that a region of code associated with this
582 /// counter was executed.
583 Expected<int64_t> evaluate(const Counter &C) const;
584
585 /// Return an MCDC record that indicates executed test vectors and condition
586 /// pairs.
587 Expected<MCDCRecord>
588 evaluateMCDCRegion(const CounterMappingRegion &Region,
589 ArrayRef<const CounterMappingRegion *> Branches);
590
591 unsigned getMaxCounterID(const Counter &C) const;
592};
593
594/// Code coverage information for a single function.
595struct FunctionRecord {
596 /// Raw function name.
597 std::string Name;
598 /// Mapping from FileID (i.e. vector index) to filename. Used to support
599 /// macro expansions within a function in which the macro and function are
600 /// defined in separate files.
601 ///
602 /// TODO: Uniquing filenames across all function records may be a performance
603 /// optimization.
604 std::vector<std::string> Filenames;
605 /// Regions in the function along with their counts.
606 std::vector<CountedRegion> CountedRegions;
607 /// Branch Regions in the function along with their counts.
608 std::vector<CountedRegion> CountedBranchRegions;
609 /// MCDC Records record a DecisionRegion and associated BranchRegions.
610 std::vector<MCDCRecord> MCDCRecords;
611 /// The number of times this function was executed.
612 uint64_t ExecutionCount = 0;
613
614 FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames)
615 : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {}
616
617 FunctionRecord(FunctionRecord &&FR) = default;
618 FunctionRecord &operator=(FunctionRecord &&) = default;
619
620 void pushMCDCRecord(MCDCRecord &&Record) {
621 MCDCRecords.push_back(x: std::move(Record));
622 }
623
624 void pushRegion(CounterMappingRegion Region, uint64_t Count,
625 uint64_t FalseCount) {
626 if (Region.Kind == CounterMappingRegion::BranchRegion ||
627 Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
628 CountedBranchRegions.emplace_back(args&: Region, args&: Count, args&: FalseCount);
629 // If both counters are hard-coded to zero, then this region represents a
630 // constant-folded branch.
631 if (Region.Count.isZero() && Region.FalseCount.isZero())
632 CountedBranchRegions.back().Folded = true;
633 return;
634 }
635 if (CountedRegions.empty())
636 ExecutionCount = Count;
637 CountedRegions.emplace_back(args&: Region, args&: Count, args&: FalseCount);
638 }
639};
640
641/// Iterator over Functions, optionally filtered to a single file.
642class FunctionRecordIterator
643 : public iterator_facade_base<FunctionRecordIterator,
644 std::forward_iterator_tag, FunctionRecord> {
645 ArrayRef<FunctionRecord> Records;
646 ArrayRef<FunctionRecord>::iterator Current;
647 StringRef Filename;
648
649 /// Skip records whose primary file is not \c Filename.
650 void skipOtherFiles();
651
652public:
653 FunctionRecordIterator(ArrayRef<FunctionRecord> Records_,
654 StringRef Filename = "")
655 : Records(Records_), Current(Records.begin()), Filename(Filename) {
656 skipOtherFiles();
657 }
658
659 FunctionRecordIterator() : Current(Records.begin()) {}
660
661 bool operator==(const FunctionRecordIterator &RHS) const {
662 return Current == RHS.Current && Filename == RHS.Filename;
663 }
664
665 const FunctionRecord &operator*() const { return *Current; }
666
667 FunctionRecordIterator &operator++() {
668 assert(Current != Records.end() && "incremented past end");
669 ++Current;
670 skipOtherFiles();
671 return *this;
672 }
673};
674
675/// Coverage information for a macro expansion or #included file.
676///
677/// When covered code has pieces that can be expanded for more detail, such as a
678/// preprocessor macro use and its definition, these are represented as
679/// expansions whose coverage can be looked up independently.
680struct ExpansionRecord {
681 /// The abstract file this expansion covers.
682 unsigned FileID;
683 /// The region that expands to this record.
684 const CountedRegion &Region;
685 /// Coverage for the expansion.
686 const FunctionRecord &Function;
687
688 ExpansionRecord(const CountedRegion &Region,
689 const FunctionRecord &Function)
690 : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {}
691};
692
693/// The execution count information starting at a point in a file.
694///
695/// A sequence of CoverageSegments gives execution counts for a file in format
696/// that's simple to iterate through for processing.
697struct CoverageSegment {
698 /// The line where this segment begins.
699 unsigned Line;
700 /// The column where this segment begins.
701 unsigned Col;
702 /// The execution count, or zero if no count was recorded.
703 uint64_t Count;
704 /// When false, the segment was uninstrumented or skipped.
705 bool HasCount;
706 /// Whether this enters a new region or returns to a previous count.
707 bool IsRegionEntry;
708 /// Whether this enters a gap region.
709 bool IsGapRegion;
710
711 CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry)
712 : Line(Line), Col(Col), Count(0), HasCount(false),
713 IsRegionEntry(IsRegionEntry), IsGapRegion(false) {}
714
715 CoverageSegment(unsigned Line, unsigned Col, uint64_t Count,
716 bool IsRegionEntry, bool IsGapRegion = false,
717 bool IsBranchRegion = false)
718 : Line(Line), Col(Col), Count(Count), HasCount(true),
719 IsRegionEntry(IsRegionEntry), IsGapRegion(IsGapRegion) {}
720
721 friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) {
722 return std::tie(args: L.Line, args: L.Col, args: L.Count, args: L.HasCount, args: L.IsRegionEntry,
723 args: L.IsGapRegion) == std::tie(args: R.Line, args: R.Col, args: R.Count,
724 args: R.HasCount, args: R.IsRegionEntry,
725 args: R.IsGapRegion);
726 }
727};
728
729/// An instantiation group contains a \c FunctionRecord list, such that each
730/// record corresponds to a distinct instantiation of the same function.
731///
732/// Note that it's possible for a function to have more than one instantiation
733/// (consider C++ template specializations or static inline functions).
734class InstantiationGroup {
735 friend class CoverageMapping;
736
737 unsigned Line;
738 unsigned Col;
739 std::vector<const FunctionRecord *> Instantiations;
740
741 InstantiationGroup(unsigned Line, unsigned Col,
742 std::vector<const FunctionRecord *> Instantiations)
743 : Line(Line), Col(Col), Instantiations(std::move(Instantiations)) {}
744
745public:
746 InstantiationGroup(const InstantiationGroup &) = delete;
747 InstantiationGroup(InstantiationGroup &&) = default;
748
749 /// Get the number of instantiations in this group.
750 size_t size() const { return Instantiations.size(); }
751
752 /// Get the line where the common function was defined.
753 unsigned getLine() const { return Line; }
754
755 /// Get the column where the common function was defined.
756 unsigned getColumn() const { return Col; }
757
758 /// Check if the instantiations in this group have a common mangled name.
759 bool hasName() const {
760 for (unsigned I = 1, E = Instantiations.size(); I < E; ++I)
761 if (Instantiations[I]->Name != Instantiations[0]->Name)
762 return false;
763 return true;
764 }
765
766 /// Get the common mangled name for instantiations in this group.
767 StringRef getName() const {
768 assert(hasName() && "Instantiations don't have a shared name");
769 return Instantiations[0]->Name;
770 }
771
772 /// Get the total execution count of all instantiations in this group.
773 uint64_t getTotalExecutionCount() const {
774 uint64_t Count = 0;
775 for (const FunctionRecord *F : Instantiations)
776 Count += F->ExecutionCount;
777 return Count;
778 }
779
780 /// Get the instantiations in this group.
781 ArrayRef<const FunctionRecord *> getInstantiations() const {
782 return Instantiations;
783 }
784};
785
786/// Coverage information to be processed or displayed.
787///
788/// This represents the coverage of an entire file, expansion, or function. It
789/// provides a sequence of CoverageSegments to iterate through, as well as the
790/// list of expansions that can be further processed.
791class CoverageData {
792 friend class CoverageMapping;
793
794 std::string Filename;
795 std::vector<CoverageSegment> Segments;
796 std::vector<ExpansionRecord> Expansions;
797 std::vector<CountedRegion> BranchRegions;
798 std::vector<MCDCRecord> MCDCRecords;
799
800public:
801 CoverageData() = default;
802
803 CoverageData(StringRef Filename) : Filename(Filename) {}
804
805 /// Get the name of the file this data covers.
806 StringRef getFilename() const { return Filename; }
807
808 /// Get an iterator over the coverage segments for this object. The segments
809 /// are guaranteed to be uniqued and sorted by location.
810 std::vector<CoverageSegment>::const_iterator begin() const {
811 return Segments.begin();
812 }
813
814 std::vector<CoverageSegment>::const_iterator end() const {
815 return Segments.end();
816 }
817
818 bool empty() const { return Segments.empty(); }
819
820 /// Expansions that can be further processed.
821 ArrayRef<ExpansionRecord> getExpansions() const { return Expansions; }
822
823 /// Branches that can be further processed.
824 ArrayRef<CountedRegion> getBranches() const { return BranchRegions; }
825
826 /// MCDC Records that can be further processed.
827 ArrayRef<MCDCRecord> getMCDCRecords() const { return MCDCRecords; }
828};
829
830/// The mapping of profile information to coverage data.
831///
832/// This is the main interface to get coverage information, using a profile to
833/// fill out execution counts.
834class CoverageMapping {
835 DenseMap<size_t, DenseSet<size_t>> RecordProvenance;
836 std::vector<FunctionRecord> Functions;
837 DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
838 std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
839
840 CoverageMapping() = default;
841
842 // Load coverage records from readers.
843 static Error loadFromReaders(
844 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
845 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage);
846
847 // Load coverage records from file.
848 static Error
849 loadFromFile(StringRef Filename, StringRef Arch, StringRef CompilationDir,
850 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
851 bool &DataFound,
852 SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr);
853
854 /// Add a function record corresponding to \p Record.
855 Error loadFunctionRecord(const CoverageMappingRecord &Record,
856 IndexedInstrProfReader &ProfileReader);
857
858 /// Look up the indices for function records which are at least partially
859 /// defined in the specified file. This is guaranteed to return a superset of
860 /// such records: extra records not in the file may be included if there is
861 /// a hash collision on the filename. Clients must be robust to collisions.
862 ArrayRef<unsigned>
863 getImpreciseRecordIndicesForFilename(StringRef Filename) const;
864
865public:
866 CoverageMapping(const CoverageMapping &) = delete;
867 CoverageMapping &operator=(const CoverageMapping &) = delete;
868
869 /// Load the coverage mapping using the given readers.
870 static Expected<std::unique_ptr<CoverageMapping>>
871 load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
872 IndexedInstrProfReader &ProfileReader);
873
874 /// Load the coverage mapping from the given object files and profile. If
875 /// \p Arches is non-empty, it must specify an architecture for each object.
876 /// Ignores non-instrumented object files unless all are not instrumented.
877 static Expected<std::unique_ptr<CoverageMapping>>
878 load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
879 vfs::FileSystem &FS, ArrayRef<StringRef> Arches = std::nullopt,
880 StringRef CompilationDir = "",
881 const object::BuildIDFetcher *BIDFetcher = nullptr,
882 bool CheckBinaryIDs = false);
883
884 /// The number of functions that couldn't have their profiles mapped.
885 ///
886 /// This is a count of functions whose profile is out of date or otherwise
887 /// can't be associated with any coverage information.
888 unsigned getMismatchedCount() const { return FuncHashMismatches.size(); }
889
890 /// A hash mismatch occurs when a profile record for a symbol does not have
891 /// the same hash as a coverage mapping record for the same symbol. This
892 /// returns a list of hash mismatches, where each mismatch is a pair of the
893 /// symbol name and its coverage mapping hash.
894 ArrayRef<std::pair<std::string, uint64_t>> getHashMismatches() const {
895 return FuncHashMismatches;
896 }
897
898 /// Returns a lexicographically sorted, unique list of files that are
899 /// covered.
900 std::vector<StringRef> getUniqueSourceFiles() const;
901
902 /// Get the coverage for a particular file.
903 ///
904 /// The given filename must be the name as recorded in the coverage
905 /// information. That is, only names returned from getUniqueSourceFiles will
906 /// yield a result.
907 CoverageData getCoverageForFile(StringRef Filename) const;
908
909 /// Get the coverage for a particular function.
910 CoverageData getCoverageForFunction(const FunctionRecord &Function) const;
911
912 /// Get the coverage for an expansion within a coverage set.
913 CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const;
914
915 /// Gets all of the functions covered by this profile.
916 iterator_range<FunctionRecordIterator> getCoveredFunctions() const {
917 return make_range(x: FunctionRecordIterator(Functions),
918 y: FunctionRecordIterator());
919 }
920
921 /// Gets all of the functions in a particular file.
922 iterator_range<FunctionRecordIterator>
923 getCoveredFunctions(StringRef Filename) const {
924 return make_range(x: FunctionRecordIterator(Functions, Filename),
925 y: FunctionRecordIterator());
926 }
927
928 /// Get the list of function instantiation groups in a particular file.
929 ///
930 /// Every instantiation group in a program is attributed to exactly one file:
931 /// the file in which the definition for the common function begins.
932 std::vector<InstantiationGroup>
933 getInstantiationGroups(StringRef Filename) const;
934};
935
936/// Coverage statistics for a single line.
937class LineCoverageStats {
938 uint64_t ExecutionCount;
939 bool HasMultipleRegions;
940 bool Mapped;
941 unsigned Line;
942 ArrayRef<const CoverageSegment *> LineSegments;
943 const CoverageSegment *WrappedSegment;
944
945 friend class LineCoverageIterator;
946 LineCoverageStats() = default;
947
948public:
949 LineCoverageStats(ArrayRef<const CoverageSegment *> LineSegments,
950 const CoverageSegment *WrappedSegment, unsigned Line);
951
952 uint64_t getExecutionCount() const { return ExecutionCount; }
953
954 bool hasMultipleRegions() const { return HasMultipleRegions; }
955
956 bool isMapped() const { return Mapped; }
957
958 unsigned getLine() const { return Line; }
959
960 ArrayRef<const CoverageSegment *> getLineSegments() const {
961 return LineSegments;
962 }
963
964 const CoverageSegment *getWrappedSegment() const { return WrappedSegment; }
965};
966
967/// An iterator over the \c LineCoverageStats objects for lines described by
968/// a \c CoverageData instance.
969class LineCoverageIterator
970 : public iterator_facade_base<LineCoverageIterator,
971 std::forward_iterator_tag,
972 const LineCoverageStats> {
973public:
974 LineCoverageIterator(const CoverageData &CD)
975 : LineCoverageIterator(CD, CD.begin()->Line) {}
976
977 LineCoverageIterator(const CoverageData &CD, unsigned Line)
978 : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false),
979 Line(Line) {
980 this->operator++();
981 }
982
983 bool operator==(const LineCoverageIterator &R) const {
984 return &CD == &R.CD && Next == R.Next && Ended == R.Ended;
985 }
986
987 const LineCoverageStats &operator*() const { return Stats; }
988
989 LineCoverageIterator &operator++();
990
991 LineCoverageIterator getEnd() const {
992 auto EndIt = *this;
993 EndIt.Next = CD.end();
994 EndIt.Ended = true;
995 return EndIt;
996 }
997
998private:
999 const CoverageData &CD;
1000 const CoverageSegment *WrappedSegment;
1001 std::vector<CoverageSegment>::const_iterator Next;
1002 bool Ended;
1003 unsigned Line;
1004 SmallVector<const CoverageSegment *, 4> Segments;
1005 LineCoverageStats Stats;
1006};
1007
1008/// Get a \c LineCoverageIterator range for the lines described by \p CD.
1009static inline iterator_range<LineCoverageIterator>
1010getLineCoverageStats(const coverage::CoverageData &CD) {
1011 auto Begin = LineCoverageIterator(CD);
1012 auto End = Begin.getEnd();
1013 return make_range(x: Begin, y: End);
1014}
1015
1016// Coverage mappping data (V2) has the following layout:
1017// IPSK_covmap:
1018// [CoverageMapFileHeader]
1019// [ArrayStart]
1020// [CovMapFunctionRecordV2]
1021// [CovMapFunctionRecordV2]
1022// ...
1023// [ArrayEnd]
1024// [Encoded Filenames and Region Mapping Data]
1025//
1026// Coverage mappping data (V3) has the following layout:
1027// IPSK_covmap:
1028// [CoverageMapFileHeader]
1029// [Encoded Filenames]
1030// IPSK_covfun:
1031// [ArrayStart]
1032// odr_name_1: [CovMapFunctionRecordV3]
1033// odr_name_2: [CovMapFunctionRecordV3]
1034// ...
1035// [ArrayEnd]
1036//
1037// Both versions of the coverage mapping format encode the same information,
1038// but the V3 format does so more compactly by taking advantage of linkonce_odr
1039// semantics (it allows exactly 1 function record per name reference).
1040
1041/// This namespace defines accessors shared by different versions of coverage
1042/// mapping records.
1043namespace accessors {
1044
1045/// Return the structural hash associated with the function.
1046template <class FuncRecordTy, llvm::endianness Endian>
1047uint64_t getFuncHash(const FuncRecordTy *Record) {
1048 return support::endian::byte_swap<uint64_t, Endian>(Record->FuncHash);
1049}
1050
1051/// Return the coverage map data size for the function.
1052template <class FuncRecordTy, llvm::endianness Endian>
1053uint64_t getDataSize(const FuncRecordTy *Record) {
1054 return support::endian::byte_swap<uint32_t, Endian>(Record->DataSize);
1055}
1056
1057/// Return the function lookup key. The value is considered opaque.
1058template <class FuncRecordTy, llvm::endianness Endian>
1059uint64_t getFuncNameRef(const FuncRecordTy *Record) {
1060 return support::endian::byte_swap<uint64_t, Endian>(Record->NameRef);
1061}
1062
1063/// Return the PGO name of the function. Used for formats in which the name is
1064/// a hash.
1065template <class FuncRecordTy, llvm::endianness Endian>
1066Error getFuncNameViaRef(const FuncRecordTy *Record,
1067 InstrProfSymtab &ProfileNames, StringRef &FuncName) {
1068 uint64_t NameRef = getFuncNameRef<FuncRecordTy, Endian>(Record);
1069 FuncName = ProfileNames.getFuncOrVarName(MD5Hash: NameRef);
1070 return Error::success();
1071}
1072
1073/// Read coverage mapping out-of-line, from \p MappingBuf. This is used when the
1074/// coverage mapping is attached to the file header, instead of to the function
1075/// record.
1076template <class FuncRecordTy, llvm::endianness Endian>
1077StringRef getCoverageMappingOutOfLine(const FuncRecordTy *Record,
1078 const char *MappingBuf) {
1079 return {MappingBuf, size_t(getDataSize<FuncRecordTy, Endian>(Record))};
1080}
1081
1082/// Advance to the next out-of-line coverage mapping and its associated
1083/// function record.
1084template <class FuncRecordTy, llvm::endianness Endian>
1085std::pair<const char *, const FuncRecordTy *>
1086advanceByOneOutOfLine(const FuncRecordTy *Record, const char *MappingBuf) {
1087 return {MappingBuf + getDataSize<FuncRecordTy, Endian>(Record), Record + 1};
1088}
1089
1090} // end namespace accessors
1091
1092LLVM_PACKED_START
1093template <class IntPtrT>
1094struct CovMapFunctionRecordV1 {
1095 using ThisT = CovMapFunctionRecordV1<IntPtrT>;
1096
1097#define COVMAP_V1
1098#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
1099#include "llvm/ProfileData/InstrProfData.inc"
1100#undef COVMAP_V1
1101 CovMapFunctionRecordV1() = delete;
1102
1103 template <llvm::endianness Endian> uint64_t getFuncHash() const {
1104 return accessors::getFuncHash<ThisT, Endian>(this);
1105 }
1106
1107 template <llvm::endianness Endian> uint64_t getDataSize() const {
1108 return accessors::getDataSize<ThisT, Endian>(this);
1109 }
1110
1111 /// Return function lookup key. The value is consider opaque.
1112 template <llvm::endianness Endian> IntPtrT getFuncNameRef() const {
1113 return support::endian::byte_swap<IntPtrT, Endian>(NamePtr);
1114 }
1115
1116 /// Return the PGO name of the function.
1117 template <llvm::endianness Endian>
1118 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
1119 IntPtrT NameRef = getFuncNameRef<Endian>();
1120 uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize);
1121 FuncName = ProfileNames.getFuncName(FuncNameAddress: NameRef, NameSize: NameS);
1122 if (NameS && FuncName.empty())
1123 return make_error<CoverageMapError>(Args: coveragemap_error::malformed,
1124 Args: "function name is empty");
1125 return Error::success();
1126 }
1127
1128 template <llvm::endianness Endian>
1129 std::pair<const char *, const ThisT *>
1130 advanceByOne(const char *MappingBuf) const {
1131 return accessors::advanceByOneOutOfLine<ThisT, Endian>(this, MappingBuf);
1132 }
1133
1134 template <llvm::endianness Endian> uint64_t getFilenamesRef() const {
1135 llvm_unreachable("V1 function format does not contain a filenames ref");
1136 }
1137
1138 template <llvm::endianness Endian>
1139 StringRef getCoverageMapping(const char *MappingBuf) const {
1140 return accessors::getCoverageMappingOutOfLine<ThisT, Endian>(this,
1141 MappingBuf);
1142 }
1143};
1144
1145struct CovMapFunctionRecordV2 {
1146 using ThisT = CovMapFunctionRecordV2;
1147
1148#define COVMAP_V2
1149#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
1150#include "llvm/ProfileData/InstrProfData.inc"
1151#undef COVMAP_V2
1152 CovMapFunctionRecordV2() = delete;
1153
1154 template <llvm::endianness Endian> uint64_t getFuncHash() const {
1155 return accessors::getFuncHash<ThisT, Endian>(this);
1156 }
1157
1158 template <llvm::endianness Endian> uint64_t getDataSize() const {
1159 return accessors::getDataSize<ThisT, Endian>(this);
1160 }
1161
1162 template <llvm::endianness Endian> uint64_t getFuncNameRef() const {
1163 return accessors::getFuncNameRef<ThisT, Endian>(this);
1164 }
1165
1166 template <llvm::endianness Endian>
1167 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
1168 return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames,
1169 FuncName);
1170 }
1171
1172 template <llvm::endianness Endian>
1173 std::pair<const char *, const ThisT *>
1174 advanceByOne(const char *MappingBuf) const {
1175 return accessors::advanceByOneOutOfLine<ThisT, Endian>(this, MappingBuf);
1176 }
1177
1178 template <llvm::endianness Endian> uint64_t getFilenamesRef() const {
1179 llvm_unreachable("V2 function format does not contain a filenames ref");
1180 }
1181
1182 template <llvm::endianness Endian>
1183 StringRef getCoverageMapping(const char *MappingBuf) const {
1184 return accessors::getCoverageMappingOutOfLine<ThisT, Endian>(this,
1185 MappingBuf);
1186 }
1187};
1188
1189struct CovMapFunctionRecordV3 {
1190 using ThisT = CovMapFunctionRecordV3;
1191
1192#define COVMAP_V3
1193#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
1194#include "llvm/ProfileData/InstrProfData.inc"
1195#undef COVMAP_V3
1196 CovMapFunctionRecordV3() = delete;
1197
1198 template <llvm::endianness Endian> uint64_t getFuncHash() const {
1199 return accessors::getFuncHash<ThisT, Endian>(this);
1200 }
1201
1202 template <llvm::endianness Endian> uint64_t getDataSize() const {
1203 return accessors::getDataSize<ThisT, Endian>(this);
1204 }
1205
1206 template <llvm::endianness Endian> uint64_t getFuncNameRef() const {
1207 return accessors::getFuncNameRef<ThisT, Endian>(this);
1208 }
1209
1210 template <llvm::endianness Endian>
1211 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
1212 return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames,
1213 FuncName);
1214 }
1215
1216 /// Get the filename set reference.
1217 template <llvm::endianness Endian> uint64_t getFilenamesRef() const {
1218 return support::endian::byte_swap<uint64_t, Endian>(FilenamesRef);
1219 }
1220
1221 /// Read the inline coverage mapping. Ignore the buffer parameter, it is for
1222 /// out-of-line coverage mapping data only.
1223 template <llvm::endianness Endian>
1224 StringRef getCoverageMapping(const char *) const {
1225 return StringRef(&CoverageMapping, getDataSize<Endian>());
1226 }
1227
1228 // Advance to the next inline coverage mapping and its associated function
1229 // record. Ignore the out-of-line coverage mapping buffer.
1230 template <llvm::endianness Endian>
1231 std::pair<const char *, const CovMapFunctionRecordV3 *>
1232 advanceByOne(const char *) const {
1233 assert(isAddrAligned(Align(8), this) && "Function record not aligned");
1234 const char *Next = ((const char *)this) + sizeof(CovMapFunctionRecordV3) -
1235 sizeof(char) + getDataSize<Endian>();
1236 // Each function record has an alignment of 8, so we need to adjust
1237 // alignment before reading the next record.
1238 Next += offsetToAlignedAddr(Addr: Next, Alignment: Align(8));
1239 return {nullptr, reinterpret_cast<const CovMapFunctionRecordV3 *>(Next)};
1240 }
1241};
1242
1243// Per module coverage mapping data header, i.e. CoverageMapFileHeader
1244// documented above.
1245struct CovMapHeader {
1246#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
1247#include "llvm/ProfileData/InstrProfData.inc"
1248 template <llvm::endianness Endian> uint32_t getNRecords() const {
1249 return support::endian::byte_swap<uint32_t, Endian>(NRecords);
1250 }
1251
1252 template <llvm::endianness Endian> uint32_t getFilenamesSize() const {
1253 return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize);
1254 }
1255
1256 template <llvm::endianness Endian> uint32_t getCoverageSize() const {
1257 return support::endian::byte_swap<uint32_t, Endian>(CoverageSize);
1258 }
1259
1260 template <llvm::endianness Endian> uint32_t getVersion() const {
1261 return support::endian::byte_swap<uint32_t, Endian>(Version);
1262 }
1263};
1264
1265LLVM_PACKED_END
1266
1267enum CovMapVersion {
1268 Version1 = 0,
1269 // Function's name reference from CovMapFuncRecord is changed from raw
1270 // name string pointer to MD5 to support name section compression. Name
1271 // section is also compressed.
1272 Version2 = 1,
1273 // A new interpretation of the columnEnd field is added in order to mark
1274 // regions as gap areas.
1275 Version3 = 2,
1276 // Function records are named, uniqued, and moved to a dedicated section.
1277 Version4 = 3,
1278 // Branch regions referring to two counters are added
1279 Version5 = 4,
1280 // Compilation directory is stored separately and combined with relative
1281 // filenames to produce an absolute file path.
1282 Version6 = 5,
1283 // Branch regions extended and Decision Regions added for MC/DC.
1284 Version7 = 6,
1285 // The current version is Version7.
1286 CurrentVersion = INSTR_PROF_COVMAP_VERSION
1287};
1288
1289// Correspond to "llvmcovm", in little-endian.
1290constexpr uint64_t TestingFormatMagic = 0x6d766f636d766c6c;
1291
1292enum class TestingFormatVersion : uint64_t {
1293 // The first version's number corresponds to the string "testdata" in
1294 // little-endian. This is for a historical reason.
1295 Version1 = 0x6174616474736574,
1296 // Version1 has a defect that it can't store multiple file records. Version2
1297 // fix this problem by adding a new field before the file records section.
1298 Version2 = 1,
1299 // The current testing format version is Version2.
1300 CurrentVersion = Version2
1301};
1302
1303template <int CovMapVersion, class IntPtrT> struct CovMapTraits {
1304 using CovMapFuncRecordType = CovMapFunctionRecordV3;
1305 using NameRefType = uint64_t;
1306};
1307
1308template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version3, IntPtrT> {
1309 using CovMapFuncRecordType = CovMapFunctionRecordV2;
1310 using NameRefType = uint64_t;
1311};
1312
1313template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version2, IntPtrT> {
1314 using CovMapFuncRecordType = CovMapFunctionRecordV2;
1315 using NameRefType = uint64_t;
1316};
1317
1318template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version1, IntPtrT> {
1319 using CovMapFuncRecordType = CovMapFunctionRecordV1<IntPtrT>;
1320 using NameRefType = IntPtrT;
1321};
1322
1323} // end namespace coverage
1324
1325/// Provide DenseMapInfo for CounterExpression
1326template<> struct DenseMapInfo<coverage::CounterExpression> {
1327 static inline coverage::CounterExpression getEmptyKey() {
1328 using namespace coverage;
1329
1330 return CounterExpression(CounterExpression::ExprKind::Subtract,
1331 Counter::getCounter(CounterId: ~0U),
1332 Counter::getCounter(CounterId: ~0U));
1333 }
1334
1335 static inline coverage::CounterExpression getTombstoneKey() {
1336 using namespace coverage;
1337
1338 return CounterExpression(CounterExpression::ExprKind::Add,
1339 Counter::getCounter(CounterId: ~0U),
1340 Counter::getCounter(CounterId: ~0U));
1341 }
1342
1343 static unsigned getHashValue(const coverage::CounterExpression &V) {
1344 return static_cast<unsigned>(
1345 hash_combine(args: V.Kind, args: V.LHS.getKind(), args: V.LHS.getCounterID(),
1346 args: V.RHS.getKind(), args: V.RHS.getCounterID()));
1347 }
1348
1349 static bool isEqual(const coverage::CounterExpression &LHS,
1350 const coverage::CounterExpression &RHS) {
1351 return LHS.Kind == RHS.Kind && LHS.LHS == RHS.LHS && LHS.RHS == RHS.RHS;
1352 }
1353};
1354
1355} // end namespace llvm
1356
1357#endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
1358

source code of llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h