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