10b57cec5SDimitry Andric //===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Instrumentation-based code coverage mapping generator 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "CoverageMappingGen.h" 140b57cec5SDimitry Andric #include "CodeGenFunction.h" 150b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h" 165ffd83dbSDimitry Andric #include "clang/Basic/Diagnostic.h" 175ffd83dbSDimitry Andric #include "clang/Basic/FileManager.h" 185ffd83dbSDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h" 190b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 20*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseSet.h" 210b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 220b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 230b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h" 240b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" 250b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" 260b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h" 270b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 280b57cec5SDimitry Andric #include "llvm/Support/Path.h" 29bdd1243dSDimitry Andric #include <optional> 300b57cec5SDimitry Andric 315ffd83dbSDimitry Andric // This selects the coverage mapping format defined when `InstrProfData.inc` 325ffd83dbSDimitry Andric // is textually included. 335ffd83dbSDimitry Andric #define COVMAP_V3 345ffd83dbSDimitry Andric 35*0fca6ea1SDimitry Andric namespace llvm { 36*0fca6ea1SDimitry Andric cl::opt<bool> 37*0fca6ea1SDimitry Andric EnableSingleByteCoverage("enable-single-byte-coverage", 38*0fca6ea1SDimitry Andric llvm::cl::ZeroOrMore, 39*0fca6ea1SDimitry Andric llvm::cl::desc("Enable single byte coverage"), 40*0fca6ea1SDimitry Andric llvm::cl::Hidden, llvm::cl::init(false)); 41*0fca6ea1SDimitry Andric } // namespace llvm 42*0fca6ea1SDimitry Andric 43e8d8bef9SDimitry Andric static llvm::cl::opt<bool> EmptyLineCommentCoverage( 44e8d8bef9SDimitry Andric "emptyline-comment-coverage", 45e8d8bef9SDimitry Andric llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only " 46e8d8bef9SDimitry Andric "disable it on test)"), 47e8d8bef9SDimitry Andric llvm::cl::init(true), llvm::cl::Hidden); 48e8d8bef9SDimitry Andric 49*0fca6ea1SDimitry Andric namespace llvm::coverage { 50*0fca6ea1SDimitry Andric cl::opt<bool> SystemHeadersCoverage( 5106c3fb27SDimitry Andric "system-headers-coverage", 52*0fca6ea1SDimitry Andric cl::desc("Enable collecting coverage from system headers"), cl::init(false), 53*0fca6ea1SDimitry Andric cl::Hidden); 54*0fca6ea1SDimitry Andric } 5506c3fb27SDimitry Andric 560b57cec5SDimitry Andric using namespace clang; 570b57cec5SDimitry Andric using namespace CodeGen; 580b57cec5SDimitry Andric using namespace llvm::coverage; 590b57cec5SDimitry Andric 60e8d8bef9SDimitry Andric CoverageSourceInfo * 61e8d8bef9SDimitry Andric CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) { 62e8d8bef9SDimitry Andric CoverageSourceInfo *CoverageInfo = 63e8d8bef9SDimitry Andric new CoverageSourceInfo(PP.getSourceManager()); 64e8d8bef9SDimitry Andric PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo)); 65e8d8bef9SDimitry Andric if (EmptyLineCommentCoverage) { 66e8d8bef9SDimitry Andric PP.addCommentHandler(CoverageInfo); 67e8d8bef9SDimitry Andric PP.setEmptylineHandler(CoverageInfo); 68e8d8bef9SDimitry Andric PP.setPreprocessToken(true); 69e8d8bef9SDimitry Andric PP.setTokenWatcher([CoverageInfo](clang::Token Tok) { 70e8d8bef9SDimitry Andric // Update previous token location. 71e8d8bef9SDimitry Andric CoverageInfo->PrevTokLoc = Tok.getLocation(); 72e8d8bef9SDimitry Andric if (Tok.getKind() != clang::tok::eod) 73e8d8bef9SDimitry Andric CoverageInfo->updateNextTokLoc(Tok.getLocation()); 74e8d8bef9SDimitry Andric }); 75e8d8bef9SDimitry Andric } 76e8d8bef9SDimitry Andric return CoverageInfo; 77e8d8bef9SDimitry Andric } 78e8d8bef9SDimitry Andric 7981ad6265SDimitry Andric void CoverageSourceInfo::AddSkippedRange(SourceRange Range, 8081ad6265SDimitry Andric SkippedRange::Kind RangeKind) { 81e8d8bef9SDimitry Andric if (EmptyLineCommentCoverage && !SkippedRanges.empty() && 82e8d8bef9SDimitry Andric PrevTokLoc == SkippedRanges.back().PrevTokLoc && 83e8d8bef9SDimitry Andric SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(), 84e8d8bef9SDimitry Andric Range.getBegin())) 85e8d8bef9SDimitry Andric SkippedRanges.back().Range.setEnd(Range.getEnd()); 86e8d8bef9SDimitry Andric else 8781ad6265SDimitry Andric SkippedRanges.push_back({Range, RangeKind, PrevTokLoc}); 88e8d8bef9SDimitry Andric } 89e8d8bef9SDimitry Andric 900b57cec5SDimitry Andric void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) { 9181ad6265SDimitry Andric AddSkippedRange(Range, SkippedRange::PPIfElse); 92e8d8bef9SDimitry Andric } 93e8d8bef9SDimitry Andric 94e8d8bef9SDimitry Andric void CoverageSourceInfo::HandleEmptyline(SourceRange Range) { 9581ad6265SDimitry Andric AddSkippedRange(Range, SkippedRange::EmptyLine); 96e8d8bef9SDimitry Andric } 97e8d8bef9SDimitry Andric 98e8d8bef9SDimitry Andric bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) { 9981ad6265SDimitry Andric AddSkippedRange(Range, SkippedRange::Comment); 100e8d8bef9SDimitry Andric return false; 101e8d8bef9SDimitry Andric } 102e8d8bef9SDimitry Andric 103e8d8bef9SDimitry Andric void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) { 104e8d8bef9SDimitry Andric if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid()) 105e8d8bef9SDimitry Andric SkippedRanges.back().NextTokLoc = Loc; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric namespace { 1090b57cec5SDimitry Andric /// A region of source code that can be mapped to a counter. 1100b57cec5SDimitry Andric class SourceMappingRegion { 111e8d8bef9SDimitry Andric /// Primary Counter that is also used for Branch Regions for "True" branches. 1120b57cec5SDimitry Andric Counter Count; 1130b57cec5SDimitry Andric 114e8d8bef9SDimitry Andric /// Secondary Counter used for Branch Regions for "False" branches. 115bdd1243dSDimitry Andric std::optional<Counter> FalseCount; 116e8d8bef9SDimitry Andric 1171db9f3b2SDimitry Andric /// Parameters used for Modified Condition/Decision Coverage 118*0fca6ea1SDimitry Andric mcdc::Parameters MCDCParams; 1191db9f3b2SDimitry Andric 1200b57cec5SDimitry Andric /// The region's starting location. 121bdd1243dSDimitry Andric std::optional<SourceLocation> LocStart; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric /// The region's ending location. 124bdd1243dSDimitry Andric std::optional<SourceLocation> LocEnd; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric /// Whether this region is a gap region. The count from a gap region is set 1270b57cec5SDimitry Andric /// as the line execution count if there are no other regions on the line. 1280b57cec5SDimitry Andric bool GapRegion; 1290b57cec5SDimitry Andric 1307a6dacacSDimitry Andric /// Whetever this region is skipped ('if constexpr' or 'if consteval' untaken 1317a6dacacSDimitry Andric /// branch, or anything skipped but not empty line / comments) 1327a6dacacSDimitry Andric bool SkippedRegion; 1337a6dacacSDimitry Andric 1340b57cec5SDimitry Andric public: 135bdd1243dSDimitry Andric SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart, 136bdd1243dSDimitry Andric std::optional<SourceLocation> LocEnd, 137bdd1243dSDimitry Andric bool GapRegion = false) 1387a6dacacSDimitry Andric : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion), 1397a6dacacSDimitry Andric SkippedRegion(false) {} 1400b57cec5SDimitry Andric 141bdd1243dSDimitry Andric SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount, 142*0fca6ea1SDimitry Andric mcdc::Parameters MCDCParams, 143bdd1243dSDimitry Andric std::optional<SourceLocation> LocStart, 144bdd1243dSDimitry Andric std::optional<SourceLocation> LocEnd, 145bdd1243dSDimitry Andric bool GapRegion = false) 1461db9f3b2SDimitry Andric : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams), 1477a6dacacSDimitry Andric LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion), 1487a6dacacSDimitry Andric SkippedRegion(false) {} 1491db9f3b2SDimitry Andric 150*0fca6ea1SDimitry Andric SourceMappingRegion(mcdc::Parameters MCDCParams, 1511db9f3b2SDimitry Andric std::optional<SourceLocation> LocStart, 1521db9f3b2SDimitry Andric std::optional<SourceLocation> LocEnd) 1531db9f3b2SDimitry Andric : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd), 1547a6dacacSDimitry Andric GapRegion(false), SkippedRegion(false) {} 155e8d8bef9SDimitry Andric 1560b57cec5SDimitry Andric const Counter &getCounter() const { return Count; } 1570b57cec5SDimitry Andric 158e8d8bef9SDimitry Andric const Counter &getFalseCounter() const { 159e8d8bef9SDimitry Andric assert(FalseCount && "Region has no alternate counter"); 160e8d8bef9SDimitry Andric return *FalseCount; 161e8d8bef9SDimitry Andric } 162e8d8bef9SDimitry Andric 1630b57cec5SDimitry Andric void setCounter(Counter C) { Count = C; } 1640b57cec5SDimitry Andric 16581ad6265SDimitry Andric bool hasStartLoc() const { return LocStart.has_value(); } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric void setStartLoc(SourceLocation Loc) { LocStart = Loc; } 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric SourceLocation getBeginLoc() const { 1700b57cec5SDimitry Andric assert(LocStart && "Region has no start location"); 1710b57cec5SDimitry Andric return *LocStart; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 17481ad6265SDimitry Andric bool hasEndLoc() const { return LocEnd.has_value(); } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric void setEndLoc(SourceLocation Loc) { 1770b57cec5SDimitry Andric assert(Loc.isValid() && "Setting an invalid end location"); 1780b57cec5SDimitry Andric LocEnd = Loc; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric SourceLocation getEndLoc() const { 1820b57cec5SDimitry Andric assert(LocEnd && "Region has no end location"); 1830b57cec5SDimitry Andric return *LocEnd; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric bool isGap() const { return GapRegion; } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric void setGap(bool Gap) { GapRegion = Gap; } 189e8d8bef9SDimitry Andric 1907a6dacacSDimitry Andric bool isSkipped() const { return SkippedRegion; } 1917a6dacacSDimitry Andric 1927a6dacacSDimitry Andric void setSkipped(bool Skipped) { SkippedRegion = Skipped; } 1937a6dacacSDimitry Andric 19481ad6265SDimitry Andric bool isBranch() const { return FalseCount.has_value(); } 1951db9f3b2SDimitry Andric 196*0fca6ea1SDimitry Andric bool isMCDCBranch() const { 197*0fca6ea1SDimitry Andric return std::holds_alternative<mcdc::BranchParameters>(MCDCParams); 198*0fca6ea1SDimitry Andric } 1991db9f3b2SDimitry Andric 200*0fca6ea1SDimitry Andric const auto &getMCDCBranchParams() const { 201*0fca6ea1SDimitry Andric return mcdc::getParams<const mcdc::BranchParameters>(MCDCParams); 202*0fca6ea1SDimitry Andric } 203*0fca6ea1SDimitry Andric 204*0fca6ea1SDimitry Andric bool isMCDCDecision() const { 205*0fca6ea1SDimitry Andric return std::holds_alternative<mcdc::DecisionParameters>(MCDCParams); 206*0fca6ea1SDimitry Andric } 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric const auto &getMCDCDecisionParams() const { 209*0fca6ea1SDimitry Andric return mcdc::getParams<const mcdc::DecisionParameters>(MCDCParams); 210*0fca6ea1SDimitry Andric } 211*0fca6ea1SDimitry Andric 212*0fca6ea1SDimitry Andric const mcdc::Parameters &getMCDCParams() const { return MCDCParams; } 213*0fca6ea1SDimitry Andric 214*0fca6ea1SDimitry Andric void resetMCDCParams() { MCDCParams = mcdc::Parameters(); } 2150b57cec5SDimitry Andric }; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric /// Spelling locations for the start and end of a source region. 2180b57cec5SDimitry Andric struct SpellingRegion { 2190b57cec5SDimitry Andric /// The line where the region starts. 2200b57cec5SDimitry Andric unsigned LineStart; 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric /// The column where the region starts. 2230b57cec5SDimitry Andric unsigned ColumnStart; 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric /// The line where the region ends. 2260b57cec5SDimitry Andric unsigned LineEnd; 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric /// The column where the region ends. 2290b57cec5SDimitry Andric unsigned ColumnEnd; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric SpellingRegion(SourceManager &SM, SourceLocation LocStart, 2320b57cec5SDimitry Andric SourceLocation LocEnd) { 2330b57cec5SDimitry Andric LineStart = SM.getSpellingLineNumber(LocStart); 2340b57cec5SDimitry Andric ColumnStart = SM.getSpellingColumnNumber(LocStart); 2350b57cec5SDimitry Andric LineEnd = SM.getSpellingLineNumber(LocEnd); 2360b57cec5SDimitry Andric ColumnEnd = SM.getSpellingColumnNumber(LocEnd); 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric SpellingRegion(SourceManager &SM, SourceMappingRegion &R) 2400b57cec5SDimitry Andric : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {} 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric /// Check if the start and end locations appear in source order, i.e 2430b57cec5SDimitry Andric /// top->bottom, left->right. 2440b57cec5SDimitry Andric bool isInSourceOrder() const { 2450b57cec5SDimitry Andric return (LineStart < LineEnd) || 2460b57cec5SDimitry Andric (LineStart == LineEnd && ColumnStart <= ColumnEnd); 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric }; 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric /// Provides the common functionality for the different 2510b57cec5SDimitry Andric /// coverage mapping region builders. 2520b57cec5SDimitry Andric class CoverageMappingBuilder { 2530b57cec5SDimitry Andric public: 2540b57cec5SDimitry Andric CoverageMappingModuleGen &CVM; 2550b57cec5SDimitry Andric SourceManager &SM; 2560b57cec5SDimitry Andric const LangOptions &LangOpts; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric private: 2590b57cec5SDimitry Andric /// Map of clang's FileIDs to IDs used for coverage mapping. 2600b57cec5SDimitry Andric llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8> 2610b57cec5SDimitry Andric FileIDMapping; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric public: 2640b57cec5SDimitry Andric /// The coverage mapping regions for this function 2650b57cec5SDimitry Andric llvm::SmallVector<CounterMappingRegion, 32> MappingRegions; 2660b57cec5SDimitry Andric /// The source mapping regions for this function. 2670b57cec5SDimitry Andric std::vector<SourceMappingRegion> SourceRegions; 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric /// A set of regions which can be used as a filter. 2700b57cec5SDimitry Andric /// 2710b57cec5SDimitry Andric /// It is produced by emitExpansionRegions() and is used in 2720b57cec5SDimitry Andric /// emitSourceRegions() to suppress producing code regions if 2730b57cec5SDimitry Andric /// the same area is covered by expansion regions. 2740b57cec5SDimitry Andric typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8> 2750b57cec5SDimitry Andric SourceRegionFilter; 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, 2780b57cec5SDimitry Andric const LangOptions &LangOpts) 2790b57cec5SDimitry Andric : CVM(CVM), SM(SM), LangOpts(LangOpts) {} 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric /// Return the precise end location for the given token. 2820b57cec5SDimitry Andric SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) { 2830b57cec5SDimitry Andric // We avoid getLocForEndOfToken here, because it doesn't do what we want for 2840b57cec5SDimitry Andric // macro locations, which we just treat as expanded files. 2850b57cec5SDimitry Andric unsigned TokLen = 2860b57cec5SDimitry Andric Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts); 2870b57cec5SDimitry Andric return Loc.getLocWithOffset(TokLen); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric /// Return the start location of an included file or expanded macro. 2910b57cec5SDimitry Andric SourceLocation getStartOfFileOrMacro(SourceLocation Loc) { 2920b57cec5SDimitry Andric if (Loc.isMacroID()) 2930b57cec5SDimitry Andric return Loc.getLocWithOffset(-SM.getFileOffset(Loc)); 2940b57cec5SDimitry Andric return SM.getLocForStartOfFile(SM.getFileID(Loc)); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric /// Return the end location of an included file or expanded macro. 2980b57cec5SDimitry Andric SourceLocation getEndOfFileOrMacro(SourceLocation Loc) { 2990b57cec5SDimitry Andric if (Loc.isMacroID()) 3000b57cec5SDimitry Andric return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) - 3010b57cec5SDimitry Andric SM.getFileOffset(Loc)); 3020b57cec5SDimitry Andric return SM.getLocForEndOfFile(SM.getFileID(Loc)); 3030b57cec5SDimitry Andric } 3040b57cec5SDimitry Andric 305*0fca6ea1SDimitry Andric /// Find out where a macro is expanded. If the immediate result is a 306*0fca6ea1SDimitry Andric /// <scratch space>, keep looking until the result isn't. Return a pair of 307*0fca6ea1SDimitry Andric /// \c SourceLocation. The first object is always the begin sloc of found 308*0fca6ea1SDimitry Andric /// result. The second should be checked by the caller: if it has value, it's 309*0fca6ea1SDimitry Andric /// the end sloc of the found result. Otherwise the while loop didn't get 310*0fca6ea1SDimitry Andric /// executed, which means the location wasn't changed and the caller has to 311*0fca6ea1SDimitry Andric /// learn the end sloc from somewhere else. 312*0fca6ea1SDimitry Andric std::pair<SourceLocation, std::optional<SourceLocation>> 313*0fca6ea1SDimitry Andric getNonScratchExpansionLoc(SourceLocation Loc) { 314*0fca6ea1SDimitry Andric std::optional<SourceLocation> EndLoc = std::nullopt; 315*0fca6ea1SDimitry Andric while (Loc.isMacroID() && 316*0fca6ea1SDimitry Andric SM.isWrittenInScratchSpace(SM.getSpellingLoc(Loc))) { 317*0fca6ea1SDimitry Andric auto ExpansionRange = SM.getImmediateExpansionRange(Loc); 318*0fca6ea1SDimitry Andric Loc = ExpansionRange.getBegin(); 319*0fca6ea1SDimitry Andric EndLoc = ExpansionRange.getEnd(); 320*0fca6ea1SDimitry Andric } 321*0fca6ea1SDimitry Andric return std::make_pair(Loc, EndLoc); 322*0fca6ea1SDimitry Andric } 323*0fca6ea1SDimitry Andric 324*0fca6ea1SDimitry Andric /// Find out where the current file is included or macro is expanded. If 325*0fca6ea1SDimitry Andric /// \c AcceptScratch is set to false, keep looking for expansions until the 326*0fca6ea1SDimitry Andric /// found sloc is not a <scratch space>. 327*0fca6ea1SDimitry Andric SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc, 328*0fca6ea1SDimitry Andric bool AcceptScratch = true) { 329*0fca6ea1SDimitry Andric if (!Loc.isMacroID()) 330*0fca6ea1SDimitry Andric return SM.getIncludeLoc(SM.getFileID(Loc)); 331*0fca6ea1SDimitry Andric Loc = SM.getImmediateExpansionRange(Loc).getBegin(); 332*0fca6ea1SDimitry Andric if (AcceptScratch) 333*0fca6ea1SDimitry Andric return Loc; 334*0fca6ea1SDimitry Andric return getNonScratchExpansionLoc(Loc).first; 3350b57cec5SDimitry Andric } 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric /// Return true if \c Loc is a location in a built-in macro. 3380b57cec5SDimitry Andric bool isInBuiltin(SourceLocation Loc) { 3390b57cec5SDimitry Andric return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>"; 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric /// Check whether \c Loc is included or expanded from \c Parent. 3430b57cec5SDimitry Andric bool isNestedIn(SourceLocation Loc, FileID Parent) { 3440b57cec5SDimitry Andric do { 3450b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc); 3460b57cec5SDimitry Andric if (Loc.isInvalid()) 3470b57cec5SDimitry Andric return false; 3480b57cec5SDimitry Andric } while (!SM.isInFileID(Loc, Parent)); 3490b57cec5SDimitry Andric return true; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric /// Get the start of \c S ignoring macro arguments and builtin macros. 3530b57cec5SDimitry Andric SourceLocation getStart(const Stmt *S) { 3540b57cec5SDimitry Andric SourceLocation Loc = S->getBeginLoc(); 3550b57cec5SDimitry Andric while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) 3560b57cec5SDimitry Andric Loc = SM.getImmediateExpansionRange(Loc).getBegin(); 3570b57cec5SDimitry Andric return Loc; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric /// Get the end of \c S ignoring macro arguments and builtin macros. 3610b57cec5SDimitry Andric SourceLocation getEnd(const Stmt *S) { 3620b57cec5SDimitry Andric SourceLocation Loc = S->getEndLoc(); 3630b57cec5SDimitry Andric while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) 3640b57cec5SDimitry Andric Loc = SM.getImmediateExpansionRange(Loc).getBegin(); 3650b57cec5SDimitry Andric return getPreciseTokenLocEnd(Loc); 3660b57cec5SDimitry Andric } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric /// Find the set of files we have regions for and assign IDs 3690b57cec5SDimitry Andric /// 3700b57cec5SDimitry Andric /// Fills \c Mapping with the virtual file mapping needed to write out 3710b57cec5SDimitry Andric /// coverage and collects the necessary file information to emit source and 3720b57cec5SDimitry Andric /// expansion regions. 3730b57cec5SDimitry Andric void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) { 3740b57cec5SDimitry Andric FileIDMapping.clear(); 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric llvm::SmallSet<FileID, 8> Visited; 3770b57cec5SDimitry Andric SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs; 378*0fca6ea1SDimitry Andric for (auto &Region : SourceRegions) { 3790b57cec5SDimitry Andric SourceLocation Loc = Region.getBeginLoc(); 380*0fca6ea1SDimitry Andric 381*0fca6ea1SDimitry Andric // Replace Region with its definition if it is in <scratch space>. 382*0fca6ea1SDimitry Andric auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc); 383*0fca6ea1SDimitry Andric auto EndLoc = NonScratchExpansionLoc.second; 384*0fca6ea1SDimitry Andric if (EndLoc.has_value()) { 385*0fca6ea1SDimitry Andric Loc = NonScratchExpansionLoc.first; 386*0fca6ea1SDimitry Andric Region.setStartLoc(Loc); 387*0fca6ea1SDimitry Andric Region.setEndLoc(EndLoc.value()); 388*0fca6ea1SDimitry Andric } 389*0fca6ea1SDimitry Andric 390*0fca6ea1SDimitry Andric // Replace Loc with FileLoc if it is expanded with system headers. 391*0fca6ea1SDimitry Andric if (!SystemHeadersCoverage && SM.isInSystemMacro(Loc)) { 392*0fca6ea1SDimitry Andric auto BeginLoc = SM.getSpellingLoc(Loc); 393*0fca6ea1SDimitry Andric auto EndLoc = SM.getSpellingLoc(Region.getEndLoc()); 394*0fca6ea1SDimitry Andric if (SM.isWrittenInSameFile(BeginLoc, EndLoc)) { 395*0fca6ea1SDimitry Andric Loc = SM.getFileLoc(Loc); 396*0fca6ea1SDimitry Andric Region.setStartLoc(Loc); 397*0fca6ea1SDimitry Andric Region.setEndLoc(SM.getFileLoc(Region.getEndLoc())); 398*0fca6ea1SDimitry Andric } 399*0fca6ea1SDimitry Andric } 400*0fca6ea1SDimitry Andric 4010b57cec5SDimitry Andric FileID File = SM.getFileID(Loc); 4020b57cec5SDimitry Andric if (!Visited.insert(File).second) 4030b57cec5SDimitry Andric continue; 4040b57cec5SDimitry Andric 405*0fca6ea1SDimitry Andric assert(SystemHeadersCoverage || 406*0fca6ea1SDimitry Andric !SM.isInSystemHeader(SM.getSpellingLoc(Loc))); 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric unsigned Depth = 0; 4090b57cec5SDimitry Andric for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc); 4100b57cec5SDimitry Andric Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent)) 4110b57cec5SDimitry Andric ++Depth; 4120b57cec5SDimitry Andric FileLocs.push_back(std::make_pair(Loc, Depth)); 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric llvm::stable_sort(FileLocs, llvm::less_second()); 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric for (const auto &FL : FileLocs) { 4170b57cec5SDimitry Andric SourceLocation Loc = FL.first; 4180b57cec5SDimitry Andric FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first; 4195f757f3fSDimitry Andric auto Entry = SM.getFileEntryRefForID(SpellingFile); 4200b57cec5SDimitry Andric if (!Entry) 4210b57cec5SDimitry Andric continue; 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc); 4245f757f3fSDimitry Andric Mapping.push_back(CVM.getFileID(*Entry)); 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric /// Get the coverage mapping file ID for \c Loc. 4290b57cec5SDimitry Andric /// 430bdd1243dSDimitry Andric /// If such file id doesn't exist, return std::nullopt. 431bdd1243dSDimitry Andric std::optional<unsigned> getCoverageFileID(SourceLocation Loc) { 4320b57cec5SDimitry Andric auto Mapping = FileIDMapping.find(SM.getFileID(Loc)); 4330b57cec5SDimitry Andric if (Mapping != FileIDMapping.end()) 4340b57cec5SDimitry Andric return Mapping->second.first; 435bdd1243dSDimitry Andric return std::nullopt; 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 438e8d8bef9SDimitry Andric /// This shrinks the skipped range if it spans a line that contains a 439e8d8bef9SDimitry Andric /// non-comment token. If shrinking the skipped range would make it empty, 440bdd1243dSDimitry Andric /// this returns std::nullopt. 44181ad6265SDimitry Andric /// Note this function can potentially be expensive because 44281ad6265SDimitry Andric /// getSpellingLineNumber uses getLineNumber, which is expensive. 443bdd1243dSDimitry Andric std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM, 444e8d8bef9SDimitry Andric SourceLocation LocStart, 445e8d8bef9SDimitry Andric SourceLocation LocEnd, 446e8d8bef9SDimitry Andric SourceLocation PrevTokLoc, 447e8d8bef9SDimitry Andric SourceLocation NextTokLoc) { 448e8d8bef9SDimitry Andric SpellingRegion SR{SM, LocStart, LocEnd}; 449e8d8bef9SDimitry Andric SR.ColumnStart = 1; 450e8d8bef9SDimitry Andric if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) && 451e8d8bef9SDimitry Andric SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc)) 452e8d8bef9SDimitry Andric SR.LineStart++; 453e8d8bef9SDimitry Andric if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) && 454e8d8bef9SDimitry Andric SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) { 455e8d8bef9SDimitry Andric SR.LineEnd--; 456e8d8bef9SDimitry Andric SR.ColumnEnd++; 457e8d8bef9SDimitry Andric } 458e8d8bef9SDimitry Andric if (SR.isInSourceOrder()) 459e8d8bef9SDimitry Andric return SR; 460bdd1243dSDimitry Andric return std::nullopt; 461e8d8bef9SDimitry Andric } 462e8d8bef9SDimitry Andric 4630b57cec5SDimitry Andric /// Gather all the regions that were skipped by the preprocessor 464e8d8bef9SDimitry Andric /// using the constructs like #if or comments. 4650b57cec5SDimitry Andric void gatherSkippedRegions() { 4660b57cec5SDimitry Andric /// An array of the minimum lineStarts and the maximum lineEnds 4670b57cec5SDimitry Andric /// for mapping regions from the appropriate source files. 4680b57cec5SDimitry Andric llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges; 4690b57cec5SDimitry Andric FileLineRanges.resize( 4700b57cec5SDimitry Andric FileIDMapping.size(), 4710b57cec5SDimitry Andric std::make_pair(std::numeric_limits<unsigned>::max(), 0)); 4720b57cec5SDimitry Andric for (const auto &R : MappingRegions) { 4730b57cec5SDimitry Andric FileLineRanges[R.FileID].first = 4740b57cec5SDimitry Andric std::min(FileLineRanges[R.FileID].first, R.LineStart); 4750b57cec5SDimitry Andric FileLineRanges[R.FileID].second = 4760b57cec5SDimitry Andric std::max(FileLineRanges[R.FileID].second, R.LineEnd); 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges(); 480e8d8bef9SDimitry Andric for (auto &I : SkippedRanges) { 481e8d8bef9SDimitry Andric SourceRange Range = I.Range; 482e8d8bef9SDimitry Andric auto LocStart = Range.getBegin(); 483e8d8bef9SDimitry Andric auto LocEnd = Range.getEnd(); 4840b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(LocStart, LocEnd) && 4850b57cec5SDimitry Andric "region spans multiple files"); 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric auto CovFileID = getCoverageFileID(LocStart); 4880b57cec5SDimitry Andric if (!CovFileID) 4890b57cec5SDimitry Andric continue; 490bdd1243dSDimitry Andric std::optional<SpellingRegion> SR; 49181ad6265SDimitry Andric if (I.isComment()) 49281ad6265SDimitry Andric SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc, 49381ad6265SDimitry Andric I.NextTokLoc); 49481ad6265SDimitry Andric else if (I.isPPIfElse() || I.isEmptyLine()) 49581ad6265SDimitry Andric SR = {SM, LocStart, LocEnd}; 49681ad6265SDimitry Andric 49781ad6265SDimitry Andric if (!SR) 498e8d8bef9SDimitry Andric continue; 4990b57cec5SDimitry Andric auto Region = CounterMappingRegion::makeSkipped( 500e8d8bef9SDimitry Andric *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd, 501e8d8bef9SDimitry Andric SR->ColumnEnd); 5020b57cec5SDimitry Andric // Make sure that we only collect the regions that are inside 5030b57cec5SDimitry Andric // the source code of this function. 5040b57cec5SDimitry Andric if (Region.LineStart >= FileLineRanges[*CovFileID].first && 5050b57cec5SDimitry Andric Region.LineEnd <= FileLineRanges[*CovFileID].second) 5060b57cec5SDimitry Andric MappingRegions.push_back(Region); 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric } 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric /// Generate the coverage counter mapping regions from collected 5110b57cec5SDimitry Andric /// source regions. 5120b57cec5SDimitry Andric void emitSourceRegions(const SourceRegionFilter &Filter) { 5130b57cec5SDimitry Andric for (const auto &Region : SourceRegions) { 5140b57cec5SDimitry Andric assert(Region.hasEndLoc() && "incomplete region"); 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric SourceLocation LocStart = Region.getBeginLoc(); 5170b57cec5SDimitry Andric assert(SM.getFileID(LocStart).isValid() && "region in invalid file"); 5180b57cec5SDimitry Andric 51906c3fb27SDimitry Andric // Ignore regions from system headers unless collecting coverage from 52006c3fb27SDimitry Andric // system headers is explicitly enabled. 52106c3fb27SDimitry Andric if (!SystemHeadersCoverage && 522*0fca6ea1SDimitry Andric SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) { 523*0fca6ea1SDimitry Andric assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() && 524*0fca6ea1SDimitry Andric "Don't suppress the condition in system headers"); 5250b57cec5SDimitry Andric continue; 526*0fca6ea1SDimitry Andric } 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric auto CovFileID = getCoverageFileID(LocStart); 5290b57cec5SDimitry Andric // Ignore regions that don't have a file, such as builtin macros. 530*0fca6ea1SDimitry Andric if (!CovFileID) { 531*0fca6ea1SDimitry Andric assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() && 532*0fca6ea1SDimitry Andric "Don't suppress the condition in non-file regions"); 5330b57cec5SDimitry Andric continue; 534*0fca6ea1SDimitry Andric } 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric SourceLocation LocEnd = Region.getEndLoc(); 5370b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(LocStart, LocEnd) && 5380b57cec5SDimitry Andric "region spans multiple files"); 5390b57cec5SDimitry Andric 5400b57cec5SDimitry Andric // Don't add code regions for the area covered by expansion regions. 5410b57cec5SDimitry Andric // This not only suppresses redundant regions, but sometimes prevents 5420b57cec5SDimitry Andric // creating regions with wrong counters if, for example, a statement's 5430b57cec5SDimitry Andric // body ends at the end of a nested macro. 544*0fca6ea1SDimitry Andric if (Filter.count(std::make_pair(LocStart, LocEnd))) { 545*0fca6ea1SDimitry Andric assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() && 546*0fca6ea1SDimitry Andric "Don't suppress the condition"); 5470b57cec5SDimitry Andric continue; 548*0fca6ea1SDimitry Andric } 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric // Find the spelling locations for the mapping region. 5510b57cec5SDimitry Andric SpellingRegion SR{SM, LocStart, LocEnd}; 5520b57cec5SDimitry Andric assert(SR.isInSourceOrder() && "region start and end out of order"); 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric if (Region.isGap()) { 5550b57cec5SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeGapRegion( 5560b57cec5SDimitry Andric Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, 5570b57cec5SDimitry Andric SR.LineEnd, SR.ColumnEnd)); 5587a6dacacSDimitry Andric } else if (Region.isSkipped()) { 5597a6dacacSDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeSkipped( 5607a6dacacSDimitry Andric *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, 5617a6dacacSDimitry Andric SR.ColumnEnd)); 562e8d8bef9SDimitry Andric } else if (Region.isBranch()) { 563e8d8bef9SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeBranchRegion( 564*0fca6ea1SDimitry Andric Region.getCounter(), Region.getFalseCounter(), *CovFileID, 565*0fca6ea1SDimitry Andric SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd, 566*0fca6ea1SDimitry Andric Region.getMCDCParams())); 5671db9f3b2SDimitry Andric } else if (Region.isMCDCDecision()) { 5681db9f3b2SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion( 569*0fca6ea1SDimitry Andric Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart, 570*0fca6ea1SDimitry Andric SR.ColumnStart, SR.LineEnd, SR.ColumnEnd)); 5710b57cec5SDimitry Andric } else { 5720b57cec5SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeRegion( 5730b57cec5SDimitry Andric Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, 5740b57cec5SDimitry Andric SR.LineEnd, SR.ColumnEnd)); 5750b57cec5SDimitry Andric } 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric } 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric /// Generate expansion regions for each virtual file we've seen. 5800b57cec5SDimitry Andric SourceRegionFilter emitExpansionRegions() { 5810b57cec5SDimitry Andric SourceRegionFilter Filter; 5820b57cec5SDimitry Andric for (const auto &FM : FileIDMapping) { 5830b57cec5SDimitry Andric SourceLocation ExpandedLoc = FM.second.second; 584*0fca6ea1SDimitry Andric SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc, false); 5850b57cec5SDimitry Andric if (ParentLoc.isInvalid()) 5860b57cec5SDimitry Andric continue; 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric auto ParentFileID = getCoverageFileID(ParentLoc); 5890b57cec5SDimitry Andric if (!ParentFileID) 5900b57cec5SDimitry Andric continue; 5910b57cec5SDimitry Andric auto ExpandedFileID = getCoverageFileID(ExpandedLoc); 5920b57cec5SDimitry Andric assert(ExpandedFileID && "expansion in uncovered file"); 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc); 5950b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) && 5960b57cec5SDimitry Andric "region spans multiple files"); 5970b57cec5SDimitry Andric Filter.insert(std::make_pair(ParentLoc, LocEnd)); 5980b57cec5SDimitry Andric 5990b57cec5SDimitry Andric SpellingRegion SR{SM, ParentLoc, LocEnd}; 6000b57cec5SDimitry Andric assert(SR.isInSourceOrder() && "region start and end out of order"); 6010b57cec5SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeExpansion( 6020b57cec5SDimitry Andric *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart, 6030b57cec5SDimitry Andric SR.LineEnd, SR.ColumnEnd)); 6040b57cec5SDimitry Andric } 6050b57cec5SDimitry Andric return Filter; 6060b57cec5SDimitry Andric } 6070b57cec5SDimitry Andric }; 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric /// Creates unreachable coverage regions for the functions that 6100b57cec5SDimitry Andric /// are not emitted. 6110b57cec5SDimitry Andric struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { 6120b57cec5SDimitry Andric EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, 6130b57cec5SDimitry Andric const LangOptions &LangOpts) 6140b57cec5SDimitry Andric : CoverageMappingBuilder(CVM, SM, LangOpts) {} 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric void VisitDecl(const Decl *D) { 6170b57cec5SDimitry Andric if (!D->hasBody()) 6180b57cec5SDimitry Andric return; 6190b57cec5SDimitry Andric auto Body = D->getBody(); 6200b57cec5SDimitry Andric SourceLocation Start = getStart(Body); 6210b57cec5SDimitry Andric SourceLocation End = getEnd(Body); 6220b57cec5SDimitry Andric if (!SM.isWrittenInSameFile(Start, End)) { 6230b57cec5SDimitry Andric // Walk up to find the common ancestor. 6240b57cec5SDimitry Andric // Correct the locations accordingly. 6250b57cec5SDimitry Andric FileID StartFileID = SM.getFileID(Start); 6260b57cec5SDimitry Andric FileID EndFileID = SM.getFileID(End); 6270b57cec5SDimitry Andric while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) { 6280b57cec5SDimitry Andric Start = getIncludeOrExpansionLoc(Start); 6290b57cec5SDimitry Andric assert(Start.isValid() && 6300b57cec5SDimitry Andric "Declaration start location not nested within a known region"); 6310b57cec5SDimitry Andric StartFileID = SM.getFileID(Start); 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric while (StartFileID != EndFileID) { 6340b57cec5SDimitry Andric End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End)); 6350b57cec5SDimitry Andric assert(End.isValid() && 6360b57cec5SDimitry Andric "Declaration end location not nested within a known region"); 6370b57cec5SDimitry Andric EndFileID = SM.getFileID(End); 6380b57cec5SDimitry Andric } 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric SourceRegions.emplace_back(Counter(), Start, End); 6410b57cec5SDimitry Andric } 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric /// Write the mapping data to the output stream 6440b57cec5SDimitry Andric void write(llvm::raw_ostream &OS) { 6450b57cec5SDimitry Andric SmallVector<unsigned, 16> FileIDMapping; 6460b57cec5SDimitry Andric gatherFileIDs(FileIDMapping); 6470b57cec5SDimitry Andric emitSourceRegions(SourceRegionFilter()); 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric if (MappingRegions.empty()) 6500b57cec5SDimitry Andric return; 6510b57cec5SDimitry Andric 652bdd1243dSDimitry Andric CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions); 6530b57cec5SDimitry Andric Writer.write(OS); 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric }; 6560b57cec5SDimitry Andric 6571db9f3b2SDimitry Andric /// A wrapper object for maintaining stacks to track the resursive AST visitor 6581db9f3b2SDimitry Andric /// walks for the purpose of assigning IDs to leaf-level conditions measured by 6591db9f3b2SDimitry Andric /// MC/DC. The object is created with a reference to the MCDCBitmapMap that was 6601db9f3b2SDimitry Andric /// created during the initial AST walk. The presence of a bitmap associated 6611db9f3b2SDimitry Andric /// with a boolean expression (top-level logical operator nest) indicates that 6621db9f3b2SDimitry Andric /// the boolean expression qualified for MC/DC. The resulting condition IDs 6631db9f3b2SDimitry Andric /// are preserved in a map reference that is also provided during object 6641db9f3b2SDimitry Andric /// creation. 6651db9f3b2SDimitry Andric struct MCDCCoverageBuilder { 6661db9f3b2SDimitry Andric 6671db9f3b2SDimitry Andric /// The AST walk recursively visits nested logical-AND or logical-OR binary 6681db9f3b2SDimitry Andric /// operator nodes and then visits their LHS and RHS children nodes. As this 6691db9f3b2SDimitry Andric /// happens, the algorithm will assign IDs to each operator's LHS and RHS side 6701db9f3b2SDimitry Andric /// as the walk moves deeper into the nest. At each level of the recursive 6711db9f3b2SDimitry Andric /// nest, the LHS and RHS may actually correspond to larger subtrees (not 6721db9f3b2SDimitry Andric /// leaf-conditions). If this is the case, when that node is visited, the ID 6731db9f3b2SDimitry Andric /// assigned to the subtree is re-assigned to its LHS, and a new ID is given 6741db9f3b2SDimitry Andric /// to its RHS. At the end of the walk, all leaf-level conditions will have a 6751db9f3b2SDimitry Andric /// unique ID -- keep in mind that the final set of IDs may not be in 6761db9f3b2SDimitry Andric /// numerical order from left to right. 6771db9f3b2SDimitry Andric /// 6781db9f3b2SDimitry Andric /// Example: "x = (A && B) || (C && D) || (D && F)" 6791db9f3b2SDimitry Andric /// 6801db9f3b2SDimitry Andric /// Visit Depth1: 6811db9f3b2SDimitry Andric /// (A && B) || (C && D) || (D && F) 6821db9f3b2SDimitry Andric /// ^-------LHS--------^ ^-RHS--^ 6831db9f3b2SDimitry Andric /// ID=1 ID=2 6841db9f3b2SDimitry Andric /// 6851db9f3b2SDimitry Andric /// Visit LHS-Depth2: 6861db9f3b2SDimitry Andric /// (A && B) || (C && D) 6871db9f3b2SDimitry Andric /// ^-LHS--^ ^-RHS--^ 6881db9f3b2SDimitry Andric /// ID=1 ID=3 6891db9f3b2SDimitry Andric /// 6901db9f3b2SDimitry Andric /// Visit LHS-Depth3: 6911db9f3b2SDimitry Andric /// (A && B) 6921db9f3b2SDimitry Andric /// LHS RHS 6931db9f3b2SDimitry Andric /// ID=1 ID=4 6941db9f3b2SDimitry Andric /// 6951db9f3b2SDimitry Andric /// Visit RHS-Depth3: 6961db9f3b2SDimitry Andric /// (C && D) 6971db9f3b2SDimitry Andric /// LHS RHS 6981db9f3b2SDimitry Andric /// ID=3 ID=5 6991db9f3b2SDimitry Andric /// 7001db9f3b2SDimitry Andric /// Visit RHS-Depth2: (D && F) 7011db9f3b2SDimitry Andric /// LHS RHS 7021db9f3b2SDimitry Andric /// ID=2 ID=6 7031db9f3b2SDimitry Andric /// 7041db9f3b2SDimitry Andric /// Visit Depth1: 7051db9f3b2SDimitry Andric /// (A && B) || (C && D) || (D && F) 7061db9f3b2SDimitry Andric /// ID=1 ID=4 ID=3 ID=5 ID=2 ID=6 7071db9f3b2SDimitry Andric /// 7081db9f3b2SDimitry Andric /// A node ID of '0' always means MC/DC isn't being tracked. 7091db9f3b2SDimitry Andric /// 7107a6dacacSDimitry Andric /// As the AST walk proceeds recursively, the algorithm will also use a stack 7111db9f3b2SDimitry Andric /// to track the IDs of logical-AND and logical-OR operations on the RHS so 7121db9f3b2SDimitry Andric /// that it can be determined which nodes are executed next, depending on how 7131db9f3b2SDimitry Andric /// a LHS or RHS of a logical-AND or logical-OR is evaluated. This 7141db9f3b2SDimitry Andric /// information relies on the assigned IDs and are embedded within the 7151db9f3b2SDimitry Andric /// coverage region IDs of each branch region associated with a leaf-level 7161db9f3b2SDimitry Andric /// condition. This information helps the visualization tool reconstruct all 7177a6dacacSDimitry Andric /// possible test vectors for the purposes of MC/DC analysis. If a "next" node 7181db9f3b2SDimitry Andric /// ID is '0', it means it's the end of the test vector. The following rules 7191db9f3b2SDimitry Andric /// are used: 7201db9f3b2SDimitry Andric /// 7211db9f3b2SDimitry Andric /// For logical-AND ("LHS && RHS"): 7221db9f3b2SDimitry Andric /// - If LHS is TRUE, execution goes to the RHS node. 7231db9f3b2SDimitry Andric /// - If LHS is FALSE, execution goes to the LHS node of the next logical-OR. 7241db9f3b2SDimitry Andric /// If that does not exist, execution exits (ID == 0). 7251db9f3b2SDimitry Andric /// 7261db9f3b2SDimitry Andric /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND. 7271db9f3b2SDimitry Andric /// If that does not exist, execution exits (ID == 0). 7281db9f3b2SDimitry Andric /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR. 7291db9f3b2SDimitry Andric /// If that does not exist, execution exits (ID == 0). 7301db9f3b2SDimitry Andric /// 7311db9f3b2SDimitry Andric /// For logical-OR ("LHS || RHS"): 7321db9f3b2SDimitry Andric /// - If LHS is TRUE, execution goes to the LHS node of the next logical-AND. 7331db9f3b2SDimitry Andric /// If that does not exist, execution exits (ID == 0). 7341db9f3b2SDimitry Andric /// - If LHS is FALSE, execution goes to the RHS node. 7351db9f3b2SDimitry Andric /// 7361db9f3b2SDimitry Andric /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND. 7371db9f3b2SDimitry Andric /// If that does not exist, execution exits (ID == 0). 7381db9f3b2SDimitry Andric /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR. 7391db9f3b2SDimitry Andric /// If that does not exist, execution exits (ID == 0). 7401db9f3b2SDimitry Andric /// 7411db9f3b2SDimitry Andric /// Finally, the condition IDs are also used when instrumenting the code to 7421db9f3b2SDimitry Andric /// indicate a unique offset into a temporary bitmap that represents the true 7431db9f3b2SDimitry Andric /// or false evaluation of that particular condition. 7441db9f3b2SDimitry Andric /// 7451db9f3b2SDimitry Andric /// NOTE regarding the use of CodeGenFunction::stripCond(). Even though, for 7461db9f3b2SDimitry Andric /// simplicity, parentheses and unary logical-NOT operators are considered 7471db9f3b2SDimitry Andric /// part of their underlying condition for both MC/DC and branch coverage, the 7481db9f3b2SDimitry Andric /// condition IDs themselves are assigned and tracked using the underlying 7491db9f3b2SDimitry Andric /// condition itself. This is done solely for consistency since parentheses 7501db9f3b2SDimitry Andric /// and logical-NOTs are ignored when checking whether the condition is 7511db9f3b2SDimitry Andric /// actually an instrumentable condition. This can also make debugging a bit 7521db9f3b2SDimitry Andric /// easier. 7531db9f3b2SDimitry Andric 7541db9f3b2SDimitry Andric private: 7551db9f3b2SDimitry Andric CodeGenModule &CGM; 7561db9f3b2SDimitry Andric 757*0fca6ea1SDimitry Andric llvm::SmallVector<mcdc::ConditionIDs> DecisionStack; 758*0fca6ea1SDimitry Andric MCDC::State &MCDCState; 759*0fca6ea1SDimitry Andric const Stmt *DecisionStmt = nullptr; 760*0fca6ea1SDimitry Andric mcdc::ConditionID NextID = 0; 7611db9f3b2SDimitry Andric bool NotMapped = false; 7621db9f3b2SDimitry Andric 763*0fca6ea1SDimitry Andric /// Represent a sentinel value as a pair of final decisions for the bottom 764*0fca6ea1SDimitry Andric // of DecisionStack. 765*0fca6ea1SDimitry Andric static constexpr mcdc::ConditionIDs DecisionStackSentinel{-1, -1}; 7667a6dacacSDimitry Andric 7671db9f3b2SDimitry Andric /// Is this a logical-AND operation? 7681db9f3b2SDimitry Andric bool isLAnd(const BinaryOperator *E) const { 7691db9f3b2SDimitry Andric return E->getOpcode() == BO_LAnd; 7701db9f3b2SDimitry Andric } 7711db9f3b2SDimitry Andric 7721db9f3b2SDimitry Andric public: 773*0fca6ea1SDimitry Andric MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState) 774*0fca6ea1SDimitry Andric : CGM(CGM), DecisionStack(1, DecisionStackSentinel), 775*0fca6ea1SDimitry Andric MCDCState(MCDCState) {} 7761db9f3b2SDimitry Andric 7777a6dacacSDimitry Andric /// Return whether the build of the control flow map is at the top-level 7787a6dacacSDimitry Andric /// (root) of a logical operator nest in a boolean expression prior to the 7797a6dacacSDimitry Andric /// assignment of condition IDs. 780*0fca6ea1SDimitry Andric bool isIdle() const { return (NextID == 0 && !NotMapped); } 7811db9f3b2SDimitry Andric 7827a6dacacSDimitry Andric /// Return whether any IDs have been assigned in the build of the control 7837a6dacacSDimitry Andric /// flow map, indicating that the map is being generated for this boolean 7847a6dacacSDimitry Andric /// expression. 785*0fca6ea1SDimitry Andric bool isBuilding() const { return (NextID > 0); } 7867a6dacacSDimitry Andric 7877a6dacacSDimitry Andric /// Set the given condition's ID. 788*0fca6ea1SDimitry Andric void setCondID(const Expr *Cond, mcdc::ConditionID ID) { 789*0fca6ea1SDimitry Andric MCDCState.BranchByStmt[CodeGenFunction::stripCond(Cond)] = {ID, 790*0fca6ea1SDimitry Andric DecisionStmt}; 7911db9f3b2SDimitry Andric } 7921db9f3b2SDimitry Andric 7931db9f3b2SDimitry Andric /// Return the ID of a given condition. 794*0fca6ea1SDimitry Andric mcdc::ConditionID getCondID(const Expr *Cond) const { 795*0fca6ea1SDimitry Andric auto I = MCDCState.BranchByStmt.find(CodeGenFunction::stripCond(Cond)); 796*0fca6ea1SDimitry Andric if (I == MCDCState.BranchByStmt.end()) 797*0fca6ea1SDimitry Andric return -1; 7981db9f3b2SDimitry Andric else 799*0fca6ea1SDimitry Andric return I->second.ID; 8001db9f3b2SDimitry Andric } 8011db9f3b2SDimitry Andric 8027a6dacacSDimitry Andric /// Return the LHS Decision ([0,0] if not set). 803*0fca6ea1SDimitry Andric const mcdc::ConditionIDs &back() const { return DecisionStack.back(); } 8047a6dacacSDimitry Andric 8051db9f3b2SDimitry Andric /// Push the binary operator statement to track the nest level and assign IDs 8061db9f3b2SDimitry Andric /// to the operator's LHS and RHS. The RHS may be a larger subtree that is 8071db9f3b2SDimitry Andric /// broken up on successive levels. 8081db9f3b2SDimitry Andric void pushAndAssignIDs(const BinaryOperator *E) { 8091db9f3b2SDimitry Andric if (!CGM.getCodeGenOpts().MCDCCoverage) 8101db9f3b2SDimitry Andric return; 8111db9f3b2SDimitry Andric 8121db9f3b2SDimitry Andric // If binary expression is disqualified, don't do mapping. 813*0fca6ea1SDimitry Andric if (!isBuilding() && 814*0fca6ea1SDimitry Andric !MCDCState.DecisionByStmt.contains(CodeGenFunction::stripCond(E))) 8151db9f3b2SDimitry Andric NotMapped = true; 8161db9f3b2SDimitry Andric 8171db9f3b2SDimitry Andric // Don't go any further if we don't need to map condition IDs. 8181db9f3b2SDimitry Andric if (NotMapped) 8191db9f3b2SDimitry Andric return; 8201db9f3b2SDimitry Andric 821*0fca6ea1SDimitry Andric if (NextID == 0) { 822*0fca6ea1SDimitry Andric DecisionStmt = E; 823*0fca6ea1SDimitry Andric assert(MCDCState.DecisionByStmt.contains(E)); 824*0fca6ea1SDimitry Andric } 825*0fca6ea1SDimitry Andric 826*0fca6ea1SDimitry Andric const mcdc::ConditionIDs &ParentDecision = DecisionStack.back(); 8277a6dacacSDimitry Andric 8281db9f3b2SDimitry Andric // If the operator itself has an assigned ID, this means it represents a 8297a6dacacSDimitry Andric // larger subtree. In this case, assign that ID to its LHS node. Its RHS 8307a6dacacSDimitry Andric // will receive a new ID below. Otherwise, assign ID+1 to LHS. 831*0fca6ea1SDimitry Andric if (MCDCState.BranchByStmt.contains(CodeGenFunction::stripCond(E))) 8327a6dacacSDimitry Andric setCondID(E->getLHS(), getCondID(E)); 8337a6dacacSDimitry Andric else 8347a6dacacSDimitry Andric setCondID(E->getLHS(), NextID++); 8351db9f3b2SDimitry Andric 8367a6dacacSDimitry Andric // Assign a ID+1 for the RHS. 837*0fca6ea1SDimitry Andric mcdc::ConditionID RHSid = NextID++; 8387a6dacacSDimitry Andric setCondID(E->getRHS(), RHSid); 8397a6dacacSDimitry Andric 8407a6dacacSDimitry Andric // Push the LHS decision IDs onto the DecisionStack. 8417a6dacacSDimitry Andric if (isLAnd(E)) 842*0fca6ea1SDimitry Andric DecisionStack.push_back({ParentDecision[false], RHSid}); 8437a6dacacSDimitry Andric else 844*0fca6ea1SDimitry Andric DecisionStack.push_back({RHSid, ParentDecision[true]}); 8451db9f3b2SDimitry Andric } 8461db9f3b2SDimitry Andric 8477a6dacacSDimitry Andric /// Pop and return the LHS Decision ([0,0] if not set). 848*0fca6ea1SDimitry Andric mcdc::ConditionIDs pop() { 8497a6dacacSDimitry Andric if (!CGM.getCodeGenOpts().MCDCCoverage || NotMapped) 850*0fca6ea1SDimitry Andric return DecisionStackSentinel; 8511db9f3b2SDimitry Andric 8527a6dacacSDimitry Andric assert(DecisionStack.size() > 1); 853*0fca6ea1SDimitry Andric return DecisionStack.pop_back_val(); 8541db9f3b2SDimitry Andric } 8551db9f3b2SDimitry Andric 8567a6dacacSDimitry Andric /// Return the total number of conditions and reset the state. The number of 8577a6dacacSDimitry Andric /// conditions is zero if the expression isn't mapped. 8587a6dacacSDimitry Andric unsigned getTotalConditionsAndReset(const BinaryOperator *E) { 8591db9f3b2SDimitry Andric if (!CGM.getCodeGenOpts().MCDCCoverage) 8601db9f3b2SDimitry Andric return 0; 8611db9f3b2SDimitry Andric 8627a6dacacSDimitry Andric assert(!isIdle()); 8637a6dacacSDimitry Andric assert(DecisionStack.size() == 1); 8641db9f3b2SDimitry Andric 8651db9f3b2SDimitry Andric // Reset state if not doing mapping. 8667a6dacacSDimitry Andric if (NotMapped) { 8671db9f3b2SDimitry Andric NotMapped = false; 868*0fca6ea1SDimitry Andric assert(NextID == 0); 8691db9f3b2SDimitry Andric return 0; 8701db9f3b2SDimitry Andric } 8711db9f3b2SDimitry Andric 8727a6dacacSDimitry Andric // Set number of conditions and reset. 873*0fca6ea1SDimitry Andric unsigned TotalConds = NextID; 8741db9f3b2SDimitry Andric 8751db9f3b2SDimitry Andric // Reset ID back to beginning. 876*0fca6ea1SDimitry Andric NextID = 0; 8777a6dacacSDimitry Andric 8781db9f3b2SDimitry Andric return TotalConds; 8791db9f3b2SDimitry Andric } 8801db9f3b2SDimitry Andric }; 8811db9f3b2SDimitry Andric 8820b57cec5SDimitry Andric /// A StmtVisitor that creates coverage mapping regions which map 8830b57cec5SDimitry Andric /// from the source code locations to the PGO counters. 8840b57cec5SDimitry Andric struct CounterCoverageMappingBuilder 8850b57cec5SDimitry Andric : public CoverageMappingBuilder, 8860b57cec5SDimitry Andric public ConstStmtVisitor<CounterCoverageMappingBuilder> { 8870b57cec5SDimitry Andric /// The map of statements to count values. 8880b57cec5SDimitry Andric llvm::DenseMap<const Stmt *, unsigned> &CounterMap; 8890b57cec5SDimitry Andric 890*0fca6ea1SDimitry Andric MCDC::State &MCDCState; 8911db9f3b2SDimitry Andric 8920b57cec5SDimitry Andric /// A stack of currently live regions. 8931db9f3b2SDimitry Andric llvm::SmallVector<SourceMappingRegion> RegionStack; 8941db9f3b2SDimitry Andric 895*0fca6ea1SDimitry Andric /// Set if the Expr should be handled as a leaf even if it is kind of binary 896*0fca6ea1SDimitry Andric /// logical ops (&&, ||). 897*0fca6ea1SDimitry Andric llvm::DenseSet<const Stmt *> LeafExprSet; 898*0fca6ea1SDimitry Andric 8991db9f3b2SDimitry Andric /// An object to manage MCDC regions. 9001db9f3b2SDimitry Andric MCDCCoverageBuilder MCDCBuilder; 9010b57cec5SDimitry Andric 9020b57cec5SDimitry Andric CounterExpressionBuilder Builder; 9030b57cec5SDimitry Andric 9040b57cec5SDimitry Andric /// A location in the most recently visited file or macro. 9050b57cec5SDimitry Andric /// 9060b57cec5SDimitry Andric /// This is used to adjust the active source regions appropriately when 9070b57cec5SDimitry Andric /// expressions cross file or macro boundaries. 9080b57cec5SDimitry Andric SourceLocation MostRecentLocation; 9090b57cec5SDimitry Andric 910fe6060f1SDimitry Andric /// Whether the visitor at a terminate statement. 911fe6060f1SDimitry Andric bool HasTerminateStmt = false; 912fe6060f1SDimitry Andric 913fe6060f1SDimitry Andric /// Gap region counter after terminate statement. 914fe6060f1SDimitry Andric Counter GapRegionCounter; 9150b57cec5SDimitry Andric 9160b57cec5SDimitry Andric /// Return a counter for the subtraction of \c RHS from \c LHS 91781ad6265SDimitry Andric Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) { 918*0fca6ea1SDimitry Andric assert(!llvm::EnableSingleByteCoverage && 919*0fca6ea1SDimitry Andric "cannot add counters when single byte coverage mode is enabled"); 92081ad6265SDimitry Andric return Builder.subtract(LHS, RHS, Simplify); 9210b57cec5SDimitry Andric } 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric /// Return a counter for the sum of \c LHS and \c RHS. 92481ad6265SDimitry Andric Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) { 925*0fca6ea1SDimitry Andric assert(!llvm::EnableSingleByteCoverage && 926*0fca6ea1SDimitry Andric "cannot add counters when single byte coverage mode is enabled"); 92781ad6265SDimitry Andric return Builder.add(LHS, RHS, Simplify); 9280b57cec5SDimitry Andric } 9290b57cec5SDimitry Andric 93081ad6265SDimitry Andric Counter addCounters(Counter C1, Counter C2, Counter C3, 93181ad6265SDimitry Andric bool Simplify = true) { 932*0fca6ea1SDimitry Andric assert(!llvm::EnableSingleByteCoverage && 933*0fca6ea1SDimitry Andric "cannot add counters when single byte coverage mode is enabled"); 93481ad6265SDimitry Andric return addCounters(addCounters(C1, C2, Simplify), C3, Simplify); 9350b57cec5SDimitry Andric } 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric /// Return the region counter for the given statement. 9380b57cec5SDimitry Andric /// 9390b57cec5SDimitry Andric /// This should only be called on statements that have a dedicated counter. 9400b57cec5SDimitry Andric Counter getRegionCounter(const Stmt *S) { 9410b57cec5SDimitry Andric return Counter::getCounter(CounterMap[S]); 9420b57cec5SDimitry Andric } 9430b57cec5SDimitry Andric 9440b57cec5SDimitry Andric /// Push a region onto the stack. 9450b57cec5SDimitry Andric /// 9460b57cec5SDimitry Andric /// Returns the index on the stack where the region was pushed. This can be 9470b57cec5SDimitry Andric /// used with popRegions to exit a "scope", ending the region that was pushed. 948bdd1243dSDimitry Andric size_t pushRegion(Counter Count, 949bdd1243dSDimitry Andric std::optional<SourceLocation> StartLoc = std::nullopt, 950bdd1243dSDimitry Andric std::optional<SourceLocation> EndLoc = std::nullopt, 9511db9f3b2SDimitry Andric std::optional<Counter> FalseCount = std::nullopt, 952*0fca6ea1SDimitry Andric const mcdc::Parameters &BranchParams = std::monostate()) { 953e8d8bef9SDimitry Andric 95481ad6265SDimitry Andric if (StartLoc && !FalseCount) { 9550b57cec5SDimitry Andric MostRecentLocation = *StartLoc; 9560b57cec5SDimitry Andric } 957e8d8bef9SDimitry Andric 95806c3fb27SDimitry Andric // If either of these locations is invalid, something elsewhere in the 95906c3fb27SDimitry Andric // compiler has broken. 96006c3fb27SDimitry Andric assert((!StartLoc || StartLoc->isValid()) && "Start location is not valid"); 96106c3fb27SDimitry Andric assert((!EndLoc || EndLoc->isValid()) && "End location is not valid"); 96206c3fb27SDimitry Andric 96306c3fb27SDimitry Andric // However, we can still recover without crashing. 96406c3fb27SDimitry Andric // If either location is invalid, set it to std::nullopt to avoid 96506c3fb27SDimitry Andric // letting users of RegionStack think that region has a valid start/end 96606c3fb27SDimitry Andric // location. 96706c3fb27SDimitry Andric if (StartLoc && StartLoc->isInvalid()) 96806c3fb27SDimitry Andric StartLoc = std::nullopt; 96906c3fb27SDimitry Andric if (EndLoc && EndLoc->isInvalid()) 97006c3fb27SDimitry Andric EndLoc = std::nullopt; 971*0fca6ea1SDimitry Andric RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc); 9721db9f3b2SDimitry Andric 9731db9f3b2SDimitry Andric return RegionStack.size() - 1; 9741db9f3b2SDimitry Andric } 9751db9f3b2SDimitry Andric 976*0fca6ea1SDimitry Andric size_t pushRegion(const mcdc::DecisionParameters &DecisionParams, 9771db9f3b2SDimitry Andric std::optional<SourceLocation> StartLoc = std::nullopt, 9781db9f3b2SDimitry Andric std::optional<SourceLocation> EndLoc = std::nullopt) { 9791db9f3b2SDimitry Andric 980*0fca6ea1SDimitry Andric RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc); 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric return RegionStack.size() - 1; 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric size_t locationDepth(SourceLocation Loc) { 9860b57cec5SDimitry Andric size_t Depth = 0; 9870b57cec5SDimitry Andric while (Loc.isValid()) { 9880b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc); 9890b57cec5SDimitry Andric Depth++; 9900b57cec5SDimitry Andric } 9910b57cec5SDimitry Andric return Depth; 9920b57cec5SDimitry Andric } 9930b57cec5SDimitry Andric 9940b57cec5SDimitry Andric /// Pop regions from the stack into the function's list of regions. 9950b57cec5SDimitry Andric /// 9960b57cec5SDimitry Andric /// Adds all regions from \c ParentIndex to the top of the stack to the 9970b57cec5SDimitry Andric /// function's \c SourceRegions. 9980b57cec5SDimitry Andric void popRegions(size_t ParentIndex) { 9990b57cec5SDimitry Andric assert(RegionStack.size() >= ParentIndex && "parent not in stack"); 10000b57cec5SDimitry Andric while (RegionStack.size() > ParentIndex) { 10010b57cec5SDimitry Andric SourceMappingRegion &Region = RegionStack.back(); 100206c3fb27SDimitry Andric if (Region.hasStartLoc() && 100306c3fb27SDimitry Andric (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) { 10040b57cec5SDimitry Andric SourceLocation StartLoc = Region.getBeginLoc(); 10050b57cec5SDimitry Andric SourceLocation EndLoc = Region.hasEndLoc() 10060b57cec5SDimitry Andric ? Region.getEndLoc() 10070b57cec5SDimitry Andric : RegionStack[ParentIndex].getEndLoc(); 1008e8d8bef9SDimitry Andric bool isBranch = Region.isBranch(); 10090b57cec5SDimitry Andric size_t StartDepth = locationDepth(StartLoc); 10100b57cec5SDimitry Andric size_t EndDepth = locationDepth(EndLoc); 10110b57cec5SDimitry Andric while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) { 10120b57cec5SDimitry Andric bool UnnestStart = StartDepth >= EndDepth; 10130b57cec5SDimitry Andric bool UnnestEnd = EndDepth >= StartDepth; 10140b57cec5SDimitry Andric if (UnnestEnd) { 1015e8d8bef9SDimitry Andric // The region ends in a nested file or macro expansion. If the 1016e8d8bef9SDimitry Andric // region is not a branch region, create a separate region for each 1017e8d8bef9SDimitry Andric // expansion, and for all regions, update the EndLoc. Branch 1018e8d8bef9SDimitry Andric // regions should not be split in order to keep a straightforward 1019e8d8bef9SDimitry Andric // correspondance between the region and its associated branch 1020e8d8bef9SDimitry Andric // condition, even if the condition spans multiple depths. 10210b57cec5SDimitry Andric SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc); 10220b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(NestedLoc, EndLoc)); 10230b57cec5SDimitry Andric 1024e8d8bef9SDimitry Andric if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc)) 1025e8d8bef9SDimitry Andric SourceRegions.emplace_back(Region.getCounter(), NestedLoc, 1026e8d8bef9SDimitry Andric EndLoc); 10270b57cec5SDimitry Andric 10280b57cec5SDimitry Andric EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc)); 10290b57cec5SDimitry Andric if (EndLoc.isInvalid()) 1030e8d8bef9SDimitry Andric llvm::report_fatal_error( 1031e8d8bef9SDimitry Andric "File exit not handled before popRegions"); 10320b57cec5SDimitry Andric EndDepth--; 10330b57cec5SDimitry Andric } 10340b57cec5SDimitry Andric if (UnnestStart) { 1035e8d8bef9SDimitry Andric // The region ends in a nested file or macro expansion. If the 1036e8d8bef9SDimitry Andric // region is not a branch region, create a separate region for each 1037e8d8bef9SDimitry Andric // expansion, and for all regions, update the StartLoc. Branch 1038e8d8bef9SDimitry Andric // regions should not be split in order to keep a straightforward 1039e8d8bef9SDimitry Andric // correspondance between the region and its associated branch 1040e8d8bef9SDimitry Andric // condition, even if the condition spans multiple depths. 10410b57cec5SDimitry Andric SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc); 10420b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(StartLoc, NestedLoc)); 10430b57cec5SDimitry Andric 1044e8d8bef9SDimitry Andric if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc)) 1045e8d8bef9SDimitry Andric SourceRegions.emplace_back(Region.getCounter(), StartLoc, 1046e8d8bef9SDimitry Andric NestedLoc); 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric StartLoc = getIncludeOrExpansionLoc(StartLoc); 10490b57cec5SDimitry Andric if (StartLoc.isInvalid()) 1050e8d8bef9SDimitry Andric llvm::report_fatal_error( 1051e8d8bef9SDimitry Andric "File exit not handled before popRegions"); 10520b57cec5SDimitry Andric StartDepth--; 10530b57cec5SDimitry Andric } 10540b57cec5SDimitry Andric } 10550b57cec5SDimitry Andric Region.setStartLoc(StartLoc); 10560b57cec5SDimitry Andric Region.setEndLoc(EndLoc); 10570b57cec5SDimitry Andric 1058e8d8bef9SDimitry Andric if (!isBranch) { 10590b57cec5SDimitry Andric MostRecentLocation = EndLoc; 1060e8d8bef9SDimitry Andric // If this region happens to span an entire expansion, we need to 1061e8d8bef9SDimitry Andric // make sure we don't overlap the parent region with it. 10620b57cec5SDimitry Andric if (StartLoc == getStartOfFileOrMacro(StartLoc) && 10630b57cec5SDimitry Andric EndLoc == getEndOfFileOrMacro(EndLoc)) 10640b57cec5SDimitry Andric MostRecentLocation = getIncludeOrExpansionLoc(EndLoc); 1065e8d8bef9SDimitry Andric } 10660b57cec5SDimitry Andric 10670b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc)); 10680b57cec5SDimitry Andric assert(SpellingRegion(SM, Region).isInSourceOrder()); 10690b57cec5SDimitry Andric SourceRegions.push_back(Region); 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric RegionStack.pop_back(); 10720b57cec5SDimitry Andric } 10730b57cec5SDimitry Andric } 10740b57cec5SDimitry Andric 10750b57cec5SDimitry Andric /// Return the currently active region. 10760b57cec5SDimitry Andric SourceMappingRegion &getRegion() { 10770b57cec5SDimitry Andric assert(!RegionStack.empty() && "statement has no region"); 10780b57cec5SDimitry Andric return RegionStack.back(); 10790b57cec5SDimitry Andric } 10800b57cec5SDimitry Andric 10810b57cec5SDimitry Andric /// Propagate counts through the children of \p S if \p VisitChildren is true. 10820b57cec5SDimitry Andric /// Otherwise, only emit a count for \p S itself. 10830b57cec5SDimitry Andric Counter propagateCounts(Counter TopCount, const Stmt *S, 10840b57cec5SDimitry Andric bool VisitChildren = true) { 10850b57cec5SDimitry Andric SourceLocation StartLoc = getStart(S); 10860b57cec5SDimitry Andric SourceLocation EndLoc = getEnd(S); 10870b57cec5SDimitry Andric size_t Index = pushRegion(TopCount, StartLoc, EndLoc); 10880b57cec5SDimitry Andric if (VisitChildren) 10890b57cec5SDimitry Andric Visit(S); 10900b57cec5SDimitry Andric Counter ExitCount = getRegion().getCounter(); 10910b57cec5SDimitry Andric popRegions(Index); 10920b57cec5SDimitry Andric 10930b57cec5SDimitry Andric // The statement may be spanned by an expansion. Make sure we handle a file 10940b57cec5SDimitry Andric // exit out of this expansion before moving to the next statement. 10950b57cec5SDimitry Andric if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc())) 10960b57cec5SDimitry Andric MostRecentLocation = EndLoc; 10970b57cec5SDimitry Andric 10980b57cec5SDimitry Andric return ExitCount; 10990b57cec5SDimitry Andric } 11000b57cec5SDimitry Andric 1101e8d8bef9SDimitry Andric /// Determine whether the given condition can be constant folded. 1102e8d8bef9SDimitry Andric bool ConditionFoldsToBool(const Expr *Cond) { 1103e8d8bef9SDimitry Andric Expr::EvalResult Result; 1104e8d8bef9SDimitry Andric return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())); 1105e8d8bef9SDimitry Andric } 1106e8d8bef9SDimitry Andric 1107e8d8bef9SDimitry Andric /// Create a Branch Region around an instrumentable condition for coverage 1108e8d8bef9SDimitry Andric /// and add it to the function's SourceRegions. A branch region tracks a 1109e8d8bef9SDimitry Andric /// "True" counter and a "False" counter for boolean expressions that 1110e8d8bef9SDimitry Andric /// result in the generation of a branch. 1111*0fca6ea1SDimitry Andric void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt, 1112*0fca6ea1SDimitry Andric const mcdc::ConditionIDs &Conds = {}) { 1113e8d8bef9SDimitry Andric // Check for NULL conditions. 1114e8d8bef9SDimitry Andric if (!C) 1115e8d8bef9SDimitry Andric return; 1116e8d8bef9SDimitry Andric 1117e8d8bef9SDimitry Andric // Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push 1118e8d8bef9SDimitry Andric // region onto RegionStack but immediately pop it (which adds it to the 1119e8d8bef9SDimitry Andric // function's SourceRegions) because it doesn't apply to any other source 1120e8d8bef9SDimitry Andric // code other than the Condition. 1121*0fca6ea1SDimitry Andric // With !SystemHeadersCoverage, binary logical ops in system headers may be 1122*0fca6ea1SDimitry Andric // treated as instrumentable conditions. 1123*0fca6ea1SDimitry Andric if (CodeGenFunction::isInstrumentedCondition(C) || 1124*0fca6ea1SDimitry Andric LeafExprSet.count(CodeGenFunction::stripCond(C))) { 1125*0fca6ea1SDimitry Andric mcdc::Parameters BranchParams; 1126*0fca6ea1SDimitry Andric mcdc::ConditionID ID = MCDCBuilder.getCondID(C); 1127*0fca6ea1SDimitry Andric if (ID >= 0) 1128*0fca6ea1SDimitry Andric BranchParams = mcdc::BranchParameters{ID, Conds}; 11297a6dacacSDimitry Andric 1130e8d8bef9SDimitry Andric // If a condition can fold to true or false, the corresponding branch 1131e8d8bef9SDimitry Andric // will be removed. Create a region with both counters hard-coded to 1132e8d8bef9SDimitry Andric // zero. This allows us to visualize them in a special way. 1133e8d8bef9SDimitry Andric // Alternatively, we can prevent any optimization done via 1134e8d8bef9SDimitry Andric // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in 1135e8d8bef9SDimitry Andric // CodeGenFunction.c always returns false, but that is very heavy-handed. 1136e8d8bef9SDimitry Andric if (ConditionFoldsToBool(C)) 1137e8d8bef9SDimitry Andric popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C), 1138*0fca6ea1SDimitry Andric Counter::getZero(), BranchParams)); 1139e8d8bef9SDimitry Andric else 1140e8d8bef9SDimitry Andric // Otherwise, create a region with the True counter and False counter. 1141*0fca6ea1SDimitry Andric popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, 1142*0fca6ea1SDimitry Andric BranchParams)); 1143e8d8bef9SDimitry Andric } 1144e8d8bef9SDimitry Andric } 1145e8d8bef9SDimitry Andric 11461db9f3b2SDimitry Andric /// Create a Decision Region with a BitmapIdx and number of Conditions. This 11471db9f3b2SDimitry Andric /// type of region "contains" branch regions, one for each of the conditions. 11481db9f3b2SDimitry Andric /// The visualization tool will group everything together. 1149*0fca6ea1SDimitry Andric void createDecisionRegion(const Expr *C, 1150*0fca6ea1SDimitry Andric const mcdc::DecisionParameters &DecisionParams) { 1151*0fca6ea1SDimitry Andric popRegions(pushRegion(DecisionParams, getStart(C), getEnd(C))); 11521db9f3b2SDimitry Andric } 11531db9f3b2SDimitry Andric 1154e8d8bef9SDimitry Andric /// Create a Branch Region around a SwitchCase for code coverage 1155e8d8bef9SDimitry Andric /// and add it to the function's SourceRegions. 1156e8d8bef9SDimitry Andric void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt, 1157e8d8bef9SDimitry Andric Counter FalseCnt) { 1158e8d8bef9SDimitry Andric // Push region onto RegionStack but immediately pop it (which adds it to 1159e8d8bef9SDimitry Andric // the function's SourceRegions) because it doesn't apply to any other 1160e8d8bef9SDimitry Andric // source other than the SwitchCase. 1161e8d8bef9SDimitry Andric popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt)); 1162e8d8bef9SDimitry Andric } 1163e8d8bef9SDimitry Andric 11640b57cec5SDimitry Andric /// Check whether a region with bounds \c StartLoc and \c EndLoc 11650b57cec5SDimitry Andric /// is already added to \c SourceRegions. 1166e8d8bef9SDimitry Andric bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc, 1167e8d8bef9SDimitry Andric bool isBranch = false) { 1168349cc55cSDimitry Andric return llvm::any_of( 1169349cc55cSDimitry Andric llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) { 11700b57cec5SDimitry Andric return Region.getBeginLoc() == StartLoc && 1171349cc55cSDimitry Andric Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch; 11720b57cec5SDimitry Andric }); 11730b57cec5SDimitry Andric } 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric /// Adjust the most recently visited location to \c EndLoc. 11760b57cec5SDimitry Andric /// 11770b57cec5SDimitry Andric /// This should be used after visiting any statements in non-source order. 11780b57cec5SDimitry Andric void adjustForOutOfOrderTraversal(SourceLocation EndLoc) { 11790b57cec5SDimitry Andric MostRecentLocation = EndLoc; 11800b57cec5SDimitry Andric // The code region for a whole macro is created in handleFileExit() when 11810b57cec5SDimitry Andric // it detects exiting of the virtual file of that macro. If we visited 11820b57cec5SDimitry Andric // statements in non-source order, we might already have such a region 11830b57cec5SDimitry Andric // added, for example, if a body of a loop is divided among multiple 11840b57cec5SDimitry Andric // macros. Avoid adding duplicate regions in such case. 11850b57cec5SDimitry Andric if (getRegion().hasEndLoc() && 11860b57cec5SDimitry Andric MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) && 11870b57cec5SDimitry Andric isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation), 1188e8d8bef9SDimitry Andric MostRecentLocation, getRegion().isBranch())) 11890b57cec5SDimitry Andric MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation); 11900b57cec5SDimitry Andric } 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric /// Adjust regions and state when \c NewLoc exits a file. 11930b57cec5SDimitry Andric /// 11940b57cec5SDimitry Andric /// If moving from our most recently tracked location to \c NewLoc exits any 11950b57cec5SDimitry Andric /// files, this adjusts our current region stack and creates the file regions 11960b57cec5SDimitry Andric /// for the exited file. 11970b57cec5SDimitry Andric void handleFileExit(SourceLocation NewLoc) { 11980b57cec5SDimitry Andric if (NewLoc.isInvalid() || 11990b57cec5SDimitry Andric SM.isWrittenInSameFile(MostRecentLocation, NewLoc)) 12000b57cec5SDimitry Andric return; 12010b57cec5SDimitry Andric 12020b57cec5SDimitry Andric // If NewLoc is not in a file that contains MostRecentLocation, walk up to 12030b57cec5SDimitry Andric // find the common ancestor. 12040b57cec5SDimitry Andric SourceLocation LCA = NewLoc; 12050b57cec5SDimitry Andric FileID ParentFile = SM.getFileID(LCA); 12060b57cec5SDimitry Andric while (!isNestedIn(MostRecentLocation, ParentFile)) { 12070b57cec5SDimitry Andric LCA = getIncludeOrExpansionLoc(LCA); 12080b57cec5SDimitry Andric if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) { 12090b57cec5SDimitry Andric // Since there isn't a common ancestor, no file was exited. We just need 12100b57cec5SDimitry Andric // to adjust our location to the new file. 12110b57cec5SDimitry Andric MostRecentLocation = NewLoc; 12120b57cec5SDimitry Andric return; 12130b57cec5SDimitry Andric } 12140b57cec5SDimitry Andric ParentFile = SM.getFileID(LCA); 12150b57cec5SDimitry Andric } 12160b57cec5SDimitry Andric 12170b57cec5SDimitry Andric llvm::SmallSet<SourceLocation, 8> StartLocs; 1218bdd1243dSDimitry Andric std::optional<Counter> ParentCounter; 12190b57cec5SDimitry Andric for (SourceMappingRegion &I : llvm::reverse(RegionStack)) { 12200b57cec5SDimitry Andric if (!I.hasStartLoc()) 12210b57cec5SDimitry Andric continue; 12220b57cec5SDimitry Andric SourceLocation Loc = I.getBeginLoc(); 12230b57cec5SDimitry Andric if (!isNestedIn(Loc, ParentFile)) { 12240b57cec5SDimitry Andric ParentCounter = I.getCounter(); 12250b57cec5SDimitry Andric break; 12260b57cec5SDimitry Andric } 12270b57cec5SDimitry Andric 12280b57cec5SDimitry Andric while (!SM.isInFileID(Loc, ParentFile)) { 12290b57cec5SDimitry Andric // The most nested region for each start location is the one with the 12300b57cec5SDimitry Andric // correct count. We avoid creating redundant regions by stopping once 12310b57cec5SDimitry Andric // we've seen this region. 1232e8d8bef9SDimitry Andric if (StartLocs.insert(Loc).second) { 1233e8d8bef9SDimitry Andric if (I.isBranch()) 1234*0fca6ea1SDimitry Andric SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), 1235*0fca6ea1SDimitry Andric I.getMCDCParams(), Loc, 1236*0fca6ea1SDimitry Andric getEndOfFileOrMacro(Loc), I.isBranch()); 1237e8d8bef9SDimitry Andric else 12380b57cec5SDimitry Andric SourceRegions.emplace_back(I.getCounter(), Loc, 12390b57cec5SDimitry Andric getEndOfFileOrMacro(Loc)); 1240e8d8bef9SDimitry Andric } 12410b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc); 12420b57cec5SDimitry Andric } 12430b57cec5SDimitry Andric I.setStartLoc(getPreciseTokenLocEnd(Loc)); 12440b57cec5SDimitry Andric } 12450b57cec5SDimitry Andric 12460b57cec5SDimitry Andric if (ParentCounter) { 12470b57cec5SDimitry Andric // If the file is contained completely by another region and doesn't 12480b57cec5SDimitry Andric // immediately start its own region, the whole file gets a region 12490b57cec5SDimitry Andric // corresponding to the parent. 12500b57cec5SDimitry Andric SourceLocation Loc = MostRecentLocation; 12510b57cec5SDimitry Andric while (isNestedIn(Loc, ParentFile)) { 12520b57cec5SDimitry Andric SourceLocation FileStart = getStartOfFileOrMacro(Loc); 12530b57cec5SDimitry Andric if (StartLocs.insert(FileStart).second) { 12540b57cec5SDimitry Andric SourceRegions.emplace_back(*ParentCounter, FileStart, 12550b57cec5SDimitry Andric getEndOfFileOrMacro(Loc)); 12560b57cec5SDimitry Andric assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder()); 12570b57cec5SDimitry Andric } 12580b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc); 12590b57cec5SDimitry Andric } 12600b57cec5SDimitry Andric } 12610b57cec5SDimitry Andric 12620b57cec5SDimitry Andric MostRecentLocation = NewLoc; 12630b57cec5SDimitry Andric } 12640b57cec5SDimitry Andric 12650b57cec5SDimitry Andric /// Ensure that \c S is included in the current region. 12660b57cec5SDimitry Andric void extendRegion(const Stmt *S) { 12670b57cec5SDimitry Andric SourceMappingRegion &Region = getRegion(); 12680b57cec5SDimitry Andric SourceLocation StartLoc = getStart(S); 12690b57cec5SDimitry Andric 12700b57cec5SDimitry Andric handleFileExit(StartLoc); 12710b57cec5SDimitry Andric if (!Region.hasStartLoc()) 12720b57cec5SDimitry Andric Region.setStartLoc(StartLoc); 12730b57cec5SDimitry Andric } 12740b57cec5SDimitry Andric 12750b57cec5SDimitry Andric /// Mark \c S as a terminator, starting a zero region. 12760b57cec5SDimitry Andric void terminateRegion(const Stmt *S) { 12770b57cec5SDimitry Andric extendRegion(S); 12780b57cec5SDimitry Andric SourceMappingRegion &Region = getRegion(); 12790b57cec5SDimitry Andric SourceLocation EndLoc = getEnd(S); 12800b57cec5SDimitry Andric if (!Region.hasEndLoc()) 12810b57cec5SDimitry Andric Region.setEndLoc(EndLoc); 12820b57cec5SDimitry Andric pushRegion(Counter::getZero()); 1283fe6060f1SDimitry Andric HasTerminateStmt = true; 12840b57cec5SDimitry Andric } 12850b57cec5SDimitry Andric 12860b57cec5SDimitry Andric /// Find a valid gap range between \p AfterLoc and \p BeforeLoc. 1287bdd1243dSDimitry Andric std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc, 12880b57cec5SDimitry Andric SourceLocation BeforeLoc) { 12895678d1d9SDimitry Andric // Some statements (like AttributedStmt and ImplicitValueInitExpr) don't 12905678d1d9SDimitry Andric // have valid source locations. Do not emit a gap region if this is the case 12915678d1d9SDimitry Andric // in either AfterLoc end or BeforeLoc end. 12925678d1d9SDimitry Andric if (AfterLoc.isInvalid() || BeforeLoc.isInvalid()) 12935678d1d9SDimitry Andric return std::nullopt; 12945678d1d9SDimitry Andric 1295fe6060f1SDimitry Andric // If AfterLoc is in function-like macro, use the right parenthesis 1296fe6060f1SDimitry Andric // location. 1297fe6060f1SDimitry Andric if (AfterLoc.isMacroID()) { 1298fe6060f1SDimitry Andric FileID FID = SM.getFileID(AfterLoc); 1299fe6060f1SDimitry Andric const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion(); 1300fe6060f1SDimitry Andric if (EI->isFunctionMacroExpansion()) 1301fe6060f1SDimitry Andric AfterLoc = EI->getExpansionLocEnd(); 1302fe6060f1SDimitry Andric } 1303fe6060f1SDimitry Andric 1304fe6060f1SDimitry Andric size_t StartDepth = locationDepth(AfterLoc); 1305fe6060f1SDimitry Andric size_t EndDepth = locationDepth(BeforeLoc); 1306fe6060f1SDimitry Andric while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) { 1307fe6060f1SDimitry Andric bool UnnestStart = StartDepth >= EndDepth; 1308fe6060f1SDimitry Andric bool UnnestEnd = EndDepth >= StartDepth; 1309fe6060f1SDimitry Andric if (UnnestEnd) { 1310fe6060f1SDimitry Andric assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc), 1311fe6060f1SDimitry Andric BeforeLoc)); 1312fe6060f1SDimitry Andric 1313fe6060f1SDimitry Andric BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc); 1314fe6060f1SDimitry Andric assert(BeforeLoc.isValid()); 1315fe6060f1SDimitry Andric EndDepth--; 1316fe6060f1SDimitry Andric } 1317fe6060f1SDimitry Andric if (UnnestStart) { 1318fe6060f1SDimitry Andric assert(SM.isWrittenInSameFile(AfterLoc, 1319fe6060f1SDimitry Andric getEndOfFileOrMacro(AfterLoc))); 1320fe6060f1SDimitry Andric 1321fe6060f1SDimitry Andric AfterLoc = getIncludeOrExpansionLoc(AfterLoc); 1322fe6060f1SDimitry Andric assert(AfterLoc.isValid()); 1323fe6060f1SDimitry Andric AfterLoc = getPreciseTokenLocEnd(AfterLoc); 1324fe6060f1SDimitry Andric assert(AfterLoc.isValid()); 1325fe6060f1SDimitry Andric StartDepth--; 1326fe6060f1SDimitry Andric } 1327fe6060f1SDimitry Andric } 1328fe6060f1SDimitry Andric AfterLoc = getPreciseTokenLocEnd(AfterLoc); 13290b57cec5SDimitry Andric // If the start and end locations of the gap are both within the same macro 13300b57cec5SDimitry Andric // file, the range may not be in source order. 13310b57cec5SDimitry Andric if (AfterLoc.isMacroID() || BeforeLoc.isMacroID()) 1332bdd1243dSDimitry Andric return std::nullopt; 1333fe6060f1SDimitry Andric if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) || 1334fe6060f1SDimitry Andric !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder()) 1335bdd1243dSDimitry Andric return std::nullopt; 13360b57cec5SDimitry Andric return {{AfterLoc, BeforeLoc}}; 13370b57cec5SDimitry Andric } 13380b57cec5SDimitry Andric 13390b57cec5SDimitry Andric /// Emit a gap region between \p StartLoc and \p EndLoc with the given count. 13400b57cec5SDimitry Andric void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc, 13410b57cec5SDimitry Andric Counter Count) { 13420b57cec5SDimitry Andric if (StartLoc == EndLoc) 13430b57cec5SDimitry Andric return; 13440b57cec5SDimitry Andric assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder()); 13450b57cec5SDimitry Andric handleFileExit(StartLoc); 13460b57cec5SDimitry Andric size_t Index = pushRegion(Count, StartLoc, EndLoc); 13470b57cec5SDimitry Andric getRegion().setGap(true); 13480b57cec5SDimitry Andric handleFileExit(EndLoc); 13490b57cec5SDimitry Andric popRegions(Index); 13500b57cec5SDimitry Andric } 13510b57cec5SDimitry Andric 13527a6dacacSDimitry Andric /// Find a valid range starting with \p StartingLoc and ending before \p 13537a6dacacSDimitry Andric /// BeforeLoc. 13547a6dacacSDimitry Andric std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc, 13557a6dacacSDimitry Andric SourceLocation BeforeLoc) { 13567a6dacacSDimitry Andric // If StartingLoc is in function-like macro, use its start location. 13577a6dacacSDimitry Andric if (StartingLoc.isMacroID()) { 13587a6dacacSDimitry Andric FileID FID = SM.getFileID(StartingLoc); 13597a6dacacSDimitry Andric const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion(); 13607a6dacacSDimitry Andric if (EI->isFunctionMacroExpansion()) 13617a6dacacSDimitry Andric StartingLoc = EI->getExpansionLocStart(); 13627a6dacacSDimitry Andric } 13637a6dacacSDimitry Andric 13647a6dacacSDimitry Andric size_t StartDepth = locationDepth(StartingLoc); 13657a6dacacSDimitry Andric size_t EndDepth = locationDepth(BeforeLoc); 13667a6dacacSDimitry Andric while (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) { 13677a6dacacSDimitry Andric bool UnnestStart = StartDepth >= EndDepth; 13687a6dacacSDimitry Andric bool UnnestEnd = EndDepth >= StartDepth; 13697a6dacacSDimitry Andric if (UnnestEnd) { 13707a6dacacSDimitry Andric assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc), 13717a6dacacSDimitry Andric BeforeLoc)); 13727a6dacacSDimitry Andric 13737a6dacacSDimitry Andric BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc); 13747a6dacacSDimitry Andric assert(BeforeLoc.isValid()); 13757a6dacacSDimitry Andric EndDepth--; 13767a6dacacSDimitry Andric } 13777a6dacacSDimitry Andric if (UnnestStart) { 13787a6dacacSDimitry Andric assert(SM.isWrittenInSameFile(StartingLoc, 13797a6dacacSDimitry Andric getStartOfFileOrMacro(StartingLoc))); 13807a6dacacSDimitry Andric 13817a6dacacSDimitry Andric StartingLoc = getIncludeOrExpansionLoc(StartingLoc); 13827a6dacacSDimitry Andric assert(StartingLoc.isValid()); 13837a6dacacSDimitry Andric StartDepth--; 13847a6dacacSDimitry Andric } 13857a6dacacSDimitry Andric } 13867a6dacacSDimitry Andric // If the start and end locations of the gap are both within the same macro 13877a6dacacSDimitry Andric // file, the range may not be in source order. 13887a6dacacSDimitry Andric if (StartingLoc.isMacroID() || BeforeLoc.isMacroID()) 13897a6dacacSDimitry Andric return std::nullopt; 13907a6dacacSDimitry Andric if (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc) || 13917a6dacacSDimitry Andric !SpellingRegion(SM, StartingLoc, BeforeLoc).isInSourceOrder()) 13927a6dacacSDimitry Andric return std::nullopt; 13937a6dacacSDimitry Andric return {{StartingLoc, BeforeLoc}}; 13947a6dacacSDimitry Andric } 13957a6dacacSDimitry Andric 13967a6dacacSDimitry Andric void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) { 13977a6dacacSDimitry Andric const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc); 13987a6dacacSDimitry Andric 13997a6dacacSDimitry Andric if (!Skipped) 14007a6dacacSDimitry Andric return; 14017a6dacacSDimitry Andric 14027a6dacacSDimitry Andric const auto NewStartLoc = Skipped->getBegin(); 14037a6dacacSDimitry Andric const auto EndLoc = Skipped->getEnd(); 14047a6dacacSDimitry Andric 14057a6dacacSDimitry Andric if (NewStartLoc == EndLoc) 14067a6dacacSDimitry Andric return; 14077a6dacacSDimitry Andric assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder()); 14087a6dacacSDimitry Andric handleFileExit(NewStartLoc); 1409*0fca6ea1SDimitry Andric size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc); 14107a6dacacSDimitry Andric getRegion().setSkipped(true); 14117a6dacacSDimitry Andric handleFileExit(EndLoc); 14127a6dacacSDimitry Andric popRegions(Index); 14137a6dacacSDimitry Andric } 14147a6dacacSDimitry Andric 14150b57cec5SDimitry Andric /// Keep counts of breaks and continues inside loops. 14160b57cec5SDimitry Andric struct BreakContinue { 14170b57cec5SDimitry Andric Counter BreakCount; 14180b57cec5SDimitry Andric Counter ContinueCount; 14190b57cec5SDimitry Andric }; 14200b57cec5SDimitry Andric SmallVector<BreakContinue, 8> BreakContinueStack; 14210b57cec5SDimitry Andric 14220b57cec5SDimitry Andric CounterCoverageMappingBuilder( 14230b57cec5SDimitry Andric CoverageMappingModuleGen &CVM, 14241db9f3b2SDimitry Andric llvm::DenseMap<const Stmt *, unsigned> &CounterMap, 1425*0fca6ea1SDimitry Andric MCDC::State &MCDCState, SourceManager &SM, const LangOptions &LangOpts) 14261db9f3b2SDimitry Andric : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap), 1427*0fca6ea1SDimitry Andric MCDCState(MCDCState), MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {} 14280b57cec5SDimitry Andric 14290b57cec5SDimitry Andric /// Write the mapping data to the output stream 14300b57cec5SDimitry Andric void write(llvm::raw_ostream &OS) { 14310b57cec5SDimitry Andric llvm::SmallVector<unsigned, 8> VirtualFileMapping; 14320b57cec5SDimitry Andric gatherFileIDs(VirtualFileMapping); 14330b57cec5SDimitry Andric SourceRegionFilter Filter = emitExpansionRegions(); 14340b57cec5SDimitry Andric emitSourceRegions(Filter); 14350b57cec5SDimitry Andric gatherSkippedRegions(); 14360b57cec5SDimitry Andric 14370b57cec5SDimitry Andric if (MappingRegions.empty()) 14380b57cec5SDimitry Andric return; 14390b57cec5SDimitry Andric 14400b57cec5SDimitry Andric CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(), 14410b57cec5SDimitry Andric MappingRegions); 14420b57cec5SDimitry Andric Writer.write(OS); 14430b57cec5SDimitry Andric } 14440b57cec5SDimitry Andric 14450b57cec5SDimitry Andric void VisitStmt(const Stmt *S) { 14460b57cec5SDimitry Andric if (S->getBeginLoc().isValid()) 14470b57cec5SDimitry Andric extendRegion(S); 1448fe6060f1SDimitry Andric const Stmt *LastStmt = nullptr; 1449fe6060f1SDimitry Andric bool SaveTerminateStmt = HasTerminateStmt; 1450fe6060f1SDimitry Andric HasTerminateStmt = false; 1451fe6060f1SDimitry Andric GapRegionCounter = Counter::getZero(); 14520b57cec5SDimitry Andric for (const Stmt *Child : S->children()) 1453fe6060f1SDimitry Andric if (Child) { 1454fe6060f1SDimitry Andric // If last statement contains terminate statements, add a gap area 14555678d1d9SDimitry Andric // between the two statements. 14565678d1d9SDimitry Andric if (LastStmt && HasTerminateStmt) { 1457fe6060f1SDimitry Andric auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child)); 1458fe6060f1SDimitry Andric if (Gap) 1459fe6060f1SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), 1460fe6060f1SDimitry Andric GapRegionCounter); 1461fe6060f1SDimitry Andric SaveTerminateStmt = true; 1462fe6060f1SDimitry Andric HasTerminateStmt = false; 1463fe6060f1SDimitry Andric } 14640b57cec5SDimitry Andric this->Visit(Child); 1465fe6060f1SDimitry Andric LastStmt = Child; 1466fe6060f1SDimitry Andric } 1467fe6060f1SDimitry Andric if (SaveTerminateStmt) 1468fe6060f1SDimitry Andric HasTerminateStmt = true; 14690b57cec5SDimitry Andric handleFileExit(getEnd(S)); 14700b57cec5SDimitry Andric } 14710b57cec5SDimitry Andric 14720b57cec5SDimitry Andric void VisitDecl(const Decl *D) { 14730b57cec5SDimitry Andric Stmt *Body = D->getBody(); 14740b57cec5SDimitry Andric 147506c3fb27SDimitry Andric // Do not propagate region counts into system headers unless collecting 147606c3fb27SDimitry Andric // coverage from system headers is explicitly enabled. 147706c3fb27SDimitry Andric if (!SystemHeadersCoverage && Body && 147806c3fb27SDimitry Andric SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body)))) 14790b57cec5SDimitry Andric return; 14800b57cec5SDimitry Andric 14810b57cec5SDimitry Andric // Do not visit the artificial children nodes of defaulted methods. The 14820b57cec5SDimitry Andric // lexer may not be able to report back precise token end locations for 14830b57cec5SDimitry Andric // these children nodes (llvm.org/PR39822), and moreover users will not be 14840b57cec5SDimitry Andric // able to see coverage for them. 14855f757f3fSDimitry Andric Counter BodyCounter = getRegionCounter(Body); 14860b57cec5SDimitry Andric bool Defaulted = false; 14870b57cec5SDimitry Andric if (auto *Method = dyn_cast<CXXMethodDecl>(D)) 14880b57cec5SDimitry Andric Defaulted = Method->isDefaulted(); 14895f757f3fSDimitry Andric if (auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) { 14905f757f3fSDimitry Andric for (auto *Initializer : Ctor->inits()) { 14915f757f3fSDimitry Andric if (Initializer->isWritten()) { 14925f757f3fSDimitry Andric auto *Init = Initializer->getInit(); 14935f757f3fSDimitry Andric if (getStart(Init).isValid() && getEnd(Init).isValid()) 14945f757f3fSDimitry Andric propagateCounts(BodyCounter, Init); 14955f757f3fSDimitry Andric } 14965f757f3fSDimitry Andric } 14975f757f3fSDimitry Andric } 14980b57cec5SDimitry Andric 14995f757f3fSDimitry Andric propagateCounts(BodyCounter, Body, 15000b57cec5SDimitry Andric /*VisitChildren=*/!Defaulted); 15010b57cec5SDimitry Andric assert(RegionStack.empty() && "Regions entered but never exited"); 15020b57cec5SDimitry Andric } 15030b57cec5SDimitry Andric 15040b57cec5SDimitry Andric void VisitReturnStmt(const ReturnStmt *S) { 15050b57cec5SDimitry Andric extendRegion(S); 15060b57cec5SDimitry Andric if (S->getRetValue()) 15070b57cec5SDimitry Andric Visit(S->getRetValue()); 15080b57cec5SDimitry Andric terminateRegion(S); 15090b57cec5SDimitry Andric } 15100b57cec5SDimitry Andric 15115ffd83dbSDimitry Andric void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) { 15125ffd83dbSDimitry Andric extendRegion(S); 15135ffd83dbSDimitry Andric Visit(S->getBody()); 15145ffd83dbSDimitry Andric } 15155ffd83dbSDimitry Andric 15165ffd83dbSDimitry Andric void VisitCoreturnStmt(const CoreturnStmt *S) { 15175ffd83dbSDimitry Andric extendRegion(S); 15185ffd83dbSDimitry Andric if (S->getOperand()) 15195ffd83dbSDimitry Andric Visit(S->getOperand()); 15205ffd83dbSDimitry Andric terminateRegion(S); 15215ffd83dbSDimitry Andric } 15225ffd83dbSDimitry Andric 1523*0fca6ea1SDimitry Andric void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *E) { 1524*0fca6ea1SDimitry Andric Visit(E->getOperand()); 1525*0fca6ea1SDimitry Andric } 1526*0fca6ea1SDimitry Andric 15270b57cec5SDimitry Andric void VisitCXXThrowExpr(const CXXThrowExpr *E) { 15280b57cec5SDimitry Andric extendRegion(E); 15290b57cec5SDimitry Andric if (E->getSubExpr()) 15300b57cec5SDimitry Andric Visit(E->getSubExpr()); 15310b57cec5SDimitry Andric terminateRegion(E); 15320b57cec5SDimitry Andric } 15330b57cec5SDimitry Andric 15340b57cec5SDimitry Andric void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); } 15350b57cec5SDimitry Andric 15360b57cec5SDimitry Andric void VisitLabelStmt(const LabelStmt *S) { 15370b57cec5SDimitry Andric Counter LabelCount = getRegionCounter(S); 15380b57cec5SDimitry Andric SourceLocation Start = getStart(S); 15390b57cec5SDimitry Andric // We can't extendRegion here or we risk overlapping with our new region. 15400b57cec5SDimitry Andric handleFileExit(Start); 15410b57cec5SDimitry Andric pushRegion(LabelCount, Start); 15420b57cec5SDimitry Andric Visit(S->getSubStmt()); 15430b57cec5SDimitry Andric } 15440b57cec5SDimitry Andric 15450b57cec5SDimitry Andric void VisitBreakStmt(const BreakStmt *S) { 15460b57cec5SDimitry Andric assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); 1547*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 15480b57cec5SDimitry Andric BreakContinueStack.back().BreakCount = addCounters( 15490b57cec5SDimitry Andric BreakContinueStack.back().BreakCount, getRegion().getCounter()); 15500b57cec5SDimitry Andric // FIXME: a break in a switch should terminate regions for all preceding 15510b57cec5SDimitry Andric // case statements, not just the most recent one. 15520b57cec5SDimitry Andric terminateRegion(S); 15530b57cec5SDimitry Andric } 15540b57cec5SDimitry Andric 15550b57cec5SDimitry Andric void VisitContinueStmt(const ContinueStmt *S) { 15560b57cec5SDimitry Andric assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); 1557*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 15580b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount = addCounters( 15590b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount, getRegion().getCounter()); 15600b57cec5SDimitry Andric terminateRegion(S); 15610b57cec5SDimitry Andric } 15620b57cec5SDimitry Andric 15630b57cec5SDimitry Andric void VisitCallExpr(const CallExpr *E) { 15640b57cec5SDimitry Andric VisitStmt(E); 15650b57cec5SDimitry Andric 15660b57cec5SDimitry Andric // Terminate the region when we hit a noreturn function. 15670b57cec5SDimitry Andric // (This is helpful dealing with switch statements.) 15680b57cec5SDimitry Andric QualType CalleeType = E->getCallee()->getType(); 15690b57cec5SDimitry Andric if (getFunctionExtInfo(*CalleeType).getNoReturn()) 15700b57cec5SDimitry Andric terminateRegion(E); 15710b57cec5SDimitry Andric } 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric void VisitWhileStmt(const WhileStmt *S) { 15740b57cec5SDimitry Andric extendRegion(S); 15750b57cec5SDimitry Andric 15760b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 1577*0fca6ea1SDimitry Andric Counter BodyCount = llvm::EnableSingleByteCoverage 1578*0fca6ea1SDimitry Andric ? getRegionCounter(S->getBody()) 1579*0fca6ea1SDimitry Andric : getRegionCounter(S); 15800b57cec5SDimitry Andric 15810b57cec5SDimitry Andric // Handle the body first so that we can get the backedge count. 15820b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue()); 15830b57cec5SDimitry Andric extendRegion(S->getBody()); 15840b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 15850b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val(); 15860b57cec5SDimitry Andric 1587fe6060f1SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt; 1588fe6060f1SDimitry Andric HasTerminateStmt = false; 1589fe6060f1SDimitry Andric 15900b57cec5SDimitry Andric // Go back to handle the condition. 15910b57cec5SDimitry Andric Counter CondCount = 1592*0fca6ea1SDimitry Andric llvm::EnableSingleByteCoverage 1593*0fca6ea1SDimitry Andric ? getRegionCounter(S->getCond()) 1594*0fca6ea1SDimitry Andric : addCounters(ParentCount, BackedgeCount, BC.ContinueCount); 15950b57cec5SDimitry Andric propagateCounts(CondCount, S->getCond()); 15960b57cec5SDimitry Andric adjustForOutOfOrderTraversal(getEnd(S)); 15970b57cec5SDimitry Andric 15980b57cec5SDimitry Andric // The body count applies to the area immediately after the increment. 1599fe6060f1SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 16000b57cec5SDimitry Andric if (Gap) 16010b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 16020b57cec5SDimitry Andric 16030b57cec5SDimitry Andric Counter OutCount = 1604*0fca6ea1SDimitry Andric llvm::EnableSingleByteCoverage 1605*0fca6ea1SDimitry Andric ? getRegionCounter(S) 1606*0fca6ea1SDimitry Andric : addCounters(BC.BreakCount, 1607*0fca6ea1SDimitry Andric subtractCounters(CondCount, BodyCount)); 1608*0fca6ea1SDimitry Andric 1609fe6060f1SDimitry Andric if (OutCount != ParentCount) { 16100b57cec5SDimitry Andric pushRegion(OutCount); 1611fe6060f1SDimitry Andric GapRegionCounter = OutCount; 1612fe6060f1SDimitry Andric if (BodyHasTerminateStmt) 1613fe6060f1SDimitry Andric HasTerminateStmt = true; 1614fe6060f1SDimitry Andric } 1615e8d8bef9SDimitry Andric 1616e8d8bef9SDimitry Andric // Create Branch Region around condition. 1617*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 1618e8d8bef9SDimitry Andric createBranchRegion(S->getCond(), BodyCount, 1619e8d8bef9SDimitry Andric subtractCounters(CondCount, BodyCount)); 16200b57cec5SDimitry Andric } 16210b57cec5SDimitry Andric 16220b57cec5SDimitry Andric void VisitDoStmt(const DoStmt *S) { 16230b57cec5SDimitry Andric extendRegion(S); 16240b57cec5SDimitry Andric 16250b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 1626*0fca6ea1SDimitry Andric Counter BodyCount = llvm::EnableSingleByteCoverage 1627*0fca6ea1SDimitry Andric ? getRegionCounter(S->getBody()) 1628*0fca6ea1SDimitry Andric : getRegionCounter(S); 16290b57cec5SDimitry Andric 16300b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue()); 16310b57cec5SDimitry Andric extendRegion(S->getBody()); 1632*0fca6ea1SDimitry Andric 1633*0fca6ea1SDimitry Andric Counter BackedgeCount; 1634*0fca6ea1SDimitry Andric if (llvm::EnableSingleByteCoverage) 1635*0fca6ea1SDimitry Andric propagateCounts(BodyCount, S->getBody()); 1636*0fca6ea1SDimitry Andric else 1637*0fca6ea1SDimitry Andric BackedgeCount = 16380b57cec5SDimitry Andric propagateCounts(addCounters(ParentCount, BodyCount), S->getBody()); 1639*0fca6ea1SDimitry Andric 16400b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val(); 16410b57cec5SDimitry Andric 1642fe6060f1SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt; 1643fe6060f1SDimitry Andric HasTerminateStmt = false; 1644fe6060f1SDimitry Andric 1645*0fca6ea1SDimitry Andric Counter CondCount = llvm::EnableSingleByteCoverage 1646*0fca6ea1SDimitry Andric ? getRegionCounter(S->getCond()) 1647*0fca6ea1SDimitry Andric : addCounters(BackedgeCount, BC.ContinueCount); 16480b57cec5SDimitry Andric propagateCounts(CondCount, S->getCond()); 16490b57cec5SDimitry Andric 16500b57cec5SDimitry Andric Counter OutCount = 1651*0fca6ea1SDimitry Andric llvm::EnableSingleByteCoverage 1652*0fca6ea1SDimitry Andric ? getRegionCounter(S) 1653*0fca6ea1SDimitry Andric : addCounters(BC.BreakCount, 1654*0fca6ea1SDimitry Andric subtractCounters(CondCount, BodyCount)); 1655fe6060f1SDimitry Andric if (OutCount != ParentCount) { 16560b57cec5SDimitry Andric pushRegion(OutCount); 1657fe6060f1SDimitry Andric GapRegionCounter = OutCount; 1658fe6060f1SDimitry Andric } 1659e8d8bef9SDimitry Andric 1660e8d8bef9SDimitry Andric // Create Branch Region around condition. 1661*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 1662e8d8bef9SDimitry Andric createBranchRegion(S->getCond(), BodyCount, 1663e8d8bef9SDimitry Andric subtractCounters(CondCount, BodyCount)); 1664fe6060f1SDimitry Andric 1665fe6060f1SDimitry Andric if (BodyHasTerminateStmt) 1666fe6060f1SDimitry Andric HasTerminateStmt = true; 16670b57cec5SDimitry Andric } 16680b57cec5SDimitry Andric 16690b57cec5SDimitry Andric void VisitForStmt(const ForStmt *S) { 16700b57cec5SDimitry Andric extendRegion(S); 16710b57cec5SDimitry Andric if (S->getInit()) 16720b57cec5SDimitry Andric Visit(S->getInit()); 16730b57cec5SDimitry Andric 16740b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 1675*0fca6ea1SDimitry Andric Counter BodyCount = llvm::EnableSingleByteCoverage 1676*0fca6ea1SDimitry Andric ? getRegionCounter(S->getBody()) 1677*0fca6ea1SDimitry Andric : getRegionCounter(S); 16780b57cec5SDimitry Andric 16790b57cec5SDimitry Andric // The loop increment may contain a break or continue. 16800b57cec5SDimitry Andric if (S->getInc()) 16810b57cec5SDimitry Andric BreakContinueStack.emplace_back(); 16820b57cec5SDimitry Andric 16830b57cec5SDimitry Andric // Handle the body first so that we can get the backedge count. 16840b57cec5SDimitry Andric BreakContinueStack.emplace_back(); 16850b57cec5SDimitry Andric extendRegion(S->getBody()); 16860b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 16870b57cec5SDimitry Andric BreakContinue BodyBC = BreakContinueStack.pop_back_val(); 16880b57cec5SDimitry Andric 1689fe6060f1SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt; 1690fe6060f1SDimitry Andric HasTerminateStmt = false; 1691fe6060f1SDimitry Andric 16920b57cec5SDimitry Andric // The increment is essentially part of the body but it needs to include 16930b57cec5SDimitry Andric // the count for all the continue statements. 16940b57cec5SDimitry Andric BreakContinue IncrementBC; 16950b57cec5SDimitry Andric if (const Stmt *Inc = S->getInc()) { 1696*0fca6ea1SDimitry Andric Counter IncCount; 1697*0fca6ea1SDimitry Andric if (llvm::EnableSingleByteCoverage) 1698*0fca6ea1SDimitry Andric IncCount = getRegionCounter(S->getInc()); 1699*0fca6ea1SDimitry Andric else 1700*0fca6ea1SDimitry Andric IncCount = addCounters(BackedgeCount, BodyBC.ContinueCount); 1701*0fca6ea1SDimitry Andric propagateCounts(IncCount, Inc); 17020b57cec5SDimitry Andric IncrementBC = BreakContinueStack.pop_back_val(); 17030b57cec5SDimitry Andric } 17040b57cec5SDimitry Andric 17050b57cec5SDimitry Andric // Go back to handle the condition. 1706*0fca6ea1SDimitry Andric Counter CondCount = 1707*0fca6ea1SDimitry Andric llvm::EnableSingleByteCoverage 1708*0fca6ea1SDimitry Andric ? getRegionCounter(S->getCond()) 1709*0fca6ea1SDimitry Andric : addCounters( 17100b57cec5SDimitry Andric addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount), 17110b57cec5SDimitry Andric IncrementBC.ContinueCount); 1712*0fca6ea1SDimitry Andric 17130b57cec5SDimitry Andric if (const Expr *Cond = S->getCond()) { 17140b57cec5SDimitry Andric propagateCounts(CondCount, Cond); 17150b57cec5SDimitry Andric adjustForOutOfOrderTraversal(getEnd(S)); 17160b57cec5SDimitry Andric } 17170b57cec5SDimitry Andric 17180b57cec5SDimitry Andric // The body count applies to the area immediately after the increment. 1719fe6060f1SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 17200b57cec5SDimitry Andric if (Gap) 17210b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 17220b57cec5SDimitry Andric 1723*0fca6ea1SDimitry Andric Counter OutCount = 1724*0fca6ea1SDimitry Andric llvm::EnableSingleByteCoverage 1725*0fca6ea1SDimitry Andric ? getRegionCounter(S) 1726*0fca6ea1SDimitry Andric : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, 17270b57cec5SDimitry Andric subtractCounters(CondCount, BodyCount)); 1728fe6060f1SDimitry Andric if (OutCount != ParentCount) { 17290b57cec5SDimitry Andric pushRegion(OutCount); 1730fe6060f1SDimitry Andric GapRegionCounter = OutCount; 1731fe6060f1SDimitry Andric if (BodyHasTerminateStmt) 1732fe6060f1SDimitry Andric HasTerminateStmt = true; 1733fe6060f1SDimitry Andric } 1734e8d8bef9SDimitry Andric 1735e8d8bef9SDimitry Andric // Create Branch Region around condition. 1736*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 1737e8d8bef9SDimitry Andric createBranchRegion(S->getCond(), BodyCount, 1738e8d8bef9SDimitry Andric subtractCounters(CondCount, BodyCount)); 17390b57cec5SDimitry Andric } 17400b57cec5SDimitry Andric 17410b57cec5SDimitry Andric void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { 17420b57cec5SDimitry Andric extendRegion(S); 17430b57cec5SDimitry Andric if (S->getInit()) 17440b57cec5SDimitry Andric Visit(S->getInit()); 17450b57cec5SDimitry Andric Visit(S->getLoopVarStmt()); 17460b57cec5SDimitry Andric Visit(S->getRangeStmt()); 17470b57cec5SDimitry Andric 17480b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 1749*0fca6ea1SDimitry Andric Counter BodyCount = llvm::EnableSingleByteCoverage 1750*0fca6ea1SDimitry Andric ? getRegionCounter(S->getBody()) 1751*0fca6ea1SDimitry Andric : getRegionCounter(S); 17520b57cec5SDimitry Andric 17530b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue()); 17540b57cec5SDimitry Andric extendRegion(S->getBody()); 17550b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 17560b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val(); 17570b57cec5SDimitry Andric 1758fe6060f1SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt; 1759fe6060f1SDimitry Andric HasTerminateStmt = false; 1760fe6060f1SDimitry Andric 17610b57cec5SDimitry Andric // The body count applies to the area immediately after the range. 1762fe6060f1SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 17630b57cec5SDimitry Andric if (Gap) 17640b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 17650b57cec5SDimitry Andric 1766*0fca6ea1SDimitry Andric Counter OutCount; 1767*0fca6ea1SDimitry Andric Counter LoopCount; 1768*0fca6ea1SDimitry Andric if (llvm::EnableSingleByteCoverage) 1769*0fca6ea1SDimitry Andric OutCount = getRegionCounter(S); 1770*0fca6ea1SDimitry Andric else { 1771*0fca6ea1SDimitry Andric LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount); 1772*0fca6ea1SDimitry Andric OutCount = 17730b57cec5SDimitry Andric addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); 1774*0fca6ea1SDimitry Andric } 1775fe6060f1SDimitry Andric if (OutCount != ParentCount) { 17760b57cec5SDimitry Andric pushRegion(OutCount); 1777fe6060f1SDimitry Andric GapRegionCounter = OutCount; 1778fe6060f1SDimitry Andric if (BodyHasTerminateStmt) 1779fe6060f1SDimitry Andric HasTerminateStmt = true; 1780fe6060f1SDimitry Andric } 1781e8d8bef9SDimitry Andric 1782e8d8bef9SDimitry Andric // Create Branch Region around condition. 1783*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 1784e8d8bef9SDimitry Andric createBranchRegion(S->getCond(), BodyCount, 1785e8d8bef9SDimitry Andric subtractCounters(LoopCount, BodyCount)); 17860b57cec5SDimitry Andric } 17870b57cec5SDimitry Andric 17880b57cec5SDimitry Andric void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { 17890b57cec5SDimitry Andric extendRegion(S); 17900b57cec5SDimitry Andric Visit(S->getElement()); 17910b57cec5SDimitry Andric 17920b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 17930b57cec5SDimitry Andric Counter BodyCount = getRegionCounter(S); 17940b57cec5SDimitry Andric 17950b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue()); 17960b57cec5SDimitry Andric extendRegion(S->getBody()); 17970b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); 17980b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val(); 17990b57cec5SDimitry Andric 18000b57cec5SDimitry Andric // The body count applies to the area immediately after the collection. 1801fe6060f1SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); 18020b57cec5SDimitry Andric if (Gap) 18030b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); 18040b57cec5SDimitry Andric 18050b57cec5SDimitry Andric Counter LoopCount = 18060b57cec5SDimitry Andric addCounters(ParentCount, BackedgeCount, BC.ContinueCount); 18070b57cec5SDimitry Andric Counter OutCount = 18080b57cec5SDimitry Andric addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); 1809fe6060f1SDimitry Andric if (OutCount != ParentCount) { 18100b57cec5SDimitry Andric pushRegion(OutCount); 1811fe6060f1SDimitry Andric GapRegionCounter = OutCount; 1812fe6060f1SDimitry Andric } 18130b57cec5SDimitry Andric } 18140b57cec5SDimitry Andric 18150b57cec5SDimitry Andric void VisitSwitchStmt(const SwitchStmt *S) { 18160b57cec5SDimitry Andric extendRegion(S); 18170b57cec5SDimitry Andric if (S->getInit()) 18180b57cec5SDimitry Andric Visit(S->getInit()); 18190b57cec5SDimitry Andric Visit(S->getCond()); 18200b57cec5SDimitry Andric 18210b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue()); 18220b57cec5SDimitry Andric 18230b57cec5SDimitry Andric const Stmt *Body = S->getBody(); 18240b57cec5SDimitry Andric extendRegion(Body); 18250b57cec5SDimitry Andric if (const auto *CS = dyn_cast<CompoundStmt>(Body)) { 18260b57cec5SDimitry Andric if (!CS->body_empty()) { 18270b57cec5SDimitry Andric // Make a region for the body of the switch. If the body starts with 18280b57cec5SDimitry Andric // a case, that case will reuse this region; otherwise, this covers 18290b57cec5SDimitry Andric // the unreachable code at the beginning of the switch body. 1830480093f4SDimitry Andric size_t Index = pushRegion(Counter::getZero(), getStart(CS)); 1831480093f4SDimitry Andric getRegion().setGap(true); 1832fe6060f1SDimitry Andric Visit(Body); 18330b57cec5SDimitry Andric 18340b57cec5SDimitry Andric // Set the end for the body of the switch, if it isn't already set. 18350b57cec5SDimitry Andric for (size_t i = RegionStack.size(); i != Index; --i) { 18360b57cec5SDimitry Andric if (!RegionStack[i - 1].hasEndLoc()) 18370b57cec5SDimitry Andric RegionStack[i - 1].setEndLoc(getEnd(CS->body_back())); 18380b57cec5SDimitry Andric } 18390b57cec5SDimitry Andric 18400b57cec5SDimitry Andric popRegions(Index); 18410b57cec5SDimitry Andric } 18420b57cec5SDimitry Andric } else 18430b57cec5SDimitry Andric propagateCounts(Counter::getZero(), Body); 18440b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val(); 18450b57cec5SDimitry Andric 1846*0fca6ea1SDimitry Andric if (!BreakContinueStack.empty() && !llvm::EnableSingleByteCoverage) 18470b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount = addCounters( 18480b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount, BC.ContinueCount); 18490b57cec5SDimitry Andric 1850e8d8bef9SDimitry Andric Counter ParentCount = getRegion().getCounter(); 18510b57cec5SDimitry Andric Counter ExitCount = getRegionCounter(S); 18520b57cec5SDimitry Andric SourceLocation ExitLoc = getEnd(S); 18530b57cec5SDimitry Andric pushRegion(ExitCount); 1854fe6060f1SDimitry Andric GapRegionCounter = ExitCount; 18550b57cec5SDimitry Andric 18560b57cec5SDimitry Andric // Ensure that handleFileExit recognizes when the end location is located 18570b57cec5SDimitry Andric // in a different file. 18580b57cec5SDimitry Andric MostRecentLocation = getStart(S); 18590b57cec5SDimitry Andric handleFileExit(ExitLoc); 1860e8d8bef9SDimitry Andric 1861*0fca6ea1SDimitry Andric // When single byte coverage mode is enabled, do not create branch region by 1862*0fca6ea1SDimitry Andric // early returning. 1863*0fca6ea1SDimitry Andric if (llvm::EnableSingleByteCoverage) 1864*0fca6ea1SDimitry Andric return; 1865*0fca6ea1SDimitry Andric 1866e8d8bef9SDimitry Andric // Create a Branch Region around each Case. Subtract the case's 1867e8d8bef9SDimitry Andric // counter from the Parent counter to track the "False" branch count. 1868e8d8bef9SDimitry Andric Counter CaseCountSum; 1869e8d8bef9SDimitry Andric bool HasDefaultCase = false; 1870e8d8bef9SDimitry Andric const SwitchCase *Case = S->getSwitchCaseList(); 1871e8d8bef9SDimitry Andric for (; Case; Case = Case->getNextSwitchCase()) { 1872e8d8bef9SDimitry Andric HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case); 187381ad6265SDimitry Andric CaseCountSum = 187481ad6265SDimitry Andric addCounters(CaseCountSum, getRegionCounter(Case), /*Simplify=*/false); 1875e8d8bef9SDimitry Andric createSwitchCaseRegion( 1876e8d8bef9SDimitry Andric Case, getRegionCounter(Case), 1877e8d8bef9SDimitry Andric subtractCounters(ParentCount, getRegionCounter(Case))); 1878e8d8bef9SDimitry Andric } 187981ad6265SDimitry Andric // Simplify is skipped while building the counters above: it can get really 188081ad6265SDimitry Andric // slow on top of switches with thousands of cases. Instead, trigger 188181ad6265SDimitry Andric // simplification by adding zero to the last counter. 188281ad6265SDimitry Andric CaseCountSum = addCounters(CaseCountSum, Counter::getZero()); 1883e8d8bef9SDimitry Andric 1884e8d8bef9SDimitry Andric // If no explicit default case exists, create a branch region to represent 1885e8d8bef9SDimitry Andric // the hidden branch, which will be added later by the CodeGen. This region 1886e8d8bef9SDimitry Andric // will be associated with the switch statement's condition. 1887e8d8bef9SDimitry Andric if (!HasDefaultCase) { 1888e8d8bef9SDimitry Andric Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum); 1889e8d8bef9SDimitry Andric Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue); 1890e8d8bef9SDimitry Andric createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse); 1891e8d8bef9SDimitry Andric } 18920b57cec5SDimitry Andric } 18930b57cec5SDimitry Andric 18940b57cec5SDimitry Andric void VisitSwitchCase(const SwitchCase *S) { 18950b57cec5SDimitry Andric extendRegion(S); 18960b57cec5SDimitry Andric 18970b57cec5SDimitry Andric SourceMappingRegion &Parent = getRegion(); 1898*0fca6ea1SDimitry Andric Counter Count = llvm::EnableSingleByteCoverage 1899*0fca6ea1SDimitry Andric ? getRegionCounter(S) 1900*0fca6ea1SDimitry Andric : addCounters(Parent.getCounter(), getRegionCounter(S)); 19010b57cec5SDimitry Andric 19020b57cec5SDimitry Andric // Reuse the existing region if it starts at our label. This is typical of 19030b57cec5SDimitry Andric // the first case in a switch. 19040b57cec5SDimitry Andric if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S)) 19050b57cec5SDimitry Andric Parent.setCounter(Count); 19060b57cec5SDimitry Andric else 19070b57cec5SDimitry Andric pushRegion(Count, getStart(S)); 19080b57cec5SDimitry Andric 1909fe6060f1SDimitry Andric GapRegionCounter = Count; 1910fe6060f1SDimitry Andric 19110b57cec5SDimitry Andric if (const auto *CS = dyn_cast<CaseStmt>(S)) { 19120b57cec5SDimitry Andric Visit(CS->getLHS()); 19130b57cec5SDimitry Andric if (const Expr *RHS = CS->getRHS()) 19140b57cec5SDimitry Andric Visit(RHS); 19150b57cec5SDimitry Andric } 19160b57cec5SDimitry Andric Visit(S->getSubStmt()); 19170b57cec5SDimitry Andric } 19180b57cec5SDimitry Andric 19197a6dacacSDimitry Andric void coverIfConsteval(const IfStmt *S) { 19207a6dacacSDimitry Andric assert(S->isConsteval()); 19217a6dacacSDimitry Andric 19227a6dacacSDimitry Andric const auto *Then = S->getThen(); 19237a6dacacSDimitry Andric const auto *Else = S->getElse(); 19247a6dacacSDimitry Andric 19257a6dacacSDimitry Andric // It's better for llvm-cov to create a new region with same counter 19267a6dacacSDimitry Andric // so line-coverage can be properly calculated for lines containing 19277a6dacacSDimitry Andric // a skipped region (without it the line is marked uncovered) 19287a6dacacSDimitry Andric const Counter ParentCount = getRegion().getCounter(); 19297a6dacacSDimitry Andric 19307a6dacacSDimitry Andric extendRegion(S); 19317a6dacacSDimitry Andric 19327a6dacacSDimitry Andric if (S->isNegatedConsteval()) { 19337a6dacacSDimitry Andric // ignore 'if consteval' 19347a6dacacSDimitry Andric markSkipped(S->getIfLoc(), getStart(Then)); 19357a6dacacSDimitry Andric propagateCounts(ParentCount, Then); 19367a6dacacSDimitry Andric 19377a6dacacSDimitry Andric if (Else) { 19387a6dacacSDimitry Andric // ignore 'else <else>' 19397a6dacacSDimitry Andric markSkipped(getEnd(Then), getEnd(Else)); 19407a6dacacSDimitry Andric } 19417a6dacacSDimitry Andric } else { 19427a6dacacSDimitry Andric assert(S->isNonNegatedConsteval()); 19437a6dacacSDimitry Andric // ignore 'if consteval <then> [else]' 19447a6dacacSDimitry Andric markSkipped(S->getIfLoc(), Else ? getStart(Else) : getEnd(Then)); 19457a6dacacSDimitry Andric 19467a6dacacSDimitry Andric if (Else) 19477a6dacacSDimitry Andric propagateCounts(ParentCount, Else); 19487a6dacacSDimitry Andric } 19497a6dacacSDimitry Andric } 19507a6dacacSDimitry Andric 19517a6dacacSDimitry Andric void coverIfConstexpr(const IfStmt *S) { 19527a6dacacSDimitry Andric assert(S->isConstexpr()); 19537a6dacacSDimitry Andric 19547a6dacacSDimitry Andric // evaluate constant condition... 1955b3edf446SDimitry Andric const bool isTrue = 1956b3edf446SDimitry Andric S->getCond() 1957b3edf446SDimitry Andric ->EvaluateKnownConstInt(CVM.getCodeGenModule().getContext()) 1958b3edf446SDimitry Andric .getBoolValue(); 19597a6dacacSDimitry Andric 19607a6dacacSDimitry Andric extendRegion(S); 19617a6dacacSDimitry Andric 19627a6dacacSDimitry Andric // I'm using 'propagateCounts' later as new region is better and allows me 19637a6dacacSDimitry Andric // to properly calculate line coverage in llvm-cov utility 19647a6dacacSDimitry Andric const Counter ParentCount = getRegion().getCounter(); 19657a6dacacSDimitry Andric 19667a6dacacSDimitry Andric // ignore 'if constexpr (' 19677a6dacacSDimitry Andric SourceLocation startOfSkipped = S->getIfLoc(); 19687a6dacacSDimitry Andric 19697a6dacacSDimitry Andric if (const auto *Init = S->getInit()) { 19707a6dacacSDimitry Andric const auto start = getStart(Init); 19717a6dacacSDimitry Andric const auto end = getEnd(Init); 19727a6dacacSDimitry Andric 19737a6dacacSDimitry Andric // this check is to make sure typedef here which doesn't have valid source 19747a6dacacSDimitry Andric // location won't crash it 19757a6dacacSDimitry Andric if (start.isValid() && end.isValid()) { 19767a6dacacSDimitry Andric markSkipped(startOfSkipped, start); 19777a6dacacSDimitry Andric propagateCounts(ParentCount, Init); 19787a6dacacSDimitry Andric startOfSkipped = getEnd(Init); 19797a6dacacSDimitry Andric } 19807a6dacacSDimitry Andric } 19817a6dacacSDimitry Andric 19827a6dacacSDimitry Andric const auto *Then = S->getThen(); 19837a6dacacSDimitry Andric const auto *Else = S->getElse(); 19847a6dacacSDimitry Andric 19857a6dacacSDimitry Andric if (isTrue) { 19867a6dacacSDimitry Andric // ignore '<condition>)' 19877a6dacacSDimitry Andric markSkipped(startOfSkipped, getStart(Then)); 19887a6dacacSDimitry Andric propagateCounts(ParentCount, Then); 19897a6dacacSDimitry Andric 19907a6dacacSDimitry Andric if (Else) 19917a6dacacSDimitry Andric // ignore 'else <else>' 19927a6dacacSDimitry Andric markSkipped(getEnd(Then), getEnd(Else)); 19937a6dacacSDimitry Andric } else { 19947a6dacacSDimitry Andric // ignore '<condition>) <then> [else]' 19957a6dacacSDimitry Andric markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then)); 19967a6dacacSDimitry Andric 19977a6dacacSDimitry Andric if (Else) 19987a6dacacSDimitry Andric propagateCounts(ParentCount, Else); 19997a6dacacSDimitry Andric } 20007a6dacacSDimitry Andric } 20017a6dacacSDimitry Andric 20020b57cec5SDimitry Andric void VisitIfStmt(const IfStmt *S) { 20037a6dacacSDimitry Andric // "if constexpr" and "if consteval" are not normal conditional statements, 20047a6dacacSDimitry Andric // their discarded statement should be skipped 20057a6dacacSDimitry Andric if (S->isConsteval()) 20067a6dacacSDimitry Andric return coverIfConsteval(S); 20077a6dacacSDimitry Andric else if (S->isConstexpr()) 20087a6dacacSDimitry Andric return coverIfConstexpr(S); 20097a6dacacSDimitry Andric 20100b57cec5SDimitry Andric extendRegion(S); 20110b57cec5SDimitry Andric if (S->getInit()) 20120b57cec5SDimitry Andric Visit(S->getInit()); 20130b57cec5SDimitry Andric 20140b57cec5SDimitry Andric // Extend into the condition before we propagate through it below - this is 20150b57cec5SDimitry Andric // needed to handle macros that generate the "if" but not the condition. 20160b57cec5SDimitry Andric extendRegion(S->getCond()); 20170b57cec5SDimitry Andric 20180b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 2019*0fca6ea1SDimitry Andric Counter ThenCount = llvm::EnableSingleByteCoverage 2020*0fca6ea1SDimitry Andric ? getRegionCounter(S->getThen()) 2021*0fca6ea1SDimitry Andric : getRegionCounter(S); 2022297eecfbSDimitry Andric 20230b57cec5SDimitry Andric // Emitting a counter for the condition makes it easier to interpret the 20240b57cec5SDimitry Andric // counter for the body when looking at the coverage. 20250b57cec5SDimitry Andric propagateCounts(ParentCount, S->getCond()); 20260b57cec5SDimitry Andric 20270b57cec5SDimitry Andric // The 'then' count applies to the area immediately after the condition. 2028bdd1243dSDimitry Andric std::optional<SourceRange> Gap = 20296246ae0bSDimitry Andric findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen())); 20300b57cec5SDimitry Andric if (Gap) 20310b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount); 20320b57cec5SDimitry Andric 20330b57cec5SDimitry Andric extendRegion(S->getThen()); 20340b57cec5SDimitry Andric Counter OutCount = propagateCounts(ThenCount, S->getThen()); 2035*0fca6ea1SDimitry Andric 2036*0fca6ea1SDimitry Andric Counter ElseCount; 2037*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 2038*0fca6ea1SDimitry Andric ElseCount = subtractCounters(ParentCount, ThenCount); 2039*0fca6ea1SDimitry Andric else if (S->getElse()) 2040*0fca6ea1SDimitry Andric ElseCount = getRegionCounter(S->getElse()); 2041297eecfbSDimitry Andric 20420b57cec5SDimitry Andric if (const Stmt *Else = S->getElse()) { 2043fe6060f1SDimitry Andric bool ThenHasTerminateStmt = HasTerminateStmt; 2044fe6060f1SDimitry Andric HasTerminateStmt = false; 20450b57cec5SDimitry Andric // The 'else' count applies to the area immediately after the 'then'. 2046bdd1243dSDimitry Andric std::optional<SourceRange> Gap = 20476246ae0bSDimitry Andric findGapAreaBetween(getEnd(S->getThen()), getStart(Else)); 20480b57cec5SDimitry Andric if (Gap) 20490b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount); 20500b57cec5SDimitry Andric extendRegion(Else); 2051*0fca6ea1SDimitry Andric 2052*0fca6ea1SDimitry Andric Counter ElseOutCount = propagateCounts(ElseCount, Else); 2053*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 2054*0fca6ea1SDimitry Andric OutCount = addCounters(OutCount, ElseOutCount); 2055fe6060f1SDimitry Andric 2056fe6060f1SDimitry Andric if (ThenHasTerminateStmt) 2057fe6060f1SDimitry Andric HasTerminateStmt = true; 2058*0fca6ea1SDimitry Andric } else if (!llvm::EnableSingleByteCoverage) 20590b57cec5SDimitry Andric OutCount = addCounters(OutCount, ElseCount); 20600b57cec5SDimitry Andric 2061*0fca6ea1SDimitry Andric if (llvm::EnableSingleByteCoverage) 2062*0fca6ea1SDimitry Andric OutCount = getRegionCounter(S); 2063*0fca6ea1SDimitry Andric 2064fe6060f1SDimitry Andric if (OutCount != ParentCount) { 20650b57cec5SDimitry Andric pushRegion(OutCount); 2066fe6060f1SDimitry Andric GapRegionCounter = OutCount; 2067fe6060f1SDimitry Andric } 2068e8d8bef9SDimitry Andric 2069*0fca6ea1SDimitry Andric if (!S->isConsteval() && !llvm::EnableSingleByteCoverage) 2070e8d8bef9SDimitry Andric // Create Branch Region around condition. 2071e8d8bef9SDimitry Andric createBranchRegion(S->getCond(), ThenCount, 2072e8d8bef9SDimitry Andric subtractCounters(ParentCount, ThenCount)); 20730b57cec5SDimitry Andric } 20740b57cec5SDimitry Andric 20750b57cec5SDimitry Andric void VisitCXXTryStmt(const CXXTryStmt *S) { 20760b57cec5SDimitry Andric extendRegion(S); 20770b57cec5SDimitry Andric // Handle macros that generate the "try" but not the rest. 20780b57cec5SDimitry Andric extendRegion(S->getTryBlock()); 20790b57cec5SDimitry Andric 20800b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 20810b57cec5SDimitry Andric propagateCounts(ParentCount, S->getTryBlock()); 20820b57cec5SDimitry Andric 20830b57cec5SDimitry Andric for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I) 20840b57cec5SDimitry Andric Visit(S->getHandler(I)); 20850b57cec5SDimitry Andric 20860b57cec5SDimitry Andric Counter ExitCount = getRegionCounter(S); 20870b57cec5SDimitry Andric pushRegion(ExitCount); 20880b57cec5SDimitry Andric } 20890b57cec5SDimitry Andric 20900b57cec5SDimitry Andric void VisitCXXCatchStmt(const CXXCatchStmt *S) { 20910b57cec5SDimitry Andric propagateCounts(getRegionCounter(S), S->getHandlerBlock()); 20920b57cec5SDimitry Andric } 20930b57cec5SDimitry Andric 20940b57cec5SDimitry Andric void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { 20950b57cec5SDimitry Andric extendRegion(E); 20960b57cec5SDimitry Andric 20970b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter(); 2098*0fca6ea1SDimitry Andric Counter TrueCount = llvm::EnableSingleByteCoverage 2099*0fca6ea1SDimitry Andric ? getRegionCounter(E->getTrueExpr()) 2100*0fca6ea1SDimitry Andric : getRegionCounter(E); 210106c3fb27SDimitry Andric Counter OutCount; 21020b57cec5SDimitry Andric 2103*0fca6ea1SDimitry Andric if (const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) { 2104*0fca6ea1SDimitry Andric propagateCounts(ParentCount, BCO->getCommon()); 2105*0fca6ea1SDimitry Andric OutCount = TrueCount; 2106*0fca6ea1SDimitry Andric } else { 2107*0fca6ea1SDimitry Andric propagateCounts(ParentCount, E->getCond()); 21080b57cec5SDimitry Andric // The 'then' count applies to the area immediately after the condition. 21090b57cec5SDimitry Andric auto Gap = 21100b57cec5SDimitry Andric findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr())); 21110b57cec5SDimitry Andric if (Gap) 21120b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount); 21130b57cec5SDimitry Andric 21140b57cec5SDimitry Andric extendRegion(E->getTrueExpr()); 211506c3fb27SDimitry Andric OutCount = propagateCounts(TrueCount, E->getTrueExpr()); 21160b57cec5SDimitry Andric } 21170b57cec5SDimitry Andric 21180b57cec5SDimitry Andric extendRegion(E->getFalseExpr()); 2119*0fca6ea1SDimitry Andric Counter FalseCount = llvm::EnableSingleByteCoverage 2120*0fca6ea1SDimitry Andric ? getRegionCounter(E->getFalseExpr()) 2121*0fca6ea1SDimitry Andric : subtractCounters(ParentCount, TrueCount); 2122*0fca6ea1SDimitry Andric 2123*0fca6ea1SDimitry Andric Counter FalseOutCount = propagateCounts(FalseCount, E->getFalseExpr()); 2124*0fca6ea1SDimitry Andric if (llvm::EnableSingleByteCoverage) 2125*0fca6ea1SDimitry Andric OutCount = getRegionCounter(E); 2126*0fca6ea1SDimitry Andric else 2127*0fca6ea1SDimitry Andric OutCount = addCounters(OutCount, FalseOutCount); 212806c3fb27SDimitry Andric 212906c3fb27SDimitry Andric if (OutCount != ParentCount) { 213006c3fb27SDimitry Andric pushRegion(OutCount); 213106c3fb27SDimitry Andric GapRegionCounter = OutCount; 213206c3fb27SDimitry Andric } 2133e8d8bef9SDimitry Andric 2134e8d8bef9SDimitry Andric // Create Branch Region around condition. 2135*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 2136e8d8bef9SDimitry Andric createBranchRegion(E->getCond(), TrueCount, 2137e8d8bef9SDimitry Andric subtractCounters(ParentCount, TrueCount)); 21380b57cec5SDimitry Andric } 21390b57cec5SDimitry Andric 2140*0fca6ea1SDimitry Andric void createOrCancelDecision(const BinaryOperator *E, unsigned Since) { 2141*0fca6ea1SDimitry Andric unsigned NumConds = MCDCBuilder.getTotalConditionsAndReset(E); 2142*0fca6ea1SDimitry Andric if (NumConds == 0) 2143*0fca6ea1SDimitry Andric return; 2144*0fca6ea1SDimitry Andric 2145*0fca6ea1SDimitry Andric // Extract [ID, Conds] to construct the graph. 2146*0fca6ea1SDimitry Andric llvm::SmallVector<mcdc::ConditionIDs> CondIDs(NumConds); 2147*0fca6ea1SDimitry Andric for (const auto &SR : ArrayRef(SourceRegions).slice(Since)) { 2148*0fca6ea1SDimitry Andric if (SR.isMCDCBranch()) { 2149*0fca6ea1SDimitry Andric auto [ID, Conds] = SR.getMCDCBranchParams(); 2150*0fca6ea1SDimitry Andric CondIDs[ID] = Conds; 2151*0fca6ea1SDimitry Andric } 2152*0fca6ea1SDimitry Andric } 2153*0fca6ea1SDimitry Andric 2154*0fca6ea1SDimitry Andric // Construct the graph and calculate `Indices`. 2155*0fca6ea1SDimitry Andric mcdc::TVIdxBuilder Builder(CondIDs); 2156*0fca6ea1SDimitry Andric unsigned NumTVs = Builder.NumTestVectors; 2157*0fca6ea1SDimitry Andric unsigned MaxTVs = CVM.getCodeGenModule().getCodeGenOpts().MCDCMaxTVs; 2158*0fca6ea1SDimitry Andric assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs); 2159*0fca6ea1SDimitry Andric 2160*0fca6ea1SDimitry Andric if (NumTVs > MaxTVs) { 2161*0fca6ea1SDimitry Andric // NumTVs exceeds MaxTVs -- warn and cancel the Decision. 2162*0fca6ea1SDimitry Andric cancelDecision(E, Since, NumTVs, MaxTVs); 2163*0fca6ea1SDimitry Andric return; 2164*0fca6ea1SDimitry Andric } 2165*0fca6ea1SDimitry Andric 2166*0fca6ea1SDimitry Andric // Update the state for CodeGenPGO 2167*0fca6ea1SDimitry Andric assert(MCDCState.DecisionByStmt.contains(E)); 2168*0fca6ea1SDimitry Andric MCDCState.DecisionByStmt[E] = { 2169*0fca6ea1SDimitry Andric MCDCState.BitmapBits, // Top 2170*0fca6ea1SDimitry Andric std::move(Builder.Indices), 2171*0fca6ea1SDimitry Andric }; 2172*0fca6ea1SDimitry Andric 2173*0fca6ea1SDimitry Andric auto DecisionParams = mcdc::DecisionParameters{ 2174*0fca6ea1SDimitry Andric MCDCState.BitmapBits += NumTVs, // Tail 2175*0fca6ea1SDimitry Andric NumConds, 2176*0fca6ea1SDimitry Andric }; 2177*0fca6ea1SDimitry Andric 2178*0fca6ea1SDimitry Andric // Create MCDC Decision Region. 2179*0fca6ea1SDimitry Andric createDecisionRegion(E, DecisionParams); 2180*0fca6ea1SDimitry Andric } 2181*0fca6ea1SDimitry Andric 2182*0fca6ea1SDimitry Andric // Warn and cancel the Decision. 2183*0fca6ea1SDimitry Andric void cancelDecision(const BinaryOperator *E, unsigned Since, int NumTVs, 2184*0fca6ea1SDimitry Andric int MaxTVs) { 2185*0fca6ea1SDimitry Andric auto &Diag = CVM.getCodeGenModule().getDiags(); 2186*0fca6ea1SDimitry Andric unsigned DiagID = 2187*0fca6ea1SDimitry Andric Diag.getCustomDiagID(DiagnosticsEngine::Warning, 2188*0fca6ea1SDimitry Andric "unsupported MC/DC boolean expression; " 2189*0fca6ea1SDimitry Andric "number of test vectors (%0) exceeds max (%1). " 2190*0fca6ea1SDimitry Andric "Expression will not be covered"); 2191*0fca6ea1SDimitry Andric Diag.Report(E->getBeginLoc(), DiagID) << NumTVs << MaxTVs; 2192*0fca6ea1SDimitry Andric 2193*0fca6ea1SDimitry Andric // Restore MCDCBranch to Branch. 2194*0fca6ea1SDimitry Andric for (auto &SR : MutableArrayRef(SourceRegions).slice(Since)) { 2195*0fca6ea1SDimitry Andric assert(!SR.isMCDCDecision() && "Decision shouldn't be seen here"); 2196*0fca6ea1SDimitry Andric if (SR.isMCDCBranch()) 2197*0fca6ea1SDimitry Andric SR.resetMCDCParams(); 2198*0fca6ea1SDimitry Andric } 2199*0fca6ea1SDimitry Andric 2200*0fca6ea1SDimitry Andric // Tell CodeGenPGO not to instrument. 2201*0fca6ea1SDimitry Andric MCDCState.DecisionByStmt.erase(E); 2202*0fca6ea1SDimitry Andric } 2203*0fca6ea1SDimitry Andric 2204*0fca6ea1SDimitry Andric /// Check if E belongs to system headers. 2205*0fca6ea1SDimitry Andric bool isExprInSystemHeader(const BinaryOperator *E) const { 2206*0fca6ea1SDimitry Andric return (!SystemHeadersCoverage && 2207*0fca6ea1SDimitry Andric SM.isInSystemHeader(SM.getSpellingLoc(E->getOperatorLoc())) && 2208*0fca6ea1SDimitry Andric SM.isInSystemHeader(SM.getSpellingLoc(E->getBeginLoc())) && 2209*0fca6ea1SDimitry Andric SM.isInSystemHeader(SM.getSpellingLoc(E->getEndLoc()))); 2210*0fca6ea1SDimitry Andric } 2211*0fca6ea1SDimitry Andric 22120b57cec5SDimitry Andric void VisitBinLAnd(const BinaryOperator *E) { 2213*0fca6ea1SDimitry Andric if (isExprInSystemHeader(E)) { 2214*0fca6ea1SDimitry Andric LeafExprSet.insert(E); 2215*0fca6ea1SDimitry Andric return; 2216*0fca6ea1SDimitry Andric } 2217*0fca6ea1SDimitry Andric 22187a6dacacSDimitry Andric bool IsRootNode = MCDCBuilder.isIdle(); 22197a6dacacSDimitry Andric 2220*0fca6ea1SDimitry Andric unsigned SourceRegionsSince = SourceRegions.size(); 2221*0fca6ea1SDimitry Andric 22227a6dacacSDimitry Andric // Keep track of Binary Operator and assign MCDC condition IDs. 22231db9f3b2SDimitry Andric MCDCBuilder.pushAndAssignIDs(E); 22241db9f3b2SDimitry Andric 22250b57cec5SDimitry Andric extendRegion(E->getLHS()); 22260b57cec5SDimitry Andric propagateCounts(getRegion().getCounter(), E->getLHS()); 22270b57cec5SDimitry Andric handleFileExit(getEnd(E->getLHS())); 22280b57cec5SDimitry Andric 22297a6dacacSDimitry Andric // Track LHS True/False Decision. 22307a6dacacSDimitry Andric const auto DecisionLHS = MCDCBuilder.pop(); 22317a6dacacSDimitry Andric 2232e8d8bef9SDimitry Andric // Counter tracks the right hand side of a logical and operator. 22330b57cec5SDimitry Andric extendRegion(E->getRHS()); 22340b57cec5SDimitry Andric propagateCounts(getRegionCounter(E), E->getRHS()); 2235e8d8bef9SDimitry Andric 22367a6dacacSDimitry Andric // Track RHS True/False Decision. 22377a6dacacSDimitry Andric const auto DecisionRHS = MCDCBuilder.back(); 22387a6dacacSDimitry Andric 2239e8d8bef9SDimitry Andric // Extract the RHS's Execution Counter. 2240e8d8bef9SDimitry Andric Counter RHSExecCnt = getRegionCounter(E); 2241e8d8bef9SDimitry Andric 2242e8d8bef9SDimitry Andric // Extract the RHS's "True" Instance Counter. 2243e8d8bef9SDimitry Andric Counter RHSTrueCnt = getRegionCounter(E->getRHS()); 2244e8d8bef9SDimitry Andric 2245e8d8bef9SDimitry Andric // Extract the Parent Region Counter. 2246e8d8bef9SDimitry Andric Counter ParentCnt = getRegion().getCounter(); 2247e8d8bef9SDimitry Andric 2248e8d8bef9SDimitry Andric // Create Branch Region around LHS condition. 2249*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 2250e8d8bef9SDimitry Andric createBranchRegion(E->getLHS(), RHSExecCnt, 22517a6dacacSDimitry Andric subtractCounters(ParentCnt, RHSExecCnt), DecisionLHS); 2252e8d8bef9SDimitry Andric 2253e8d8bef9SDimitry Andric // Create Branch Region around RHS condition. 2254*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 2255e8d8bef9SDimitry Andric createBranchRegion(E->getRHS(), RHSTrueCnt, 22567a6dacacSDimitry Andric subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS); 2257*0fca6ea1SDimitry Andric 2258*0fca6ea1SDimitry Andric // Create MCDC Decision Region if at top-level (root). 2259*0fca6ea1SDimitry Andric if (IsRootNode) 2260*0fca6ea1SDimitry Andric createOrCancelDecision(E, SourceRegionsSince); 22610b57cec5SDimitry Andric } 22620b57cec5SDimitry Andric 226306c3fb27SDimitry Andric // Determine whether the right side of OR operation need to be visited. 226406c3fb27SDimitry Andric bool shouldVisitRHS(const Expr *LHS) { 226506c3fb27SDimitry Andric bool LHSIsTrue = false; 226606c3fb27SDimitry Andric bool LHSIsConst = false; 226706c3fb27SDimitry Andric if (!LHS->isValueDependent()) 226806c3fb27SDimitry Andric LHSIsConst = LHS->EvaluateAsBooleanCondition( 226906c3fb27SDimitry Andric LHSIsTrue, CVM.getCodeGenModule().getContext()); 227006c3fb27SDimitry Andric return !LHSIsConst || (LHSIsConst && !LHSIsTrue); 227106c3fb27SDimitry Andric } 227206c3fb27SDimitry Andric 22730b57cec5SDimitry Andric void VisitBinLOr(const BinaryOperator *E) { 2274*0fca6ea1SDimitry Andric if (isExprInSystemHeader(E)) { 2275*0fca6ea1SDimitry Andric LeafExprSet.insert(E); 2276*0fca6ea1SDimitry Andric return; 2277*0fca6ea1SDimitry Andric } 2278*0fca6ea1SDimitry Andric 22797a6dacacSDimitry Andric bool IsRootNode = MCDCBuilder.isIdle(); 22807a6dacacSDimitry Andric 2281*0fca6ea1SDimitry Andric unsigned SourceRegionsSince = SourceRegions.size(); 2282*0fca6ea1SDimitry Andric 22837a6dacacSDimitry Andric // Keep track of Binary Operator and assign MCDC condition IDs. 22841db9f3b2SDimitry Andric MCDCBuilder.pushAndAssignIDs(E); 22851db9f3b2SDimitry Andric 22860b57cec5SDimitry Andric extendRegion(E->getLHS()); 228706c3fb27SDimitry Andric Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS()); 22880b57cec5SDimitry Andric handleFileExit(getEnd(E->getLHS())); 22890b57cec5SDimitry Andric 22907a6dacacSDimitry Andric // Track LHS True/False Decision. 22917a6dacacSDimitry Andric const auto DecisionLHS = MCDCBuilder.pop(); 22927a6dacacSDimitry Andric 2293e8d8bef9SDimitry Andric // Counter tracks the right hand side of a logical or operator. 22940b57cec5SDimitry Andric extendRegion(E->getRHS()); 22950b57cec5SDimitry Andric propagateCounts(getRegionCounter(E), E->getRHS()); 2296e8d8bef9SDimitry Andric 22977a6dacacSDimitry Andric // Track RHS True/False Decision. 22987a6dacacSDimitry Andric const auto DecisionRHS = MCDCBuilder.back(); 22997a6dacacSDimitry Andric 2300e8d8bef9SDimitry Andric // Extract the RHS's Execution Counter. 2301e8d8bef9SDimitry Andric Counter RHSExecCnt = getRegionCounter(E); 2302e8d8bef9SDimitry Andric 2303e8d8bef9SDimitry Andric // Extract the RHS's "False" Instance Counter. 2304e8d8bef9SDimitry Andric Counter RHSFalseCnt = getRegionCounter(E->getRHS()); 2305e8d8bef9SDimitry Andric 230606c3fb27SDimitry Andric if (!shouldVisitRHS(E->getLHS())) { 230706c3fb27SDimitry Andric GapRegionCounter = OutCount; 230806c3fb27SDimitry Andric } 230906c3fb27SDimitry Andric 2310e8d8bef9SDimitry Andric // Extract the Parent Region Counter. 2311e8d8bef9SDimitry Andric Counter ParentCnt = getRegion().getCounter(); 2312e8d8bef9SDimitry Andric 2313e8d8bef9SDimitry Andric // Create Branch Region around LHS condition. 2314*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 2315e8d8bef9SDimitry Andric createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt), 23167a6dacacSDimitry Andric RHSExecCnt, DecisionLHS); 2317e8d8bef9SDimitry Andric 2318e8d8bef9SDimitry Andric // Create Branch Region around RHS condition. 2319*0fca6ea1SDimitry Andric if (!llvm::EnableSingleByteCoverage) 2320e8d8bef9SDimitry Andric createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt), 23217a6dacacSDimitry Andric RHSFalseCnt, DecisionRHS); 2322*0fca6ea1SDimitry Andric 2323*0fca6ea1SDimitry Andric // Create MCDC Decision Region if at top-level (root). 2324*0fca6ea1SDimitry Andric if (IsRootNode) 2325*0fca6ea1SDimitry Andric createOrCancelDecision(E, SourceRegionsSince); 23260b57cec5SDimitry Andric } 23270b57cec5SDimitry Andric 23280b57cec5SDimitry Andric void VisitLambdaExpr(const LambdaExpr *LE) { 23290b57cec5SDimitry Andric // Lambdas are treated as their own functions for now, so we shouldn't 23300b57cec5SDimitry Andric // propagate counts into them. 23310b57cec5SDimitry Andric } 233206c3fb27SDimitry Andric 2333*0fca6ea1SDimitry Andric void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *AILE) { 2334*0fca6ea1SDimitry Andric Visit(AILE->getCommonExpr()->getSourceExpr()); 2335*0fca6ea1SDimitry Andric } 2336*0fca6ea1SDimitry Andric 233706c3fb27SDimitry Andric void VisitPseudoObjectExpr(const PseudoObjectExpr *POE) { 233806c3fb27SDimitry Andric // Just visit syntatic expression as this is what users actually write. 233906c3fb27SDimitry Andric VisitStmt(POE->getSyntacticForm()); 234006c3fb27SDimitry Andric } 234106c3fb27SDimitry Andric 234206c3fb27SDimitry Andric void VisitOpaqueValueExpr(const OpaqueValueExpr* OVE) { 2343*0fca6ea1SDimitry Andric if (OVE->isUnique()) 234406c3fb27SDimitry Andric Visit(OVE->getSourceExpr()); 234506c3fb27SDimitry Andric } 23460b57cec5SDimitry Andric }; 23470b57cec5SDimitry Andric 23480b57cec5SDimitry Andric } // end anonymous namespace 23490b57cec5SDimitry Andric 23500b57cec5SDimitry Andric static void dump(llvm::raw_ostream &OS, StringRef FunctionName, 23510b57cec5SDimitry Andric ArrayRef<CounterExpression> Expressions, 23520b57cec5SDimitry Andric ArrayRef<CounterMappingRegion> Regions) { 23530b57cec5SDimitry Andric OS << FunctionName << ":\n"; 23540b57cec5SDimitry Andric CounterMappingContext Ctx(Expressions); 23550b57cec5SDimitry Andric for (const auto &R : Regions) { 23560b57cec5SDimitry Andric OS.indent(2); 23570b57cec5SDimitry Andric switch (R.Kind) { 23580b57cec5SDimitry Andric case CounterMappingRegion::CodeRegion: 23590b57cec5SDimitry Andric break; 23600b57cec5SDimitry Andric case CounterMappingRegion::ExpansionRegion: 23610b57cec5SDimitry Andric OS << "Expansion,"; 23620b57cec5SDimitry Andric break; 23630b57cec5SDimitry Andric case CounterMappingRegion::SkippedRegion: 23640b57cec5SDimitry Andric OS << "Skipped,"; 23650b57cec5SDimitry Andric break; 23660b57cec5SDimitry Andric case CounterMappingRegion::GapRegion: 23670b57cec5SDimitry Andric OS << "Gap,"; 23680b57cec5SDimitry Andric break; 2369e8d8bef9SDimitry Andric case CounterMappingRegion::BranchRegion: 23705f757f3fSDimitry Andric case CounterMappingRegion::MCDCBranchRegion: 2371e8d8bef9SDimitry Andric OS << "Branch,"; 2372e8d8bef9SDimitry Andric break; 23735f757f3fSDimitry Andric case CounterMappingRegion::MCDCDecisionRegion: 23745f757f3fSDimitry Andric OS << "Decision,"; 23755f757f3fSDimitry Andric break; 23760b57cec5SDimitry Andric } 23770b57cec5SDimitry Andric 23780b57cec5SDimitry Andric OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart 23790b57cec5SDimitry Andric << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = "; 23801db9f3b2SDimitry Andric 2381*0fca6ea1SDimitry Andric if (const auto *DecisionParams = 2382*0fca6ea1SDimitry Andric std::get_if<mcdc::DecisionParameters>(&R.MCDCParams)) { 2383*0fca6ea1SDimitry Andric OS << "M:" << DecisionParams->BitmapIdx; 2384*0fca6ea1SDimitry Andric OS << ", C:" << DecisionParams->NumConditions; 23851db9f3b2SDimitry Andric } else { 23860b57cec5SDimitry Andric Ctx.dump(R.Count, OS); 2387e8d8bef9SDimitry Andric 23881db9f3b2SDimitry Andric if (R.Kind == CounterMappingRegion::BranchRegion || 23891db9f3b2SDimitry Andric R.Kind == CounterMappingRegion::MCDCBranchRegion) { 2390e8d8bef9SDimitry Andric OS << ", "; 2391e8d8bef9SDimitry Andric Ctx.dump(R.FalseCount, OS); 2392e8d8bef9SDimitry Andric } 23931db9f3b2SDimitry Andric } 23941db9f3b2SDimitry Andric 2395*0fca6ea1SDimitry Andric if (const auto *BranchParams = 2396*0fca6ea1SDimitry Andric std::get_if<mcdc::BranchParameters>(&R.MCDCParams)) { 2397*0fca6ea1SDimitry Andric OS << " [" << BranchParams->ID + 1 << "," 2398*0fca6ea1SDimitry Andric << BranchParams->Conds[true] + 1; 2399*0fca6ea1SDimitry Andric OS << "," << BranchParams->Conds[false] + 1 << "] "; 24001db9f3b2SDimitry Andric } 2401e8d8bef9SDimitry Andric 24020b57cec5SDimitry Andric if (R.Kind == CounterMappingRegion::ExpansionRegion) 24030b57cec5SDimitry Andric OS << " (Expanded file = " << R.ExpandedFileID << ")"; 24040b57cec5SDimitry Andric OS << "\n"; 24050b57cec5SDimitry Andric } 24060b57cec5SDimitry Andric } 24070b57cec5SDimitry Andric 2408e8d8bef9SDimitry Andric CoverageMappingModuleGen::CoverageMappingModuleGen( 2409e8d8bef9SDimitry Andric CodeGenModule &CGM, CoverageSourceInfo &SourceInfo) 241006c3fb27SDimitry Andric : CGM(CGM), SourceInfo(SourceInfo) {} 2411fe6060f1SDimitry Andric 2412fe6060f1SDimitry Andric std::string CoverageMappingModuleGen::getCurrentDirname() { 2413fe6060f1SDimitry Andric if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty()) 2414fe6060f1SDimitry Andric return CGM.getCodeGenOpts().CoverageCompilationDir; 2415fe6060f1SDimitry Andric 2416fe6060f1SDimitry Andric SmallString<256> CWD; 2417fe6060f1SDimitry Andric llvm::sys::fs::current_path(CWD); 2418fe6060f1SDimitry Andric return CWD.str().str(); 2419e8d8bef9SDimitry Andric } 2420e8d8bef9SDimitry Andric 2421e8d8bef9SDimitry Andric std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) { 2422e8d8bef9SDimitry Andric llvm::SmallString<256> Path(Filename); 2423e8d8bef9SDimitry Andric llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); 242406c3fb27SDimitry Andric 242506c3fb27SDimitry Andric /// Traverse coverage prefix map in reverse order because prefix replacements 242606c3fb27SDimitry Andric /// are applied in reverse order starting from the last one when multiple 242706c3fb27SDimitry Andric /// prefix replacement options are provided. 242806c3fb27SDimitry Andric for (const auto &[From, To] : 242906c3fb27SDimitry Andric llvm::reverse(CGM.getCodeGenOpts().CoveragePrefixMap)) { 243006c3fb27SDimitry Andric if (llvm::sys::path::replace_path_prefix(Path, From, To)) 2431e8d8bef9SDimitry Andric break; 2432e8d8bef9SDimitry Andric } 2433e8d8bef9SDimitry Andric return Path.str().str(); 2434e8d8bef9SDimitry Andric } 2435e8d8bef9SDimitry Andric 24365ffd83dbSDimitry Andric static std::string getInstrProfSection(const CodeGenModule &CGM, 24375ffd83dbSDimitry Andric llvm::InstrProfSectKind SK) { 24385ffd83dbSDimitry Andric return llvm::getInstrProfSectionName( 24395ffd83dbSDimitry Andric SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat()); 24405ffd83dbSDimitry Andric } 24415ffd83dbSDimitry Andric 24425ffd83dbSDimitry Andric void CoverageMappingModuleGen::emitFunctionMappingRecord( 24435ffd83dbSDimitry Andric const FunctionInfo &Info, uint64_t FilenamesRef) { 24440b57cec5SDimitry Andric llvm::LLVMContext &Ctx = CGM.getLLVMContext(); 24455ffd83dbSDimitry Andric 24465ffd83dbSDimitry Andric // Assign a name to the function record. This is used to merge duplicates. 24475ffd83dbSDimitry Andric std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash); 24485ffd83dbSDimitry Andric 24495ffd83dbSDimitry Andric // A dummy description for a function included-but-not-used in a TU can be 24505ffd83dbSDimitry Andric // replaced by full description provided by a different TU. The two kinds of 24515ffd83dbSDimitry Andric // descriptions play distinct roles: therefore, assign them different names 24525ffd83dbSDimitry Andric // to prevent `linkonce_odr` merging. 24535ffd83dbSDimitry Andric if (Info.IsUsed) 24545ffd83dbSDimitry Andric FuncRecordName += "u"; 24555ffd83dbSDimitry Andric 24565ffd83dbSDimitry Andric // Create the function record type. 24575ffd83dbSDimitry Andric const uint64_t NameHash = Info.NameHash; 24585ffd83dbSDimitry Andric const uint64_t FuncHash = Info.FuncHash; 24595ffd83dbSDimitry Andric const std::string &CoverageMapping = Info.CoverageMapping; 24600b57cec5SDimitry Andric #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType, 24610b57cec5SDimitry Andric llvm::Type *FunctionRecordTypes[] = { 24620b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 24630b57cec5SDimitry Andric }; 24645ffd83dbSDimitry Andric auto *FunctionRecordTy = 2465bdd1243dSDimitry Andric llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes), 24660b57cec5SDimitry Andric /*isPacked=*/true); 24670b57cec5SDimitry Andric 24685ffd83dbSDimitry Andric // Create the function record constant. 24690b57cec5SDimitry Andric #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init, 24700b57cec5SDimitry Andric llvm::Constant *FunctionRecordVals[] = { 24710b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 24720b57cec5SDimitry Andric }; 2473bdd1243dSDimitry Andric auto *FuncRecordConstant = 2474bdd1243dSDimitry Andric llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals)); 24755ffd83dbSDimitry Andric 24765ffd83dbSDimitry Andric // Create the function record global. 24775ffd83dbSDimitry Andric auto *FuncRecord = new llvm::GlobalVariable( 24785ffd83dbSDimitry Andric CGM.getModule(), FunctionRecordTy, /*isConstant=*/true, 24795ffd83dbSDimitry Andric llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant, 24805ffd83dbSDimitry Andric FuncRecordName); 24815ffd83dbSDimitry Andric FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility); 24825ffd83dbSDimitry Andric FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun)); 24835ffd83dbSDimitry Andric FuncRecord->setAlignment(llvm::Align(8)); 24845ffd83dbSDimitry Andric if (CGM.supportsCOMDAT()) 24855ffd83dbSDimitry Andric FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName)); 24865ffd83dbSDimitry Andric 24875ffd83dbSDimitry Andric // Make sure the data doesn't get deleted. 24885ffd83dbSDimitry Andric CGM.addUsedGlobal(FuncRecord); 24895ffd83dbSDimitry Andric } 24905ffd83dbSDimitry Andric 24915ffd83dbSDimitry Andric void CoverageMappingModuleGen::addFunctionMappingRecord( 24925ffd83dbSDimitry Andric llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash, 24935ffd83dbSDimitry Andric const std::string &CoverageMapping, bool IsUsed) { 24945ffd83dbSDimitry Andric const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue); 24955ffd83dbSDimitry Andric FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed}); 24965ffd83dbSDimitry Andric 24970b57cec5SDimitry Andric if (!IsUsed) 24985f757f3fSDimitry Andric FunctionNames.push_back(NamePtr); 24990b57cec5SDimitry Andric 25000b57cec5SDimitry Andric if (CGM.getCodeGenOpts().DumpCoverageMapping) { 25010b57cec5SDimitry Andric // Dump the coverage mapping data for this function by decoding the 25020b57cec5SDimitry Andric // encoded data. This allows us to dump the mapping regions which were 25030b57cec5SDimitry Andric // also processed by the CoverageMappingWriter which performs 25040b57cec5SDimitry Andric // additional minimization operations such as reducing the number of 25050b57cec5SDimitry Andric // expressions. 2506fe6060f1SDimitry Andric llvm::SmallVector<std::string, 16> FilenameStrs; 25070b57cec5SDimitry Andric std::vector<StringRef> Filenames; 25080b57cec5SDimitry Andric std::vector<CounterExpression> Expressions; 25090b57cec5SDimitry Andric std::vector<CounterMappingRegion> Regions; 2510fe6060f1SDimitry Andric FilenameStrs.resize(FileEntries.size() + 1); 2511fe6060f1SDimitry Andric FilenameStrs[0] = normalizeFilename(getCurrentDirname()); 25120b57cec5SDimitry Andric for (const auto &Entry : FileEntries) { 25130b57cec5SDimitry Andric auto I = Entry.second; 25145f757f3fSDimitry Andric FilenameStrs[I] = normalizeFilename(Entry.first.getName()); 25150b57cec5SDimitry Andric } 2516bdd1243dSDimitry Andric ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(FilenameStrs); 25170b57cec5SDimitry Andric RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames, 25180b57cec5SDimitry Andric Expressions, Regions); 25190b57cec5SDimitry Andric if (Reader.read()) 25200b57cec5SDimitry Andric return; 25210b57cec5SDimitry Andric dump(llvm::outs(), NameValue, Expressions, Regions); 25220b57cec5SDimitry Andric } 25230b57cec5SDimitry Andric } 25240b57cec5SDimitry Andric 25250b57cec5SDimitry Andric void CoverageMappingModuleGen::emit() { 25260b57cec5SDimitry Andric if (FunctionRecords.empty()) 25270b57cec5SDimitry Andric return; 25280b57cec5SDimitry Andric llvm::LLVMContext &Ctx = CGM.getLLVMContext(); 25290b57cec5SDimitry Andric auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); 25300b57cec5SDimitry Andric 25310b57cec5SDimitry Andric // Create the filenames and merge them with coverage mappings 25320b57cec5SDimitry Andric llvm::SmallVector<std::string, 16> FilenameStrs; 2533fe6060f1SDimitry Andric FilenameStrs.resize(FileEntries.size() + 1); 2534fe6060f1SDimitry Andric // The first filename is the current working directory. 2535fe6060f1SDimitry Andric FilenameStrs[0] = normalizeFilename(getCurrentDirname()); 25360b57cec5SDimitry Andric for (const auto &Entry : FileEntries) { 25370b57cec5SDimitry Andric auto I = Entry.second; 25385f757f3fSDimitry Andric FilenameStrs[I] = normalizeFilename(Entry.first.getName()); 25390b57cec5SDimitry Andric } 25400b57cec5SDimitry Andric 25415ffd83dbSDimitry Andric std::string Filenames; 25425ffd83dbSDimitry Andric { 25435ffd83dbSDimitry Andric llvm::raw_string_ostream OS(Filenames); 2544fe6060f1SDimitry Andric CoverageFilenamesSectionWriter(FilenameStrs).write(OS); 25450b57cec5SDimitry Andric } 25465ffd83dbSDimitry Andric auto *FilenamesVal = 25475ffd83dbSDimitry Andric llvm::ConstantDataArray::getString(Ctx, Filenames, false); 25485ffd83dbSDimitry Andric const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames); 25490b57cec5SDimitry Andric 25505ffd83dbSDimitry Andric // Emit the function records. 25515ffd83dbSDimitry Andric for (const FunctionInfo &Info : FunctionRecords) 25525ffd83dbSDimitry Andric emitFunctionMappingRecord(Info, FilenamesRef); 25530b57cec5SDimitry Andric 25545ffd83dbSDimitry Andric const unsigned NRecords = 0; 25555ffd83dbSDimitry Andric const size_t FilenamesSize = Filenames.size(); 25565ffd83dbSDimitry Andric const unsigned CoverageMappingSize = 0; 25570b57cec5SDimitry Andric llvm::Type *CovDataHeaderTypes[] = { 25580b57cec5SDimitry Andric #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType, 25590b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 25600b57cec5SDimitry Andric }; 25610b57cec5SDimitry Andric auto CovDataHeaderTy = 2562bdd1243dSDimitry Andric llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes)); 25630b57cec5SDimitry Andric llvm::Constant *CovDataHeaderVals[] = { 25640b57cec5SDimitry Andric #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init, 25650b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc" 25660b57cec5SDimitry Andric }; 2567bdd1243dSDimitry Andric auto CovDataHeaderVal = 2568bdd1243dSDimitry Andric llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals)); 25690b57cec5SDimitry Andric 25700b57cec5SDimitry Andric // Create the coverage data record 25715ffd83dbSDimitry Andric llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()}; 2572bdd1243dSDimitry Andric auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes)); 25735ffd83dbSDimitry Andric llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal}; 2574bdd1243dSDimitry Andric auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals)); 25750b57cec5SDimitry Andric auto CovData = new llvm::GlobalVariable( 25765ffd83dbSDimitry Andric CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage, 25770b57cec5SDimitry Andric CovDataVal, llvm::getCoverageMappingVarName()); 25780b57cec5SDimitry Andric 25795ffd83dbSDimitry Andric CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap)); 2580a7dea167SDimitry Andric CovData->setAlignment(llvm::Align(8)); 25810b57cec5SDimitry Andric 25820b57cec5SDimitry Andric // Make sure the data doesn't get deleted. 25830b57cec5SDimitry Andric CGM.addUsedGlobal(CovData); 25840b57cec5SDimitry Andric // Create the deferred function records array 25850b57cec5SDimitry Andric if (!FunctionNames.empty()) { 25865f757f3fSDimitry Andric auto NamesArrTy = llvm::ArrayType::get(llvm::PointerType::getUnqual(Ctx), 25870b57cec5SDimitry Andric FunctionNames.size()); 25880b57cec5SDimitry Andric auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames); 25890b57cec5SDimitry Andric // This variable will *NOT* be emitted to the object file. It is used 25900b57cec5SDimitry Andric // to pass the list of names referenced to codegen. 25910b57cec5SDimitry Andric new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true, 25920b57cec5SDimitry Andric llvm::GlobalValue::InternalLinkage, NamesArrVal, 25930b57cec5SDimitry Andric llvm::getCoverageUnusedNamesVarName()); 25940b57cec5SDimitry Andric } 25950b57cec5SDimitry Andric } 25960b57cec5SDimitry Andric 25975f757f3fSDimitry Andric unsigned CoverageMappingModuleGen::getFileID(FileEntryRef File) { 25980b57cec5SDimitry Andric auto It = FileEntries.find(File); 25990b57cec5SDimitry Andric if (It != FileEntries.end()) 26000b57cec5SDimitry Andric return It->second; 2601fe6060f1SDimitry Andric unsigned FileID = FileEntries.size() + 1; 26020b57cec5SDimitry Andric FileEntries.insert(std::make_pair(File, FileID)); 26030b57cec5SDimitry Andric return FileID; 26040b57cec5SDimitry Andric } 26050b57cec5SDimitry Andric 26060b57cec5SDimitry Andric void CoverageMappingGen::emitCounterMapping(const Decl *D, 26070b57cec5SDimitry Andric llvm::raw_ostream &OS) { 2608*0fca6ea1SDimitry Andric assert(CounterMap && MCDCState); 2609*0fca6ea1SDimitry Andric CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM, 2610*0fca6ea1SDimitry Andric LangOpts); 26110b57cec5SDimitry Andric Walker.VisitDecl(D); 26120b57cec5SDimitry Andric Walker.write(OS); 26130b57cec5SDimitry Andric } 26140b57cec5SDimitry Andric 26150b57cec5SDimitry Andric void CoverageMappingGen::emitEmptyMapping(const Decl *D, 26160b57cec5SDimitry Andric llvm::raw_ostream &OS) { 26170b57cec5SDimitry Andric EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts); 26180b57cec5SDimitry Andric Walker.VisitDecl(D); 26190b57cec5SDimitry Andric Walker.write(OS); 26200b57cec5SDimitry Andric } 2621