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