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

source code of clang/lib/CodeGen/CoverageMappingGen.cpp