1 //===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- 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 // Instrumentation-based code coverage mapping generator 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CoverageMappingGen.h" 14 #include "CodeGenFunction.h" 15 #include "clang/AST/StmtVisitor.h" 16 #include "clang/Basic/Diagnostic.h" 17 #include "clang/Basic/FileManager.h" 18 #include "clang/Frontend/FrontendDiagnostic.h" 19 #include "clang/Lex/Lexer.h" 20 #include "llvm/ADT/SmallSet.h" 21 #include "llvm/ADT/StringExtras.h" 22 #include "llvm/ProfileData/Coverage/CoverageMapping.h" 23 #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" 24 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" 25 #include "llvm/ProfileData/InstrProfReader.h" 26 #include "llvm/Support/FileSystem.h" 27 #include "llvm/Support/Path.h" 28 #include <optional> 29 30 // This selects the coverage mapping format defined when `InstrProfData.inc` 31 // is textually included. 32 #define COVMAP_V3 33 34 static llvm::cl::opt<bool> EmptyLineCommentCoverage( 35 "emptyline-comment-coverage", 36 llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only " 37 "disable it on test)"), 38 llvm::cl::init(true), llvm::cl::Hidden); 39 40 llvm::cl::opt<bool> SystemHeadersCoverage( 41 "system-headers-coverage", 42 llvm::cl::desc("Enable collecting coverage from system headers"), 43 llvm::cl::init(false), llvm::cl::Hidden); 44 45 using namespace clang; 46 using namespace CodeGen; 47 using namespace llvm::coverage; 48 49 CoverageSourceInfo * 50 CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) { 51 CoverageSourceInfo *CoverageInfo = 52 new CoverageSourceInfo(PP.getSourceManager()); 53 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo)); 54 if (EmptyLineCommentCoverage) { 55 PP.addCommentHandler(CoverageInfo); 56 PP.setEmptylineHandler(CoverageInfo); 57 PP.setPreprocessToken(true); 58 PP.setTokenWatcher([CoverageInfo](clang::Token Tok) { 59 // Update previous token location. 60 CoverageInfo->PrevTokLoc = Tok.getLocation(); 61 if (Tok.getKind() != clang::tok::eod) 62 CoverageInfo->updateNextTokLoc(Tok.getLocation()); 63 }); 64 } 65 return CoverageInfo; 66 } 67 68 void CoverageSourceInfo::AddSkippedRange(SourceRange Range, 69 SkippedRange::Kind RangeKind) { 70 if (EmptyLineCommentCoverage && !SkippedRanges.empty() && 71 PrevTokLoc == SkippedRanges.back().PrevTokLoc && 72 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(), 73 Range.getBegin())) 74 SkippedRanges.back().Range.setEnd(Range.getEnd()); 75 else 76 SkippedRanges.push_back({Range, RangeKind, PrevTokLoc}); 77 } 78 79 void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) { 80 AddSkippedRange(Range, SkippedRange::PPIfElse); 81 } 82 83 void CoverageSourceInfo::HandleEmptyline(SourceRange Range) { 84 AddSkippedRange(Range, SkippedRange::EmptyLine); 85 } 86 87 bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) { 88 AddSkippedRange(Range, SkippedRange::Comment); 89 return false; 90 } 91 92 void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) { 93 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid()) 94 SkippedRanges.back().NextTokLoc = Loc; 95 } 96 97 namespace { 98 /// A region of source code that can be mapped to a counter. 99 class SourceMappingRegion { 100 /// Primary Counter that is also used for Branch Regions for "True" branches. 101 Counter Count; 102 103 /// Secondary Counter used for Branch Regions for "False" branches. 104 std::optional<Counter> FalseCount; 105 106 /// Parameters used for Modified Condition/Decision Coverage 107 mcdc::Parameters MCDCParams; 108 109 /// The region's starting location. 110 std::optional<SourceLocation> LocStart; 111 112 /// The region's ending location. 113 std::optional<SourceLocation> LocEnd; 114 115 /// Whether this region is a gap region. The count from a gap region is set 116 /// as the line execution count if there are no other regions on the line. 117 bool GapRegion; 118 119 /// Whetever this region is skipped ('if constexpr' or 'if consteval' untaken 120 /// branch, or anything skipped but not empty line / comments) 121 bool SkippedRegion; 122 123 public: 124 SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart, 125 std::optional<SourceLocation> LocEnd, 126 bool GapRegion = false) 127 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion), 128 SkippedRegion(false) {} 129 130 SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount, 131 mcdc::Parameters MCDCParams, 132 std::optional<SourceLocation> LocStart, 133 std::optional<SourceLocation> LocEnd, 134 bool GapRegion = false) 135 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams), 136 LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion), 137 SkippedRegion(false) {} 138 139 SourceMappingRegion(mcdc::Parameters MCDCParams, 140 std::optional<SourceLocation> LocStart, 141 std::optional<SourceLocation> LocEnd) 142 : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd), 143 GapRegion(false), SkippedRegion(false) {} 144 145 const Counter &getCounter() const { return Count; } 146 147 const Counter &getFalseCounter() const { 148 assert(FalseCount && "Region has no alternate counter"); 149 return *FalseCount; 150 } 151 152 void setCounter(Counter C) { Count = C; } 153 154 bool hasStartLoc() const { return LocStart.has_value(); } 155 156 void setStartLoc(SourceLocation Loc) { LocStart = Loc; } 157 158 SourceLocation getBeginLoc() const { 159 assert(LocStart && "Region has no start location"); 160 return *LocStart; 161 } 162 163 bool hasEndLoc() const { return LocEnd.has_value(); } 164 165 void setEndLoc(SourceLocation Loc) { 166 assert(Loc.isValid() && "Setting an invalid end location"); 167 LocEnd = Loc; 168 } 169 170 SourceLocation getEndLoc() const { 171 assert(LocEnd && "Region has no end location"); 172 return *LocEnd; 173 } 174 175 bool isGap() const { return GapRegion; } 176 177 void setGap(bool Gap) { GapRegion = Gap; } 178 179 bool isSkipped() const { return SkippedRegion; } 180 181 void setSkipped(bool Skipped) { SkippedRegion = Skipped; } 182 183 bool isBranch() const { return FalseCount.has_value(); } 184 185 bool isMCDCDecision() const { 186 const auto *DecisionParams = 187 std::get_if<mcdc::DecisionParameters>(&MCDCParams); 188 assert(!DecisionParams || DecisionParams->NumConditions > 0); 189 return DecisionParams; 190 } 191 192 const auto &getMCDCDecisionParams() const { 193 return mcdc::getParams<const mcdc::DecisionParameters>(MCDCParams); 194 } 195 196 const mcdc::Parameters &getMCDCParams() const { return MCDCParams; } 197 }; 198 199 /// Spelling locations for the start and end of a source region. 200 struct SpellingRegion { 201 /// The line where the region starts. 202 unsigned LineStart; 203 204 /// The column where the region starts. 205 unsigned ColumnStart; 206 207 /// The line where the region ends. 208 unsigned LineEnd; 209 210 /// The column where the region ends. 211 unsigned ColumnEnd; 212 213 SpellingRegion(SourceManager &SM, SourceLocation LocStart, 214 SourceLocation LocEnd) { 215 LineStart = SM.getSpellingLineNumber(LocStart); 216 ColumnStart = SM.getSpellingColumnNumber(LocStart); 217 LineEnd = SM.getSpellingLineNumber(LocEnd); 218 ColumnEnd = SM.getSpellingColumnNumber(LocEnd); 219 } 220 221 SpellingRegion(SourceManager &SM, SourceMappingRegion &R) 222 : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {} 223 224 /// Check if the start and end locations appear in source order, i.e 225 /// top->bottom, left->right. 226 bool isInSourceOrder() const { 227 return (LineStart < LineEnd) || 228 (LineStart == LineEnd && ColumnStart <= ColumnEnd); 229 } 230 }; 231 232 /// Provides the common functionality for the different 233 /// coverage mapping region builders. 234 class CoverageMappingBuilder { 235 public: 236 CoverageMappingModuleGen &CVM; 237 SourceManager &SM; 238 const LangOptions &LangOpts; 239 240 private: 241 /// Map of clang's FileIDs to IDs used for coverage mapping. 242 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8> 243 FileIDMapping; 244 245 public: 246 /// The coverage mapping regions for this function 247 llvm::SmallVector<CounterMappingRegion, 32> MappingRegions; 248 /// The source mapping regions for this function. 249 std::vector<SourceMappingRegion> SourceRegions; 250 251 /// A set of regions which can be used as a filter. 252 /// 253 /// It is produced by emitExpansionRegions() and is used in 254 /// emitSourceRegions() to suppress producing code regions if 255 /// the same area is covered by expansion regions. 256 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8> 257 SourceRegionFilter; 258 259 CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, 260 const LangOptions &LangOpts) 261 : CVM(CVM), SM(SM), LangOpts(LangOpts) {} 262 263 /// Return the precise end location for the given token. 264 SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) { 265 // We avoid getLocForEndOfToken here, because it doesn't do what we want for 266 // macro locations, which we just treat as expanded files. 267 unsigned TokLen = 268 Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts); 269 return Loc.getLocWithOffset(TokLen); 270 } 271 272 /// Return the start location of an included file or expanded macro. 273 SourceLocation getStartOfFileOrMacro(SourceLocation Loc) { 274 if (Loc.isMacroID()) 275 return Loc.getLocWithOffset(-SM.getFileOffset(Loc)); 276 return SM.getLocForStartOfFile(SM.getFileID(Loc)); 277 } 278 279 /// Return the end location of an included file or expanded macro. 280 SourceLocation getEndOfFileOrMacro(SourceLocation Loc) { 281 if (Loc.isMacroID()) 282 return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) - 283 SM.getFileOffset(Loc)); 284 return SM.getLocForEndOfFile(SM.getFileID(Loc)); 285 } 286 287 /// Find out where the current file is included or macro is expanded. 288 SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) { 289 return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin() 290 : SM.getIncludeLoc(SM.getFileID(Loc)); 291 } 292 293 /// Return true if \c Loc is a location in a built-in macro. 294 bool isInBuiltin(SourceLocation Loc) { 295 return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>"; 296 } 297 298 /// Check whether \c Loc is included or expanded from \c Parent. 299 bool isNestedIn(SourceLocation Loc, FileID Parent) { 300 do { 301 Loc = getIncludeOrExpansionLoc(Loc); 302 if (Loc.isInvalid()) 303 return false; 304 } while (!SM.isInFileID(Loc, Parent)); 305 return true; 306 } 307 308 /// Get the start of \c S ignoring macro arguments and builtin macros. 309 SourceLocation getStart(const Stmt *S) { 310 SourceLocation Loc = S->getBeginLoc(); 311 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) 312 Loc = SM.getImmediateExpansionRange(Loc).getBegin(); 313 return Loc; 314 } 315 316 /// Get the end of \c S ignoring macro arguments and builtin macros. 317 SourceLocation getEnd(const Stmt *S) { 318 SourceLocation Loc = S->getEndLoc(); 319 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) 320 Loc = SM.getImmediateExpansionRange(Loc).getBegin(); 321 return getPreciseTokenLocEnd(Loc); 322 } 323 324 /// Find the set of files we have regions for and assign IDs 325 /// 326 /// Fills \c Mapping with the virtual file mapping needed to write out 327 /// coverage and collects the necessary file information to emit source and 328 /// expansion regions. 329 void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) { 330 FileIDMapping.clear(); 331 332 llvm::SmallSet<FileID, 8> Visited; 333 SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs; 334 for (const auto &Region : SourceRegions) { 335 SourceLocation Loc = Region.getBeginLoc(); 336 FileID File = SM.getFileID(Loc); 337 if (!Visited.insert(File).second) 338 continue; 339 340 // Do not map FileID's associated with system headers unless collecting 341 // coverage from system headers is explicitly enabled. 342 if (!SystemHeadersCoverage && SM.isInSystemHeader(SM.getSpellingLoc(Loc))) 343 continue; 344 345 unsigned Depth = 0; 346 for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc); 347 Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent)) 348 ++Depth; 349 FileLocs.push_back(std::make_pair(Loc, Depth)); 350 } 351 llvm::stable_sort(FileLocs, llvm::less_second()); 352 353 for (const auto &FL : FileLocs) { 354 SourceLocation Loc = FL.first; 355 FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first; 356 auto Entry = SM.getFileEntryRefForID(SpellingFile); 357 if (!Entry) 358 continue; 359 360 FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc); 361 Mapping.push_back(CVM.getFileID(*Entry)); 362 } 363 } 364 365 /// Get the coverage mapping file ID for \c Loc. 366 /// 367 /// If such file id doesn't exist, return std::nullopt. 368 std::optional<unsigned> getCoverageFileID(SourceLocation Loc) { 369 auto Mapping = FileIDMapping.find(SM.getFileID(Loc)); 370 if (Mapping != FileIDMapping.end()) 371 return Mapping->second.first; 372 return std::nullopt; 373 } 374 375 /// This shrinks the skipped range if it spans a line that contains a 376 /// non-comment token. If shrinking the skipped range would make it empty, 377 /// this returns std::nullopt. 378 /// Note this function can potentially be expensive because 379 /// getSpellingLineNumber uses getLineNumber, which is expensive. 380 std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM, 381 SourceLocation LocStart, 382 SourceLocation LocEnd, 383 SourceLocation PrevTokLoc, 384 SourceLocation NextTokLoc) { 385 SpellingRegion SR{SM, LocStart, LocEnd}; 386 SR.ColumnStart = 1; 387 if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) && 388 SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc)) 389 SR.LineStart++; 390 if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) && 391 SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) { 392 SR.LineEnd--; 393 SR.ColumnEnd++; 394 } 395 if (SR.isInSourceOrder()) 396 return SR; 397 return std::nullopt; 398 } 399 400 /// Gather all the regions that were skipped by the preprocessor 401 /// using the constructs like #if or comments. 402 void gatherSkippedRegions() { 403 /// An array of the minimum lineStarts and the maximum lineEnds 404 /// for mapping regions from the appropriate source files. 405 llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges; 406 FileLineRanges.resize( 407 FileIDMapping.size(), 408 std::make_pair(std::numeric_limits<unsigned>::max(), 0)); 409 for (const auto &R : MappingRegions) { 410 FileLineRanges[R.FileID].first = 411 std::min(FileLineRanges[R.FileID].first, R.LineStart); 412 FileLineRanges[R.FileID].second = 413 std::max(FileLineRanges[R.FileID].second, R.LineEnd); 414 } 415 416 auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges(); 417 for (auto &I : SkippedRanges) { 418 SourceRange Range = I.Range; 419 auto LocStart = Range.getBegin(); 420 auto LocEnd = Range.getEnd(); 421 assert(SM.isWrittenInSameFile(LocStart, LocEnd) && 422 "region spans multiple files"); 423 424 auto CovFileID = getCoverageFileID(LocStart); 425 if (!CovFileID) 426 continue; 427 std::optional<SpellingRegion> SR; 428 if (I.isComment()) 429 SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc, 430 I.NextTokLoc); 431 else if (I.isPPIfElse() || I.isEmptyLine()) 432 SR = {SM, LocStart, LocEnd}; 433 434 if (!SR) 435 continue; 436 auto Region = CounterMappingRegion::makeSkipped( 437 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd, 438 SR->ColumnEnd); 439 // Make sure that we only collect the regions that are inside 440 // the source code of this function. 441 if (Region.LineStart >= FileLineRanges[*CovFileID].first && 442 Region.LineEnd <= FileLineRanges[*CovFileID].second) 443 MappingRegions.push_back(Region); 444 } 445 } 446 447 /// Generate the coverage counter mapping regions from collected 448 /// source regions. 449 void emitSourceRegions(const SourceRegionFilter &Filter) { 450 for (const auto &Region : SourceRegions) { 451 assert(Region.hasEndLoc() && "incomplete region"); 452 453 SourceLocation LocStart = Region.getBeginLoc(); 454 assert(SM.getFileID(LocStart).isValid() && "region in invalid file"); 455 456 // Ignore regions from system headers unless collecting coverage from 457 // system headers is explicitly enabled. 458 if (!SystemHeadersCoverage && 459 SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) 460 continue; 461 462 auto CovFileID = getCoverageFileID(LocStart); 463 // Ignore regions that don't have a file, such as builtin macros. 464 if (!CovFileID) 465 continue; 466 467 SourceLocation LocEnd = Region.getEndLoc(); 468 assert(SM.isWrittenInSameFile(LocStart, LocEnd) && 469 "region spans multiple files"); 470 471 // Don't add code regions for the area covered by expansion regions. 472 // This not only suppresses redundant regions, but sometimes prevents 473 // creating regions with wrong counters if, for example, a statement's 474 // body ends at the end of a nested macro. 475 if (Filter.count(std::make_pair(LocStart, LocEnd))) 476 continue; 477 478 // Find the spelling locations for the mapping region. 479 SpellingRegion SR{SM, LocStart, LocEnd}; 480 assert(SR.isInSourceOrder() && "region start and end out of order"); 481 482 if (Region.isGap()) { 483 MappingRegions.push_back(CounterMappingRegion::makeGapRegion( 484 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, 485 SR.LineEnd, SR.ColumnEnd)); 486 } else if (Region.isSkipped()) { 487 MappingRegions.push_back(CounterMappingRegion::makeSkipped( 488 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, 489 SR.ColumnEnd)); 490 } else if (Region.isBranch()) { 491 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion( 492 Region.getCounter(), Region.getFalseCounter(), *CovFileID, 493 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd, 494 Region.getMCDCParams())); 495 } else if (Region.isMCDCDecision()) { 496 MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion( 497 Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart, 498 SR.ColumnStart, SR.LineEnd, SR.ColumnEnd)); 499 } else { 500 MappingRegions.push_back(CounterMappingRegion::makeRegion( 501 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, 502 SR.LineEnd, SR.ColumnEnd)); 503 } 504 } 505 } 506 507 /// Generate expansion regions for each virtual file we've seen. 508 SourceRegionFilter emitExpansionRegions() { 509 SourceRegionFilter Filter; 510 for (const auto &FM : FileIDMapping) { 511 SourceLocation ExpandedLoc = FM.second.second; 512 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc); 513 if (ParentLoc.isInvalid()) 514 continue; 515 516 auto ParentFileID = getCoverageFileID(ParentLoc); 517 if (!ParentFileID) 518 continue; 519 auto ExpandedFileID = getCoverageFileID(ExpandedLoc); 520 assert(ExpandedFileID && "expansion in uncovered file"); 521 522 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc); 523 assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) && 524 "region spans multiple files"); 525 Filter.insert(std::make_pair(ParentLoc, LocEnd)); 526 527 SpellingRegion SR{SM, ParentLoc, LocEnd}; 528 assert(SR.isInSourceOrder() && "region start and end out of order"); 529 MappingRegions.push_back(CounterMappingRegion::makeExpansion( 530 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart, 531 SR.LineEnd, SR.ColumnEnd)); 532 } 533 return Filter; 534 } 535 }; 536 537 /// Creates unreachable coverage regions for the functions that 538 /// are not emitted. 539 struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { 540 EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, 541 const LangOptions &LangOpts) 542 : CoverageMappingBuilder(CVM, SM, LangOpts) {} 543 544 void VisitDecl(const Decl *D) { 545 if (!D->hasBody()) 546 return; 547 auto Body = D->getBody(); 548 SourceLocation Start = getStart(Body); 549 SourceLocation End = getEnd(Body); 550 if (!SM.isWrittenInSameFile(Start, End)) { 551 // Walk up to find the common ancestor. 552 // Correct the locations accordingly. 553 FileID StartFileID = SM.getFileID(Start); 554 FileID EndFileID = SM.getFileID(End); 555 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) { 556 Start = getIncludeOrExpansionLoc(Start); 557 assert(Start.isValid() && 558 "Declaration start location not nested within a known region"); 559 StartFileID = SM.getFileID(Start); 560 } 561 while (StartFileID != EndFileID) { 562 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End)); 563 assert(End.isValid() && 564 "Declaration end location not nested within a known region"); 565 EndFileID = SM.getFileID(End); 566 } 567 } 568 SourceRegions.emplace_back(Counter(), Start, End); 569 } 570 571 /// Write the mapping data to the output stream 572 void write(llvm::raw_ostream &OS) { 573 SmallVector<unsigned, 16> FileIDMapping; 574 gatherFileIDs(FileIDMapping); 575 emitSourceRegions(SourceRegionFilter()); 576 577 if (MappingRegions.empty()) 578 return; 579 580 CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions); 581 Writer.write(OS); 582 } 583 }; 584 585 /// A wrapper object for maintaining stacks to track the resursive AST visitor 586 /// walks for the purpose of assigning IDs to leaf-level conditions measured by 587 /// MC/DC. The object is created with a reference to the MCDCBitmapMap that was 588 /// created during the initial AST walk. The presence of a bitmap associated 589 /// with a boolean expression (top-level logical operator nest) indicates that 590 /// the boolean expression qualified for MC/DC. The resulting condition IDs 591 /// are preserved in a map reference that is also provided during object 592 /// creation. 593 struct MCDCCoverageBuilder { 594 595 /// The AST walk recursively visits nested logical-AND or logical-OR binary 596 /// operator nodes and then visits their LHS and RHS children nodes. As this 597 /// happens, the algorithm will assign IDs to each operator's LHS and RHS side 598 /// as the walk moves deeper into the nest. At each level of the recursive 599 /// nest, the LHS and RHS may actually correspond to larger subtrees (not 600 /// leaf-conditions). If this is the case, when that node is visited, the ID 601 /// assigned to the subtree is re-assigned to its LHS, and a new ID is given 602 /// to its RHS. At the end of the walk, all leaf-level conditions will have a 603 /// unique ID -- keep in mind that the final set of IDs may not be in 604 /// numerical order from left to right. 605 /// 606 /// Example: "x = (A && B) || (C && D) || (D && F)" 607 /// 608 /// Visit Depth1: 609 /// (A && B) || (C && D) || (D && F) 610 /// ^-------LHS--------^ ^-RHS--^ 611 /// ID=1 ID=2 612 /// 613 /// Visit LHS-Depth2: 614 /// (A && B) || (C && D) 615 /// ^-LHS--^ ^-RHS--^ 616 /// ID=1 ID=3 617 /// 618 /// Visit LHS-Depth3: 619 /// (A && B) 620 /// LHS RHS 621 /// ID=1 ID=4 622 /// 623 /// Visit RHS-Depth3: 624 /// (C && D) 625 /// LHS RHS 626 /// ID=3 ID=5 627 /// 628 /// Visit RHS-Depth2: (D && F) 629 /// LHS RHS 630 /// ID=2 ID=6 631 /// 632 /// Visit Depth1: 633 /// (A && B) || (C && D) || (D && F) 634 /// ID=1 ID=4 ID=3 ID=5 ID=2 ID=6 635 /// 636 /// A node ID of '0' always means MC/DC isn't being tracked. 637 /// 638 /// As the AST walk proceeds recursively, the algorithm will also use a stack 639 /// to track the IDs of logical-AND and logical-OR operations on the RHS so 640 /// that it can be determined which nodes are executed next, depending on how 641 /// a LHS or RHS of a logical-AND or logical-OR is evaluated. This 642 /// information relies on the assigned IDs and are embedded within the 643 /// coverage region IDs of each branch region associated with a leaf-level 644 /// condition. This information helps the visualization tool reconstruct all 645 /// possible test vectors for the purposes of MC/DC analysis. If a "next" node 646 /// ID is '0', it means it's the end of the test vector. The following rules 647 /// are used: 648 /// 649 /// For logical-AND ("LHS && RHS"): 650 /// - If LHS is TRUE, execution goes to the RHS node. 651 /// - If LHS is FALSE, execution goes to the LHS node of the next logical-OR. 652 /// If that does not exist, execution exits (ID == 0). 653 /// 654 /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND. 655 /// If that does not exist, execution exits (ID == 0). 656 /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR. 657 /// If that does not exist, execution exits (ID == 0). 658 /// 659 /// For logical-OR ("LHS || RHS"): 660 /// - If LHS is TRUE, execution goes to the LHS node of the next logical-AND. 661 /// If that does not exist, execution exits (ID == 0). 662 /// - If LHS is FALSE, execution goes to the RHS node. 663 /// 664 /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND. 665 /// If that does not exist, execution exits (ID == 0). 666 /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR. 667 /// If that does not exist, execution exits (ID == 0). 668 /// 669 /// Finally, the condition IDs are also used when instrumenting the code to 670 /// indicate a unique offset into a temporary bitmap that represents the true 671 /// or false evaluation of that particular condition. 672 /// 673 /// NOTE regarding the use of CodeGenFunction::stripCond(). Even though, for 674 /// simplicity, parentheses and unary logical-NOT operators are considered 675 /// part of their underlying condition for both MC/DC and branch coverage, the 676 /// condition IDs themselves are assigned and tracked using the underlying 677 /// condition itself. This is done solely for consistency since parentheses 678 /// and logical-NOTs are ignored when checking whether the condition is 679 /// actually an instrumentable condition. This can also make debugging a bit 680 /// easier. 681 682 private: 683 CodeGenModule &CGM; 684 685 llvm::SmallVector<mcdc::ConditionIDs> DecisionStack; 686 MCDC::State &MCDCState; 687 mcdc::ConditionID NextID = 0; 688 bool NotMapped = false; 689 690 /// Represent a sentinel value as a pair of final decisions for the bottom 691 // of DecisionStack. 692 static constexpr mcdc::ConditionIDs DecisionStackSentinel{-1, -1}; 693 694 /// Is this a logical-AND operation? 695 bool isLAnd(const BinaryOperator *E) const { 696 return E->getOpcode() == BO_LAnd; 697 } 698 699 public: 700 MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState) 701 : CGM(CGM), DecisionStack(1, DecisionStackSentinel), 702 MCDCState(MCDCState) {} 703 704 /// Return whether the build of the control flow map is at the top-level 705 /// (root) of a logical operator nest in a boolean expression prior to the 706 /// assignment of condition IDs. 707 bool isIdle() const { return (NextID == 0 && !NotMapped); } 708 709 /// Return whether any IDs have been assigned in the build of the control 710 /// flow map, indicating that the map is being generated for this boolean 711 /// expression. 712 bool isBuilding() const { return (NextID > 0); } 713 714 /// Set the given condition's ID. 715 void setCondID(const Expr *Cond, mcdc::ConditionID ID) { 716 MCDCState.BranchByStmt[CodeGenFunction::stripCond(Cond)].ID = ID; 717 } 718 719 /// Return the ID of a given condition. 720 mcdc::ConditionID getCondID(const Expr *Cond) const { 721 auto I = MCDCState.BranchByStmt.find(CodeGenFunction::stripCond(Cond)); 722 if (I == MCDCState.BranchByStmt.end()) 723 return -1; 724 else 725 return I->second.ID; 726 } 727 728 /// Return the LHS Decision ([0,0] if not set). 729 const mcdc::ConditionIDs &back() const { return DecisionStack.back(); } 730 731 /// Push the binary operator statement to track the nest level and assign IDs 732 /// to the operator's LHS and RHS. The RHS may be a larger subtree that is 733 /// broken up on successive levels. 734 void pushAndAssignIDs(const BinaryOperator *E) { 735 if (!CGM.getCodeGenOpts().MCDCCoverage) 736 return; 737 738 // If binary expression is disqualified, don't do mapping. 739 if (!isBuilding() && 740 !MCDCState.DecisionByStmt.contains(CodeGenFunction::stripCond(E))) 741 NotMapped = true; 742 743 // Don't go any further if we don't need to map condition IDs. 744 if (NotMapped) 745 return; 746 747 const mcdc::ConditionIDs &ParentDecision = DecisionStack.back(); 748 749 // If the operator itself has an assigned ID, this means it represents a 750 // larger subtree. In this case, assign that ID to its LHS node. Its RHS 751 // will receive a new ID below. Otherwise, assign ID+1 to LHS. 752 if (MCDCState.BranchByStmt.contains(CodeGenFunction::stripCond(E))) 753 setCondID(E->getLHS(), getCondID(E)); 754 else 755 setCondID(E->getLHS(), NextID++); 756 757 // Assign a ID+1 for the RHS. 758 mcdc::ConditionID RHSid = NextID++; 759 setCondID(E->getRHS(), RHSid); 760 761 // Push the LHS decision IDs onto the DecisionStack. 762 if (isLAnd(E)) 763 DecisionStack.push_back({ParentDecision[false], RHSid}); 764 else 765 DecisionStack.push_back({RHSid, ParentDecision[true]}); 766 } 767 768 /// Pop and return the LHS Decision ([0,0] if not set). 769 mcdc::ConditionIDs pop() { 770 if (!CGM.getCodeGenOpts().MCDCCoverage || NotMapped) 771 return DecisionStackSentinel; 772 773 assert(DecisionStack.size() > 1); 774 return DecisionStack.pop_back_val(); 775 } 776 777 /// Return the total number of conditions and reset the state. The number of 778 /// conditions is zero if the expression isn't mapped. 779 unsigned getTotalConditionsAndReset(const BinaryOperator *E) { 780 if (!CGM.getCodeGenOpts().MCDCCoverage) 781 return 0; 782 783 assert(!isIdle()); 784 assert(DecisionStack.size() == 1); 785 786 // Reset state if not doing mapping. 787 if (NotMapped) { 788 NotMapped = false; 789 assert(NextID == 0); 790 return 0; 791 } 792 793 // Set number of conditions and reset. 794 unsigned TotalConds = NextID; 795 796 // Reset ID back to beginning. 797 NextID = 0; 798 799 return TotalConds; 800 } 801 }; 802 803 /// A StmtVisitor that creates coverage mapping regions which map 804 /// from the source code locations to the PGO counters. 805 struct CounterCoverageMappingBuilder 806 : public CoverageMappingBuilder, 807 public ConstStmtVisitor<CounterCoverageMappingBuilder> { 808 /// The map of statements to count values. 809 llvm::DenseMap<const Stmt *, unsigned> &CounterMap; 810 811 MCDC::State &MCDCState; 812 813 /// A stack of currently live regions. 814 llvm::SmallVector<SourceMappingRegion> RegionStack; 815 816 /// An object to manage MCDC regions. 817 MCDCCoverageBuilder MCDCBuilder; 818 819 CounterExpressionBuilder Builder; 820 821 /// A location in the most recently visited file or macro. 822 /// 823 /// This is used to adjust the active source regions appropriately when 824 /// expressions cross file or macro boundaries. 825 SourceLocation MostRecentLocation; 826 827 /// Whether the visitor at a terminate statement. 828 bool HasTerminateStmt = false; 829 830 /// Gap region counter after terminate statement. 831 Counter GapRegionCounter; 832 833 /// Return a counter for the subtraction of \c RHS from \c LHS 834 Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) { 835 return Builder.subtract(LHS, RHS, Simplify); 836 } 837 838 /// Return a counter for the sum of \c LHS and \c RHS. 839 Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) { 840 return Builder.add(LHS, RHS, Simplify); 841 } 842 843 Counter addCounters(Counter C1, Counter C2, Counter C3, 844 bool Simplify = true) { 845 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify); 846 } 847 848 /// Return the region counter for the given statement. 849 /// 850 /// This should only be called on statements that have a dedicated counter. 851 Counter getRegionCounter(const Stmt *S) { 852 return Counter::getCounter(CounterMap[S]); 853 } 854 855 auto getBitmapIdx(const Stmt *S) { 856 return MCDCState.DecisionByStmt[S].BitmapIdx; 857 } 858 859 /// Push a region onto the stack. 860 /// 861 /// Returns the index on the stack where the region was pushed. This can be 862 /// used with popRegions to exit a "scope", ending the region that was pushed. 863 size_t pushRegion(Counter Count, 864 std::optional<SourceLocation> StartLoc = std::nullopt, 865 std::optional<SourceLocation> EndLoc = std::nullopt, 866 std::optional<Counter> FalseCount = std::nullopt, 867 const mcdc::Parameters &BranchParams = std::monostate()) { 868 869 if (StartLoc && !FalseCount) { 870 MostRecentLocation = *StartLoc; 871 } 872 873 // If either of these locations is invalid, something elsewhere in the 874 // compiler has broken. 875 assert((!StartLoc || StartLoc->isValid()) && "Start location is not valid"); 876 assert((!EndLoc || EndLoc->isValid()) && "End location is not valid"); 877 878 // However, we can still recover without crashing. 879 // If either location is invalid, set it to std::nullopt to avoid 880 // letting users of RegionStack think that region has a valid start/end 881 // location. 882 if (StartLoc && StartLoc->isInvalid()) 883 StartLoc = std::nullopt; 884 if (EndLoc && EndLoc->isInvalid()) 885 EndLoc = std::nullopt; 886 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc); 887 888 return RegionStack.size() - 1; 889 } 890 891 size_t pushRegion(unsigned BitmapIdx, uint16_t Conditions, 892 std::optional<SourceLocation> StartLoc = std::nullopt, 893 std::optional<SourceLocation> EndLoc = std::nullopt) { 894 895 RegionStack.emplace_back(mcdc::DecisionParameters{BitmapIdx, Conditions}, 896 StartLoc, EndLoc); 897 898 return RegionStack.size() - 1; 899 } 900 901 size_t locationDepth(SourceLocation Loc) { 902 size_t Depth = 0; 903 while (Loc.isValid()) { 904 Loc = getIncludeOrExpansionLoc(Loc); 905 Depth++; 906 } 907 return Depth; 908 } 909 910 /// Pop regions from the stack into the function's list of regions. 911 /// 912 /// Adds all regions from \c ParentIndex to the top of the stack to the 913 /// function's \c SourceRegions. 914 void popRegions(size_t ParentIndex) { 915 assert(RegionStack.size() >= ParentIndex && "parent not in stack"); 916 while (RegionStack.size() > ParentIndex) { 917 SourceMappingRegion &Region = RegionStack.back(); 918 if (Region.hasStartLoc() && 919 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) { 920 SourceLocation StartLoc = Region.getBeginLoc(); 921 SourceLocation EndLoc = Region.hasEndLoc() 922 ? Region.getEndLoc() 923 : RegionStack[ParentIndex].getEndLoc(); 924 bool isBranch = Region.isBranch(); 925 size_t StartDepth = locationDepth(StartLoc); 926 size_t EndDepth = locationDepth(EndLoc); 927 while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) { 928 bool UnnestStart = StartDepth >= EndDepth; 929 bool UnnestEnd = EndDepth >= StartDepth; 930 if (UnnestEnd) { 931 // The region ends in a nested file or macro expansion. If the 932 // region is not a branch region, create a separate region for each 933 // expansion, and for all regions, update the EndLoc. Branch 934 // regions should not be split in order to keep a straightforward 935 // correspondance between the region and its associated branch 936 // condition, even if the condition spans multiple depths. 937 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc); 938 assert(SM.isWrittenInSameFile(NestedLoc, EndLoc)); 939 940 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc)) 941 SourceRegions.emplace_back(Region.getCounter(), NestedLoc, 942 EndLoc); 943 944 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc)); 945 if (EndLoc.isInvalid()) 946 llvm::report_fatal_error( 947 "File exit not handled before popRegions"); 948 EndDepth--; 949 } 950 if (UnnestStart) { 951 // The region ends in a nested file or macro expansion. If the 952 // region is not a branch region, create a separate region for each 953 // expansion, and for all regions, update the StartLoc. Branch 954 // regions should not be split in order to keep a straightforward 955 // correspondance between the region and its associated branch 956 // condition, even if the condition spans multiple depths. 957 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc); 958 assert(SM.isWrittenInSameFile(StartLoc, NestedLoc)); 959 960 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc)) 961 SourceRegions.emplace_back(Region.getCounter(), StartLoc, 962 NestedLoc); 963 964 StartLoc = getIncludeOrExpansionLoc(StartLoc); 965 if (StartLoc.isInvalid()) 966 llvm::report_fatal_error( 967 "File exit not handled before popRegions"); 968 StartDepth--; 969 } 970 } 971 Region.setStartLoc(StartLoc); 972 Region.setEndLoc(EndLoc); 973 974 if (!isBranch) { 975 MostRecentLocation = EndLoc; 976 // If this region happens to span an entire expansion, we need to 977 // make sure we don't overlap the parent region with it. 978 if (StartLoc == getStartOfFileOrMacro(StartLoc) && 979 EndLoc == getEndOfFileOrMacro(EndLoc)) 980 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc); 981 } 982 983 assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc)); 984 assert(SpellingRegion(SM, Region).isInSourceOrder()); 985 SourceRegions.push_back(Region); 986 } 987 RegionStack.pop_back(); 988 } 989 } 990 991 /// Return the currently active region. 992 SourceMappingRegion &getRegion() { 993 assert(!RegionStack.empty() && "statement has no region"); 994 return RegionStack.back(); 995 } 996 997 /// Propagate counts through the children of \p S if \p VisitChildren is true. 998 /// Otherwise, only emit a count for \p S itself. 999 Counter propagateCounts(Counter TopCount, const Stmt *S, 1000 bool VisitChildren = true) { 1001 SourceLocation StartLoc = getStart(S); 1002 SourceLocation EndLoc = getEnd(S); 1003 size_t Index = pushRegion(TopCount, StartLoc, EndLoc); 1004 if (VisitChildren) 1005 Visit(S); 1006 Counter ExitCount = getRegion().getCounter(); 1007 popRegions(Index); 1008 1009 // The statement may be spanned by an expansion. Make sure we handle a file 1010 // exit out of this expansion before moving to the next statement. 1011 if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc())) 1012 MostRecentLocation = EndLoc; 1013 1014 return ExitCount; 1015 } 1016 1017 /// Determine whether the given condition can be constant folded. 1018 bool ConditionFoldsToBool(const Expr *Cond) { 1019 Expr::EvalResult Result; 1020 return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())); 1021 } 1022 1023 /// Create a Branch Region around an instrumentable condition for coverage 1024 /// and add it to the function's SourceRegions. A branch region tracks a 1025 /// "True" counter and a "False" counter for boolean expressions that 1026 /// result in the generation of a branch. 1027 void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt, 1028 const mcdc::ConditionIDs &Conds = {}) { 1029 // Check for NULL conditions. 1030 if (!C) 1031 return; 1032 1033 // Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push 1034 // region onto RegionStack but immediately pop it (which adds it to the 1035 // function's SourceRegions) because it doesn't apply to any other source 1036 // code other than the Condition. 1037 if (CodeGenFunction::isInstrumentedCondition(C)) { 1038 mcdc::Parameters BranchParams; 1039 mcdc::ConditionID ID = MCDCBuilder.getCondID(C); 1040 if (ID >= 0) 1041 BranchParams = mcdc::BranchParameters{ID, Conds}; 1042 1043 // If a condition can fold to true or false, the corresponding branch 1044 // will be removed. Create a region with both counters hard-coded to 1045 // zero. This allows us to visualize them in a special way. 1046 // Alternatively, we can prevent any optimization done via 1047 // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in 1048 // CodeGenFunction.c always returns false, but that is very heavy-handed. 1049 if (ConditionFoldsToBool(C)) 1050 popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C), 1051 Counter::getZero(), BranchParams)); 1052 else 1053 // Otherwise, create a region with the True counter and False counter. 1054 popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, 1055 BranchParams)); 1056 } 1057 } 1058 1059 /// Create a Decision Region with a BitmapIdx and number of Conditions. This 1060 /// type of region "contains" branch regions, one for each of the conditions. 1061 /// The visualization tool will group everything together. 1062 void createDecisionRegion(const Expr *C, unsigned BitmapIdx, unsigned Conds) { 1063 popRegions(pushRegion(BitmapIdx, Conds, getStart(C), getEnd(C))); 1064 } 1065 1066 /// Create a Branch Region around a SwitchCase for code coverage 1067 /// and add it to the function's SourceRegions. 1068 void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt, 1069 Counter FalseCnt) { 1070 // Push region onto RegionStack but immediately pop it (which adds it to 1071 // the function's SourceRegions) because it doesn't apply to any other 1072 // source other than the SwitchCase. 1073 popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt)); 1074 } 1075 1076 /// Check whether a region with bounds \c StartLoc and \c EndLoc 1077 /// is already added to \c SourceRegions. 1078 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc, 1079 bool isBranch = false) { 1080 return llvm::any_of( 1081 llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) { 1082 return Region.getBeginLoc() == StartLoc && 1083 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch; 1084 }); 1085 } 1086 1087 /// Adjust the most recently visited location to \c EndLoc. 1088 /// 1089 /// This should be used after visiting any statements in non-source order. 1090 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) { 1091 MostRecentLocation = EndLoc; 1092 // The code region for a whole macro is created in handleFileExit() when 1093 // it detects exiting of the virtual file of that macro. If we visited 1094 // statements in non-source order, we might already have such a region 1095 // added, for example, if a body of a loop is divided among multiple 1096 // macros. Avoid adding duplicate regions in such case. 1097 if (getRegion().hasEndLoc() && 1098 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) && 1099 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation), 1100 MostRecentLocation, getRegion().isBranch())) 1101 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation); 1102 } 1103 1104 /// Adjust regions and state when \c NewLoc exits a file. 1105 /// 1106 /// If moving from our most recently tracked location to \c NewLoc exits any 1107 /// files, this adjusts our current region stack and creates the file regions 1108 /// for the exited file. 1109 void handleFileExit(SourceLocation NewLoc) { 1110 if (NewLoc.isInvalid() || 1111 SM.isWrittenInSameFile(MostRecentLocation, NewLoc)) 1112 return; 1113 1114 // If NewLoc is not in a file that contains MostRecentLocation, walk up to 1115 // find the common ancestor. 1116 SourceLocation LCA = NewLoc; 1117 FileID ParentFile = SM.getFileID(LCA); 1118 while (!isNestedIn(MostRecentLocation, ParentFile)) { 1119 LCA = getIncludeOrExpansionLoc(LCA); 1120 if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) { 1121 // Since there isn't a common ancestor, no file was exited. We just need 1122 // to adjust our location to the new file. 1123 MostRecentLocation = NewLoc; 1124 return; 1125 } 1126 ParentFile = SM.getFileID(LCA); 1127 } 1128 1129 llvm::SmallSet<SourceLocation, 8> StartLocs; 1130 std::optional<Counter> ParentCounter; 1131 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) { 1132 if (!I.hasStartLoc()) 1133 continue; 1134 SourceLocation Loc = I.getBeginLoc(); 1135 if (!isNestedIn(Loc, ParentFile)) { 1136 ParentCounter = I.getCounter(); 1137 break; 1138 } 1139 1140 while (!SM.isInFileID(Loc, ParentFile)) { 1141 // The most nested region for each start location is the one with the 1142 // correct count. We avoid creating redundant regions by stopping once 1143 // we've seen this region. 1144 if (StartLocs.insert(Loc).second) { 1145 if (I.isBranch()) 1146 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), 1147 I.getMCDCParams(), Loc, 1148 getEndOfFileOrMacro(Loc), I.isBranch()); 1149 else 1150 SourceRegions.emplace_back(I.getCounter(), Loc, 1151 getEndOfFileOrMacro(Loc)); 1152 } 1153 Loc = getIncludeOrExpansionLoc(Loc); 1154 } 1155 I.setStartLoc(getPreciseTokenLocEnd(Loc)); 1156 } 1157 1158 if (ParentCounter) { 1159 // If the file is contained completely by another region and doesn't 1160 // immediately start its own region, the whole file gets a region 1161 // corresponding to the parent. 1162 SourceLocation Loc = MostRecentLocation; 1163 while (isNestedIn(Loc, ParentFile)) { 1164 SourceLocation FileStart = getStartOfFileOrMacro(Loc); 1165 if (StartLocs.insert(FileStart).second) { 1166 SourceRegions.emplace_back(*ParentCounter, FileStart, 1167 getEndOfFileOrMacro(Loc)); 1168 assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder()); 1169 } 1170 Loc = getIncludeOrExpansionLoc(Loc); 1171 } 1172 } 1173 1174 MostRecentLocation = NewLoc; 1175 } 1176 1177 /// Ensure that \c S is included in the current region. 1178 void extendRegion(const Stmt *S) { 1179 SourceMappingRegion &Region = getRegion(); 1180 SourceLocation StartLoc = getStart(S); 1181 1182 handleFileExit(StartLoc); 1183 if (!Region.hasStartLoc()) 1184 Region.setStartLoc(StartLoc); 1185 } 1186 1187 /// Mark \c S as a terminator, starting a zero region. 1188 void terminateRegion(const Stmt *S) { 1189 extendRegion(S); 1190 SourceMappingRegion &Region = getRegion(); 1191 SourceLocation EndLoc = getEnd(S); 1192 if (!Region.hasEndLoc()) 1193 Region.setEndLoc(EndLoc); 1194 pushRegion(Counter::getZero()); 1195 HasTerminateStmt = true; 1196 } 1197 1198 /// Find a valid gap range between \p AfterLoc and \p BeforeLoc. 1199 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc, 1200 SourceLocation BeforeLoc) { 1201 // If AfterLoc is in function-like macro, use the right parenthesis 1202 // location. 1203 if (AfterLoc.isMacroID()) { 1204 FileID FID = SM.getFileID(AfterLoc); 1205 const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion(); 1206 if (EI->isFunctionMacroExpansion()) 1207 AfterLoc = EI->getExpansionLocEnd(); 1208 } 1209 1210 size_t StartDepth = locationDepth(AfterLoc); 1211 size_t EndDepth = locationDepth(BeforeLoc); 1212 while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) { 1213 bool UnnestStart = StartDepth >= EndDepth; 1214 bool UnnestEnd = EndDepth >= StartDepth; 1215 if (UnnestEnd) { 1216 assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc), 1217 BeforeLoc)); 1218 1219 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc); 1220 assert(BeforeLoc.isValid()); 1221 EndDepth--; 1222 } 1223 if (UnnestStart) { 1224 assert(SM.isWrittenInSameFile(AfterLoc, 1225 getEndOfFileOrMacro(AfterLoc))); 1226 1227 AfterLoc = getIncludeOrExpansionLoc(AfterLoc); 1228 assert(AfterLoc.isValid()); 1229 AfterLoc = getPreciseTokenLocEnd(AfterLoc); 1230 assert(AfterLoc.isValid()); 1231 StartDepth--; 1232 } 1233 } 1234 AfterLoc = getPreciseTokenLocEnd(AfterLoc); 1235 // If the start and end locations of the gap are both within the same macro 1236 // file, the range may not be in source order. 1237 if (AfterLoc.isMacroID() || BeforeLoc.isMacroID()) 1238 return std::nullopt; 1239 if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) || 1240 !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder()) 1241 return std::nullopt; 1242 return {{AfterLoc, BeforeLoc}}; 1243 } 1244 1245 /// Emit a gap region between \p StartLoc and \p EndLoc with the given count. 1246 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc, 1247 Counter Count) { 1248 if (StartLoc == EndLoc) 1249 return; 1250 assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder()); 1251 handleFileExit(StartLoc); 1252 size_t Index = pushRegion(Count, StartLoc, EndLoc); 1253 getRegion().setGap(true); 1254 handleFileExit(EndLoc); 1255 popRegions(Index); 1256 } 1257 1258 /// Find a valid range starting with \p StartingLoc and ending before \p 1259 /// BeforeLoc. 1260 std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc, 1261 SourceLocation BeforeLoc) { 1262 // If StartingLoc is in function-like macro, use its start location. 1263 if (StartingLoc.isMacroID()) { 1264 FileID FID = SM.getFileID(StartingLoc); 1265 const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion(); 1266 if (EI->isFunctionMacroExpansion()) 1267 StartingLoc = EI->getExpansionLocStart(); 1268 } 1269 1270 size_t StartDepth = locationDepth(StartingLoc); 1271 size_t EndDepth = locationDepth(BeforeLoc); 1272 while (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) { 1273 bool UnnestStart = StartDepth >= EndDepth; 1274 bool UnnestEnd = EndDepth >= StartDepth; 1275 if (UnnestEnd) { 1276 assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc), 1277 BeforeLoc)); 1278 1279 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc); 1280 assert(BeforeLoc.isValid()); 1281 EndDepth--; 1282 } 1283 if (UnnestStart) { 1284 assert(SM.isWrittenInSameFile(StartingLoc, 1285 getStartOfFileOrMacro(StartingLoc))); 1286 1287 StartingLoc = getIncludeOrExpansionLoc(StartingLoc); 1288 assert(StartingLoc.isValid()); 1289 StartDepth--; 1290 } 1291 } 1292 // If the start and end locations of the gap are both within the same macro 1293 // file, the range may not be in source order. 1294 if (StartingLoc.isMacroID() || BeforeLoc.isMacroID()) 1295 return std::nullopt; 1296 if (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc) || 1297 !SpellingRegion(SM, StartingLoc, BeforeLoc).isInSourceOrder()) 1298 return std::nullopt; 1299 return {{StartingLoc, BeforeLoc}}; 1300 } 1301 1302 void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) { 1303 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc); 1304 1305 if (!Skipped) 1306 return; 1307 1308 const auto NewStartLoc = Skipped->getBegin(); 1309 const auto EndLoc = Skipped->getEnd(); 1310 1311 if (NewStartLoc == EndLoc) 1312 return; 1313 assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder()); 1314 handleFileExit(NewStartLoc); 1315 size_t Index = pushRegion({}, NewStartLoc, EndLoc); 1316 getRegion().setSkipped(true); 1317 handleFileExit(EndLoc); 1318 popRegions(Index); 1319 } 1320 1321 /// Keep counts of breaks and continues inside loops. 1322 struct BreakContinue { 1323 Counter BreakCount; 1324 Counter ContinueCount; 1325 }; 1326 SmallVector<BreakContinue, 8> BreakContinueStack; 1327 1328 CounterCoverageMappingBuilder( 1329 CoverageMappingModuleGen &CVM, 1330 llvm::DenseMap<const Stmt *, unsigned> &CounterMap, 1331 MCDC::State &MCDCState, SourceManager &SM, const LangOptions &LangOpts) 1332 : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap), 1333 MCDCState(MCDCState), MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {} 1334 1335 /// Write the mapping data to the output stream 1336 void write(llvm::raw_ostream &OS) { 1337 llvm::SmallVector<unsigned, 8> VirtualFileMapping; 1338 gatherFileIDs(VirtualFileMapping); 1339 SourceRegionFilter Filter = emitExpansionRegions(); 1340 emitSourceRegions(Filter); 1341 gatherSkippedRegions(); 1342 1343 if (MappingRegions.empty()) 1344 return; 1345 1346 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(), 1347 MappingRegions); 1348 Writer.write(OS); 1349 } 1350 1351 void VisitStmt(const Stmt *S) { 1352 if (S->getBeginLoc().isValid()) 1353 extendRegion(S); 1354 const Stmt *LastStmt = nullptr; 1355 bool SaveTerminateStmt = HasTerminateStmt; 1356 HasTerminateStmt = false; 1357 GapRegionCounter = Counter::getZero(); 1358 for (const Stmt *Child : S->children()) 1359 if (Child) { 1360 // If last statement contains terminate statements, add a gap area 1361 // between the two statements. Skipping attributed statements, because 1362 // they don't have valid start location. 1363 if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) { 1364 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child)); 1365 if (Gap) 1366 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), 1367 GapRegionCounter); 1368 SaveTerminateStmt = true; 1369 HasTerminateStmt = false; 1370 } 1371 this->Visit(Child); 1372 LastStmt = Child; 1373 } 1374 if (SaveTerminateStmt) 1375 HasTerminateStmt = true; 1376 handleFileExit(getEnd(S)); 1377 } 1378 1379 void VisitDecl(const Decl *D) { 1380 Stmt *Body = D->getBody(); 1381 1382 // Do not propagate region counts into system headers unless collecting 1383 // coverage from system headers is explicitly enabled. 1384 if (!SystemHeadersCoverage && Body && 1385 SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body)))) 1386 return; 1387 1388 // Do not visit the artificial children nodes of defaulted methods. The 1389 // lexer may not be able to report back precise token end locations for 1390 // these children nodes (llvm.org/PR39822), and moreover users will not be 1391 // able to see coverage for them. 1392 Counter BodyCounter = getRegionCounter(Body); 1393 bool Defaulted = false; 1394 if (auto *Method = dyn_cast<CXXMethodDecl>(D)) 1395 Defaulted = Method->isDefaulted(); 1396 if (auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) { 1397 for (auto *Initializer : Ctor->inits()) { 1398 if (Initializer->isWritten()) { 1399 auto *Init = Initializer->getInit(); 1400 if (getStart(Init).isValid() && getEnd(Init).isValid()) 1401 propagateCounts(BodyCounter, Init); 1402 } 1403 } 1404 } 1405 1406 propagateCounts(BodyCounter, Body, 1407 /*VisitChildren=*/!Defaulted); 1408 assert(RegionStack.empty() && "Regions entered but never exited"); 1409 } 1410 1411 void VisitReturnStmt(const ReturnStmt *S) { 1412 extendRegion(S); 1413 if (S->getRetValue()) 1414 Visit(S->getRetValue()); 1415 terminateRegion(S); 1416 } 1417 1418 void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) { 1419 extendRegion(S); 1420 Visit(S->getBody()); 1421 } 1422 1423 void VisitCoreturnStmt(const CoreturnStmt *S) { 1424 extendRegion(S); 1425 if (S->getOperand()) 1426 Visit(S->getOperand()); 1427 terminateRegion(S); 1428 } 1429 1430 void VisitCXXThrowExpr(const CXXThrowExpr *E) { 1431 extendRegion(E); 1432 if (E->getSubExpr()) 1433 Visit(E->getSubExpr()); 1434 terminateRegion(E); 1435 } 1436 1437 void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); } 1438 1439 void VisitLabelStmt(const LabelStmt *S) { 1440 Counter LabelCount = getRegionCounter(S); 1441 SourceLocation Start = getStart(S); 1442 // We can't extendRegion here or we risk overlapping with our new region. 1443 handleFileExit(Start); 1444 pushRegion(LabelCount, Start); 1445 Visit(S->getSubStmt()); 1446 } 1447 1448 void VisitBreakStmt(const BreakStmt *S) { 1449 assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); 1450 BreakContinueStack.back().BreakCount = addCounters( 1451 BreakContinueStack.back().BreakCount, getRegion().getCounter()); 1452 // FIXME: a break in a switch should terminate regions for all preceding 1453 // case statements, not just the most recent one. 1454 terminateRegion(S); 1455 } 1456 1457 void VisitContinueStmt(const ContinueStmt *S) { 1458 assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); 1459 BreakContinueStack.back().ContinueCount = addCounters( 1460 BreakContinueStack.back().ContinueCount, getRegion().getCounter()); 1461 terminateRegion(S); 1462 } 1463 1464 void VisitCallExpr(const CallExpr *E) { 1465 VisitStmt(E); 1466 1467 // Terminate the region when we hit a noreturn function. 1468 // (This is helpful dealing with switch statements.) 1469 QualType CalleeType = E->getCallee()->getType(); 1470 if (getFunctionExtInfo(*CalleeType).getNoReturn()) 1471 terminateRegion(E); 1472 } 1473 1474 void VisitWhileStmt(const WhileStmt *S) { 1475 extendRegion(S); 1476 1477 Counter ParentCount = getRegion().getCounter(); 1478 Counter BodyCount = getRegionCounter(S); 1479 1480 // Handle the body first so that we can get the backedge count. 1481 BreakContinueStack.push_back(BreakContinue()); 1482 extendRegion(S->getBody()); 1483 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 1484 BreakContinue BC = BreakContinueStack.pop_back_val(); 1485 1486 bool BodyHasTerminateStmt = HasTerminateStmt; 1487 HasTerminateStmt = false; 1488 1489 // Go back to handle the condition. 1490 Counter CondCount = 1491 addCounters(ParentCount, BackedgeCount, BC.ContinueCount); 1492 propagateCounts(CondCount, S->getCond()); 1493 adjustForOutOfOrderTraversal(getEnd(S)); 1494 1495 // The body count applies to the area immediately after the increment. 1496 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 1497 if (Gap) 1498 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 1499 1500 Counter OutCount = 1501 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); 1502 if (OutCount != ParentCount) { 1503 pushRegion(OutCount); 1504 GapRegionCounter = OutCount; 1505 if (BodyHasTerminateStmt) 1506 HasTerminateStmt = true; 1507 } 1508 1509 // Create Branch Region around condition. 1510 createBranchRegion(S->getCond(), BodyCount, 1511 subtractCounters(CondCount, BodyCount)); 1512 } 1513 1514 void VisitDoStmt(const DoStmt *S) { 1515 extendRegion(S); 1516 1517 Counter ParentCount = getRegion().getCounter(); 1518 Counter BodyCount = getRegionCounter(S); 1519 1520 BreakContinueStack.push_back(BreakContinue()); 1521 extendRegion(S->getBody()); 1522 Counter BackedgeCount = 1523 propagateCounts(addCounters(ParentCount, BodyCount), S->getBody()); 1524 BreakContinue BC = BreakContinueStack.pop_back_val(); 1525 1526 bool BodyHasTerminateStmt = HasTerminateStmt; 1527 HasTerminateStmt = false; 1528 1529 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount); 1530 propagateCounts(CondCount, S->getCond()); 1531 1532 Counter OutCount = 1533 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); 1534 if (OutCount != ParentCount) { 1535 pushRegion(OutCount); 1536 GapRegionCounter = OutCount; 1537 } 1538 1539 // Create Branch Region around condition. 1540 createBranchRegion(S->getCond(), BodyCount, 1541 subtractCounters(CondCount, BodyCount)); 1542 1543 if (BodyHasTerminateStmt) 1544 HasTerminateStmt = true; 1545 } 1546 1547 void VisitForStmt(const ForStmt *S) { 1548 extendRegion(S); 1549 if (S->getInit()) 1550 Visit(S->getInit()); 1551 1552 Counter ParentCount = getRegion().getCounter(); 1553 Counter BodyCount = getRegionCounter(S); 1554 1555 // The loop increment may contain a break or continue. 1556 if (S->getInc()) 1557 BreakContinueStack.emplace_back(); 1558 1559 // Handle the body first so that we can get the backedge count. 1560 BreakContinueStack.emplace_back(); 1561 extendRegion(S->getBody()); 1562 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 1563 BreakContinue BodyBC = BreakContinueStack.pop_back_val(); 1564 1565 bool BodyHasTerminateStmt = HasTerminateStmt; 1566 HasTerminateStmt = false; 1567 1568 // The increment is essentially part of the body but it needs to include 1569 // the count for all the continue statements. 1570 BreakContinue IncrementBC; 1571 if (const Stmt *Inc = S->getInc()) { 1572 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc); 1573 IncrementBC = BreakContinueStack.pop_back_val(); 1574 } 1575 1576 // Go back to handle the condition. 1577 Counter CondCount = addCounters( 1578 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount), 1579 IncrementBC.ContinueCount); 1580 if (const Expr *Cond = S->getCond()) { 1581 propagateCounts(CondCount, Cond); 1582 adjustForOutOfOrderTraversal(getEnd(S)); 1583 } 1584 1585 // The body count applies to the area immediately after the increment. 1586 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 1587 if (Gap) 1588 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 1589 1590 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, 1591 subtractCounters(CondCount, BodyCount)); 1592 if (OutCount != ParentCount) { 1593 pushRegion(OutCount); 1594 GapRegionCounter = OutCount; 1595 if (BodyHasTerminateStmt) 1596 HasTerminateStmt = true; 1597 } 1598 1599 // Create Branch Region around condition. 1600 createBranchRegion(S->getCond(), BodyCount, 1601 subtractCounters(CondCount, BodyCount)); 1602 } 1603 1604 void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { 1605 extendRegion(S); 1606 if (S->getInit()) 1607 Visit(S->getInit()); 1608 Visit(S->getLoopVarStmt()); 1609 Visit(S->getRangeStmt()); 1610 1611 Counter ParentCount = getRegion().getCounter(); 1612 Counter BodyCount = getRegionCounter(S); 1613 1614 BreakContinueStack.push_back(BreakContinue()); 1615 extendRegion(S->getBody()); 1616 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 1617 BreakContinue BC = BreakContinueStack.pop_back_val(); 1618 1619 bool BodyHasTerminateStmt = HasTerminateStmt; 1620 HasTerminateStmt = false; 1621 1622 // The body count applies to the area immediately after the range. 1623 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 1624 if (Gap) 1625 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 1626 1627 Counter LoopCount = 1628 addCounters(ParentCount, BackedgeCount, BC.ContinueCount); 1629 Counter OutCount = 1630 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); 1631 if (OutCount != ParentCount) { 1632 pushRegion(OutCount); 1633 GapRegionCounter = OutCount; 1634 if (BodyHasTerminateStmt) 1635 HasTerminateStmt = true; 1636 } 1637 1638 // Create Branch Region around condition. 1639 createBranchRegion(S->getCond(), BodyCount, 1640 subtractCounters(LoopCount, BodyCount)); 1641 } 1642 1643 void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { 1644 extendRegion(S); 1645 Visit(S->getElement()); 1646 1647 Counter ParentCount = getRegion().getCounter(); 1648 Counter BodyCount = getRegionCounter(S); 1649 1650 BreakContinueStack.push_back(BreakContinue()); 1651 extendRegion(S->getBody()); 1652 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 1653 BreakContinue BC = BreakContinueStack.pop_back_val(); 1654 1655 // The body count applies to the area immediately after the collection. 1656 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 1657 if (Gap) 1658 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 1659 1660 Counter LoopCount = 1661 addCounters(ParentCount, BackedgeCount, BC.ContinueCount); 1662 Counter OutCount = 1663 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); 1664 if (OutCount != ParentCount) { 1665 pushRegion(OutCount); 1666 GapRegionCounter = OutCount; 1667 } 1668 } 1669 1670 void VisitSwitchStmt(const SwitchStmt *S) { 1671 extendRegion(S); 1672 if (S->getInit()) 1673 Visit(S->getInit()); 1674 Visit(S->getCond()); 1675 1676 BreakContinueStack.push_back(BreakContinue()); 1677 1678 const Stmt *Body = S->getBody(); 1679 extendRegion(Body); 1680 if (const auto *CS = dyn_cast<CompoundStmt>(Body)) { 1681 if (!CS->body_empty()) { 1682 // Make a region for the body of the switch. If the body starts with 1683 // a case, that case will reuse this region; otherwise, this covers 1684 // the unreachable code at the beginning of the switch body. 1685 size_t Index = pushRegion(Counter::getZero(), getStart(CS)); 1686 getRegion().setGap(true); 1687 Visit(Body); 1688 1689 // Set the end for the body of the switch, if it isn't already set. 1690 for (size_t i = RegionStack.size(); i != Index; --i) { 1691 if (!RegionStack[i - 1].hasEndLoc()) 1692 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back())); 1693 } 1694 1695 popRegions(Index); 1696 } 1697 } else 1698 propagateCounts(Counter::getZero(), Body); 1699 BreakContinue BC = BreakContinueStack.pop_back_val(); 1700 1701 if (!BreakContinueStack.empty()) 1702 BreakContinueStack.back().ContinueCount = addCounters( 1703 BreakContinueStack.back().ContinueCount, BC.ContinueCount); 1704 1705 Counter ParentCount = getRegion().getCounter(); 1706 Counter ExitCount = getRegionCounter(S); 1707 SourceLocation ExitLoc = getEnd(S); 1708 pushRegion(ExitCount); 1709 GapRegionCounter = ExitCount; 1710 1711 // Ensure that handleFileExit recognizes when the end location is located 1712 // in a different file. 1713 MostRecentLocation = getStart(S); 1714 handleFileExit(ExitLoc); 1715 1716 // Create a Branch Region around each Case. Subtract the case's 1717 // counter from the Parent counter to track the "False" branch count. 1718 Counter CaseCountSum; 1719 bool HasDefaultCase = false; 1720 const SwitchCase *Case = S->getSwitchCaseList(); 1721 for (; Case; Case = Case->getNextSwitchCase()) { 1722 HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case); 1723 CaseCountSum = 1724 addCounters(CaseCountSum, getRegionCounter(Case), /*Simplify=*/false); 1725 createSwitchCaseRegion( 1726 Case, getRegionCounter(Case), 1727 subtractCounters(ParentCount, getRegionCounter(Case))); 1728 } 1729 // Simplify is skipped while building the counters above: it can get really 1730 // slow on top of switches with thousands of cases. Instead, trigger 1731 // simplification by adding zero to the last counter. 1732 CaseCountSum = addCounters(CaseCountSum, Counter::getZero()); 1733 1734 // If no explicit default case exists, create a branch region to represent 1735 // the hidden branch, which will be added later by the CodeGen. This region 1736 // will be associated with the switch statement's condition. 1737 if (!HasDefaultCase) { 1738 Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum); 1739 Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue); 1740 createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse); 1741 } 1742 } 1743 1744 void VisitSwitchCase(const SwitchCase *S) { 1745 extendRegion(S); 1746 1747 SourceMappingRegion &Parent = getRegion(); 1748 1749 Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S)); 1750 // Reuse the existing region if it starts at our label. This is typical of 1751 // the first case in a switch. 1752 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S)) 1753 Parent.setCounter(Count); 1754 else 1755 pushRegion(Count, getStart(S)); 1756 1757 GapRegionCounter = Count; 1758 1759 if (const auto *CS = dyn_cast<CaseStmt>(S)) { 1760 Visit(CS->getLHS()); 1761 if (const Expr *RHS = CS->getRHS()) 1762 Visit(RHS); 1763 } 1764 Visit(S->getSubStmt()); 1765 } 1766 1767 void coverIfConsteval(const IfStmt *S) { 1768 assert(S->isConsteval()); 1769 1770 const auto *Then = S->getThen(); 1771 const auto *Else = S->getElse(); 1772 1773 // It's better for llvm-cov to create a new region with same counter 1774 // so line-coverage can be properly calculated for lines containing 1775 // a skipped region (without it the line is marked uncovered) 1776 const Counter ParentCount = getRegion().getCounter(); 1777 1778 extendRegion(S); 1779 1780 if (S->isNegatedConsteval()) { 1781 // ignore 'if consteval' 1782 markSkipped(S->getIfLoc(), getStart(Then)); 1783 propagateCounts(ParentCount, Then); 1784 1785 if (Else) { 1786 // ignore 'else <else>' 1787 markSkipped(getEnd(Then), getEnd(Else)); 1788 } 1789 } else { 1790 assert(S->isNonNegatedConsteval()); 1791 // ignore 'if consteval <then> [else]' 1792 markSkipped(S->getIfLoc(), Else ? getStart(Else) : getEnd(Then)); 1793 1794 if (Else) 1795 propagateCounts(ParentCount, Else); 1796 } 1797 } 1798 1799 void coverIfConstexpr(const IfStmt *S) { 1800 assert(S->isConstexpr()); 1801 1802 // evaluate constant condition... 1803 const bool isTrue = 1804 S->getCond() 1805 ->EvaluateKnownConstInt(CVM.getCodeGenModule().getContext()) 1806 .getBoolValue(); 1807 1808 extendRegion(S); 1809 1810 // I'm using 'propagateCounts' later as new region is better and allows me 1811 // to properly calculate line coverage in llvm-cov utility 1812 const Counter ParentCount = getRegion().getCounter(); 1813 1814 // ignore 'if constexpr (' 1815 SourceLocation startOfSkipped = S->getIfLoc(); 1816 1817 if (const auto *Init = S->getInit()) { 1818 const auto start = getStart(Init); 1819 const auto end = getEnd(Init); 1820 1821 // this check is to make sure typedef here which doesn't have valid source 1822 // location won't crash it 1823 if (start.isValid() && end.isValid()) { 1824 markSkipped(startOfSkipped, start); 1825 propagateCounts(ParentCount, Init); 1826 startOfSkipped = getEnd(Init); 1827 } 1828 } 1829 1830 const auto *Then = S->getThen(); 1831 const auto *Else = S->getElse(); 1832 1833 if (isTrue) { 1834 // ignore '<condition>)' 1835 markSkipped(startOfSkipped, getStart(Then)); 1836 propagateCounts(ParentCount, Then); 1837 1838 if (Else) 1839 // ignore 'else <else>' 1840 markSkipped(getEnd(Then), getEnd(Else)); 1841 } else { 1842 // ignore '<condition>) <then> [else]' 1843 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then)); 1844 1845 if (Else) 1846 propagateCounts(ParentCount, Else); 1847 } 1848 } 1849 1850 void VisitIfStmt(const IfStmt *S) { 1851 // "if constexpr" and "if consteval" are not normal conditional statements, 1852 // their discarded statement should be skipped 1853 if (S->isConsteval()) 1854 return coverIfConsteval(S); 1855 else if (S->isConstexpr()) 1856 return coverIfConstexpr(S); 1857 1858 extendRegion(S); 1859 if (S->getInit()) 1860 Visit(S->getInit()); 1861 1862 // Extend into the condition before we propagate through it below - this is 1863 // needed to handle macros that generate the "if" but not the condition. 1864 extendRegion(S->getCond()); 1865 1866 Counter ParentCount = getRegion().getCounter(); 1867 Counter ThenCount = getRegionCounter(S); 1868 1869 // Emitting a counter for the condition makes it easier to interpret the 1870 // counter for the body when looking at the coverage. 1871 propagateCounts(ParentCount, S->getCond()); 1872 1873 // The 'then' count applies to the area immediately after the condition. 1874 std::optional<SourceRange> Gap = 1875 findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen())); 1876 if (Gap) 1877 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount); 1878 1879 extendRegion(S->getThen()); 1880 Counter OutCount = propagateCounts(ThenCount, S->getThen()); 1881 Counter ElseCount = subtractCounters(ParentCount, ThenCount); 1882 1883 if (const Stmt *Else = S->getElse()) { 1884 bool ThenHasTerminateStmt = HasTerminateStmt; 1885 HasTerminateStmt = false; 1886 // The 'else' count applies to the area immediately after the 'then'. 1887 std::optional<SourceRange> Gap = 1888 findGapAreaBetween(getEnd(S->getThen()), getStart(Else)); 1889 if (Gap) 1890 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount); 1891 extendRegion(Else); 1892 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); 1893 1894 if (ThenHasTerminateStmt) 1895 HasTerminateStmt = true; 1896 } else 1897 OutCount = addCounters(OutCount, ElseCount); 1898 1899 if (OutCount != ParentCount) { 1900 pushRegion(OutCount); 1901 GapRegionCounter = OutCount; 1902 } 1903 1904 // Create Branch Region around condition. 1905 createBranchRegion(S->getCond(), ThenCount, 1906 subtractCounters(ParentCount, ThenCount)); 1907 } 1908 1909 void VisitCXXTryStmt(const CXXTryStmt *S) { 1910 extendRegion(S); 1911 // Handle macros that generate the "try" but not the rest. 1912 extendRegion(S->getTryBlock()); 1913 1914 Counter ParentCount = getRegion().getCounter(); 1915 propagateCounts(ParentCount, S->getTryBlock()); 1916 1917 for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I) 1918 Visit(S->getHandler(I)); 1919 1920 Counter ExitCount = getRegionCounter(S); 1921 pushRegion(ExitCount); 1922 } 1923 1924 void VisitCXXCatchStmt(const CXXCatchStmt *S) { 1925 propagateCounts(getRegionCounter(S), S->getHandlerBlock()); 1926 } 1927 1928 void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { 1929 extendRegion(E); 1930 1931 Counter ParentCount = getRegion().getCounter(); 1932 Counter TrueCount = getRegionCounter(E); 1933 1934 propagateCounts(ParentCount, E->getCond()); 1935 Counter OutCount; 1936 1937 if (!isa<BinaryConditionalOperator>(E)) { 1938 // The 'then' count applies to the area immediately after the condition. 1939 auto Gap = 1940 findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr())); 1941 if (Gap) 1942 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount); 1943 1944 extendRegion(E->getTrueExpr()); 1945 OutCount = propagateCounts(TrueCount, E->getTrueExpr()); 1946 } else { 1947 OutCount = TrueCount; 1948 } 1949 1950 extendRegion(E->getFalseExpr()); 1951 OutCount = addCounters( 1952 OutCount, propagateCounts(subtractCounters(ParentCount, TrueCount), 1953 E->getFalseExpr())); 1954 1955 if (OutCount != ParentCount) { 1956 pushRegion(OutCount); 1957 GapRegionCounter = OutCount; 1958 } 1959 1960 // Create Branch Region around condition. 1961 createBranchRegion(E->getCond(), TrueCount, 1962 subtractCounters(ParentCount, TrueCount)); 1963 } 1964 1965 void VisitBinLAnd(const BinaryOperator *E) { 1966 bool IsRootNode = MCDCBuilder.isIdle(); 1967 1968 // Keep track of Binary Operator and assign MCDC condition IDs. 1969 MCDCBuilder.pushAndAssignIDs(E); 1970 1971 extendRegion(E->getLHS()); 1972 propagateCounts(getRegion().getCounter(), E->getLHS()); 1973 handleFileExit(getEnd(E->getLHS())); 1974 1975 // Track LHS True/False Decision. 1976 const auto DecisionLHS = MCDCBuilder.pop(); 1977 1978 // Counter tracks the right hand side of a logical and operator. 1979 extendRegion(E->getRHS()); 1980 propagateCounts(getRegionCounter(E), E->getRHS()); 1981 1982 // Track RHS True/False Decision. 1983 const auto DecisionRHS = MCDCBuilder.back(); 1984 1985 // Create MCDC Decision Region if at top-level (root). 1986 unsigned NumConds = 0; 1987 if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E))) 1988 createDecisionRegion(E, getBitmapIdx(E), NumConds); 1989 1990 // Extract the RHS's Execution Counter. 1991 Counter RHSExecCnt = getRegionCounter(E); 1992 1993 // Extract the RHS's "True" Instance Counter. 1994 Counter RHSTrueCnt = getRegionCounter(E->getRHS()); 1995 1996 // Extract the Parent Region Counter. 1997 Counter ParentCnt = getRegion().getCounter(); 1998 1999 // Create Branch Region around LHS condition. 2000 createBranchRegion(E->getLHS(), RHSExecCnt, 2001 subtractCounters(ParentCnt, RHSExecCnt), DecisionLHS); 2002 2003 // Create Branch Region around RHS condition. 2004 createBranchRegion(E->getRHS(), RHSTrueCnt, 2005 subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS); 2006 } 2007 2008 // Determine whether the right side of OR operation need to be visited. 2009 bool shouldVisitRHS(const Expr *LHS) { 2010 bool LHSIsTrue = false; 2011 bool LHSIsConst = false; 2012 if (!LHS->isValueDependent()) 2013 LHSIsConst = LHS->EvaluateAsBooleanCondition( 2014 LHSIsTrue, CVM.getCodeGenModule().getContext()); 2015 return !LHSIsConst || (LHSIsConst && !LHSIsTrue); 2016 } 2017 2018 void VisitBinLOr(const BinaryOperator *E) { 2019 bool IsRootNode = MCDCBuilder.isIdle(); 2020 2021 // Keep track of Binary Operator and assign MCDC condition IDs. 2022 MCDCBuilder.pushAndAssignIDs(E); 2023 2024 extendRegion(E->getLHS()); 2025 Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS()); 2026 handleFileExit(getEnd(E->getLHS())); 2027 2028 // Track LHS True/False Decision. 2029 const auto DecisionLHS = MCDCBuilder.pop(); 2030 2031 // Counter tracks the right hand side of a logical or operator. 2032 extendRegion(E->getRHS()); 2033 propagateCounts(getRegionCounter(E), E->getRHS()); 2034 2035 // Track RHS True/False Decision. 2036 const auto DecisionRHS = MCDCBuilder.back(); 2037 2038 // Create MCDC Decision Region if at top-level (root). 2039 unsigned NumConds = 0; 2040 if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E))) 2041 createDecisionRegion(E, getBitmapIdx(E), NumConds); 2042 2043 // Extract the RHS's Execution Counter. 2044 Counter RHSExecCnt = getRegionCounter(E); 2045 2046 // Extract the RHS's "False" Instance Counter. 2047 Counter RHSFalseCnt = getRegionCounter(E->getRHS()); 2048 2049 if (!shouldVisitRHS(E->getLHS())) { 2050 GapRegionCounter = OutCount; 2051 } 2052 2053 // Extract the Parent Region Counter. 2054 Counter ParentCnt = getRegion().getCounter(); 2055 2056 // Create Branch Region around LHS condition. 2057 createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt), 2058 RHSExecCnt, DecisionLHS); 2059 2060 // Create Branch Region around RHS condition. 2061 createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt), 2062 RHSFalseCnt, DecisionRHS); 2063 } 2064 2065 void VisitLambdaExpr(const LambdaExpr *LE) { 2066 // Lambdas are treated as their own functions for now, so we shouldn't 2067 // propagate counts into them. 2068 } 2069 2070 void VisitPseudoObjectExpr(const PseudoObjectExpr *POE) { 2071 // Just visit syntatic expression as this is what users actually write. 2072 VisitStmt(POE->getSyntacticForm()); 2073 } 2074 2075 void VisitOpaqueValueExpr(const OpaqueValueExpr* OVE) { 2076 Visit(OVE->getSourceExpr()); 2077 } 2078 }; 2079 2080 } // end anonymous namespace 2081 2082 static void dump(llvm::raw_ostream &OS, StringRef FunctionName, 2083 ArrayRef<CounterExpression> Expressions, 2084 ArrayRef<CounterMappingRegion> Regions) { 2085 OS << FunctionName << ":\n"; 2086 CounterMappingContext Ctx(Expressions); 2087 for (const auto &R : Regions) { 2088 OS.indent(2); 2089 switch (R.Kind) { 2090 case CounterMappingRegion::CodeRegion: 2091 break; 2092 case CounterMappingRegion::ExpansionRegion: 2093 OS << "Expansion,"; 2094 break; 2095 case CounterMappingRegion::SkippedRegion: 2096 OS << "Skipped,"; 2097 break; 2098 case CounterMappingRegion::GapRegion: 2099 OS << "Gap,"; 2100 break; 2101 case CounterMappingRegion::BranchRegion: 2102 case CounterMappingRegion::MCDCBranchRegion: 2103 OS << "Branch,"; 2104 break; 2105 case CounterMappingRegion::MCDCDecisionRegion: 2106 OS << "Decision,"; 2107 break; 2108 } 2109 2110 OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart 2111 << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = "; 2112 2113 if (const auto *DecisionParams = 2114 std::get_if<mcdc::DecisionParameters>(&R.MCDCParams)) { 2115 OS << "M:" << DecisionParams->BitmapIdx; 2116 OS << ", C:" << DecisionParams->NumConditions; 2117 } else { 2118 Ctx.dump(R.Count, OS); 2119 2120 if (R.Kind == CounterMappingRegion::BranchRegion || 2121 R.Kind == CounterMappingRegion::MCDCBranchRegion) { 2122 OS << ", "; 2123 Ctx.dump(R.FalseCount, OS); 2124 } 2125 } 2126 2127 if (const auto *BranchParams = 2128 std::get_if<mcdc::BranchParameters>(&R.MCDCParams)) { 2129 OS << " [" << BranchParams->ID + 1 << "," 2130 << BranchParams->Conds[true] + 1; 2131 OS << "," << BranchParams->Conds[false] + 1 << "] "; 2132 } 2133 2134 if (R.Kind == CounterMappingRegion::ExpansionRegion) 2135 OS << " (Expanded file = " << R.ExpandedFileID << ")"; 2136 OS << "\n"; 2137 } 2138 } 2139 2140 CoverageMappingModuleGen::CoverageMappingModuleGen( 2141 CodeGenModule &CGM, CoverageSourceInfo &SourceInfo) 2142 : CGM(CGM), SourceInfo(SourceInfo) {} 2143 2144 std::string CoverageMappingModuleGen::getCurrentDirname() { 2145 if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty()) 2146 return CGM.getCodeGenOpts().CoverageCompilationDir; 2147 2148 SmallString<256> CWD; 2149 llvm::sys::fs::current_path(CWD); 2150 return CWD.str().str(); 2151 } 2152 2153 std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) { 2154 llvm::SmallString<256> Path(Filename); 2155 llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); 2156 2157 /// Traverse coverage prefix map in reverse order because prefix replacements 2158 /// are applied in reverse order starting from the last one when multiple 2159 /// prefix replacement options are provided. 2160 for (const auto &[From, To] : 2161 llvm::reverse(CGM.getCodeGenOpts().CoveragePrefixMap)) { 2162 if (llvm::sys::path::replace_path_prefix(Path, From, To)) 2163 break; 2164 } 2165 return Path.str().str(); 2166 } 2167 2168 static std::string getInstrProfSection(const CodeGenModule &CGM, 2169 llvm::InstrProfSectKind SK) { 2170 return llvm::getInstrProfSectionName( 2171 SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat()); 2172 } 2173 2174 void CoverageMappingModuleGen::emitFunctionMappingRecord( 2175 const FunctionInfo &Info, uint64_t FilenamesRef) { 2176 llvm::LLVMContext &Ctx = CGM.getLLVMContext(); 2177 2178 // Assign a name to the function record. This is used to merge duplicates. 2179 std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash); 2180 2181 // A dummy description for a function included-but-not-used in a TU can be 2182 // replaced by full description provided by a different TU. The two kinds of 2183 // descriptions play distinct roles: therefore, assign them different names 2184 // to prevent `linkonce_odr` merging. 2185 if (Info.IsUsed) 2186 FuncRecordName += "u"; 2187 2188 // Create the function record type. 2189 const uint64_t NameHash = Info.NameHash; 2190 const uint64_t FuncHash = Info.FuncHash; 2191 const std::string &CoverageMapping = Info.CoverageMapping; 2192 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType, 2193 llvm::Type *FunctionRecordTypes[] = { 2194 #include "llvm/ProfileData/InstrProfData.inc" 2195 }; 2196 auto *FunctionRecordTy = 2197 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes), 2198 /*isPacked=*/true); 2199 2200 // Create the function record constant. 2201 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init, 2202 llvm::Constant *FunctionRecordVals[] = { 2203 #include "llvm/ProfileData/InstrProfData.inc" 2204 }; 2205 auto *FuncRecordConstant = 2206 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals)); 2207 2208 // Create the function record global. 2209 auto *FuncRecord = new llvm::GlobalVariable( 2210 CGM.getModule(), FunctionRecordTy, /*isConstant=*/true, 2211 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant, 2212 FuncRecordName); 2213 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility); 2214 FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun)); 2215 FuncRecord->setAlignment(llvm::Align(8)); 2216 if (CGM.supportsCOMDAT()) 2217 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName)); 2218 2219 // Make sure the data doesn't get deleted. 2220 CGM.addUsedGlobal(FuncRecord); 2221 } 2222 2223 void CoverageMappingModuleGen::addFunctionMappingRecord( 2224 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash, 2225 const std::string &CoverageMapping, bool IsUsed) { 2226 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue); 2227 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed}); 2228 2229 if (!IsUsed) 2230 FunctionNames.push_back(NamePtr); 2231 2232 if (CGM.getCodeGenOpts().DumpCoverageMapping) { 2233 // Dump the coverage mapping data for this function by decoding the 2234 // encoded data. This allows us to dump the mapping regions which were 2235 // also processed by the CoverageMappingWriter which performs 2236 // additional minimization operations such as reducing the number of 2237 // expressions. 2238 llvm::SmallVector<std::string, 16> FilenameStrs; 2239 std::vector<StringRef> Filenames; 2240 std::vector<CounterExpression> Expressions; 2241 std::vector<CounterMappingRegion> Regions; 2242 FilenameStrs.resize(FileEntries.size() + 1); 2243 FilenameStrs[0] = normalizeFilename(getCurrentDirname()); 2244 for (const auto &Entry : FileEntries) { 2245 auto I = Entry.second; 2246 FilenameStrs[I] = normalizeFilename(Entry.first.getName()); 2247 } 2248 ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(FilenameStrs); 2249 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames, 2250 Expressions, Regions); 2251 if (Reader.read()) 2252 return; 2253 dump(llvm::outs(), NameValue, Expressions, Regions); 2254 } 2255 } 2256 2257 void CoverageMappingModuleGen::emit() { 2258 if (FunctionRecords.empty()) 2259 return; 2260 llvm::LLVMContext &Ctx = CGM.getLLVMContext(); 2261 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); 2262 2263 // Create the filenames and merge them with coverage mappings 2264 llvm::SmallVector<std::string, 16> FilenameStrs; 2265 FilenameStrs.resize(FileEntries.size() + 1); 2266 // The first filename is the current working directory. 2267 FilenameStrs[0] = normalizeFilename(getCurrentDirname()); 2268 for (const auto &Entry : FileEntries) { 2269 auto I = Entry.second; 2270 FilenameStrs[I] = normalizeFilename(Entry.first.getName()); 2271 } 2272 2273 std::string Filenames; 2274 { 2275 llvm::raw_string_ostream OS(Filenames); 2276 CoverageFilenamesSectionWriter(FilenameStrs).write(OS); 2277 } 2278 auto *FilenamesVal = 2279 llvm::ConstantDataArray::getString(Ctx, Filenames, false); 2280 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames); 2281 2282 // Emit the function records. 2283 for (const FunctionInfo &Info : FunctionRecords) 2284 emitFunctionMappingRecord(Info, FilenamesRef); 2285 2286 const unsigned NRecords = 0; 2287 const size_t FilenamesSize = Filenames.size(); 2288 const unsigned CoverageMappingSize = 0; 2289 llvm::Type *CovDataHeaderTypes[] = { 2290 #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType, 2291 #include "llvm/ProfileData/InstrProfData.inc" 2292 }; 2293 auto CovDataHeaderTy = 2294 llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes)); 2295 llvm::Constant *CovDataHeaderVals[] = { 2296 #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init, 2297 #include "llvm/ProfileData/InstrProfData.inc" 2298 }; 2299 auto CovDataHeaderVal = 2300 llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals)); 2301 2302 // Create the coverage data record 2303 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()}; 2304 auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes)); 2305 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal}; 2306 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals)); 2307 auto CovData = new llvm::GlobalVariable( 2308 CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage, 2309 CovDataVal, llvm::getCoverageMappingVarName()); 2310 2311 CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap)); 2312 CovData->setAlignment(llvm::Align(8)); 2313 2314 // Make sure the data doesn't get deleted. 2315 CGM.addUsedGlobal(CovData); 2316 // Create the deferred function records array 2317 if (!FunctionNames.empty()) { 2318 auto NamesArrTy = llvm::ArrayType::get(llvm::PointerType::getUnqual(Ctx), 2319 FunctionNames.size()); 2320 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames); 2321 // This variable will *NOT* be emitted to the object file. It is used 2322 // to pass the list of names referenced to codegen. 2323 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true, 2324 llvm::GlobalValue::InternalLinkage, NamesArrVal, 2325 llvm::getCoverageUnusedNamesVarName()); 2326 } 2327 } 2328 2329 unsigned CoverageMappingModuleGen::getFileID(FileEntryRef File) { 2330 auto It = FileEntries.find(File); 2331 if (It != FileEntries.end()) 2332 return It->second; 2333 unsigned FileID = FileEntries.size() + 1; 2334 FileEntries.insert(std::make_pair(File, FileID)); 2335 return FileID; 2336 } 2337 2338 void CoverageMappingGen::emitCounterMapping(const Decl *D, 2339 llvm::raw_ostream &OS) { 2340 assert(CounterMap && MCDCState); 2341 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM, 2342 LangOpts); 2343 Walker.VisitDecl(D); 2344 Walker.write(OS); 2345 } 2346 2347 void CoverageMappingGen::emitEmptyMapping(const Decl *D, 2348 llvm::raw_ostream &OS) { 2349 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts); 2350 Walker.VisitDecl(D); 2351 Walker.write(OS); 2352 } 2353