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