xref: /openbsd-src/gnu/llvm/clang/lib/CodeGen/CoverageMappingGen.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Instrumentation-based code coverage mapping generator
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "CoverageMappingGen.h"
14e5dd7070Spatrick #include "CodeGenFunction.h"
15e5dd7070Spatrick #include "clang/AST/StmtVisitor.h"
16ec727ea7Spatrick #include "clang/Basic/Diagnostic.h"
17ec727ea7Spatrick #include "clang/Basic/FileManager.h"
18ec727ea7Spatrick #include "clang/Frontend/FrontendDiagnostic.h"
19e5dd7070Spatrick #include "clang/Lex/Lexer.h"
20e5dd7070Spatrick #include "llvm/ADT/SmallSet.h"
21e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
22e5dd7070Spatrick #include "llvm/ProfileData/Coverage/CoverageMapping.h"
23e5dd7070Spatrick #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
24e5dd7070Spatrick #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
25e5dd7070Spatrick #include "llvm/ProfileData/InstrProfReader.h"
26e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
27e5dd7070Spatrick #include "llvm/Support/Path.h"
28*12c85518Srobert #include <optional>
29e5dd7070Spatrick 
30ec727ea7Spatrick // This selects the coverage mapping format defined when `InstrProfData.inc`
31ec727ea7Spatrick // is textually included.
32ec727ea7Spatrick #define COVMAP_V3
33ec727ea7Spatrick 
34a9ac8606Spatrick static llvm::cl::opt<bool> EmptyLineCommentCoverage(
35a9ac8606Spatrick     "emptyline-comment-coverage",
36a9ac8606Spatrick     llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
37a9ac8606Spatrick                    "disable it on test)"),
38a9ac8606Spatrick     llvm::cl::init(true), llvm::cl::Hidden);
39a9ac8606Spatrick 
40e5dd7070Spatrick using namespace clang;
41e5dd7070Spatrick using namespace CodeGen;
42e5dd7070Spatrick using namespace llvm::coverage;
43e5dd7070Spatrick 
44a9ac8606Spatrick CoverageSourceInfo *
setUpCoverageCallbacks(Preprocessor & PP)45a9ac8606Spatrick CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) {
46a9ac8606Spatrick   CoverageSourceInfo *CoverageInfo =
47a9ac8606Spatrick       new CoverageSourceInfo(PP.getSourceManager());
48a9ac8606Spatrick   PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
49a9ac8606Spatrick   if (EmptyLineCommentCoverage) {
50a9ac8606Spatrick     PP.addCommentHandler(CoverageInfo);
51a9ac8606Spatrick     PP.setEmptylineHandler(CoverageInfo);
52a9ac8606Spatrick     PP.setPreprocessToken(true);
53a9ac8606Spatrick     PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
54a9ac8606Spatrick       // Update previous token location.
55a9ac8606Spatrick       CoverageInfo->PrevTokLoc = Tok.getLocation();
56a9ac8606Spatrick       if (Tok.getKind() != clang::tok::eod)
57a9ac8606Spatrick         CoverageInfo->updateNextTokLoc(Tok.getLocation());
58a9ac8606Spatrick     });
59a9ac8606Spatrick   }
60a9ac8606Spatrick   return CoverageInfo;
61a9ac8606Spatrick }
62a9ac8606Spatrick 
AddSkippedRange(SourceRange Range,SkippedRange::Kind RangeKind)63*12c85518Srobert void CoverageSourceInfo::AddSkippedRange(SourceRange Range,
64*12c85518Srobert                                          SkippedRange::Kind RangeKind) {
65a9ac8606Spatrick   if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
66a9ac8606Spatrick       PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
67a9ac8606Spatrick       SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
68a9ac8606Spatrick                                     Range.getBegin()))
69a9ac8606Spatrick     SkippedRanges.back().Range.setEnd(Range.getEnd());
70a9ac8606Spatrick   else
71*12c85518Srobert     SkippedRanges.push_back({Range, RangeKind, PrevTokLoc});
72a9ac8606Spatrick }
73a9ac8606Spatrick 
SourceRangeSkipped(SourceRange Range,SourceLocation)74e5dd7070Spatrick void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
75*12c85518Srobert   AddSkippedRange(Range, SkippedRange::PPIfElse);
76a9ac8606Spatrick }
77a9ac8606Spatrick 
HandleEmptyline(SourceRange Range)78a9ac8606Spatrick void CoverageSourceInfo::HandleEmptyline(SourceRange Range) {
79*12c85518Srobert   AddSkippedRange(Range, SkippedRange::EmptyLine);
80a9ac8606Spatrick }
81a9ac8606Spatrick 
HandleComment(Preprocessor & PP,SourceRange Range)82a9ac8606Spatrick bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) {
83*12c85518Srobert   AddSkippedRange(Range, SkippedRange::Comment);
84a9ac8606Spatrick   return false;
85a9ac8606Spatrick }
86a9ac8606Spatrick 
updateNextTokLoc(SourceLocation Loc)87a9ac8606Spatrick void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
88a9ac8606Spatrick   if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
89a9ac8606Spatrick     SkippedRanges.back().NextTokLoc = Loc;
90e5dd7070Spatrick }
91e5dd7070Spatrick 
92e5dd7070Spatrick namespace {
93e5dd7070Spatrick 
94e5dd7070Spatrick /// A region of source code that can be mapped to a counter.
95e5dd7070Spatrick class SourceMappingRegion {
96a9ac8606Spatrick   /// Primary Counter that is also used for Branch Regions for "True" branches.
97e5dd7070Spatrick   Counter Count;
98e5dd7070Spatrick 
99a9ac8606Spatrick   /// Secondary Counter used for Branch Regions for "False" branches.
100*12c85518Srobert   std::optional<Counter> FalseCount;
101a9ac8606Spatrick 
102e5dd7070Spatrick   /// The region's starting location.
103*12c85518Srobert   std::optional<SourceLocation> LocStart;
104e5dd7070Spatrick 
105e5dd7070Spatrick   /// The region's ending location.
106*12c85518Srobert   std::optional<SourceLocation> LocEnd;
107e5dd7070Spatrick 
108e5dd7070Spatrick   /// Whether this region is a gap region. The count from a gap region is set
109e5dd7070Spatrick   /// as the line execution count if there are no other regions on the line.
110e5dd7070Spatrick   bool GapRegion;
111e5dd7070Spatrick 
112e5dd7070Spatrick public:
SourceMappingRegion(Counter Count,std::optional<SourceLocation> LocStart,std::optional<SourceLocation> LocEnd,bool GapRegion=false)113*12c85518Srobert   SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
114*12c85518Srobert                       std::optional<SourceLocation> LocEnd,
115*12c85518Srobert                       bool GapRegion = false)
116a9ac8606Spatrick       : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
117a9ac8606Spatrick   }
118a9ac8606Spatrick 
SourceMappingRegion(Counter Count,std::optional<Counter> FalseCount,std::optional<SourceLocation> LocStart,std::optional<SourceLocation> LocEnd,bool GapRegion=false)119*12c85518Srobert   SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
120*12c85518Srobert                       std::optional<SourceLocation> LocStart,
121*12c85518Srobert                       std::optional<SourceLocation> LocEnd,
122*12c85518Srobert                       bool GapRegion = false)
123a9ac8606Spatrick       : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
124a9ac8606Spatrick         LocEnd(LocEnd), GapRegion(GapRegion) {}
125e5dd7070Spatrick 
getCounter() const126e5dd7070Spatrick   const Counter &getCounter() const { return Count; }
127e5dd7070Spatrick 
getFalseCounter() const128a9ac8606Spatrick   const Counter &getFalseCounter() const {
129a9ac8606Spatrick     assert(FalseCount && "Region has no alternate counter");
130a9ac8606Spatrick     return *FalseCount;
131a9ac8606Spatrick   }
132a9ac8606Spatrick 
setCounter(Counter C)133e5dd7070Spatrick   void setCounter(Counter C) { Count = C; }
134e5dd7070Spatrick 
hasStartLoc() const135*12c85518Srobert   bool hasStartLoc() const { return LocStart.has_value(); }
136e5dd7070Spatrick 
setStartLoc(SourceLocation Loc)137e5dd7070Spatrick   void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
138e5dd7070Spatrick 
getBeginLoc() const139e5dd7070Spatrick   SourceLocation getBeginLoc() const {
140e5dd7070Spatrick     assert(LocStart && "Region has no start location");
141e5dd7070Spatrick     return *LocStart;
142e5dd7070Spatrick   }
143e5dd7070Spatrick 
hasEndLoc() const144*12c85518Srobert   bool hasEndLoc() const { return LocEnd.has_value(); }
145e5dd7070Spatrick 
setEndLoc(SourceLocation Loc)146e5dd7070Spatrick   void setEndLoc(SourceLocation Loc) {
147e5dd7070Spatrick     assert(Loc.isValid() && "Setting an invalid end location");
148e5dd7070Spatrick     LocEnd = Loc;
149e5dd7070Spatrick   }
150e5dd7070Spatrick 
getEndLoc() const151e5dd7070Spatrick   SourceLocation getEndLoc() const {
152e5dd7070Spatrick     assert(LocEnd && "Region has no end location");
153e5dd7070Spatrick     return *LocEnd;
154e5dd7070Spatrick   }
155e5dd7070Spatrick 
isGap() const156e5dd7070Spatrick   bool isGap() const { return GapRegion; }
157e5dd7070Spatrick 
setGap(bool Gap)158e5dd7070Spatrick   void setGap(bool Gap) { GapRegion = Gap; }
159a9ac8606Spatrick 
isBranch() const160*12c85518Srobert   bool isBranch() const { return FalseCount.has_value(); }
161e5dd7070Spatrick };
162e5dd7070Spatrick 
163e5dd7070Spatrick /// Spelling locations for the start and end of a source region.
164e5dd7070Spatrick struct SpellingRegion {
165e5dd7070Spatrick   /// The line where the region starts.
166e5dd7070Spatrick   unsigned LineStart;
167e5dd7070Spatrick 
168e5dd7070Spatrick   /// The column where the region starts.
169e5dd7070Spatrick   unsigned ColumnStart;
170e5dd7070Spatrick 
171e5dd7070Spatrick   /// The line where the region ends.
172e5dd7070Spatrick   unsigned LineEnd;
173e5dd7070Spatrick 
174e5dd7070Spatrick   /// The column where the region ends.
175e5dd7070Spatrick   unsigned ColumnEnd;
176e5dd7070Spatrick 
SpellingRegion__anond4b6e5a70211::SpellingRegion177e5dd7070Spatrick   SpellingRegion(SourceManager &SM, SourceLocation LocStart,
178e5dd7070Spatrick                  SourceLocation LocEnd) {
179e5dd7070Spatrick     LineStart = SM.getSpellingLineNumber(LocStart);
180e5dd7070Spatrick     ColumnStart = SM.getSpellingColumnNumber(LocStart);
181e5dd7070Spatrick     LineEnd = SM.getSpellingLineNumber(LocEnd);
182e5dd7070Spatrick     ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
183e5dd7070Spatrick   }
184e5dd7070Spatrick 
SpellingRegion__anond4b6e5a70211::SpellingRegion185e5dd7070Spatrick   SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
186e5dd7070Spatrick       : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
187e5dd7070Spatrick 
188e5dd7070Spatrick   /// Check if the start and end locations appear in source order, i.e
189e5dd7070Spatrick   /// top->bottom, left->right.
isInSourceOrder__anond4b6e5a70211::SpellingRegion190e5dd7070Spatrick   bool isInSourceOrder() const {
191e5dd7070Spatrick     return (LineStart < LineEnd) ||
192e5dd7070Spatrick            (LineStart == LineEnd && ColumnStart <= ColumnEnd);
193e5dd7070Spatrick   }
194e5dd7070Spatrick };
195e5dd7070Spatrick 
196e5dd7070Spatrick /// Provides the common functionality for the different
197e5dd7070Spatrick /// coverage mapping region builders.
198e5dd7070Spatrick class CoverageMappingBuilder {
199e5dd7070Spatrick public:
200e5dd7070Spatrick   CoverageMappingModuleGen &CVM;
201e5dd7070Spatrick   SourceManager &SM;
202e5dd7070Spatrick   const LangOptions &LangOpts;
203e5dd7070Spatrick 
204e5dd7070Spatrick private:
205e5dd7070Spatrick   /// Map of clang's FileIDs to IDs used for coverage mapping.
206e5dd7070Spatrick   llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
207e5dd7070Spatrick       FileIDMapping;
208e5dd7070Spatrick 
209e5dd7070Spatrick public:
210e5dd7070Spatrick   /// The coverage mapping regions for this function
211e5dd7070Spatrick   llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
212e5dd7070Spatrick   /// The source mapping regions for this function.
213e5dd7070Spatrick   std::vector<SourceMappingRegion> SourceRegions;
214e5dd7070Spatrick 
215e5dd7070Spatrick   /// A set of regions which can be used as a filter.
216e5dd7070Spatrick   ///
217e5dd7070Spatrick   /// It is produced by emitExpansionRegions() and is used in
218e5dd7070Spatrick   /// emitSourceRegions() to suppress producing code regions if
219e5dd7070Spatrick   /// the same area is covered by expansion regions.
220e5dd7070Spatrick   typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
221e5dd7070Spatrick       SourceRegionFilter;
222e5dd7070Spatrick 
CoverageMappingBuilder(CoverageMappingModuleGen & CVM,SourceManager & SM,const LangOptions & LangOpts)223e5dd7070Spatrick   CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
224e5dd7070Spatrick                          const LangOptions &LangOpts)
225e5dd7070Spatrick       : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
226e5dd7070Spatrick 
227e5dd7070Spatrick   /// Return the precise end location for the given token.
getPreciseTokenLocEnd(SourceLocation Loc)228e5dd7070Spatrick   SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
229e5dd7070Spatrick     // We avoid getLocForEndOfToken here, because it doesn't do what we want for
230e5dd7070Spatrick     // macro locations, which we just treat as expanded files.
231e5dd7070Spatrick     unsigned TokLen =
232e5dd7070Spatrick         Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
233e5dd7070Spatrick     return Loc.getLocWithOffset(TokLen);
234e5dd7070Spatrick   }
235e5dd7070Spatrick 
236e5dd7070Spatrick   /// Return the start location of an included file or expanded macro.
getStartOfFileOrMacro(SourceLocation Loc)237e5dd7070Spatrick   SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
238e5dd7070Spatrick     if (Loc.isMacroID())
239e5dd7070Spatrick       return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
240e5dd7070Spatrick     return SM.getLocForStartOfFile(SM.getFileID(Loc));
241e5dd7070Spatrick   }
242e5dd7070Spatrick 
243e5dd7070Spatrick   /// Return the end location of an included file or expanded macro.
getEndOfFileOrMacro(SourceLocation Loc)244e5dd7070Spatrick   SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
245e5dd7070Spatrick     if (Loc.isMacroID())
246e5dd7070Spatrick       return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
247e5dd7070Spatrick                                   SM.getFileOffset(Loc));
248e5dd7070Spatrick     return SM.getLocForEndOfFile(SM.getFileID(Loc));
249e5dd7070Spatrick   }
250e5dd7070Spatrick 
251e5dd7070Spatrick   /// Find out where the current file is included or macro is expanded.
getIncludeOrExpansionLoc(SourceLocation Loc)252e5dd7070Spatrick   SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
253e5dd7070Spatrick     return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
254e5dd7070Spatrick                            : SM.getIncludeLoc(SM.getFileID(Loc));
255e5dd7070Spatrick   }
256e5dd7070Spatrick 
257e5dd7070Spatrick   /// Return true if \c Loc is a location in a built-in macro.
isInBuiltin(SourceLocation Loc)258e5dd7070Spatrick   bool isInBuiltin(SourceLocation Loc) {
259e5dd7070Spatrick     return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
260e5dd7070Spatrick   }
261e5dd7070Spatrick 
262e5dd7070Spatrick   /// Check whether \c Loc is included or expanded from \c Parent.
isNestedIn(SourceLocation Loc,FileID Parent)263e5dd7070Spatrick   bool isNestedIn(SourceLocation Loc, FileID Parent) {
264e5dd7070Spatrick     do {
265e5dd7070Spatrick       Loc = getIncludeOrExpansionLoc(Loc);
266e5dd7070Spatrick       if (Loc.isInvalid())
267e5dd7070Spatrick         return false;
268e5dd7070Spatrick     } while (!SM.isInFileID(Loc, Parent));
269e5dd7070Spatrick     return true;
270e5dd7070Spatrick   }
271e5dd7070Spatrick 
272e5dd7070Spatrick   /// Get the start of \c S ignoring macro arguments and builtin macros.
getStart(const Stmt * S)273e5dd7070Spatrick   SourceLocation getStart(const Stmt *S) {
274e5dd7070Spatrick     SourceLocation Loc = S->getBeginLoc();
275e5dd7070Spatrick     while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
276e5dd7070Spatrick       Loc = SM.getImmediateExpansionRange(Loc).getBegin();
277e5dd7070Spatrick     return Loc;
278e5dd7070Spatrick   }
279e5dd7070Spatrick 
280e5dd7070Spatrick   /// Get the end of \c S ignoring macro arguments and builtin macros.
getEnd(const Stmt * S)281e5dd7070Spatrick   SourceLocation getEnd(const Stmt *S) {
282e5dd7070Spatrick     SourceLocation Loc = S->getEndLoc();
283e5dd7070Spatrick     while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
284e5dd7070Spatrick       Loc = SM.getImmediateExpansionRange(Loc).getBegin();
285e5dd7070Spatrick     return getPreciseTokenLocEnd(Loc);
286e5dd7070Spatrick   }
287e5dd7070Spatrick 
288e5dd7070Spatrick   /// Find the set of files we have regions for and assign IDs
289e5dd7070Spatrick   ///
290e5dd7070Spatrick   /// Fills \c Mapping with the virtual file mapping needed to write out
291e5dd7070Spatrick   /// coverage and collects the necessary file information to emit source and
292e5dd7070Spatrick   /// expansion regions.
gatherFileIDs(SmallVectorImpl<unsigned> & Mapping)293e5dd7070Spatrick   void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
294e5dd7070Spatrick     FileIDMapping.clear();
295e5dd7070Spatrick 
296e5dd7070Spatrick     llvm::SmallSet<FileID, 8> Visited;
297e5dd7070Spatrick     SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
298e5dd7070Spatrick     for (const auto &Region : SourceRegions) {
299e5dd7070Spatrick       SourceLocation Loc = Region.getBeginLoc();
300e5dd7070Spatrick       FileID File = SM.getFileID(Loc);
301e5dd7070Spatrick       if (!Visited.insert(File).second)
302e5dd7070Spatrick         continue;
303e5dd7070Spatrick 
304e5dd7070Spatrick       // Do not map FileID's associated with system headers.
305e5dd7070Spatrick       if (SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
306e5dd7070Spatrick         continue;
307e5dd7070Spatrick 
308e5dd7070Spatrick       unsigned Depth = 0;
309e5dd7070Spatrick       for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
310e5dd7070Spatrick            Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
311e5dd7070Spatrick         ++Depth;
312e5dd7070Spatrick       FileLocs.push_back(std::make_pair(Loc, Depth));
313e5dd7070Spatrick     }
314e5dd7070Spatrick     llvm::stable_sort(FileLocs, llvm::less_second());
315e5dd7070Spatrick 
316e5dd7070Spatrick     for (const auto &FL : FileLocs) {
317e5dd7070Spatrick       SourceLocation Loc = FL.first;
318e5dd7070Spatrick       FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
319e5dd7070Spatrick       auto Entry = SM.getFileEntryForID(SpellingFile);
320e5dd7070Spatrick       if (!Entry)
321e5dd7070Spatrick         continue;
322e5dd7070Spatrick 
323e5dd7070Spatrick       FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
324e5dd7070Spatrick       Mapping.push_back(CVM.getFileID(Entry));
325e5dd7070Spatrick     }
326e5dd7070Spatrick   }
327e5dd7070Spatrick 
328e5dd7070Spatrick   /// Get the coverage mapping file ID for \c Loc.
329e5dd7070Spatrick   ///
330*12c85518Srobert   /// If such file id doesn't exist, return std::nullopt.
getCoverageFileID(SourceLocation Loc)331*12c85518Srobert   std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
332e5dd7070Spatrick     auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
333e5dd7070Spatrick     if (Mapping != FileIDMapping.end())
334e5dd7070Spatrick       return Mapping->second.first;
335*12c85518Srobert     return std::nullopt;
336e5dd7070Spatrick   }
337e5dd7070Spatrick 
338a9ac8606Spatrick   /// This shrinks the skipped range if it spans a line that contains a
339a9ac8606Spatrick   /// non-comment token. If shrinking the skipped range would make it empty,
340*12c85518Srobert   /// this returns std::nullopt.
341*12c85518Srobert   /// Note this function can potentially be expensive because
342*12c85518Srobert   /// getSpellingLineNumber uses getLineNumber, which is expensive.
adjustSkippedRange(SourceManager & SM,SourceLocation LocStart,SourceLocation LocEnd,SourceLocation PrevTokLoc,SourceLocation NextTokLoc)343*12c85518Srobert   std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
344a9ac8606Spatrick                                                    SourceLocation LocStart,
345a9ac8606Spatrick                                                    SourceLocation LocEnd,
346a9ac8606Spatrick                                                    SourceLocation PrevTokLoc,
347a9ac8606Spatrick                                                    SourceLocation NextTokLoc) {
348a9ac8606Spatrick     SpellingRegion SR{SM, LocStart, LocEnd};
349a9ac8606Spatrick     SR.ColumnStart = 1;
350a9ac8606Spatrick     if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
351a9ac8606Spatrick         SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
352a9ac8606Spatrick       SR.LineStart++;
353a9ac8606Spatrick     if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
354a9ac8606Spatrick         SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
355a9ac8606Spatrick       SR.LineEnd--;
356a9ac8606Spatrick       SR.ColumnEnd++;
357a9ac8606Spatrick     }
358a9ac8606Spatrick     if (SR.isInSourceOrder())
359a9ac8606Spatrick       return SR;
360*12c85518Srobert     return std::nullopt;
361a9ac8606Spatrick   }
362a9ac8606Spatrick 
363e5dd7070Spatrick   /// Gather all the regions that were skipped by the preprocessor
364a9ac8606Spatrick   /// using the constructs like #if or comments.
gatherSkippedRegions()365e5dd7070Spatrick   void gatherSkippedRegions() {
366e5dd7070Spatrick     /// An array of the minimum lineStarts and the maximum lineEnds
367e5dd7070Spatrick     /// for mapping regions from the appropriate source files.
368e5dd7070Spatrick     llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
369e5dd7070Spatrick     FileLineRanges.resize(
370e5dd7070Spatrick         FileIDMapping.size(),
371e5dd7070Spatrick         std::make_pair(std::numeric_limits<unsigned>::max(), 0));
372e5dd7070Spatrick     for (const auto &R : MappingRegions) {
373e5dd7070Spatrick       FileLineRanges[R.FileID].first =
374e5dd7070Spatrick           std::min(FileLineRanges[R.FileID].first, R.LineStart);
375e5dd7070Spatrick       FileLineRanges[R.FileID].second =
376e5dd7070Spatrick           std::max(FileLineRanges[R.FileID].second, R.LineEnd);
377e5dd7070Spatrick     }
378e5dd7070Spatrick 
379e5dd7070Spatrick     auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
380a9ac8606Spatrick     for (auto &I : SkippedRanges) {
381a9ac8606Spatrick       SourceRange Range = I.Range;
382a9ac8606Spatrick       auto LocStart = Range.getBegin();
383a9ac8606Spatrick       auto LocEnd = Range.getEnd();
384e5dd7070Spatrick       assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
385e5dd7070Spatrick              "region spans multiple files");
386e5dd7070Spatrick 
387e5dd7070Spatrick       auto CovFileID = getCoverageFileID(LocStart);
388e5dd7070Spatrick       if (!CovFileID)
389e5dd7070Spatrick         continue;
390*12c85518Srobert       std::optional<SpellingRegion> SR;
391*12c85518Srobert       if (I.isComment())
392*12c85518Srobert         SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
393*12c85518Srobert                                 I.NextTokLoc);
394*12c85518Srobert       else if (I.isPPIfElse() || I.isEmptyLine())
395*12c85518Srobert         SR = {SM, LocStart, LocEnd};
396*12c85518Srobert 
397*12c85518Srobert       if (!SR)
398a9ac8606Spatrick         continue;
399e5dd7070Spatrick       auto Region = CounterMappingRegion::makeSkipped(
400a9ac8606Spatrick           *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
401a9ac8606Spatrick           SR->ColumnEnd);
402e5dd7070Spatrick       // Make sure that we only collect the regions that are inside
403e5dd7070Spatrick       // the source code of this function.
404e5dd7070Spatrick       if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
405e5dd7070Spatrick           Region.LineEnd <= FileLineRanges[*CovFileID].second)
406e5dd7070Spatrick         MappingRegions.push_back(Region);
407e5dd7070Spatrick     }
408e5dd7070Spatrick   }
409e5dd7070Spatrick 
410e5dd7070Spatrick   /// Generate the coverage counter mapping regions from collected
411e5dd7070Spatrick   /// source regions.
emitSourceRegions(const SourceRegionFilter & Filter)412e5dd7070Spatrick   void emitSourceRegions(const SourceRegionFilter &Filter) {
413e5dd7070Spatrick     for (const auto &Region : SourceRegions) {
414e5dd7070Spatrick       assert(Region.hasEndLoc() && "incomplete region");
415e5dd7070Spatrick 
416e5dd7070Spatrick       SourceLocation LocStart = Region.getBeginLoc();
417e5dd7070Spatrick       assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
418e5dd7070Spatrick 
419e5dd7070Spatrick       // Ignore regions from system headers.
420e5dd7070Spatrick       if (SM.isInSystemHeader(SM.getSpellingLoc(LocStart)))
421e5dd7070Spatrick         continue;
422e5dd7070Spatrick 
423e5dd7070Spatrick       auto CovFileID = getCoverageFileID(LocStart);
424e5dd7070Spatrick       // Ignore regions that don't have a file, such as builtin macros.
425e5dd7070Spatrick       if (!CovFileID)
426e5dd7070Spatrick         continue;
427e5dd7070Spatrick 
428e5dd7070Spatrick       SourceLocation LocEnd = Region.getEndLoc();
429e5dd7070Spatrick       assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
430e5dd7070Spatrick              "region spans multiple files");
431e5dd7070Spatrick 
432e5dd7070Spatrick       // Don't add code regions for the area covered by expansion regions.
433e5dd7070Spatrick       // This not only suppresses redundant regions, but sometimes prevents
434e5dd7070Spatrick       // creating regions with wrong counters if, for example, a statement's
435e5dd7070Spatrick       // body ends at the end of a nested macro.
436e5dd7070Spatrick       if (Filter.count(std::make_pair(LocStart, LocEnd)))
437e5dd7070Spatrick         continue;
438e5dd7070Spatrick 
439e5dd7070Spatrick       // Find the spelling locations for the mapping region.
440e5dd7070Spatrick       SpellingRegion SR{SM, LocStart, LocEnd};
441e5dd7070Spatrick       assert(SR.isInSourceOrder() && "region start and end out of order");
442e5dd7070Spatrick 
443e5dd7070Spatrick       if (Region.isGap()) {
444e5dd7070Spatrick         MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
445e5dd7070Spatrick             Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
446e5dd7070Spatrick             SR.LineEnd, SR.ColumnEnd));
447a9ac8606Spatrick       } else if (Region.isBranch()) {
448a9ac8606Spatrick         MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
449a9ac8606Spatrick             Region.getCounter(), Region.getFalseCounter(), *CovFileID,
450a9ac8606Spatrick             SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
451e5dd7070Spatrick       } else {
452e5dd7070Spatrick         MappingRegions.push_back(CounterMappingRegion::makeRegion(
453e5dd7070Spatrick             Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
454e5dd7070Spatrick             SR.LineEnd, SR.ColumnEnd));
455e5dd7070Spatrick       }
456e5dd7070Spatrick     }
457e5dd7070Spatrick   }
458e5dd7070Spatrick 
459e5dd7070Spatrick   /// Generate expansion regions for each virtual file we've seen.
emitExpansionRegions()460e5dd7070Spatrick   SourceRegionFilter emitExpansionRegions() {
461e5dd7070Spatrick     SourceRegionFilter Filter;
462e5dd7070Spatrick     for (const auto &FM : FileIDMapping) {
463e5dd7070Spatrick       SourceLocation ExpandedLoc = FM.second.second;
464e5dd7070Spatrick       SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
465e5dd7070Spatrick       if (ParentLoc.isInvalid())
466e5dd7070Spatrick         continue;
467e5dd7070Spatrick 
468e5dd7070Spatrick       auto ParentFileID = getCoverageFileID(ParentLoc);
469e5dd7070Spatrick       if (!ParentFileID)
470e5dd7070Spatrick         continue;
471e5dd7070Spatrick       auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
472e5dd7070Spatrick       assert(ExpandedFileID && "expansion in uncovered file");
473e5dd7070Spatrick 
474e5dd7070Spatrick       SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
475e5dd7070Spatrick       assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
476e5dd7070Spatrick              "region spans multiple files");
477e5dd7070Spatrick       Filter.insert(std::make_pair(ParentLoc, LocEnd));
478e5dd7070Spatrick 
479e5dd7070Spatrick       SpellingRegion SR{SM, ParentLoc, LocEnd};
480e5dd7070Spatrick       assert(SR.isInSourceOrder() && "region start and end out of order");
481e5dd7070Spatrick       MappingRegions.push_back(CounterMappingRegion::makeExpansion(
482e5dd7070Spatrick           *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
483e5dd7070Spatrick           SR.LineEnd, SR.ColumnEnd));
484e5dd7070Spatrick     }
485e5dd7070Spatrick     return Filter;
486e5dd7070Spatrick   }
487e5dd7070Spatrick };
488e5dd7070Spatrick 
489e5dd7070Spatrick /// Creates unreachable coverage regions for the functions that
490e5dd7070Spatrick /// are not emitted.
491e5dd7070Spatrick struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
EmptyCoverageMappingBuilder__anond4b6e5a70211::EmptyCoverageMappingBuilder492e5dd7070Spatrick   EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
493e5dd7070Spatrick                               const LangOptions &LangOpts)
494e5dd7070Spatrick       : CoverageMappingBuilder(CVM, SM, LangOpts) {}
495e5dd7070Spatrick 
VisitDecl__anond4b6e5a70211::EmptyCoverageMappingBuilder496e5dd7070Spatrick   void VisitDecl(const Decl *D) {
497e5dd7070Spatrick     if (!D->hasBody())
498e5dd7070Spatrick       return;
499e5dd7070Spatrick     auto Body = D->getBody();
500e5dd7070Spatrick     SourceLocation Start = getStart(Body);
501e5dd7070Spatrick     SourceLocation End = getEnd(Body);
502e5dd7070Spatrick     if (!SM.isWrittenInSameFile(Start, End)) {
503e5dd7070Spatrick       // Walk up to find the common ancestor.
504e5dd7070Spatrick       // Correct the locations accordingly.
505e5dd7070Spatrick       FileID StartFileID = SM.getFileID(Start);
506e5dd7070Spatrick       FileID EndFileID = SM.getFileID(End);
507e5dd7070Spatrick       while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
508e5dd7070Spatrick         Start = getIncludeOrExpansionLoc(Start);
509e5dd7070Spatrick         assert(Start.isValid() &&
510e5dd7070Spatrick                "Declaration start location not nested within a known region");
511e5dd7070Spatrick         StartFileID = SM.getFileID(Start);
512e5dd7070Spatrick       }
513e5dd7070Spatrick       while (StartFileID != EndFileID) {
514e5dd7070Spatrick         End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
515e5dd7070Spatrick         assert(End.isValid() &&
516e5dd7070Spatrick                "Declaration end location not nested within a known region");
517e5dd7070Spatrick         EndFileID = SM.getFileID(End);
518e5dd7070Spatrick       }
519e5dd7070Spatrick     }
520e5dd7070Spatrick     SourceRegions.emplace_back(Counter(), Start, End);
521e5dd7070Spatrick   }
522e5dd7070Spatrick 
523e5dd7070Spatrick   /// Write the mapping data to the output stream
write__anond4b6e5a70211::EmptyCoverageMappingBuilder524e5dd7070Spatrick   void write(llvm::raw_ostream &OS) {
525e5dd7070Spatrick     SmallVector<unsigned, 16> FileIDMapping;
526e5dd7070Spatrick     gatherFileIDs(FileIDMapping);
527e5dd7070Spatrick     emitSourceRegions(SourceRegionFilter());
528e5dd7070Spatrick 
529e5dd7070Spatrick     if (MappingRegions.empty())
530e5dd7070Spatrick       return;
531e5dd7070Spatrick 
532*12c85518Srobert     CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions);
533e5dd7070Spatrick     Writer.write(OS);
534e5dd7070Spatrick   }
535e5dd7070Spatrick };
536e5dd7070Spatrick 
537e5dd7070Spatrick /// A StmtVisitor that creates coverage mapping regions which map
538e5dd7070Spatrick /// from the source code locations to the PGO counters.
539e5dd7070Spatrick struct CounterCoverageMappingBuilder
540e5dd7070Spatrick     : public CoverageMappingBuilder,
541e5dd7070Spatrick       public ConstStmtVisitor<CounterCoverageMappingBuilder> {
542e5dd7070Spatrick   /// The map of statements to count values.
543e5dd7070Spatrick   llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
544e5dd7070Spatrick 
545e5dd7070Spatrick   /// A stack of currently live regions.
546e5dd7070Spatrick   std::vector<SourceMappingRegion> RegionStack;
547e5dd7070Spatrick 
548e5dd7070Spatrick   CounterExpressionBuilder Builder;
549e5dd7070Spatrick 
550e5dd7070Spatrick   /// A location in the most recently visited file or macro.
551e5dd7070Spatrick   ///
552e5dd7070Spatrick   /// This is used to adjust the active source regions appropriately when
553e5dd7070Spatrick   /// expressions cross file or macro boundaries.
554e5dd7070Spatrick   SourceLocation MostRecentLocation;
555e5dd7070Spatrick 
556a9ac8606Spatrick   /// Whether the visitor at a terminate statement.
557a9ac8606Spatrick   bool HasTerminateStmt = false;
558a9ac8606Spatrick 
559a9ac8606Spatrick   /// Gap region counter after terminate statement.
560a9ac8606Spatrick   Counter GapRegionCounter;
561e5dd7070Spatrick 
562e5dd7070Spatrick   /// Return a counter for the subtraction of \c RHS from \c LHS
subtractCounters__anond4b6e5a70211::CounterCoverageMappingBuilder563*12c85518Srobert   Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) {
564*12c85518Srobert     return Builder.subtract(LHS, RHS, Simplify);
565e5dd7070Spatrick   }
566e5dd7070Spatrick 
567e5dd7070Spatrick   /// Return a counter for the sum of \c LHS and \c RHS.
addCounters__anond4b6e5a70211::CounterCoverageMappingBuilder568*12c85518Srobert   Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
569*12c85518Srobert     return Builder.add(LHS, RHS, Simplify);
570e5dd7070Spatrick   }
571e5dd7070Spatrick 
addCounters__anond4b6e5a70211::CounterCoverageMappingBuilder572*12c85518Srobert   Counter addCounters(Counter C1, Counter C2, Counter C3,
573*12c85518Srobert                       bool Simplify = true) {
574*12c85518Srobert     return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
575e5dd7070Spatrick   }
576e5dd7070Spatrick 
577e5dd7070Spatrick   /// Return the region counter for the given statement.
578e5dd7070Spatrick   ///
579e5dd7070Spatrick   /// This should only be called on statements that have a dedicated counter.
getRegionCounter__anond4b6e5a70211::CounterCoverageMappingBuilder580e5dd7070Spatrick   Counter getRegionCounter(const Stmt *S) {
581e5dd7070Spatrick     return Counter::getCounter(CounterMap[S]);
582e5dd7070Spatrick   }
583e5dd7070Spatrick 
584e5dd7070Spatrick   /// Push a region onto the stack.
585e5dd7070Spatrick   ///
586e5dd7070Spatrick   /// Returns the index on the stack where the region was pushed. This can be
587e5dd7070Spatrick   /// used with popRegions to exit a "scope", ending the region that was pushed.
pushRegion__anond4b6e5a70211::CounterCoverageMappingBuilder588*12c85518Srobert   size_t pushRegion(Counter Count,
589*12c85518Srobert                     std::optional<SourceLocation> StartLoc = std::nullopt,
590*12c85518Srobert                     std::optional<SourceLocation> EndLoc = std::nullopt,
591*12c85518Srobert                     std::optional<Counter> FalseCount = std::nullopt) {
592a9ac8606Spatrick 
593*12c85518Srobert     if (StartLoc && !FalseCount) {
594e5dd7070Spatrick       MostRecentLocation = *StartLoc;
595e5dd7070Spatrick     }
596a9ac8606Spatrick 
597a9ac8606Spatrick     RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
598e5dd7070Spatrick 
599e5dd7070Spatrick     return RegionStack.size() - 1;
600e5dd7070Spatrick   }
601e5dd7070Spatrick 
locationDepth__anond4b6e5a70211::CounterCoverageMappingBuilder602e5dd7070Spatrick   size_t locationDepth(SourceLocation Loc) {
603e5dd7070Spatrick     size_t Depth = 0;
604e5dd7070Spatrick     while (Loc.isValid()) {
605e5dd7070Spatrick       Loc = getIncludeOrExpansionLoc(Loc);
606e5dd7070Spatrick       Depth++;
607e5dd7070Spatrick     }
608e5dd7070Spatrick     return Depth;
609e5dd7070Spatrick   }
610e5dd7070Spatrick 
611e5dd7070Spatrick   /// Pop regions from the stack into the function's list of regions.
612e5dd7070Spatrick   ///
613e5dd7070Spatrick   /// Adds all regions from \c ParentIndex to the top of the stack to the
614e5dd7070Spatrick   /// function's \c SourceRegions.
popRegions__anond4b6e5a70211::CounterCoverageMappingBuilder615e5dd7070Spatrick   void popRegions(size_t ParentIndex) {
616e5dd7070Spatrick     assert(RegionStack.size() >= ParentIndex && "parent not in stack");
617e5dd7070Spatrick     while (RegionStack.size() > ParentIndex) {
618e5dd7070Spatrick       SourceMappingRegion &Region = RegionStack.back();
619e5dd7070Spatrick       if (Region.hasStartLoc()) {
620e5dd7070Spatrick         SourceLocation StartLoc = Region.getBeginLoc();
621e5dd7070Spatrick         SourceLocation EndLoc = Region.hasEndLoc()
622e5dd7070Spatrick                                     ? Region.getEndLoc()
623e5dd7070Spatrick                                     : RegionStack[ParentIndex].getEndLoc();
624a9ac8606Spatrick         bool isBranch = Region.isBranch();
625e5dd7070Spatrick         size_t StartDepth = locationDepth(StartLoc);
626e5dd7070Spatrick         size_t EndDepth = locationDepth(EndLoc);
627e5dd7070Spatrick         while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
628e5dd7070Spatrick           bool UnnestStart = StartDepth >= EndDepth;
629e5dd7070Spatrick           bool UnnestEnd = EndDepth >= StartDepth;
630e5dd7070Spatrick           if (UnnestEnd) {
631a9ac8606Spatrick             // The region ends in a nested file or macro expansion. If the
632a9ac8606Spatrick             // region is not a branch region, create a separate region for each
633a9ac8606Spatrick             // expansion, and for all regions, update the EndLoc. Branch
634a9ac8606Spatrick             // regions should not be split in order to keep a straightforward
635a9ac8606Spatrick             // correspondance between the region and its associated branch
636a9ac8606Spatrick             // condition, even if the condition spans multiple depths.
637e5dd7070Spatrick             SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
638e5dd7070Spatrick             assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
639e5dd7070Spatrick 
640a9ac8606Spatrick             if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
641a9ac8606Spatrick               SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
642a9ac8606Spatrick                                          EndLoc);
643e5dd7070Spatrick 
644e5dd7070Spatrick             EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
645e5dd7070Spatrick             if (EndLoc.isInvalid())
646a9ac8606Spatrick               llvm::report_fatal_error(
647a9ac8606Spatrick                   "File exit not handled before popRegions");
648e5dd7070Spatrick             EndDepth--;
649e5dd7070Spatrick           }
650e5dd7070Spatrick           if (UnnestStart) {
651a9ac8606Spatrick             // The region ends in a nested file or macro expansion. If the
652a9ac8606Spatrick             // region is not a branch region, create a separate region for each
653a9ac8606Spatrick             // expansion, and for all regions, update the StartLoc. Branch
654a9ac8606Spatrick             // regions should not be split in order to keep a straightforward
655a9ac8606Spatrick             // correspondance between the region and its associated branch
656a9ac8606Spatrick             // condition, even if the condition spans multiple depths.
657e5dd7070Spatrick             SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
658e5dd7070Spatrick             assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
659e5dd7070Spatrick 
660a9ac8606Spatrick             if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
661a9ac8606Spatrick               SourceRegions.emplace_back(Region.getCounter(), StartLoc,
662a9ac8606Spatrick                                          NestedLoc);
663e5dd7070Spatrick 
664e5dd7070Spatrick             StartLoc = getIncludeOrExpansionLoc(StartLoc);
665e5dd7070Spatrick             if (StartLoc.isInvalid())
666a9ac8606Spatrick               llvm::report_fatal_error(
667a9ac8606Spatrick                   "File exit not handled before popRegions");
668e5dd7070Spatrick             StartDepth--;
669e5dd7070Spatrick           }
670e5dd7070Spatrick         }
671e5dd7070Spatrick         Region.setStartLoc(StartLoc);
672e5dd7070Spatrick         Region.setEndLoc(EndLoc);
673e5dd7070Spatrick 
674a9ac8606Spatrick         if (!isBranch) {
675e5dd7070Spatrick           MostRecentLocation = EndLoc;
676a9ac8606Spatrick           // If this region happens to span an entire expansion, we need to
677a9ac8606Spatrick           // make sure we don't overlap the parent region with it.
678e5dd7070Spatrick           if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
679e5dd7070Spatrick               EndLoc == getEndOfFileOrMacro(EndLoc))
680e5dd7070Spatrick             MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
681a9ac8606Spatrick         }
682e5dd7070Spatrick 
683e5dd7070Spatrick         assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
684e5dd7070Spatrick         assert(SpellingRegion(SM, Region).isInSourceOrder());
685e5dd7070Spatrick         SourceRegions.push_back(Region);
686e5dd7070Spatrick         }
687e5dd7070Spatrick       RegionStack.pop_back();
688e5dd7070Spatrick     }
689e5dd7070Spatrick   }
690e5dd7070Spatrick 
691e5dd7070Spatrick   /// Return the currently active region.
getRegion__anond4b6e5a70211::CounterCoverageMappingBuilder692e5dd7070Spatrick   SourceMappingRegion &getRegion() {
693e5dd7070Spatrick     assert(!RegionStack.empty() && "statement has no region");
694e5dd7070Spatrick     return RegionStack.back();
695e5dd7070Spatrick   }
696e5dd7070Spatrick 
697e5dd7070Spatrick   /// Propagate counts through the children of \p S if \p VisitChildren is true.
698e5dd7070Spatrick   /// Otherwise, only emit a count for \p S itself.
propagateCounts__anond4b6e5a70211::CounterCoverageMappingBuilder699e5dd7070Spatrick   Counter propagateCounts(Counter TopCount, const Stmt *S,
700e5dd7070Spatrick                           bool VisitChildren = true) {
701e5dd7070Spatrick     SourceLocation StartLoc = getStart(S);
702e5dd7070Spatrick     SourceLocation EndLoc = getEnd(S);
703e5dd7070Spatrick     size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
704e5dd7070Spatrick     if (VisitChildren)
705e5dd7070Spatrick       Visit(S);
706e5dd7070Spatrick     Counter ExitCount = getRegion().getCounter();
707e5dd7070Spatrick     popRegions(Index);
708e5dd7070Spatrick 
709e5dd7070Spatrick     // The statement may be spanned by an expansion. Make sure we handle a file
710e5dd7070Spatrick     // exit out of this expansion before moving to the next statement.
711e5dd7070Spatrick     if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
712e5dd7070Spatrick       MostRecentLocation = EndLoc;
713e5dd7070Spatrick 
714e5dd7070Spatrick     return ExitCount;
715e5dd7070Spatrick   }
716e5dd7070Spatrick 
717a9ac8606Spatrick   /// Determine whether the given condition can be constant folded.
ConditionFoldsToBool__anond4b6e5a70211::CounterCoverageMappingBuilder718a9ac8606Spatrick   bool ConditionFoldsToBool(const Expr *Cond) {
719a9ac8606Spatrick     Expr::EvalResult Result;
720a9ac8606Spatrick     return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext()));
721a9ac8606Spatrick   }
722a9ac8606Spatrick 
723a9ac8606Spatrick   /// Create a Branch Region around an instrumentable condition for coverage
724a9ac8606Spatrick   /// and add it to the function's SourceRegions.  A branch region tracks a
725a9ac8606Spatrick   /// "True" counter and a "False" counter for boolean expressions that
726a9ac8606Spatrick   /// result in the generation of a branch.
createBranchRegion__anond4b6e5a70211::CounterCoverageMappingBuilder727a9ac8606Spatrick   void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt) {
728a9ac8606Spatrick     // Check for NULL conditions.
729a9ac8606Spatrick     if (!C)
730a9ac8606Spatrick       return;
731a9ac8606Spatrick 
732a9ac8606Spatrick     // Ensure we are an instrumentable condition (i.e. no "&&" or "||").  Push
733a9ac8606Spatrick     // region onto RegionStack but immediately pop it (which adds it to the
734a9ac8606Spatrick     // function's SourceRegions) because it doesn't apply to any other source
735a9ac8606Spatrick     // code other than the Condition.
736a9ac8606Spatrick     if (CodeGenFunction::isInstrumentedCondition(C)) {
737a9ac8606Spatrick       // If a condition can fold to true or false, the corresponding branch
738a9ac8606Spatrick       // will be removed.  Create a region with both counters hard-coded to
739a9ac8606Spatrick       // zero. This allows us to visualize them in a special way.
740a9ac8606Spatrick       // Alternatively, we can prevent any optimization done via
741a9ac8606Spatrick       // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
742a9ac8606Spatrick       // CodeGenFunction.c always returns false, but that is very heavy-handed.
743a9ac8606Spatrick       if (ConditionFoldsToBool(C))
744a9ac8606Spatrick         popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
745a9ac8606Spatrick                               Counter::getZero()));
746a9ac8606Spatrick       else
747a9ac8606Spatrick         // Otherwise, create a region with the True counter and False counter.
748a9ac8606Spatrick         popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
749a9ac8606Spatrick     }
750a9ac8606Spatrick   }
751a9ac8606Spatrick 
752a9ac8606Spatrick   /// Create a Branch Region around a SwitchCase for code coverage
753a9ac8606Spatrick   /// and add it to the function's SourceRegions.
createSwitchCaseRegion__anond4b6e5a70211::CounterCoverageMappingBuilder754a9ac8606Spatrick   void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
755a9ac8606Spatrick                               Counter FalseCnt) {
756a9ac8606Spatrick     // Push region onto RegionStack but immediately pop it (which adds it to
757a9ac8606Spatrick     // the function's SourceRegions) because it doesn't apply to any other
758a9ac8606Spatrick     // source other than the SwitchCase.
759a9ac8606Spatrick     popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
760a9ac8606Spatrick   }
761a9ac8606Spatrick 
762e5dd7070Spatrick   /// Check whether a region with bounds \c StartLoc and \c EndLoc
763e5dd7070Spatrick   /// is already added to \c SourceRegions.
isRegionAlreadyAdded__anond4b6e5a70211::CounterCoverageMappingBuilder764a9ac8606Spatrick   bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
765a9ac8606Spatrick                             bool isBranch = false) {
766*12c85518Srobert     return llvm::any_of(
767*12c85518Srobert         llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) {
768e5dd7070Spatrick           return Region.getBeginLoc() == StartLoc &&
769*12c85518Srobert                  Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
770e5dd7070Spatrick         });
771e5dd7070Spatrick   }
772e5dd7070Spatrick 
773e5dd7070Spatrick   /// Adjust the most recently visited location to \c EndLoc.
774e5dd7070Spatrick   ///
775e5dd7070Spatrick   /// This should be used after visiting any statements in non-source order.
adjustForOutOfOrderTraversal__anond4b6e5a70211::CounterCoverageMappingBuilder776e5dd7070Spatrick   void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
777e5dd7070Spatrick     MostRecentLocation = EndLoc;
778e5dd7070Spatrick     // The code region for a whole macro is created in handleFileExit() when
779e5dd7070Spatrick     // it detects exiting of the virtual file of that macro. If we visited
780e5dd7070Spatrick     // statements in non-source order, we might already have such a region
781e5dd7070Spatrick     // added, for example, if a body of a loop is divided among multiple
782e5dd7070Spatrick     // macros. Avoid adding duplicate regions in such case.
783e5dd7070Spatrick     if (getRegion().hasEndLoc() &&
784e5dd7070Spatrick         MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
785e5dd7070Spatrick         isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
786a9ac8606Spatrick                              MostRecentLocation, getRegion().isBranch()))
787e5dd7070Spatrick       MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
788e5dd7070Spatrick   }
789e5dd7070Spatrick 
790e5dd7070Spatrick   /// Adjust regions and state when \c NewLoc exits a file.
791e5dd7070Spatrick   ///
792e5dd7070Spatrick   /// If moving from our most recently tracked location to \c NewLoc exits any
793e5dd7070Spatrick   /// files, this adjusts our current region stack and creates the file regions
794e5dd7070Spatrick   /// for the exited file.
handleFileExit__anond4b6e5a70211::CounterCoverageMappingBuilder795e5dd7070Spatrick   void handleFileExit(SourceLocation NewLoc) {
796e5dd7070Spatrick     if (NewLoc.isInvalid() ||
797e5dd7070Spatrick         SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
798e5dd7070Spatrick       return;
799e5dd7070Spatrick 
800e5dd7070Spatrick     // If NewLoc is not in a file that contains MostRecentLocation, walk up to
801e5dd7070Spatrick     // find the common ancestor.
802e5dd7070Spatrick     SourceLocation LCA = NewLoc;
803e5dd7070Spatrick     FileID ParentFile = SM.getFileID(LCA);
804e5dd7070Spatrick     while (!isNestedIn(MostRecentLocation, ParentFile)) {
805e5dd7070Spatrick       LCA = getIncludeOrExpansionLoc(LCA);
806e5dd7070Spatrick       if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
807e5dd7070Spatrick         // Since there isn't a common ancestor, no file was exited. We just need
808e5dd7070Spatrick         // to adjust our location to the new file.
809e5dd7070Spatrick         MostRecentLocation = NewLoc;
810e5dd7070Spatrick         return;
811e5dd7070Spatrick       }
812e5dd7070Spatrick       ParentFile = SM.getFileID(LCA);
813e5dd7070Spatrick     }
814e5dd7070Spatrick 
815e5dd7070Spatrick     llvm::SmallSet<SourceLocation, 8> StartLocs;
816*12c85518Srobert     std::optional<Counter> ParentCounter;
817e5dd7070Spatrick     for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
818e5dd7070Spatrick       if (!I.hasStartLoc())
819e5dd7070Spatrick         continue;
820e5dd7070Spatrick       SourceLocation Loc = I.getBeginLoc();
821e5dd7070Spatrick       if (!isNestedIn(Loc, ParentFile)) {
822e5dd7070Spatrick         ParentCounter = I.getCounter();
823e5dd7070Spatrick         break;
824e5dd7070Spatrick       }
825e5dd7070Spatrick 
826e5dd7070Spatrick       while (!SM.isInFileID(Loc, ParentFile)) {
827e5dd7070Spatrick         // The most nested region for each start location is the one with the
828e5dd7070Spatrick         // correct count. We avoid creating redundant regions by stopping once
829e5dd7070Spatrick         // we've seen this region.
830a9ac8606Spatrick         if (StartLocs.insert(Loc).second) {
831a9ac8606Spatrick           if (I.isBranch())
832a9ac8606Spatrick             SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
833a9ac8606Spatrick                                        getEndOfFileOrMacro(Loc), I.isBranch());
834a9ac8606Spatrick           else
835e5dd7070Spatrick             SourceRegions.emplace_back(I.getCounter(), Loc,
836e5dd7070Spatrick                                        getEndOfFileOrMacro(Loc));
837a9ac8606Spatrick         }
838e5dd7070Spatrick         Loc = getIncludeOrExpansionLoc(Loc);
839e5dd7070Spatrick       }
840e5dd7070Spatrick       I.setStartLoc(getPreciseTokenLocEnd(Loc));
841e5dd7070Spatrick     }
842e5dd7070Spatrick 
843e5dd7070Spatrick     if (ParentCounter) {
844e5dd7070Spatrick       // If the file is contained completely by another region and doesn't
845e5dd7070Spatrick       // immediately start its own region, the whole file gets a region
846e5dd7070Spatrick       // corresponding to the parent.
847e5dd7070Spatrick       SourceLocation Loc = MostRecentLocation;
848e5dd7070Spatrick       while (isNestedIn(Loc, ParentFile)) {
849e5dd7070Spatrick         SourceLocation FileStart = getStartOfFileOrMacro(Loc);
850e5dd7070Spatrick         if (StartLocs.insert(FileStart).second) {
851e5dd7070Spatrick           SourceRegions.emplace_back(*ParentCounter, FileStart,
852e5dd7070Spatrick                                      getEndOfFileOrMacro(Loc));
853e5dd7070Spatrick           assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
854e5dd7070Spatrick         }
855e5dd7070Spatrick         Loc = getIncludeOrExpansionLoc(Loc);
856e5dd7070Spatrick       }
857e5dd7070Spatrick     }
858e5dd7070Spatrick 
859e5dd7070Spatrick     MostRecentLocation = NewLoc;
860e5dd7070Spatrick   }
861e5dd7070Spatrick 
862e5dd7070Spatrick   /// Ensure that \c S is included in the current region.
extendRegion__anond4b6e5a70211::CounterCoverageMappingBuilder863e5dd7070Spatrick   void extendRegion(const Stmt *S) {
864e5dd7070Spatrick     SourceMappingRegion &Region = getRegion();
865e5dd7070Spatrick     SourceLocation StartLoc = getStart(S);
866e5dd7070Spatrick 
867e5dd7070Spatrick     handleFileExit(StartLoc);
868e5dd7070Spatrick     if (!Region.hasStartLoc())
869e5dd7070Spatrick       Region.setStartLoc(StartLoc);
870e5dd7070Spatrick   }
871e5dd7070Spatrick 
872e5dd7070Spatrick   /// Mark \c S as a terminator, starting a zero region.
terminateRegion__anond4b6e5a70211::CounterCoverageMappingBuilder873e5dd7070Spatrick   void terminateRegion(const Stmt *S) {
874e5dd7070Spatrick     extendRegion(S);
875e5dd7070Spatrick     SourceMappingRegion &Region = getRegion();
876e5dd7070Spatrick     SourceLocation EndLoc = getEnd(S);
877e5dd7070Spatrick     if (!Region.hasEndLoc())
878e5dd7070Spatrick       Region.setEndLoc(EndLoc);
879e5dd7070Spatrick     pushRegion(Counter::getZero());
880a9ac8606Spatrick     HasTerminateStmt = true;
881e5dd7070Spatrick   }
882e5dd7070Spatrick 
883e5dd7070Spatrick   /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
findGapAreaBetween__anond4b6e5a70211::CounterCoverageMappingBuilder884*12c85518Srobert   std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
885e5dd7070Spatrick                                                 SourceLocation BeforeLoc) {
886a9ac8606Spatrick     // If AfterLoc is in function-like macro, use the right parenthesis
887a9ac8606Spatrick     // location.
888a9ac8606Spatrick     if (AfterLoc.isMacroID()) {
889a9ac8606Spatrick       FileID FID = SM.getFileID(AfterLoc);
890a9ac8606Spatrick       const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
891a9ac8606Spatrick       if (EI->isFunctionMacroExpansion())
892a9ac8606Spatrick         AfterLoc = EI->getExpansionLocEnd();
893a9ac8606Spatrick     }
894a9ac8606Spatrick 
895a9ac8606Spatrick     size_t StartDepth = locationDepth(AfterLoc);
896a9ac8606Spatrick     size_t EndDepth = locationDepth(BeforeLoc);
897a9ac8606Spatrick     while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
898a9ac8606Spatrick       bool UnnestStart = StartDepth >= EndDepth;
899a9ac8606Spatrick       bool UnnestEnd = EndDepth >= StartDepth;
900a9ac8606Spatrick       if (UnnestEnd) {
901a9ac8606Spatrick         assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
902a9ac8606Spatrick                                       BeforeLoc));
903a9ac8606Spatrick 
904a9ac8606Spatrick         BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
905a9ac8606Spatrick         assert(BeforeLoc.isValid());
906a9ac8606Spatrick         EndDepth--;
907a9ac8606Spatrick       }
908a9ac8606Spatrick       if (UnnestStart) {
909a9ac8606Spatrick         assert(SM.isWrittenInSameFile(AfterLoc,
910a9ac8606Spatrick                                       getEndOfFileOrMacro(AfterLoc)));
911a9ac8606Spatrick 
912a9ac8606Spatrick         AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
913a9ac8606Spatrick         assert(AfterLoc.isValid());
914a9ac8606Spatrick         AfterLoc = getPreciseTokenLocEnd(AfterLoc);
915a9ac8606Spatrick         assert(AfterLoc.isValid());
916a9ac8606Spatrick         StartDepth--;
917a9ac8606Spatrick       }
918a9ac8606Spatrick     }
919a9ac8606Spatrick     AfterLoc = getPreciseTokenLocEnd(AfterLoc);
920e5dd7070Spatrick     // If the start and end locations of the gap are both within the same macro
921e5dd7070Spatrick     // file, the range may not be in source order.
922e5dd7070Spatrick     if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
923*12c85518Srobert       return std::nullopt;
924a9ac8606Spatrick     if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
925a9ac8606Spatrick         !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
926*12c85518Srobert       return std::nullopt;
927e5dd7070Spatrick     return {{AfterLoc, BeforeLoc}};
928e5dd7070Spatrick   }
929e5dd7070Spatrick 
930e5dd7070Spatrick   /// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
fillGapAreaWithCount__anond4b6e5a70211::CounterCoverageMappingBuilder931e5dd7070Spatrick   void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
932e5dd7070Spatrick                             Counter Count) {
933e5dd7070Spatrick     if (StartLoc == EndLoc)
934e5dd7070Spatrick       return;
935e5dd7070Spatrick     assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
936e5dd7070Spatrick     handleFileExit(StartLoc);
937e5dd7070Spatrick     size_t Index = pushRegion(Count, StartLoc, EndLoc);
938e5dd7070Spatrick     getRegion().setGap(true);
939e5dd7070Spatrick     handleFileExit(EndLoc);
940e5dd7070Spatrick     popRegions(Index);
941e5dd7070Spatrick   }
942e5dd7070Spatrick 
943e5dd7070Spatrick   /// Keep counts of breaks and continues inside loops.
944e5dd7070Spatrick   struct BreakContinue {
945e5dd7070Spatrick     Counter BreakCount;
946e5dd7070Spatrick     Counter ContinueCount;
947e5dd7070Spatrick   };
948e5dd7070Spatrick   SmallVector<BreakContinue, 8> BreakContinueStack;
949e5dd7070Spatrick 
CounterCoverageMappingBuilder__anond4b6e5a70211::CounterCoverageMappingBuilder950e5dd7070Spatrick   CounterCoverageMappingBuilder(
951e5dd7070Spatrick       CoverageMappingModuleGen &CVM,
952e5dd7070Spatrick       llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
953e5dd7070Spatrick       const LangOptions &LangOpts)
954a9ac8606Spatrick       : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
955e5dd7070Spatrick 
956e5dd7070Spatrick   /// Write the mapping data to the output stream
write__anond4b6e5a70211::CounterCoverageMappingBuilder957e5dd7070Spatrick   void write(llvm::raw_ostream &OS) {
958e5dd7070Spatrick     llvm::SmallVector<unsigned, 8> VirtualFileMapping;
959e5dd7070Spatrick     gatherFileIDs(VirtualFileMapping);
960e5dd7070Spatrick     SourceRegionFilter Filter = emitExpansionRegions();
961e5dd7070Spatrick     emitSourceRegions(Filter);
962e5dd7070Spatrick     gatherSkippedRegions();
963e5dd7070Spatrick 
964e5dd7070Spatrick     if (MappingRegions.empty())
965e5dd7070Spatrick       return;
966e5dd7070Spatrick 
967e5dd7070Spatrick     CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
968e5dd7070Spatrick                                  MappingRegions);
969e5dd7070Spatrick     Writer.write(OS);
970e5dd7070Spatrick   }
971e5dd7070Spatrick 
VisitStmt__anond4b6e5a70211::CounterCoverageMappingBuilder972e5dd7070Spatrick   void VisitStmt(const Stmt *S) {
973e5dd7070Spatrick     if (S->getBeginLoc().isValid())
974e5dd7070Spatrick       extendRegion(S);
975a9ac8606Spatrick     const Stmt *LastStmt = nullptr;
976a9ac8606Spatrick     bool SaveTerminateStmt = HasTerminateStmt;
977a9ac8606Spatrick     HasTerminateStmt = false;
978a9ac8606Spatrick     GapRegionCounter = Counter::getZero();
979e5dd7070Spatrick     for (const Stmt *Child : S->children())
980a9ac8606Spatrick       if (Child) {
981a9ac8606Spatrick         // If last statement contains terminate statements, add a gap area
982a9ac8606Spatrick         // between the two statements. Skipping attributed statements, because
983a9ac8606Spatrick         // they don't have valid start location.
984*12c85518Srobert         if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
985a9ac8606Spatrick           auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
986a9ac8606Spatrick           if (Gap)
987a9ac8606Spatrick             fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
988a9ac8606Spatrick                                  GapRegionCounter);
989a9ac8606Spatrick           SaveTerminateStmt = true;
990a9ac8606Spatrick           HasTerminateStmt = false;
991a9ac8606Spatrick         }
992e5dd7070Spatrick         this->Visit(Child);
993a9ac8606Spatrick         LastStmt = Child;
994a9ac8606Spatrick       }
995a9ac8606Spatrick     if (SaveTerminateStmt)
996a9ac8606Spatrick       HasTerminateStmt = true;
997e5dd7070Spatrick     handleFileExit(getEnd(S));
998e5dd7070Spatrick   }
999e5dd7070Spatrick 
VisitDecl__anond4b6e5a70211::CounterCoverageMappingBuilder1000e5dd7070Spatrick   void VisitDecl(const Decl *D) {
1001e5dd7070Spatrick     Stmt *Body = D->getBody();
1002e5dd7070Spatrick 
1003e5dd7070Spatrick     // Do not propagate region counts into system headers.
1004e5dd7070Spatrick     if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
1005e5dd7070Spatrick       return;
1006e5dd7070Spatrick 
1007e5dd7070Spatrick     // Do not visit the artificial children nodes of defaulted methods. The
1008e5dd7070Spatrick     // lexer may not be able to report back precise token end locations for
1009e5dd7070Spatrick     // these children nodes (llvm.org/PR39822), and moreover users will not be
1010e5dd7070Spatrick     // able to see coverage for them.
1011e5dd7070Spatrick     bool Defaulted = false;
1012e5dd7070Spatrick     if (auto *Method = dyn_cast<CXXMethodDecl>(D))
1013e5dd7070Spatrick       Defaulted = Method->isDefaulted();
1014e5dd7070Spatrick 
1015e5dd7070Spatrick     propagateCounts(getRegionCounter(Body), Body,
1016e5dd7070Spatrick                     /*VisitChildren=*/!Defaulted);
1017e5dd7070Spatrick     assert(RegionStack.empty() && "Regions entered but never exited");
1018e5dd7070Spatrick   }
1019e5dd7070Spatrick 
VisitReturnStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1020e5dd7070Spatrick   void VisitReturnStmt(const ReturnStmt *S) {
1021e5dd7070Spatrick     extendRegion(S);
1022e5dd7070Spatrick     if (S->getRetValue())
1023e5dd7070Spatrick       Visit(S->getRetValue());
1024e5dd7070Spatrick     terminateRegion(S);
1025e5dd7070Spatrick   }
1026e5dd7070Spatrick 
VisitCoroutineBodyStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1027ec727ea7Spatrick   void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
1028ec727ea7Spatrick     extendRegion(S);
1029ec727ea7Spatrick     Visit(S->getBody());
1030ec727ea7Spatrick   }
1031ec727ea7Spatrick 
VisitCoreturnStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1032ec727ea7Spatrick   void VisitCoreturnStmt(const CoreturnStmt *S) {
1033ec727ea7Spatrick     extendRegion(S);
1034ec727ea7Spatrick     if (S->getOperand())
1035ec727ea7Spatrick       Visit(S->getOperand());
1036ec727ea7Spatrick     terminateRegion(S);
1037ec727ea7Spatrick   }
1038ec727ea7Spatrick 
VisitCXXThrowExpr__anond4b6e5a70211::CounterCoverageMappingBuilder1039e5dd7070Spatrick   void VisitCXXThrowExpr(const CXXThrowExpr *E) {
1040e5dd7070Spatrick     extendRegion(E);
1041e5dd7070Spatrick     if (E->getSubExpr())
1042e5dd7070Spatrick       Visit(E->getSubExpr());
1043e5dd7070Spatrick     terminateRegion(E);
1044e5dd7070Spatrick   }
1045e5dd7070Spatrick 
VisitGotoStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1046e5dd7070Spatrick   void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
1047e5dd7070Spatrick 
VisitLabelStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1048e5dd7070Spatrick   void VisitLabelStmt(const LabelStmt *S) {
1049e5dd7070Spatrick     Counter LabelCount = getRegionCounter(S);
1050e5dd7070Spatrick     SourceLocation Start = getStart(S);
1051e5dd7070Spatrick     // We can't extendRegion here or we risk overlapping with our new region.
1052e5dd7070Spatrick     handleFileExit(Start);
1053e5dd7070Spatrick     pushRegion(LabelCount, Start);
1054e5dd7070Spatrick     Visit(S->getSubStmt());
1055e5dd7070Spatrick   }
1056e5dd7070Spatrick 
VisitBreakStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1057e5dd7070Spatrick   void VisitBreakStmt(const BreakStmt *S) {
1058e5dd7070Spatrick     assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
1059e5dd7070Spatrick     BreakContinueStack.back().BreakCount = addCounters(
1060e5dd7070Spatrick         BreakContinueStack.back().BreakCount, getRegion().getCounter());
1061e5dd7070Spatrick     // FIXME: a break in a switch should terminate regions for all preceding
1062e5dd7070Spatrick     // case statements, not just the most recent one.
1063e5dd7070Spatrick     terminateRegion(S);
1064e5dd7070Spatrick   }
1065e5dd7070Spatrick 
VisitContinueStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1066e5dd7070Spatrick   void VisitContinueStmt(const ContinueStmt *S) {
1067e5dd7070Spatrick     assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
1068e5dd7070Spatrick     BreakContinueStack.back().ContinueCount = addCounters(
1069e5dd7070Spatrick         BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1070e5dd7070Spatrick     terminateRegion(S);
1071e5dd7070Spatrick   }
1072e5dd7070Spatrick 
VisitCallExpr__anond4b6e5a70211::CounterCoverageMappingBuilder1073e5dd7070Spatrick   void VisitCallExpr(const CallExpr *E) {
1074e5dd7070Spatrick     VisitStmt(E);
1075e5dd7070Spatrick 
1076e5dd7070Spatrick     // Terminate the region when we hit a noreturn function.
1077e5dd7070Spatrick     // (This is helpful dealing with switch statements.)
1078e5dd7070Spatrick     QualType CalleeType = E->getCallee()->getType();
1079e5dd7070Spatrick     if (getFunctionExtInfo(*CalleeType).getNoReturn())
1080e5dd7070Spatrick       terminateRegion(E);
1081e5dd7070Spatrick   }
1082e5dd7070Spatrick 
VisitWhileStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1083e5dd7070Spatrick   void VisitWhileStmt(const WhileStmt *S) {
1084e5dd7070Spatrick     extendRegion(S);
1085e5dd7070Spatrick 
1086e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1087e5dd7070Spatrick     Counter BodyCount = getRegionCounter(S);
1088e5dd7070Spatrick 
1089e5dd7070Spatrick     // Handle the body first so that we can get the backedge count.
1090e5dd7070Spatrick     BreakContinueStack.push_back(BreakContinue());
1091e5dd7070Spatrick     extendRegion(S->getBody());
1092e5dd7070Spatrick     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1093e5dd7070Spatrick     BreakContinue BC = BreakContinueStack.pop_back_val();
1094e5dd7070Spatrick 
1095a9ac8606Spatrick     bool BodyHasTerminateStmt = HasTerminateStmt;
1096a9ac8606Spatrick     HasTerminateStmt = false;
1097a9ac8606Spatrick 
1098e5dd7070Spatrick     // Go back to handle the condition.
1099e5dd7070Spatrick     Counter CondCount =
1100e5dd7070Spatrick         addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1101e5dd7070Spatrick     propagateCounts(CondCount, S->getCond());
1102e5dd7070Spatrick     adjustForOutOfOrderTraversal(getEnd(S));
1103e5dd7070Spatrick 
1104e5dd7070Spatrick     // The body count applies to the area immediately after the increment.
1105a9ac8606Spatrick     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1106e5dd7070Spatrick     if (Gap)
1107e5dd7070Spatrick       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1108e5dd7070Spatrick 
1109e5dd7070Spatrick     Counter OutCount =
1110e5dd7070Spatrick         addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1111a9ac8606Spatrick     if (OutCount != ParentCount) {
1112e5dd7070Spatrick       pushRegion(OutCount);
1113a9ac8606Spatrick       GapRegionCounter = OutCount;
1114a9ac8606Spatrick       if (BodyHasTerminateStmt)
1115a9ac8606Spatrick         HasTerminateStmt = true;
1116a9ac8606Spatrick     }
1117a9ac8606Spatrick 
1118a9ac8606Spatrick     // Create Branch Region around condition.
1119a9ac8606Spatrick     createBranchRegion(S->getCond(), BodyCount,
1120a9ac8606Spatrick                        subtractCounters(CondCount, BodyCount));
1121e5dd7070Spatrick   }
1122e5dd7070Spatrick 
VisitDoStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1123e5dd7070Spatrick   void VisitDoStmt(const DoStmt *S) {
1124e5dd7070Spatrick     extendRegion(S);
1125e5dd7070Spatrick 
1126e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1127e5dd7070Spatrick     Counter BodyCount = getRegionCounter(S);
1128e5dd7070Spatrick 
1129e5dd7070Spatrick     BreakContinueStack.push_back(BreakContinue());
1130e5dd7070Spatrick     extendRegion(S->getBody());
1131e5dd7070Spatrick     Counter BackedgeCount =
1132e5dd7070Spatrick         propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
1133e5dd7070Spatrick     BreakContinue BC = BreakContinueStack.pop_back_val();
1134e5dd7070Spatrick 
1135a9ac8606Spatrick     bool BodyHasTerminateStmt = HasTerminateStmt;
1136a9ac8606Spatrick     HasTerminateStmt = false;
1137a9ac8606Spatrick 
1138e5dd7070Spatrick     Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1139e5dd7070Spatrick     propagateCounts(CondCount, S->getCond());
1140e5dd7070Spatrick 
1141e5dd7070Spatrick     Counter OutCount =
1142e5dd7070Spatrick         addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1143a9ac8606Spatrick     if (OutCount != ParentCount) {
1144e5dd7070Spatrick       pushRegion(OutCount);
1145a9ac8606Spatrick       GapRegionCounter = OutCount;
1146a9ac8606Spatrick     }
1147a9ac8606Spatrick 
1148a9ac8606Spatrick     // Create Branch Region around condition.
1149a9ac8606Spatrick     createBranchRegion(S->getCond(), BodyCount,
1150a9ac8606Spatrick                        subtractCounters(CondCount, BodyCount));
1151a9ac8606Spatrick 
1152a9ac8606Spatrick     if (BodyHasTerminateStmt)
1153a9ac8606Spatrick       HasTerminateStmt = true;
1154e5dd7070Spatrick   }
1155e5dd7070Spatrick 
VisitForStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1156e5dd7070Spatrick   void VisitForStmt(const ForStmt *S) {
1157e5dd7070Spatrick     extendRegion(S);
1158e5dd7070Spatrick     if (S->getInit())
1159e5dd7070Spatrick       Visit(S->getInit());
1160e5dd7070Spatrick 
1161e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1162e5dd7070Spatrick     Counter BodyCount = getRegionCounter(S);
1163e5dd7070Spatrick 
1164e5dd7070Spatrick     // The loop increment may contain a break or continue.
1165e5dd7070Spatrick     if (S->getInc())
1166e5dd7070Spatrick       BreakContinueStack.emplace_back();
1167e5dd7070Spatrick 
1168e5dd7070Spatrick     // Handle the body first so that we can get the backedge count.
1169e5dd7070Spatrick     BreakContinueStack.emplace_back();
1170e5dd7070Spatrick     extendRegion(S->getBody());
1171e5dd7070Spatrick     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1172e5dd7070Spatrick     BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1173e5dd7070Spatrick 
1174a9ac8606Spatrick     bool BodyHasTerminateStmt = HasTerminateStmt;
1175a9ac8606Spatrick     HasTerminateStmt = false;
1176a9ac8606Spatrick 
1177e5dd7070Spatrick     // The increment is essentially part of the body but it needs to include
1178e5dd7070Spatrick     // the count for all the continue statements.
1179e5dd7070Spatrick     BreakContinue IncrementBC;
1180e5dd7070Spatrick     if (const Stmt *Inc = S->getInc()) {
1181e5dd7070Spatrick       propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1182e5dd7070Spatrick       IncrementBC = BreakContinueStack.pop_back_val();
1183e5dd7070Spatrick     }
1184e5dd7070Spatrick 
1185e5dd7070Spatrick     // Go back to handle the condition.
1186e5dd7070Spatrick     Counter CondCount = addCounters(
1187e5dd7070Spatrick         addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1188e5dd7070Spatrick         IncrementBC.ContinueCount);
1189e5dd7070Spatrick     if (const Expr *Cond = S->getCond()) {
1190e5dd7070Spatrick       propagateCounts(CondCount, Cond);
1191e5dd7070Spatrick       adjustForOutOfOrderTraversal(getEnd(S));
1192e5dd7070Spatrick     }
1193e5dd7070Spatrick 
1194e5dd7070Spatrick     // The body count applies to the area immediately after the increment.
1195a9ac8606Spatrick     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1196e5dd7070Spatrick     if (Gap)
1197e5dd7070Spatrick       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1198e5dd7070Spatrick 
1199e5dd7070Spatrick     Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1200e5dd7070Spatrick                                    subtractCounters(CondCount, BodyCount));
1201a9ac8606Spatrick     if (OutCount != ParentCount) {
1202e5dd7070Spatrick       pushRegion(OutCount);
1203a9ac8606Spatrick       GapRegionCounter = OutCount;
1204a9ac8606Spatrick       if (BodyHasTerminateStmt)
1205a9ac8606Spatrick         HasTerminateStmt = true;
1206a9ac8606Spatrick     }
1207a9ac8606Spatrick 
1208a9ac8606Spatrick     // Create Branch Region around condition.
1209a9ac8606Spatrick     createBranchRegion(S->getCond(), BodyCount,
1210a9ac8606Spatrick                        subtractCounters(CondCount, BodyCount));
1211e5dd7070Spatrick   }
1212e5dd7070Spatrick 
VisitCXXForRangeStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1213e5dd7070Spatrick   void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
1214e5dd7070Spatrick     extendRegion(S);
1215e5dd7070Spatrick     if (S->getInit())
1216e5dd7070Spatrick       Visit(S->getInit());
1217e5dd7070Spatrick     Visit(S->getLoopVarStmt());
1218e5dd7070Spatrick     Visit(S->getRangeStmt());
1219e5dd7070Spatrick 
1220e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1221e5dd7070Spatrick     Counter BodyCount = getRegionCounter(S);
1222e5dd7070Spatrick 
1223e5dd7070Spatrick     BreakContinueStack.push_back(BreakContinue());
1224e5dd7070Spatrick     extendRegion(S->getBody());
1225e5dd7070Spatrick     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1226e5dd7070Spatrick     BreakContinue BC = BreakContinueStack.pop_back_val();
1227e5dd7070Spatrick 
1228a9ac8606Spatrick     bool BodyHasTerminateStmt = HasTerminateStmt;
1229a9ac8606Spatrick     HasTerminateStmt = false;
1230a9ac8606Spatrick 
1231e5dd7070Spatrick     // The body count applies to the area immediately after the range.
1232a9ac8606Spatrick     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1233e5dd7070Spatrick     if (Gap)
1234e5dd7070Spatrick       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1235e5dd7070Spatrick 
1236e5dd7070Spatrick     Counter LoopCount =
1237e5dd7070Spatrick         addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1238e5dd7070Spatrick     Counter OutCount =
1239e5dd7070Spatrick         addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1240a9ac8606Spatrick     if (OutCount != ParentCount) {
1241e5dd7070Spatrick       pushRegion(OutCount);
1242a9ac8606Spatrick       GapRegionCounter = OutCount;
1243a9ac8606Spatrick       if (BodyHasTerminateStmt)
1244a9ac8606Spatrick         HasTerminateStmt = true;
1245a9ac8606Spatrick     }
1246a9ac8606Spatrick 
1247a9ac8606Spatrick     // Create Branch Region around condition.
1248a9ac8606Spatrick     createBranchRegion(S->getCond(), BodyCount,
1249a9ac8606Spatrick                        subtractCounters(LoopCount, BodyCount));
1250e5dd7070Spatrick   }
1251e5dd7070Spatrick 
VisitObjCForCollectionStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1252e5dd7070Spatrick   void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
1253e5dd7070Spatrick     extendRegion(S);
1254e5dd7070Spatrick     Visit(S->getElement());
1255e5dd7070Spatrick 
1256e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1257e5dd7070Spatrick     Counter BodyCount = getRegionCounter(S);
1258e5dd7070Spatrick 
1259e5dd7070Spatrick     BreakContinueStack.push_back(BreakContinue());
1260e5dd7070Spatrick     extendRegion(S->getBody());
1261e5dd7070Spatrick     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1262e5dd7070Spatrick     BreakContinue BC = BreakContinueStack.pop_back_val();
1263e5dd7070Spatrick 
1264e5dd7070Spatrick     // The body count applies to the area immediately after the collection.
1265a9ac8606Spatrick     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1266e5dd7070Spatrick     if (Gap)
1267e5dd7070Spatrick       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1268e5dd7070Spatrick 
1269e5dd7070Spatrick     Counter LoopCount =
1270e5dd7070Spatrick         addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1271e5dd7070Spatrick     Counter OutCount =
1272e5dd7070Spatrick         addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1273a9ac8606Spatrick     if (OutCount != ParentCount) {
1274e5dd7070Spatrick       pushRegion(OutCount);
1275a9ac8606Spatrick       GapRegionCounter = OutCount;
1276a9ac8606Spatrick     }
1277e5dd7070Spatrick   }
1278e5dd7070Spatrick 
VisitSwitchStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1279e5dd7070Spatrick   void VisitSwitchStmt(const SwitchStmt *S) {
1280e5dd7070Spatrick     extendRegion(S);
1281e5dd7070Spatrick     if (S->getInit())
1282e5dd7070Spatrick       Visit(S->getInit());
1283e5dd7070Spatrick     Visit(S->getCond());
1284e5dd7070Spatrick 
1285e5dd7070Spatrick     BreakContinueStack.push_back(BreakContinue());
1286e5dd7070Spatrick 
1287e5dd7070Spatrick     const Stmt *Body = S->getBody();
1288e5dd7070Spatrick     extendRegion(Body);
1289e5dd7070Spatrick     if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1290e5dd7070Spatrick       if (!CS->body_empty()) {
1291e5dd7070Spatrick         // Make a region for the body of the switch.  If the body starts with
1292e5dd7070Spatrick         // a case, that case will reuse this region; otherwise, this covers
1293e5dd7070Spatrick         // the unreachable code at the beginning of the switch body.
1294e5dd7070Spatrick         size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1295e5dd7070Spatrick         getRegion().setGap(true);
1296a9ac8606Spatrick         Visit(Body);
1297e5dd7070Spatrick 
1298e5dd7070Spatrick         // Set the end for the body of the switch, if it isn't already set.
1299e5dd7070Spatrick         for (size_t i = RegionStack.size(); i != Index; --i) {
1300e5dd7070Spatrick           if (!RegionStack[i - 1].hasEndLoc())
1301e5dd7070Spatrick             RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1302e5dd7070Spatrick         }
1303e5dd7070Spatrick 
1304e5dd7070Spatrick         popRegions(Index);
1305e5dd7070Spatrick       }
1306e5dd7070Spatrick     } else
1307e5dd7070Spatrick       propagateCounts(Counter::getZero(), Body);
1308e5dd7070Spatrick     BreakContinue BC = BreakContinueStack.pop_back_val();
1309e5dd7070Spatrick 
1310e5dd7070Spatrick     if (!BreakContinueStack.empty())
1311e5dd7070Spatrick       BreakContinueStack.back().ContinueCount = addCounters(
1312e5dd7070Spatrick           BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1313e5dd7070Spatrick 
1314a9ac8606Spatrick     Counter ParentCount = getRegion().getCounter();
1315e5dd7070Spatrick     Counter ExitCount = getRegionCounter(S);
1316e5dd7070Spatrick     SourceLocation ExitLoc = getEnd(S);
1317e5dd7070Spatrick     pushRegion(ExitCount);
1318a9ac8606Spatrick     GapRegionCounter = ExitCount;
1319e5dd7070Spatrick 
1320e5dd7070Spatrick     // Ensure that handleFileExit recognizes when the end location is located
1321e5dd7070Spatrick     // in a different file.
1322e5dd7070Spatrick     MostRecentLocation = getStart(S);
1323e5dd7070Spatrick     handleFileExit(ExitLoc);
1324a9ac8606Spatrick 
1325a9ac8606Spatrick     // Create a Branch Region around each Case. Subtract the case's
1326a9ac8606Spatrick     // counter from the Parent counter to track the "False" branch count.
1327a9ac8606Spatrick     Counter CaseCountSum;
1328a9ac8606Spatrick     bool HasDefaultCase = false;
1329a9ac8606Spatrick     const SwitchCase *Case = S->getSwitchCaseList();
1330a9ac8606Spatrick     for (; Case; Case = Case->getNextSwitchCase()) {
1331a9ac8606Spatrick       HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1332*12c85518Srobert       CaseCountSum =
1333*12c85518Srobert           addCounters(CaseCountSum, getRegionCounter(Case), /*Simplify=*/false);
1334a9ac8606Spatrick       createSwitchCaseRegion(
1335a9ac8606Spatrick           Case, getRegionCounter(Case),
1336a9ac8606Spatrick           subtractCounters(ParentCount, getRegionCounter(Case)));
1337a9ac8606Spatrick     }
1338*12c85518Srobert     // Simplify is skipped while building the counters above: it can get really
1339*12c85518Srobert     // slow on top of switches with thousands of cases. Instead, trigger
1340*12c85518Srobert     // simplification by adding zero to the last counter.
1341*12c85518Srobert     CaseCountSum = addCounters(CaseCountSum, Counter::getZero());
1342a9ac8606Spatrick 
1343a9ac8606Spatrick     // If no explicit default case exists, create a branch region to represent
1344a9ac8606Spatrick     // the hidden branch, which will be added later by the CodeGen. This region
1345a9ac8606Spatrick     // will be associated with the switch statement's condition.
1346a9ac8606Spatrick     if (!HasDefaultCase) {
1347a9ac8606Spatrick       Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1348a9ac8606Spatrick       Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1349a9ac8606Spatrick       createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1350a9ac8606Spatrick     }
1351e5dd7070Spatrick   }
1352e5dd7070Spatrick 
VisitSwitchCase__anond4b6e5a70211::CounterCoverageMappingBuilder1353e5dd7070Spatrick   void VisitSwitchCase(const SwitchCase *S) {
1354e5dd7070Spatrick     extendRegion(S);
1355e5dd7070Spatrick 
1356e5dd7070Spatrick     SourceMappingRegion &Parent = getRegion();
1357e5dd7070Spatrick 
1358e5dd7070Spatrick     Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
1359e5dd7070Spatrick     // Reuse the existing region if it starts at our label. This is typical of
1360e5dd7070Spatrick     // the first case in a switch.
1361e5dd7070Spatrick     if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1362e5dd7070Spatrick       Parent.setCounter(Count);
1363e5dd7070Spatrick     else
1364e5dd7070Spatrick       pushRegion(Count, getStart(S));
1365e5dd7070Spatrick 
1366a9ac8606Spatrick     GapRegionCounter = Count;
1367a9ac8606Spatrick 
1368e5dd7070Spatrick     if (const auto *CS = dyn_cast<CaseStmt>(S)) {
1369e5dd7070Spatrick       Visit(CS->getLHS());
1370e5dd7070Spatrick       if (const Expr *RHS = CS->getRHS())
1371e5dd7070Spatrick         Visit(RHS);
1372e5dd7070Spatrick     }
1373e5dd7070Spatrick     Visit(S->getSubStmt());
1374e5dd7070Spatrick   }
1375e5dd7070Spatrick 
VisitIfStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1376e5dd7070Spatrick   void VisitIfStmt(const IfStmt *S) {
1377e5dd7070Spatrick     extendRegion(S);
1378e5dd7070Spatrick     if (S->getInit())
1379e5dd7070Spatrick       Visit(S->getInit());
1380e5dd7070Spatrick 
1381e5dd7070Spatrick     // Extend into the condition before we propagate through it below - this is
1382e5dd7070Spatrick     // needed to handle macros that generate the "if" but not the condition.
1383*12c85518Srobert     if (!S->isConsteval())
1384e5dd7070Spatrick       extendRegion(S->getCond());
1385e5dd7070Spatrick 
1386e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1387e5dd7070Spatrick     Counter ThenCount = getRegionCounter(S);
1388e5dd7070Spatrick 
1389*12c85518Srobert     if (!S->isConsteval()) {
1390e5dd7070Spatrick       // Emitting a counter for the condition makes it easier to interpret the
1391e5dd7070Spatrick       // counter for the body when looking at the coverage.
1392e5dd7070Spatrick       propagateCounts(ParentCount, S->getCond());
1393e5dd7070Spatrick 
1394e5dd7070Spatrick       // The 'then' count applies to the area immediately after the condition.
1395*12c85518Srobert       std::optional<SourceRange> Gap =
1396*12c85518Srobert           findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
1397e5dd7070Spatrick       if (Gap)
1398e5dd7070Spatrick         fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
1399*12c85518Srobert     }
1400e5dd7070Spatrick 
1401e5dd7070Spatrick     extendRegion(S->getThen());
1402e5dd7070Spatrick     Counter OutCount = propagateCounts(ThenCount, S->getThen());
1403e5dd7070Spatrick 
1404e5dd7070Spatrick     Counter ElseCount = subtractCounters(ParentCount, ThenCount);
1405e5dd7070Spatrick     if (const Stmt *Else = S->getElse()) {
1406a9ac8606Spatrick       bool ThenHasTerminateStmt = HasTerminateStmt;
1407a9ac8606Spatrick       HasTerminateStmt = false;
1408e5dd7070Spatrick       // The 'else' count applies to the area immediately after the 'then'.
1409*12c85518Srobert       std::optional<SourceRange> Gap =
1410*12c85518Srobert           findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
1411e5dd7070Spatrick       if (Gap)
1412e5dd7070Spatrick         fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
1413e5dd7070Spatrick       extendRegion(Else);
1414e5dd7070Spatrick       OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1415a9ac8606Spatrick 
1416a9ac8606Spatrick       if (ThenHasTerminateStmt)
1417a9ac8606Spatrick         HasTerminateStmt = true;
1418e5dd7070Spatrick     } else
1419e5dd7070Spatrick       OutCount = addCounters(OutCount, ElseCount);
1420e5dd7070Spatrick 
1421a9ac8606Spatrick     if (OutCount != ParentCount) {
1422e5dd7070Spatrick       pushRegion(OutCount);
1423a9ac8606Spatrick       GapRegionCounter = OutCount;
1424a9ac8606Spatrick     }
1425a9ac8606Spatrick 
1426*12c85518Srobert     if (!S->isConsteval()) {
1427a9ac8606Spatrick       // Create Branch Region around condition.
1428a9ac8606Spatrick       createBranchRegion(S->getCond(), ThenCount,
1429a9ac8606Spatrick                          subtractCounters(ParentCount, ThenCount));
1430e5dd7070Spatrick     }
1431*12c85518Srobert   }
1432e5dd7070Spatrick 
VisitCXXTryStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1433e5dd7070Spatrick   void VisitCXXTryStmt(const CXXTryStmt *S) {
1434e5dd7070Spatrick     extendRegion(S);
1435e5dd7070Spatrick     // Handle macros that generate the "try" but not the rest.
1436e5dd7070Spatrick     extendRegion(S->getTryBlock());
1437e5dd7070Spatrick 
1438e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1439e5dd7070Spatrick     propagateCounts(ParentCount, S->getTryBlock());
1440e5dd7070Spatrick 
1441e5dd7070Spatrick     for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
1442e5dd7070Spatrick       Visit(S->getHandler(I));
1443e5dd7070Spatrick 
1444e5dd7070Spatrick     Counter ExitCount = getRegionCounter(S);
1445e5dd7070Spatrick     pushRegion(ExitCount);
1446e5dd7070Spatrick   }
1447e5dd7070Spatrick 
VisitCXXCatchStmt__anond4b6e5a70211::CounterCoverageMappingBuilder1448e5dd7070Spatrick   void VisitCXXCatchStmt(const CXXCatchStmt *S) {
1449e5dd7070Spatrick     propagateCounts(getRegionCounter(S), S->getHandlerBlock());
1450e5dd7070Spatrick   }
1451e5dd7070Spatrick 
VisitAbstractConditionalOperator__anond4b6e5a70211::CounterCoverageMappingBuilder1452e5dd7070Spatrick   void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
1453e5dd7070Spatrick     extendRegion(E);
1454e5dd7070Spatrick 
1455e5dd7070Spatrick     Counter ParentCount = getRegion().getCounter();
1456e5dd7070Spatrick     Counter TrueCount = getRegionCounter(E);
1457e5dd7070Spatrick 
1458a9ac8606Spatrick     propagateCounts(ParentCount, E->getCond());
1459e5dd7070Spatrick 
1460e5dd7070Spatrick     if (!isa<BinaryConditionalOperator>(E)) {
1461e5dd7070Spatrick       // The 'then' count applies to the area immediately after the condition.
1462e5dd7070Spatrick       auto Gap =
1463e5dd7070Spatrick           findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
1464e5dd7070Spatrick       if (Gap)
1465e5dd7070Spatrick         fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
1466e5dd7070Spatrick 
1467e5dd7070Spatrick       extendRegion(E->getTrueExpr());
1468e5dd7070Spatrick       propagateCounts(TrueCount, E->getTrueExpr());
1469e5dd7070Spatrick     }
1470e5dd7070Spatrick 
1471e5dd7070Spatrick     extendRegion(E->getFalseExpr());
1472e5dd7070Spatrick     propagateCounts(subtractCounters(ParentCount, TrueCount),
1473e5dd7070Spatrick                     E->getFalseExpr());
1474a9ac8606Spatrick 
1475a9ac8606Spatrick     // Create Branch Region around condition.
1476a9ac8606Spatrick     createBranchRegion(E->getCond(), TrueCount,
1477a9ac8606Spatrick                        subtractCounters(ParentCount, TrueCount));
1478e5dd7070Spatrick   }
1479e5dd7070Spatrick 
VisitBinLAnd__anond4b6e5a70211::CounterCoverageMappingBuilder1480e5dd7070Spatrick   void VisitBinLAnd(const BinaryOperator *E) {
1481e5dd7070Spatrick     extendRegion(E->getLHS());
1482e5dd7070Spatrick     propagateCounts(getRegion().getCounter(), E->getLHS());
1483e5dd7070Spatrick     handleFileExit(getEnd(E->getLHS()));
1484e5dd7070Spatrick 
1485a9ac8606Spatrick     // Counter tracks the right hand side of a logical and operator.
1486e5dd7070Spatrick     extendRegion(E->getRHS());
1487e5dd7070Spatrick     propagateCounts(getRegionCounter(E), E->getRHS());
1488a9ac8606Spatrick 
1489a9ac8606Spatrick     // Extract the RHS's Execution Counter.
1490a9ac8606Spatrick     Counter RHSExecCnt = getRegionCounter(E);
1491a9ac8606Spatrick 
1492a9ac8606Spatrick     // Extract the RHS's "True" Instance Counter.
1493a9ac8606Spatrick     Counter RHSTrueCnt = getRegionCounter(E->getRHS());
1494a9ac8606Spatrick 
1495a9ac8606Spatrick     // Extract the Parent Region Counter.
1496a9ac8606Spatrick     Counter ParentCnt = getRegion().getCounter();
1497a9ac8606Spatrick 
1498a9ac8606Spatrick     // Create Branch Region around LHS condition.
1499a9ac8606Spatrick     createBranchRegion(E->getLHS(), RHSExecCnt,
1500a9ac8606Spatrick                        subtractCounters(ParentCnt, RHSExecCnt));
1501a9ac8606Spatrick 
1502a9ac8606Spatrick     // Create Branch Region around RHS condition.
1503a9ac8606Spatrick     createBranchRegion(E->getRHS(), RHSTrueCnt,
1504a9ac8606Spatrick                        subtractCounters(RHSExecCnt, RHSTrueCnt));
1505e5dd7070Spatrick   }
1506e5dd7070Spatrick 
VisitBinLOr__anond4b6e5a70211::CounterCoverageMappingBuilder1507e5dd7070Spatrick   void VisitBinLOr(const BinaryOperator *E) {
1508e5dd7070Spatrick     extendRegion(E->getLHS());
1509e5dd7070Spatrick     propagateCounts(getRegion().getCounter(), E->getLHS());
1510e5dd7070Spatrick     handleFileExit(getEnd(E->getLHS()));
1511e5dd7070Spatrick 
1512a9ac8606Spatrick     // Counter tracks the right hand side of a logical or operator.
1513e5dd7070Spatrick     extendRegion(E->getRHS());
1514e5dd7070Spatrick     propagateCounts(getRegionCounter(E), E->getRHS());
1515a9ac8606Spatrick 
1516a9ac8606Spatrick     // Extract the RHS's Execution Counter.
1517a9ac8606Spatrick     Counter RHSExecCnt = getRegionCounter(E);
1518a9ac8606Spatrick 
1519a9ac8606Spatrick     // Extract the RHS's "False" Instance Counter.
1520a9ac8606Spatrick     Counter RHSFalseCnt = getRegionCounter(E->getRHS());
1521a9ac8606Spatrick 
1522a9ac8606Spatrick     // Extract the Parent Region Counter.
1523a9ac8606Spatrick     Counter ParentCnt = getRegion().getCounter();
1524a9ac8606Spatrick 
1525a9ac8606Spatrick     // Create Branch Region around LHS condition.
1526a9ac8606Spatrick     createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
1527a9ac8606Spatrick                        RHSExecCnt);
1528a9ac8606Spatrick 
1529a9ac8606Spatrick     // Create Branch Region around RHS condition.
1530a9ac8606Spatrick     createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
1531a9ac8606Spatrick                        RHSFalseCnt);
1532e5dd7070Spatrick   }
1533e5dd7070Spatrick 
VisitLambdaExpr__anond4b6e5a70211::CounterCoverageMappingBuilder1534e5dd7070Spatrick   void VisitLambdaExpr(const LambdaExpr *LE) {
1535e5dd7070Spatrick     // Lambdas are treated as their own functions for now, so we shouldn't
1536e5dd7070Spatrick     // propagate counts into them.
1537e5dd7070Spatrick   }
1538e5dd7070Spatrick };
1539e5dd7070Spatrick 
1540e5dd7070Spatrick } // end anonymous namespace
1541e5dd7070Spatrick 
dump(llvm::raw_ostream & OS,StringRef FunctionName,ArrayRef<CounterExpression> Expressions,ArrayRef<CounterMappingRegion> Regions)1542e5dd7070Spatrick static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
1543e5dd7070Spatrick                  ArrayRef<CounterExpression> Expressions,
1544e5dd7070Spatrick                  ArrayRef<CounterMappingRegion> Regions) {
1545e5dd7070Spatrick   OS << FunctionName << ":\n";
1546e5dd7070Spatrick   CounterMappingContext Ctx(Expressions);
1547e5dd7070Spatrick   for (const auto &R : Regions) {
1548e5dd7070Spatrick     OS.indent(2);
1549e5dd7070Spatrick     switch (R.Kind) {
1550e5dd7070Spatrick     case CounterMappingRegion::CodeRegion:
1551e5dd7070Spatrick       break;
1552e5dd7070Spatrick     case CounterMappingRegion::ExpansionRegion:
1553e5dd7070Spatrick       OS << "Expansion,";
1554e5dd7070Spatrick       break;
1555e5dd7070Spatrick     case CounterMappingRegion::SkippedRegion:
1556e5dd7070Spatrick       OS << "Skipped,";
1557e5dd7070Spatrick       break;
1558e5dd7070Spatrick     case CounterMappingRegion::GapRegion:
1559e5dd7070Spatrick       OS << "Gap,";
1560e5dd7070Spatrick       break;
1561a9ac8606Spatrick     case CounterMappingRegion::BranchRegion:
1562a9ac8606Spatrick       OS << "Branch,";
1563a9ac8606Spatrick       break;
1564e5dd7070Spatrick     }
1565e5dd7070Spatrick 
1566e5dd7070Spatrick     OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
1567e5dd7070Spatrick        << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
1568e5dd7070Spatrick     Ctx.dump(R.Count, OS);
1569a9ac8606Spatrick 
1570a9ac8606Spatrick     if (R.Kind == CounterMappingRegion::BranchRegion) {
1571a9ac8606Spatrick       OS << ", ";
1572a9ac8606Spatrick       Ctx.dump(R.FalseCount, OS);
1573a9ac8606Spatrick     }
1574a9ac8606Spatrick 
1575e5dd7070Spatrick     if (R.Kind == CounterMappingRegion::ExpansionRegion)
1576e5dd7070Spatrick       OS << " (Expanded file = " << R.ExpandedFileID << ")";
1577e5dd7070Spatrick     OS << "\n";
1578e5dd7070Spatrick   }
1579e5dd7070Spatrick }
1580e5dd7070Spatrick 
CoverageMappingModuleGen(CodeGenModule & CGM,CoverageSourceInfo & SourceInfo)1581a9ac8606Spatrick CoverageMappingModuleGen::CoverageMappingModuleGen(
1582a9ac8606Spatrick     CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
1583a9ac8606Spatrick     : CGM(CGM), SourceInfo(SourceInfo) {
1584a9ac8606Spatrick   CoveragePrefixMap = CGM.getCodeGenOpts().CoveragePrefixMap;
1585a9ac8606Spatrick }
1586a9ac8606Spatrick 
getCurrentDirname()1587a9ac8606Spatrick std::string CoverageMappingModuleGen::getCurrentDirname() {
1588a9ac8606Spatrick   if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty())
1589a9ac8606Spatrick     return CGM.getCodeGenOpts().CoverageCompilationDir;
1590a9ac8606Spatrick 
1591a9ac8606Spatrick   SmallString<256> CWD;
1592a9ac8606Spatrick   llvm::sys::fs::current_path(CWD);
1593a9ac8606Spatrick   return CWD.str().str();
1594a9ac8606Spatrick }
1595a9ac8606Spatrick 
normalizeFilename(StringRef Filename)1596a9ac8606Spatrick std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
1597a9ac8606Spatrick   llvm::SmallString<256> Path(Filename);
1598a9ac8606Spatrick   llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1599a9ac8606Spatrick   for (const auto &Entry : CoveragePrefixMap) {
1600a9ac8606Spatrick     if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
1601a9ac8606Spatrick       break;
1602a9ac8606Spatrick   }
1603a9ac8606Spatrick   return Path.str().str();
1604a9ac8606Spatrick }
1605a9ac8606Spatrick 
getInstrProfSection(const CodeGenModule & CGM,llvm::InstrProfSectKind SK)1606ec727ea7Spatrick static std::string getInstrProfSection(const CodeGenModule &CGM,
1607ec727ea7Spatrick                                        llvm::InstrProfSectKind SK) {
1608ec727ea7Spatrick   return llvm::getInstrProfSectionName(
1609ec727ea7Spatrick       SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
1610ec727ea7Spatrick }
1611ec727ea7Spatrick 
emitFunctionMappingRecord(const FunctionInfo & Info,uint64_t FilenamesRef)1612ec727ea7Spatrick void CoverageMappingModuleGen::emitFunctionMappingRecord(
1613ec727ea7Spatrick     const FunctionInfo &Info, uint64_t FilenamesRef) {
1614e5dd7070Spatrick   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1615ec727ea7Spatrick 
1616ec727ea7Spatrick   // Assign a name to the function record. This is used to merge duplicates.
1617ec727ea7Spatrick   std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
1618ec727ea7Spatrick 
1619ec727ea7Spatrick   // A dummy description for a function included-but-not-used in a TU can be
1620ec727ea7Spatrick   // replaced by full description provided by a different TU. The two kinds of
1621ec727ea7Spatrick   // descriptions play distinct roles: therefore, assign them different names
1622ec727ea7Spatrick   // to prevent `linkonce_odr` merging.
1623ec727ea7Spatrick   if (Info.IsUsed)
1624ec727ea7Spatrick     FuncRecordName += "u";
1625ec727ea7Spatrick 
1626ec727ea7Spatrick   // Create the function record type.
1627ec727ea7Spatrick   const uint64_t NameHash = Info.NameHash;
1628ec727ea7Spatrick   const uint64_t FuncHash = Info.FuncHash;
1629ec727ea7Spatrick   const std::string &CoverageMapping = Info.CoverageMapping;
1630e5dd7070Spatrick #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
1631e5dd7070Spatrick   llvm::Type *FunctionRecordTypes[] = {
1632e5dd7070Spatrick #include "llvm/ProfileData/InstrProfData.inc"
1633e5dd7070Spatrick   };
1634ec727ea7Spatrick   auto *FunctionRecordTy =
1635*12c85518Srobert       llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
1636e5dd7070Spatrick                             /*isPacked=*/true);
1637e5dd7070Spatrick 
1638ec727ea7Spatrick   // Create the function record constant.
1639e5dd7070Spatrick #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
1640e5dd7070Spatrick   llvm::Constant *FunctionRecordVals[] = {
1641e5dd7070Spatrick       #include "llvm/ProfileData/InstrProfData.inc"
1642e5dd7070Spatrick   };
1643*12c85518Srobert   auto *FuncRecordConstant =
1644*12c85518Srobert       llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
1645ec727ea7Spatrick 
1646ec727ea7Spatrick   // Create the function record global.
1647ec727ea7Spatrick   auto *FuncRecord = new llvm::GlobalVariable(
1648ec727ea7Spatrick       CGM.getModule(), FunctionRecordTy, /*isConstant=*/true,
1649ec727ea7Spatrick       llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
1650ec727ea7Spatrick       FuncRecordName);
1651ec727ea7Spatrick   FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
1652ec727ea7Spatrick   FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun));
1653ec727ea7Spatrick   FuncRecord->setAlignment(llvm::Align(8));
1654ec727ea7Spatrick   if (CGM.supportsCOMDAT())
1655ec727ea7Spatrick     FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
1656ec727ea7Spatrick 
1657ec727ea7Spatrick   // Make sure the data doesn't get deleted.
1658ec727ea7Spatrick   CGM.addUsedGlobal(FuncRecord);
1659ec727ea7Spatrick }
1660ec727ea7Spatrick 
addFunctionMappingRecord(llvm::GlobalVariable * NamePtr,StringRef NameValue,uint64_t FuncHash,const std::string & CoverageMapping,bool IsUsed)1661ec727ea7Spatrick void CoverageMappingModuleGen::addFunctionMappingRecord(
1662ec727ea7Spatrick     llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
1663ec727ea7Spatrick     const std::string &CoverageMapping, bool IsUsed) {
1664ec727ea7Spatrick   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1665ec727ea7Spatrick   const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
1666ec727ea7Spatrick   FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
1667ec727ea7Spatrick 
1668e5dd7070Spatrick   if (!IsUsed)
1669e5dd7070Spatrick     FunctionNames.push_back(
1670e5dd7070Spatrick         llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
1671e5dd7070Spatrick 
1672e5dd7070Spatrick   if (CGM.getCodeGenOpts().DumpCoverageMapping) {
1673e5dd7070Spatrick     // Dump the coverage mapping data for this function by decoding the
1674e5dd7070Spatrick     // encoded data. This allows us to dump the mapping regions which were
1675e5dd7070Spatrick     // also processed by the CoverageMappingWriter which performs
1676e5dd7070Spatrick     // additional minimization operations such as reducing the number of
1677e5dd7070Spatrick     // expressions.
1678a9ac8606Spatrick     llvm::SmallVector<std::string, 16> FilenameStrs;
1679e5dd7070Spatrick     std::vector<StringRef> Filenames;
1680e5dd7070Spatrick     std::vector<CounterExpression> Expressions;
1681e5dd7070Spatrick     std::vector<CounterMappingRegion> Regions;
1682a9ac8606Spatrick     FilenameStrs.resize(FileEntries.size() + 1);
1683a9ac8606Spatrick     FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1684e5dd7070Spatrick     for (const auto &Entry : FileEntries) {
1685e5dd7070Spatrick       auto I = Entry.second;
1686e5dd7070Spatrick       FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1687e5dd7070Spatrick     }
1688*12c85518Srobert     ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(FilenameStrs);
1689e5dd7070Spatrick     RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
1690e5dd7070Spatrick                                     Expressions, Regions);
1691e5dd7070Spatrick     if (Reader.read())
1692e5dd7070Spatrick       return;
1693e5dd7070Spatrick     dump(llvm::outs(), NameValue, Expressions, Regions);
1694e5dd7070Spatrick   }
1695e5dd7070Spatrick }
1696e5dd7070Spatrick 
emit()1697e5dd7070Spatrick void CoverageMappingModuleGen::emit() {
1698e5dd7070Spatrick   if (FunctionRecords.empty())
1699e5dd7070Spatrick     return;
1700e5dd7070Spatrick   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1701e5dd7070Spatrick   auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
1702e5dd7070Spatrick 
1703e5dd7070Spatrick   // Create the filenames and merge them with coverage mappings
1704e5dd7070Spatrick   llvm::SmallVector<std::string, 16> FilenameStrs;
1705a9ac8606Spatrick   FilenameStrs.resize(FileEntries.size() + 1);
1706a9ac8606Spatrick   // The first filename is the current working directory.
1707a9ac8606Spatrick   FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1708e5dd7070Spatrick   for (const auto &Entry : FileEntries) {
1709e5dd7070Spatrick     auto I = Entry.second;
1710e5dd7070Spatrick     FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1711e5dd7070Spatrick   }
1712e5dd7070Spatrick 
1713ec727ea7Spatrick   std::string Filenames;
1714ec727ea7Spatrick   {
1715ec727ea7Spatrick     llvm::raw_string_ostream OS(Filenames);
1716a9ac8606Spatrick     CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
1717e5dd7070Spatrick   }
1718ec727ea7Spatrick   auto *FilenamesVal =
1719ec727ea7Spatrick       llvm::ConstantDataArray::getString(Ctx, Filenames, false);
1720ec727ea7Spatrick   const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
1721e5dd7070Spatrick 
1722ec727ea7Spatrick   // Emit the function records.
1723ec727ea7Spatrick   for (const FunctionInfo &Info : FunctionRecords)
1724ec727ea7Spatrick     emitFunctionMappingRecord(Info, FilenamesRef);
1725e5dd7070Spatrick 
1726ec727ea7Spatrick   const unsigned NRecords = 0;
1727ec727ea7Spatrick   const size_t FilenamesSize = Filenames.size();
1728ec727ea7Spatrick   const unsigned CoverageMappingSize = 0;
1729e5dd7070Spatrick   llvm::Type *CovDataHeaderTypes[] = {
1730e5dd7070Spatrick #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
1731e5dd7070Spatrick #include "llvm/ProfileData/InstrProfData.inc"
1732e5dd7070Spatrick   };
1733e5dd7070Spatrick   auto CovDataHeaderTy =
1734*12c85518Srobert       llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes));
1735e5dd7070Spatrick   llvm::Constant *CovDataHeaderVals[] = {
1736e5dd7070Spatrick #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
1737e5dd7070Spatrick #include "llvm/ProfileData/InstrProfData.inc"
1738e5dd7070Spatrick   };
1739*12c85518Srobert   auto CovDataHeaderVal =
1740*12c85518Srobert       llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals));
1741e5dd7070Spatrick 
1742e5dd7070Spatrick   // Create the coverage data record
1743ec727ea7Spatrick   llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
1744*12c85518Srobert   auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes));
1745ec727ea7Spatrick   llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
1746*12c85518Srobert   auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals));
1747e5dd7070Spatrick   auto CovData = new llvm::GlobalVariable(
1748ec727ea7Spatrick       CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
1749e5dd7070Spatrick       CovDataVal, llvm::getCoverageMappingVarName());
1750e5dd7070Spatrick 
1751ec727ea7Spatrick   CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap));
1752e5dd7070Spatrick   CovData->setAlignment(llvm::Align(8));
1753e5dd7070Spatrick 
1754e5dd7070Spatrick   // Make sure the data doesn't get deleted.
1755e5dd7070Spatrick   CGM.addUsedGlobal(CovData);
1756e5dd7070Spatrick   // Create the deferred function records array
1757e5dd7070Spatrick   if (!FunctionNames.empty()) {
1758e5dd7070Spatrick     auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
1759e5dd7070Spatrick                                            FunctionNames.size());
1760e5dd7070Spatrick     auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
1761e5dd7070Spatrick     // This variable will *NOT* be emitted to the object file. It is used
1762e5dd7070Spatrick     // to pass the list of names referenced to codegen.
1763e5dd7070Spatrick     new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
1764e5dd7070Spatrick                              llvm::GlobalValue::InternalLinkage, NamesArrVal,
1765e5dd7070Spatrick                              llvm::getCoverageUnusedNamesVarName());
1766e5dd7070Spatrick   }
1767e5dd7070Spatrick }
1768e5dd7070Spatrick 
getFileID(const FileEntry * File)1769e5dd7070Spatrick unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
1770e5dd7070Spatrick   auto It = FileEntries.find(File);
1771e5dd7070Spatrick   if (It != FileEntries.end())
1772e5dd7070Spatrick     return It->second;
1773a9ac8606Spatrick   unsigned FileID = FileEntries.size() + 1;
1774e5dd7070Spatrick   FileEntries.insert(std::make_pair(File, FileID));
1775e5dd7070Spatrick   return FileID;
1776e5dd7070Spatrick }
1777e5dd7070Spatrick 
emitCounterMapping(const Decl * D,llvm::raw_ostream & OS)1778e5dd7070Spatrick void CoverageMappingGen::emitCounterMapping(const Decl *D,
1779e5dd7070Spatrick                                             llvm::raw_ostream &OS) {
1780e5dd7070Spatrick   assert(CounterMap);
1781e5dd7070Spatrick   CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
1782e5dd7070Spatrick   Walker.VisitDecl(D);
1783e5dd7070Spatrick   Walker.write(OS);
1784e5dd7070Spatrick }
1785e5dd7070Spatrick 
emitEmptyMapping(const Decl * D,llvm::raw_ostream & OS)1786e5dd7070Spatrick void CoverageMappingGen::emitEmptyMapping(const Decl *D,
1787e5dd7070Spatrick                                           llvm::raw_ostream &OS) {
1788e5dd7070Spatrick   EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
1789e5dd7070Spatrick   Walker.VisitDecl(D);
1790e5dd7070Spatrick   Walker.write(OS);
1791e5dd7070Spatrick }
1792