xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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