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