10b57cec5SDimitry Andric //===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Instrumentation-based code coverage mapping generator
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "CoverageMappingGen.h"
140b57cec5SDimitry Andric #include "CodeGenFunction.h"
150b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h"
165ffd83dbSDimitry Andric #include "clang/Basic/Diagnostic.h"
175ffd83dbSDimitry Andric #include "clang/Basic/FileManager.h"
185ffd83dbSDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
190b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
205ffd83dbSDimitry Andric #include "llvm/ADT/Optional.h"
210b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
220b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
230b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h"
240b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
250b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
260b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h"
270b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
280b57cec5SDimitry Andric #include "llvm/Support/Path.h"
290b57cec5SDimitry Andric
305ffd83dbSDimitry Andric // This selects the coverage mapping format defined when `InstrProfData.inc`
315ffd83dbSDimitry Andric // is textually included.
325ffd83dbSDimitry Andric #define COVMAP_V3
335ffd83dbSDimitry Andric
34af732203SDimitry Andric static llvm::cl::opt<bool> EmptyLineCommentCoverage(
35af732203SDimitry Andric "emptyline-comment-coverage",
36af732203SDimitry Andric llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
37af732203SDimitry Andric "disable it on test)"),
38af732203SDimitry Andric llvm::cl::init(true), llvm::cl::Hidden);
39af732203SDimitry Andric
400b57cec5SDimitry Andric using namespace clang;
410b57cec5SDimitry Andric using namespace CodeGen;
420b57cec5SDimitry Andric using namespace llvm::coverage;
430b57cec5SDimitry Andric
44af732203SDimitry Andric CoverageSourceInfo *
setUpCoverageCallbacks(Preprocessor & PP)45af732203SDimitry Andric CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) {
46af732203SDimitry Andric CoverageSourceInfo *CoverageInfo =
47af732203SDimitry Andric new CoverageSourceInfo(PP.getSourceManager());
48af732203SDimitry Andric PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
49af732203SDimitry Andric if (EmptyLineCommentCoverage) {
50af732203SDimitry Andric PP.addCommentHandler(CoverageInfo);
51af732203SDimitry Andric PP.setEmptylineHandler(CoverageInfo);
52af732203SDimitry Andric PP.setPreprocessToken(true);
53af732203SDimitry Andric PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
54af732203SDimitry Andric // Update previous token location.
55af732203SDimitry Andric CoverageInfo->PrevTokLoc = Tok.getLocation();
56af732203SDimitry Andric if (Tok.getKind() != clang::tok::eod)
57af732203SDimitry Andric CoverageInfo->updateNextTokLoc(Tok.getLocation());
58af732203SDimitry Andric });
59af732203SDimitry Andric }
60af732203SDimitry Andric return CoverageInfo;
61af732203SDimitry Andric }
62af732203SDimitry Andric
AddSkippedRange(SourceRange Range)63af732203SDimitry Andric void CoverageSourceInfo::AddSkippedRange(SourceRange Range) {
64af732203SDimitry Andric if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
65af732203SDimitry Andric PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
66af732203SDimitry Andric SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
67af732203SDimitry Andric Range.getBegin()))
68af732203SDimitry Andric SkippedRanges.back().Range.setEnd(Range.getEnd());
69af732203SDimitry Andric else
70af732203SDimitry Andric SkippedRanges.push_back({Range, PrevTokLoc});
71af732203SDimitry Andric }
72af732203SDimitry Andric
SourceRangeSkipped(SourceRange Range,SourceLocation)730b57cec5SDimitry Andric void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
74af732203SDimitry Andric AddSkippedRange(Range);
75af732203SDimitry Andric }
76af732203SDimitry Andric
HandleEmptyline(SourceRange Range)77af732203SDimitry Andric void CoverageSourceInfo::HandleEmptyline(SourceRange Range) {
78af732203SDimitry Andric AddSkippedRange(Range);
79af732203SDimitry Andric }
80af732203SDimitry Andric
HandleComment(Preprocessor & PP,SourceRange Range)81af732203SDimitry Andric bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) {
82af732203SDimitry Andric AddSkippedRange(Range);
83af732203SDimitry Andric return false;
84af732203SDimitry Andric }
85af732203SDimitry Andric
updateNextTokLoc(SourceLocation Loc)86af732203SDimitry Andric void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
87af732203SDimitry Andric if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
88af732203SDimitry Andric SkippedRanges.back().NextTokLoc = Loc;
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric namespace {
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric /// A region of source code that can be mapped to a counter.
940b57cec5SDimitry Andric class SourceMappingRegion {
95af732203SDimitry Andric /// Primary Counter that is also used for Branch Regions for "True" branches.
960b57cec5SDimitry Andric Counter Count;
970b57cec5SDimitry Andric
98af732203SDimitry Andric /// Secondary Counter used for Branch Regions for "False" branches.
99af732203SDimitry Andric Optional<Counter> FalseCount;
100af732203SDimitry Andric
1010b57cec5SDimitry Andric /// The region's starting location.
1020b57cec5SDimitry Andric Optional<SourceLocation> LocStart;
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric /// The region's ending location.
1050b57cec5SDimitry Andric Optional<SourceLocation> LocEnd;
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric /// Whether this region is a gap region. The count from a gap region is set
1080b57cec5SDimitry Andric /// as the line execution count if there are no other regions on the line.
1090b57cec5SDimitry Andric bool GapRegion;
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric public:
SourceMappingRegion(Counter Count,Optional<SourceLocation> LocStart,Optional<SourceLocation> LocEnd,bool GapRegion=false)1120b57cec5SDimitry Andric SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart,
113*5f7ddb14SDimitry Andric Optional<SourceLocation> LocEnd, bool GapRegion = false)
114*5f7ddb14SDimitry Andric : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
115*5f7ddb14SDimitry Andric }
1160b57cec5SDimitry Andric
SourceMappingRegion(Counter Count,Optional<Counter> FalseCount,Optional<SourceLocation> LocStart,Optional<SourceLocation> LocEnd,bool GapRegion=false)117af732203SDimitry Andric SourceMappingRegion(Counter Count, Optional<Counter> FalseCount,
118af732203SDimitry Andric Optional<SourceLocation> LocStart,
119*5f7ddb14SDimitry Andric Optional<SourceLocation> LocEnd, bool GapRegion = false)
120af732203SDimitry Andric : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
121*5f7ddb14SDimitry Andric LocEnd(LocEnd), GapRegion(GapRegion) {}
122af732203SDimitry Andric
getCounter() const1230b57cec5SDimitry Andric const Counter &getCounter() const { return Count; }
1240b57cec5SDimitry Andric
getFalseCounter() const125af732203SDimitry Andric const Counter &getFalseCounter() const {
126af732203SDimitry Andric assert(FalseCount && "Region has no alternate counter");
127af732203SDimitry Andric return *FalseCount;
128af732203SDimitry Andric }
129af732203SDimitry Andric
setCounter(Counter C)1300b57cec5SDimitry Andric void setCounter(Counter C) { Count = C; }
1310b57cec5SDimitry Andric
hasStartLoc() const1320b57cec5SDimitry Andric bool hasStartLoc() const { return LocStart.hasValue(); }
1330b57cec5SDimitry Andric
setStartLoc(SourceLocation Loc)1340b57cec5SDimitry Andric void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
1350b57cec5SDimitry Andric
getBeginLoc() const1360b57cec5SDimitry Andric SourceLocation getBeginLoc() const {
1370b57cec5SDimitry Andric assert(LocStart && "Region has no start location");
1380b57cec5SDimitry Andric return *LocStart;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
hasEndLoc() const1410b57cec5SDimitry Andric bool hasEndLoc() const { return LocEnd.hasValue(); }
1420b57cec5SDimitry Andric
setEndLoc(SourceLocation Loc)1430b57cec5SDimitry Andric void setEndLoc(SourceLocation Loc) {
1440b57cec5SDimitry Andric assert(Loc.isValid() && "Setting an invalid end location");
1450b57cec5SDimitry Andric LocEnd = Loc;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric
getEndLoc() const1480b57cec5SDimitry Andric SourceLocation getEndLoc() const {
1490b57cec5SDimitry Andric assert(LocEnd && "Region has no end location");
1500b57cec5SDimitry Andric return *LocEnd;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
isGap() const1530b57cec5SDimitry Andric bool isGap() const { return GapRegion; }
1540b57cec5SDimitry Andric
setGap(bool Gap)1550b57cec5SDimitry Andric void setGap(bool Gap) { GapRegion = Gap; }
156af732203SDimitry Andric
isBranch() const157af732203SDimitry Andric bool isBranch() const { return FalseCount.hasValue(); }
1580b57cec5SDimitry Andric };
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric /// Spelling locations for the start and end of a source region.
1610b57cec5SDimitry Andric struct SpellingRegion {
1620b57cec5SDimitry Andric /// The line where the region starts.
1630b57cec5SDimitry Andric unsigned LineStart;
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric /// The column where the region starts.
1660b57cec5SDimitry Andric unsigned ColumnStart;
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric /// The line where the region ends.
1690b57cec5SDimitry Andric unsigned LineEnd;
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric /// The column where the region ends.
1720b57cec5SDimitry Andric unsigned ColumnEnd;
1730b57cec5SDimitry Andric
SpellingRegion__anone2f8b4240211::SpellingRegion1740b57cec5SDimitry Andric SpellingRegion(SourceManager &SM, SourceLocation LocStart,
1750b57cec5SDimitry Andric SourceLocation LocEnd) {
1760b57cec5SDimitry Andric LineStart = SM.getSpellingLineNumber(LocStart);
1770b57cec5SDimitry Andric ColumnStart = SM.getSpellingColumnNumber(LocStart);
1780b57cec5SDimitry Andric LineEnd = SM.getSpellingLineNumber(LocEnd);
1790b57cec5SDimitry Andric ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
SpellingRegion__anone2f8b4240211::SpellingRegion1820b57cec5SDimitry Andric SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
1830b57cec5SDimitry Andric : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric /// Check if the start and end locations appear in source order, i.e
1860b57cec5SDimitry Andric /// top->bottom, left->right.
isInSourceOrder__anone2f8b4240211::SpellingRegion1870b57cec5SDimitry Andric bool isInSourceOrder() const {
1880b57cec5SDimitry Andric return (LineStart < LineEnd) ||
1890b57cec5SDimitry Andric (LineStart == LineEnd && ColumnStart <= ColumnEnd);
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric };
1920b57cec5SDimitry Andric
1930b57cec5SDimitry Andric /// Provides the common functionality for the different
1940b57cec5SDimitry Andric /// coverage mapping region builders.
1950b57cec5SDimitry Andric class CoverageMappingBuilder {
1960b57cec5SDimitry Andric public:
1970b57cec5SDimitry Andric CoverageMappingModuleGen &CVM;
1980b57cec5SDimitry Andric SourceManager &SM;
1990b57cec5SDimitry Andric const LangOptions &LangOpts;
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric private:
2020b57cec5SDimitry Andric /// Map of clang's FileIDs to IDs used for coverage mapping.
2030b57cec5SDimitry Andric llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
2040b57cec5SDimitry Andric FileIDMapping;
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric public:
2070b57cec5SDimitry Andric /// The coverage mapping regions for this function
2080b57cec5SDimitry Andric llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
2090b57cec5SDimitry Andric /// The source mapping regions for this function.
2100b57cec5SDimitry Andric std::vector<SourceMappingRegion> SourceRegions;
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric /// A set of regions which can be used as a filter.
2130b57cec5SDimitry Andric ///
2140b57cec5SDimitry Andric /// It is produced by emitExpansionRegions() and is used in
2150b57cec5SDimitry Andric /// emitSourceRegions() to suppress producing code regions if
2160b57cec5SDimitry Andric /// the same area is covered by expansion regions.
2170b57cec5SDimitry Andric typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
2180b57cec5SDimitry Andric SourceRegionFilter;
2190b57cec5SDimitry Andric
CoverageMappingBuilder(CoverageMappingModuleGen & CVM,SourceManager & SM,const LangOptions & LangOpts)2200b57cec5SDimitry Andric CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
2210b57cec5SDimitry Andric const LangOptions &LangOpts)
2220b57cec5SDimitry Andric : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric /// Return the precise end location for the given token.
getPreciseTokenLocEnd(SourceLocation Loc)2250b57cec5SDimitry Andric SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
2260b57cec5SDimitry Andric // We avoid getLocForEndOfToken here, because it doesn't do what we want for
2270b57cec5SDimitry Andric // macro locations, which we just treat as expanded files.
2280b57cec5SDimitry Andric unsigned TokLen =
2290b57cec5SDimitry Andric Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
2300b57cec5SDimitry Andric return Loc.getLocWithOffset(TokLen);
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric /// Return the start location of an included file or expanded macro.
getStartOfFileOrMacro(SourceLocation Loc)2340b57cec5SDimitry Andric SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
2350b57cec5SDimitry Andric if (Loc.isMacroID())
2360b57cec5SDimitry Andric return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
2370b57cec5SDimitry Andric return SM.getLocForStartOfFile(SM.getFileID(Loc));
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric
2400b57cec5SDimitry Andric /// Return the end location of an included file or expanded macro.
getEndOfFileOrMacro(SourceLocation Loc)2410b57cec5SDimitry Andric SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
2420b57cec5SDimitry Andric if (Loc.isMacroID())
2430b57cec5SDimitry Andric return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
2440b57cec5SDimitry Andric SM.getFileOffset(Loc));
2450b57cec5SDimitry Andric return SM.getLocForEndOfFile(SM.getFileID(Loc));
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric
2480b57cec5SDimitry Andric /// Find out where the current file is included or macro is expanded.
getIncludeOrExpansionLoc(SourceLocation Loc)2490b57cec5SDimitry Andric SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
2500b57cec5SDimitry Andric return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
2510b57cec5SDimitry Andric : SM.getIncludeLoc(SM.getFileID(Loc));
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
2540b57cec5SDimitry Andric /// Return true if \c Loc is a location in a built-in macro.
isInBuiltin(SourceLocation Loc)2550b57cec5SDimitry Andric bool isInBuiltin(SourceLocation Loc) {
2560b57cec5SDimitry Andric return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric /// Check whether \c Loc is included or expanded from \c Parent.
isNestedIn(SourceLocation Loc,FileID Parent)2600b57cec5SDimitry Andric bool isNestedIn(SourceLocation Loc, FileID Parent) {
2610b57cec5SDimitry Andric do {
2620b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc);
2630b57cec5SDimitry Andric if (Loc.isInvalid())
2640b57cec5SDimitry Andric return false;
2650b57cec5SDimitry Andric } while (!SM.isInFileID(Loc, Parent));
2660b57cec5SDimitry Andric return true;
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric /// Get the start of \c S ignoring macro arguments and builtin macros.
getStart(const Stmt * S)2700b57cec5SDimitry Andric SourceLocation getStart(const Stmt *S) {
2710b57cec5SDimitry Andric SourceLocation Loc = S->getBeginLoc();
2720b57cec5SDimitry Andric while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
2730b57cec5SDimitry Andric Loc = SM.getImmediateExpansionRange(Loc).getBegin();
2740b57cec5SDimitry Andric return Loc;
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric
2770b57cec5SDimitry Andric /// Get the end of \c S ignoring macro arguments and builtin macros.
getEnd(const Stmt * S)2780b57cec5SDimitry Andric SourceLocation getEnd(const Stmt *S) {
2790b57cec5SDimitry Andric SourceLocation Loc = S->getEndLoc();
2800b57cec5SDimitry Andric while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
2810b57cec5SDimitry Andric Loc = SM.getImmediateExpansionRange(Loc).getBegin();
2820b57cec5SDimitry Andric return getPreciseTokenLocEnd(Loc);
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andric /// Find the set of files we have regions for and assign IDs
2860b57cec5SDimitry Andric ///
2870b57cec5SDimitry Andric /// Fills \c Mapping with the virtual file mapping needed to write out
2880b57cec5SDimitry Andric /// coverage and collects the necessary file information to emit source and
2890b57cec5SDimitry Andric /// expansion regions.
gatherFileIDs(SmallVectorImpl<unsigned> & Mapping)2900b57cec5SDimitry Andric void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
2910b57cec5SDimitry Andric FileIDMapping.clear();
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric llvm::SmallSet<FileID, 8> Visited;
2940b57cec5SDimitry Andric SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
2950b57cec5SDimitry Andric for (const auto &Region : SourceRegions) {
2960b57cec5SDimitry Andric SourceLocation Loc = Region.getBeginLoc();
2970b57cec5SDimitry Andric FileID File = SM.getFileID(Loc);
2980b57cec5SDimitry Andric if (!Visited.insert(File).second)
2990b57cec5SDimitry Andric continue;
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric // Do not map FileID's associated with system headers.
3020b57cec5SDimitry Andric if (SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
3030b57cec5SDimitry Andric continue;
3040b57cec5SDimitry Andric
3050b57cec5SDimitry Andric unsigned Depth = 0;
3060b57cec5SDimitry Andric for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
3070b57cec5SDimitry Andric Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
3080b57cec5SDimitry Andric ++Depth;
3090b57cec5SDimitry Andric FileLocs.push_back(std::make_pair(Loc, Depth));
3100b57cec5SDimitry Andric }
3110b57cec5SDimitry Andric llvm::stable_sort(FileLocs, llvm::less_second());
3120b57cec5SDimitry Andric
3130b57cec5SDimitry Andric for (const auto &FL : FileLocs) {
3140b57cec5SDimitry Andric SourceLocation Loc = FL.first;
3150b57cec5SDimitry Andric FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
3160b57cec5SDimitry Andric auto Entry = SM.getFileEntryForID(SpellingFile);
3170b57cec5SDimitry Andric if (!Entry)
3180b57cec5SDimitry Andric continue;
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
3210b57cec5SDimitry Andric Mapping.push_back(CVM.getFileID(Entry));
3220b57cec5SDimitry Andric }
3230b57cec5SDimitry Andric }
3240b57cec5SDimitry Andric
3250b57cec5SDimitry Andric /// Get the coverage mapping file ID for \c Loc.
3260b57cec5SDimitry Andric ///
3270b57cec5SDimitry Andric /// If such file id doesn't exist, return None.
getCoverageFileID(SourceLocation Loc)3280b57cec5SDimitry Andric Optional<unsigned> getCoverageFileID(SourceLocation Loc) {
3290b57cec5SDimitry Andric auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
3300b57cec5SDimitry Andric if (Mapping != FileIDMapping.end())
3310b57cec5SDimitry Andric return Mapping->second.first;
3320b57cec5SDimitry Andric return None;
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric
335af732203SDimitry Andric /// This shrinks the skipped range if it spans a line that contains a
336af732203SDimitry Andric /// non-comment token. If shrinking the skipped range would make it empty,
337af732203SDimitry Andric /// this returns None.
adjustSkippedRange(SourceManager & SM,SourceLocation LocStart,SourceLocation LocEnd,SourceLocation PrevTokLoc,SourceLocation NextTokLoc)338af732203SDimitry Andric Optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
339af732203SDimitry Andric SourceLocation LocStart,
340af732203SDimitry Andric SourceLocation LocEnd,
341af732203SDimitry Andric SourceLocation PrevTokLoc,
342af732203SDimitry Andric SourceLocation NextTokLoc) {
343af732203SDimitry Andric SpellingRegion SR{SM, LocStart, LocEnd};
344af732203SDimitry Andric SR.ColumnStart = 1;
345af732203SDimitry Andric if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
346af732203SDimitry Andric SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
347af732203SDimitry Andric SR.LineStart++;
348af732203SDimitry Andric if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
349af732203SDimitry Andric SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
350af732203SDimitry Andric SR.LineEnd--;
351af732203SDimitry Andric SR.ColumnEnd++;
352af732203SDimitry Andric }
353af732203SDimitry Andric if (SR.isInSourceOrder())
354af732203SDimitry Andric return SR;
355af732203SDimitry Andric return None;
356af732203SDimitry Andric }
357af732203SDimitry Andric
3580b57cec5SDimitry Andric /// Gather all the regions that were skipped by the preprocessor
359af732203SDimitry Andric /// using the constructs like #if or comments.
gatherSkippedRegions()3600b57cec5SDimitry Andric void gatherSkippedRegions() {
3610b57cec5SDimitry Andric /// An array of the minimum lineStarts and the maximum lineEnds
3620b57cec5SDimitry Andric /// for mapping regions from the appropriate source files.
3630b57cec5SDimitry Andric llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
3640b57cec5SDimitry Andric FileLineRanges.resize(
3650b57cec5SDimitry Andric FileIDMapping.size(),
3660b57cec5SDimitry Andric std::make_pair(std::numeric_limits<unsigned>::max(), 0));
3670b57cec5SDimitry Andric for (const auto &R : MappingRegions) {
3680b57cec5SDimitry Andric FileLineRanges[R.FileID].first =
3690b57cec5SDimitry Andric std::min(FileLineRanges[R.FileID].first, R.LineStart);
3700b57cec5SDimitry Andric FileLineRanges[R.FileID].second =
3710b57cec5SDimitry Andric std::max(FileLineRanges[R.FileID].second, R.LineEnd);
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric
3740b57cec5SDimitry Andric auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
375af732203SDimitry Andric for (auto &I : SkippedRanges) {
376af732203SDimitry Andric SourceRange Range = I.Range;
377af732203SDimitry Andric auto LocStart = Range.getBegin();
378af732203SDimitry Andric auto LocEnd = Range.getEnd();
3790b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
3800b57cec5SDimitry Andric "region spans multiple files");
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric auto CovFileID = getCoverageFileID(LocStart);
3830b57cec5SDimitry Andric if (!CovFileID)
3840b57cec5SDimitry Andric continue;
385af732203SDimitry Andric Optional<SpellingRegion> SR =
386af732203SDimitry Andric adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc, I.NextTokLoc);
387af732203SDimitry Andric if (!SR.hasValue())
388af732203SDimitry Andric continue;
3890b57cec5SDimitry Andric auto Region = CounterMappingRegion::makeSkipped(
390af732203SDimitry Andric *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
391af732203SDimitry Andric SR->ColumnEnd);
3920b57cec5SDimitry Andric // Make sure that we only collect the regions that are inside
3930b57cec5SDimitry Andric // the source code of this function.
3940b57cec5SDimitry Andric if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
3950b57cec5SDimitry Andric Region.LineEnd <= FileLineRanges[*CovFileID].second)
3960b57cec5SDimitry Andric MappingRegions.push_back(Region);
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric }
3990b57cec5SDimitry Andric
4000b57cec5SDimitry Andric /// Generate the coverage counter mapping regions from collected
4010b57cec5SDimitry Andric /// source regions.
emitSourceRegions(const SourceRegionFilter & Filter)4020b57cec5SDimitry Andric void emitSourceRegions(const SourceRegionFilter &Filter) {
4030b57cec5SDimitry Andric for (const auto &Region : SourceRegions) {
4040b57cec5SDimitry Andric assert(Region.hasEndLoc() && "incomplete region");
4050b57cec5SDimitry Andric
4060b57cec5SDimitry Andric SourceLocation LocStart = Region.getBeginLoc();
4070b57cec5SDimitry Andric assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
4080b57cec5SDimitry Andric
4090b57cec5SDimitry Andric // Ignore regions from system headers.
4100b57cec5SDimitry Andric if (SM.isInSystemHeader(SM.getSpellingLoc(LocStart)))
4110b57cec5SDimitry Andric continue;
4120b57cec5SDimitry Andric
4130b57cec5SDimitry Andric auto CovFileID = getCoverageFileID(LocStart);
4140b57cec5SDimitry Andric // Ignore regions that don't have a file, such as builtin macros.
4150b57cec5SDimitry Andric if (!CovFileID)
4160b57cec5SDimitry Andric continue;
4170b57cec5SDimitry Andric
4180b57cec5SDimitry Andric SourceLocation LocEnd = Region.getEndLoc();
4190b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
4200b57cec5SDimitry Andric "region spans multiple files");
4210b57cec5SDimitry Andric
4220b57cec5SDimitry Andric // Don't add code regions for the area covered by expansion regions.
4230b57cec5SDimitry Andric // This not only suppresses redundant regions, but sometimes prevents
4240b57cec5SDimitry Andric // creating regions with wrong counters if, for example, a statement's
4250b57cec5SDimitry Andric // body ends at the end of a nested macro.
4260b57cec5SDimitry Andric if (Filter.count(std::make_pair(LocStart, LocEnd)))
4270b57cec5SDimitry Andric continue;
4280b57cec5SDimitry Andric
4290b57cec5SDimitry Andric // Find the spelling locations for the mapping region.
4300b57cec5SDimitry Andric SpellingRegion SR{SM, LocStart, LocEnd};
4310b57cec5SDimitry Andric assert(SR.isInSourceOrder() && "region start and end out of order");
4320b57cec5SDimitry Andric
4330b57cec5SDimitry Andric if (Region.isGap()) {
4340b57cec5SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
4350b57cec5SDimitry Andric Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
4360b57cec5SDimitry Andric SR.LineEnd, SR.ColumnEnd));
437af732203SDimitry Andric } else if (Region.isBranch()) {
438af732203SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
439af732203SDimitry Andric Region.getCounter(), Region.getFalseCounter(), *CovFileID,
440af732203SDimitry Andric SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
4410b57cec5SDimitry Andric } else {
4420b57cec5SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeRegion(
4430b57cec5SDimitry Andric Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
4440b57cec5SDimitry Andric SR.LineEnd, SR.ColumnEnd));
4450b57cec5SDimitry Andric }
4460b57cec5SDimitry Andric }
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric
4490b57cec5SDimitry Andric /// Generate expansion regions for each virtual file we've seen.
emitExpansionRegions()4500b57cec5SDimitry Andric SourceRegionFilter emitExpansionRegions() {
4510b57cec5SDimitry Andric SourceRegionFilter Filter;
4520b57cec5SDimitry Andric for (const auto &FM : FileIDMapping) {
4530b57cec5SDimitry Andric SourceLocation ExpandedLoc = FM.second.second;
4540b57cec5SDimitry Andric SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
4550b57cec5SDimitry Andric if (ParentLoc.isInvalid())
4560b57cec5SDimitry Andric continue;
4570b57cec5SDimitry Andric
4580b57cec5SDimitry Andric auto ParentFileID = getCoverageFileID(ParentLoc);
4590b57cec5SDimitry Andric if (!ParentFileID)
4600b57cec5SDimitry Andric continue;
4610b57cec5SDimitry Andric auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
4620b57cec5SDimitry Andric assert(ExpandedFileID && "expansion in uncovered file");
4630b57cec5SDimitry Andric
4640b57cec5SDimitry Andric SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
4650b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
4660b57cec5SDimitry Andric "region spans multiple files");
4670b57cec5SDimitry Andric Filter.insert(std::make_pair(ParentLoc, LocEnd));
4680b57cec5SDimitry Andric
4690b57cec5SDimitry Andric SpellingRegion SR{SM, ParentLoc, LocEnd};
4700b57cec5SDimitry Andric assert(SR.isInSourceOrder() && "region start and end out of order");
4710b57cec5SDimitry Andric MappingRegions.push_back(CounterMappingRegion::makeExpansion(
4720b57cec5SDimitry Andric *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
4730b57cec5SDimitry Andric SR.LineEnd, SR.ColumnEnd));
4740b57cec5SDimitry Andric }
4750b57cec5SDimitry Andric return Filter;
4760b57cec5SDimitry Andric }
4770b57cec5SDimitry Andric };
4780b57cec5SDimitry Andric
4790b57cec5SDimitry Andric /// Creates unreachable coverage regions for the functions that
4800b57cec5SDimitry Andric /// are not emitted.
4810b57cec5SDimitry Andric struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
EmptyCoverageMappingBuilder__anone2f8b4240211::EmptyCoverageMappingBuilder4820b57cec5SDimitry Andric EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
4830b57cec5SDimitry Andric const LangOptions &LangOpts)
4840b57cec5SDimitry Andric : CoverageMappingBuilder(CVM, SM, LangOpts) {}
4850b57cec5SDimitry Andric
VisitDecl__anone2f8b4240211::EmptyCoverageMappingBuilder4860b57cec5SDimitry Andric void VisitDecl(const Decl *D) {
4870b57cec5SDimitry Andric if (!D->hasBody())
4880b57cec5SDimitry Andric return;
4890b57cec5SDimitry Andric auto Body = D->getBody();
4900b57cec5SDimitry Andric SourceLocation Start = getStart(Body);
4910b57cec5SDimitry Andric SourceLocation End = getEnd(Body);
4920b57cec5SDimitry Andric if (!SM.isWrittenInSameFile(Start, End)) {
4930b57cec5SDimitry Andric // Walk up to find the common ancestor.
4940b57cec5SDimitry Andric // Correct the locations accordingly.
4950b57cec5SDimitry Andric FileID StartFileID = SM.getFileID(Start);
4960b57cec5SDimitry Andric FileID EndFileID = SM.getFileID(End);
4970b57cec5SDimitry Andric while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
4980b57cec5SDimitry Andric Start = getIncludeOrExpansionLoc(Start);
4990b57cec5SDimitry Andric assert(Start.isValid() &&
5000b57cec5SDimitry Andric "Declaration start location not nested within a known region");
5010b57cec5SDimitry Andric StartFileID = SM.getFileID(Start);
5020b57cec5SDimitry Andric }
5030b57cec5SDimitry Andric while (StartFileID != EndFileID) {
5040b57cec5SDimitry Andric End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
5050b57cec5SDimitry Andric assert(End.isValid() &&
5060b57cec5SDimitry Andric "Declaration end location not nested within a known region");
5070b57cec5SDimitry Andric EndFileID = SM.getFileID(End);
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric SourceRegions.emplace_back(Counter(), Start, End);
5110b57cec5SDimitry Andric }
5120b57cec5SDimitry Andric
5130b57cec5SDimitry Andric /// Write the mapping data to the output stream
write__anone2f8b4240211::EmptyCoverageMappingBuilder5140b57cec5SDimitry Andric void write(llvm::raw_ostream &OS) {
5150b57cec5SDimitry Andric SmallVector<unsigned, 16> FileIDMapping;
5160b57cec5SDimitry Andric gatherFileIDs(FileIDMapping);
5170b57cec5SDimitry Andric emitSourceRegions(SourceRegionFilter());
5180b57cec5SDimitry Andric
5190b57cec5SDimitry Andric if (MappingRegions.empty())
5200b57cec5SDimitry Andric return;
5210b57cec5SDimitry Andric
5220b57cec5SDimitry Andric CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
5230b57cec5SDimitry Andric Writer.write(OS);
5240b57cec5SDimitry Andric }
5250b57cec5SDimitry Andric };
5260b57cec5SDimitry Andric
5270b57cec5SDimitry Andric /// A StmtVisitor that creates coverage mapping regions which map
5280b57cec5SDimitry Andric /// from the source code locations to the PGO counters.
5290b57cec5SDimitry Andric struct CounterCoverageMappingBuilder
5300b57cec5SDimitry Andric : public CoverageMappingBuilder,
5310b57cec5SDimitry Andric public ConstStmtVisitor<CounterCoverageMappingBuilder> {
5320b57cec5SDimitry Andric /// The map of statements to count values.
5330b57cec5SDimitry Andric llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
5340b57cec5SDimitry Andric
5350b57cec5SDimitry Andric /// A stack of currently live regions.
5360b57cec5SDimitry Andric std::vector<SourceMappingRegion> RegionStack;
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andric CounterExpressionBuilder Builder;
5390b57cec5SDimitry Andric
5400b57cec5SDimitry Andric /// A location in the most recently visited file or macro.
5410b57cec5SDimitry Andric ///
5420b57cec5SDimitry Andric /// This is used to adjust the active source regions appropriately when
5430b57cec5SDimitry Andric /// expressions cross file or macro boundaries.
5440b57cec5SDimitry Andric SourceLocation MostRecentLocation;
5450b57cec5SDimitry Andric
546*5f7ddb14SDimitry Andric /// Whether the visitor at a terminate statement.
547*5f7ddb14SDimitry Andric bool HasTerminateStmt = false;
548*5f7ddb14SDimitry Andric
549*5f7ddb14SDimitry Andric /// Gap region counter after terminate statement.
550*5f7ddb14SDimitry Andric Counter GapRegionCounter;
5510b57cec5SDimitry Andric
5520b57cec5SDimitry Andric /// Return a counter for the subtraction of \c RHS from \c LHS
subtractCounters__anone2f8b4240211::CounterCoverageMappingBuilder5530b57cec5SDimitry Andric Counter subtractCounters(Counter LHS, Counter RHS) {
5540b57cec5SDimitry Andric return Builder.subtract(LHS, RHS);
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric
5570b57cec5SDimitry Andric /// Return a counter for the sum of \c LHS and \c RHS.
addCounters__anone2f8b4240211::CounterCoverageMappingBuilder5580b57cec5SDimitry Andric Counter addCounters(Counter LHS, Counter RHS) {
5590b57cec5SDimitry Andric return Builder.add(LHS, RHS);
5600b57cec5SDimitry Andric }
5610b57cec5SDimitry Andric
addCounters__anone2f8b4240211::CounterCoverageMappingBuilder5620b57cec5SDimitry Andric Counter addCounters(Counter C1, Counter C2, Counter C3) {
5630b57cec5SDimitry Andric return addCounters(addCounters(C1, C2), C3);
5640b57cec5SDimitry Andric }
5650b57cec5SDimitry Andric
5660b57cec5SDimitry Andric /// Return the region counter for the given statement.
5670b57cec5SDimitry Andric ///
5680b57cec5SDimitry Andric /// This should only be called on statements that have a dedicated counter.
getRegionCounter__anone2f8b4240211::CounterCoverageMappingBuilder5690b57cec5SDimitry Andric Counter getRegionCounter(const Stmt *S) {
5700b57cec5SDimitry Andric return Counter::getCounter(CounterMap[S]);
5710b57cec5SDimitry Andric }
5720b57cec5SDimitry Andric
5730b57cec5SDimitry Andric /// Push a region onto the stack.
5740b57cec5SDimitry Andric ///
5750b57cec5SDimitry Andric /// Returns the index on the stack where the region was pushed. This can be
5760b57cec5SDimitry Andric /// used with popRegions to exit a "scope", ending the region that was pushed.
pushRegion__anone2f8b4240211::CounterCoverageMappingBuilder5770b57cec5SDimitry Andric size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None,
578af732203SDimitry Andric Optional<SourceLocation> EndLoc = None,
579af732203SDimitry Andric Optional<Counter> FalseCount = None) {
580af732203SDimitry Andric
581af732203SDimitry Andric if (StartLoc && !FalseCount.hasValue()) {
5820b57cec5SDimitry Andric MostRecentLocation = *StartLoc;
5830b57cec5SDimitry Andric }
584af732203SDimitry Andric
585*5f7ddb14SDimitry Andric RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
5860b57cec5SDimitry Andric
5870b57cec5SDimitry Andric return RegionStack.size() - 1;
5880b57cec5SDimitry Andric }
5890b57cec5SDimitry Andric
locationDepth__anone2f8b4240211::CounterCoverageMappingBuilder5900b57cec5SDimitry Andric size_t locationDepth(SourceLocation Loc) {
5910b57cec5SDimitry Andric size_t Depth = 0;
5920b57cec5SDimitry Andric while (Loc.isValid()) {
5930b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc);
5940b57cec5SDimitry Andric Depth++;
5950b57cec5SDimitry Andric }
5960b57cec5SDimitry Andric return Depth;
5970b57cec5SDimitry Andric }
5980b57cec5SDimitry Andric
5990b57cec5SDimitry Andric /// Pop regions from the stack into the function's list of regions.
6000b57cec5SDimitry Andric ///
6010b57cec5SDimitry Andric /// Adds all regions from \c ParentIndex to the top of the stack to the
6020b57cec5SDimitry Andric /// function's \c SourceRegions.
popRegions__anone2f8b4240211::CounterCoverageMappingBuilder6030b57cec5SDimitry Andric void popRegions(size_t ParentIndex) {
6040b57cec5SDimitry Andric assert(RegionStack.size() >= ParentIndex && "parent not in stack");
6050b57cec5SDimitry Andric while (RegionStack.size() > ParentIndex) {
6060b57cec5SDimitry Andric SourceMappingRegion &Region = RegionStack.back();
6070b57cec5SDimitry Andric if (Region.hasStartLoc()) {
6080b57cec5SDimitry Andric SourceLocation StartLoc = Region.getBeginLoc();
6090b57cec5SDimitry Andric SourceLocation EndLoc = Region.hasEndLoc()
6100b57cec5SDimitry Andric ? Region.getEndLoc()
6110b57cec5SDimitry Andric : RegionStack[ParentIndex].getEndLoc();
612af732203SDimitry Andric bool isBranch = Region.isBranch();
6130b57cec5SDimitry Andric size_t StartDepth = locationDepth(StartLoc);
6140b57cec5SDimitry Andric size_t EndDepth = locationDepth(EndLoc);
6150b57cec5SDimitry Andric while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
6160b57cec5SDimitry Andric bool UnnestStart = StartDepth >= EndDepth;
6170b57cec5SDimitry Andric bool UnnestEnd = EndDepth >= StartDepth;
6180b57cec5SDimitry Andric if (UnnestEnd) {
619af732203SDimitry Andric // The region ends in a nested file or macro expansion. If the
620af732203SDimitry Andric // region is not a branch region, create a separate region for each
621af732203SDimitry Andric // expansion, and for all regions, update the EndLoc. Branch
622af732203SDimitry Andric // regions should not be split in order to keep a straightforward
623af732203SDimitry Andric // correspondance between the region and its associated branch
624af732203SDimitry Andric // condition, even if the condition spans multiple depths.
6250b57cec5SDimitry Andric SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
6260b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
6270b57cec5SDimitry Andric
628af732203SDimitry Andric if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
629af732203SDimitry Andric SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
630af732203SDimitry Andric EndLoc);
6310b57cec5SDimitry Andric
6320b57cec5SDimitry Andric EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
6330b57cec5SDimitry Andric if (EndLoc.isInvalid())
634af732203SDimitry Andric llvm::report_fatal_error(
635af732203SDimitry Andric "File exit not handled before popRegions");
6360b57cec5SDimitry Andric EndDepth--;
6370b57cec5SDimitry Andric }
6380b57cec5SDimitry Andric if (UnnestStart) {
639af732203SDimitry Andric // The region ends in a nested file or macro expansion. If the
640af732203SDimitry Andric // region is not a branch region, create a separate region for each
641af732203SDimitry Andric // expansion, and for all regions, update the StartLoc. Branch
642af732203SDimitry Andric // regions should not be split in order to keep a straightforward
643af732203SDimitry Andric // correspondance between the region and its associated branch
644af732203SDimitry Andric // condition, even if the condition spans multiple depths.
6450b57cec5SDimitry Andric SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
6460b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
6470b57cec5SDimitry Andric
648af732203SDimitry Andric if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
649af732203SDimitry Andric SourceRegions.emplace_back(Region.getCounter(), StartLoc,
650af732203SDimitry Andric NestedLoc);
6510b57cec5SDimitry Andric
6520b57cec5SDimitry Andric StartLoc = getIncludeOrExpansionLoc(StartLoc);
6530b57cec5SDimitry Andric if (StartLoc.isInvalid())
654af732203SDimitry Andric llvm::report_fatal_error(
655af732203SDimitry Andric "File exit not handled before popRegions");
6560b57cec5SDimitry Andric StartDepth--;
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric }
6590b57cec5SDimitry Andric Region.setStartLoc(StartLoc);
6600b57cec5SDimitry Andric Region.setEndLoc(EndLoc);
6610b57cec5SDimitry Andric
662af732203SDimitry Andric if (!isBranch) {
6630b57cec5SDimitry Andric MostRecentLocation = EndLoc;
664af732203SDimitry Andric // If this region happens to span an entire expansion, we need to
665af732203SDimitry Andric // make sure we don't overlap the parent region with it.
6660b57cec5SDimitry Andric if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
6670b57cec5SDimitry Andric EndLoc == getEndOfFileOrMacro(EndLoc))
6680b57cec5SDimitry Andric MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
669af732203SDimitry Andric }
6700b57cec5SDimitry Andric
6710b57cec5SDimitry Andric assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
6720b57cec5SDimitry Andric assert(SpellingRegion(SM, Region).isInSourceOrder());
6730b57cec5SDimitry Andric SourceRegions.push_back(Region);
6740b57cec5SDimitry Andric }
6750b57cec5SDimitry Andric RegionStack.pop_back();
6760b57cec5SDimitry Andric }
6770b57cec5SDimitry Andric }
6780b57cec5SDimitry Andric
6790b57cec5SDimitry Andric /// Return the currently active region.
getRegion__anone2f8b4240211::CounterCoverageMappingBuilder6800b57cec5SDimitry Andric SourceMappingRegion &getRegion() {
6810b57cec5SDimitry Andric assert(!RegionStack.empty() && "statement has no region");
6820b57cec5SDimitry Andric return RegionStack.back();
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric
6850b57cec5SDimitry Andric /// Propagate counts through the children of \p S if \p VisitChildren is true.
6860b57cec5SDimitry Andric /// Otherwise, only emit a count for \p S itself.
propagateCounts__anone2f8b4240211::CounterCoverageMappingBuilder6870b57cec5SDimitry Andric Counter propagateCounts(Counter TopCount, const Stmt *S,
6880b57cec5SDimitry Andric bool VisitChildren = true) {
6890b57cec5SDimitry Andric SourceLocation StartLoc = getStart(S);
6900b57cec5SDimitry Andric SourceLocation EndLoc = getEnd(S);
6910b57cec5SDimitry Andric size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
6920b57cec5SDimitry Andric if (VisitChildren)
6930b57cec5SDimitry Andric Visit(S);
6940b57cec5SDimitry Andric Counter ExitCount = getRegion().getCounter();
6950b57cec5SDimitry Andric popRegions(Index);
6960b57cec5SDimitry Andric
6970b57cec5SDimitry Andric // The statement may be spanned by an expansion. Make sure we handle a file
6980b57cec5SDimitry Andric // exit out of this expansion before moving to the next statement.
6990b57cec5SDimitry Andric if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
7000b57cec5SDimitry Andric MostRecentLocation = EndLoc;
7010b57cec5SDimitry Andric
7020b57cec5SDimitry Andric return ExitCount;
7030b57cec5SDimitry Andric }
7040b57cec5SDimitry Andric
705af732203SDimitry Andric /// Determine whether the given condition can be constant folded.
ConditionFoldsToBool__anone2f8b4240211::CounterCoverageMappingBuilder706af732203SDimitry Andric bool ConditionFoldsToBool(const Expr *Cond) {
707af732203SDimitry Andric Expr::EvalResult Result;
708af732203SDimitry Andric return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext()));
709af732203SDimitry Andric }
710af732203SDimitry Andric
711af732203SDimitry Andric /// Create a Branch Region around an instrumentable condition for coverage
712af732203SDimitry Andric /// and add it to the function's SourceRegions. A branch region tracks a
713af732203SDimitry Andric /// "True" counter and a "False" counter for boolean expressions that
714af732203SDimitry Andric /// result in the generation of a branch.
createBranchRegion__anone2f8b4240211::CounterCoverageMappingBuilder715af732203SDimitry Andric void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt) {
716af732203SDimitry Andric // Check for NULL conditions.
717af732203SDimitry Andric if (!C)
718af732203SDimitry Andric return;
719af732203SDimitry Andric
720af732203SDimitry Andric // Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push
721af732203SDimitry Andric // region onto RegionStack but immediately pop it (which adds it to the
722af732203SDimitry Andric // function's SourceRegions) because it doesn't apply to any other source
723af732203SDimitry Andric // code other than the Condition.
724af732203SDimitry Andric if (CodeGenFunction::isInstrumentedCondition(C)) {
725af732203SDimitry Andric // If a condition can fold to true or false, the corresponding branch
726af732203SDimitry Andric // will be removed. Create a region with both counters hard-coded to
727af732203SDimitry Andric // zero. This allows us to visualize them in a special way.
728af732203SDimitry Andric // Alternatively, we can prevent any optimization done via
729af732203SDimitry Andric // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
730af732203SDimitry Andric // CodeGenFunction.c always returns false, but that is very heavy-handed.
731af732203SDimitry Andric if (ConditionFoldsToBool(C))
732af732203SDimitry Andric popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
733af732203SDimitry Andric Counter::getZero()));
734af732203SDimitry Andric else
735af732203SDimitry Andric // Otherwise, create a region with the True counter and False counter.
736af732203SDimitry Andric popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
737af732203SDimitry Andric }
738af732203SDimitry Andric }
739af732203SDimitry Andric
740af732203SDimitry Andric /// Create a Branch Region around a SwitchCase for code coverage
741af732203SDimitry Andric /// and add it to the function's SourceRegions.
createSwitchCaseRegion__anone2f8b4240211::CounterCoverageMappingBuilder742af732203SDimitry Andric void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
743af732203SDimitry Andric Counter FalseCnt) {
744af732203SDimitry Andric // Push region onto RegionStack but immediately pop it (which adds it to
745af732203SDimitry Andric // the function's SourceRegions) because it doesn't apply to any other
746af732203SDimitry Andric // source other than the SwitchCase.
747af732203SDimitry Andric popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
748af732203SDimitry Andric }
749af732203SDimitry Andric
7500b57cec5SDimitry Andric /// Check whether a region with bounds \c StartLoc and \c EndLoc
7510b57cec5SDimitry Andric /// is already added to \c SourceRegions.
isRegionAlreadyAdded__anone2f8b4240211::CounterCoverageMappingBuilder752af732203SDimitry Andric bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
753af732203SDimitry Andric bool isBranch = false) {
7540b57cec5SDimitry Andric return SourceRegions.rend() !=
7550b57cec5SDimitry Andric std::find_if(SourceRegions.rbegin(), SourceRegions.rend(),
7560b57cec5SDimitry Andric [&](const SourceMappingRegion &Region) {
7570b57cec5SDimitry Andric return Region.getBeginLoc() == StartLoc &&
758af732203SDimitry Andric Region.getEndLoc() == EndLoc &&
759af732203SDimitry Andric Region.isBranch() == isBranch;
7600b57cec5SDimitry Andric });
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric
7630b57cec5SDimitry Andric /// Adjust the most recently visited location to \c EndLoc.
7640b57cec5SDimitry Andric ///
7650b57cec5SDimitry Andric /// This should be used after visiting any statements in non-source order.
adjustForOutOfOrderTraversal__anone2f8b4240211::CounterCoverageMappingBuilder7660b57cec5SDimitry Andric void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
7670b57cec5SDimitry Andric MostRecentLocation = EndLoc;
7680b57cec5SDimitry Andric // The code region for a whole macro is created in handleFileExit() when
7690b57cec5SDimitry Andric // it detects exiting of the virtual file of that macro. If we visited
7700b57cec5SDimitry Andric // statements in non-source order, we might already have such a region
7710b57cec5SDimitry Andric // added, for example, if a body of a loop is divided among multiple
7720b57cec5SDimitry Andric // macros. Avoid adding duplicate regions in such case.
7730b57cec5SDimitry Andric if (getRegion().hasEndLoc() &&
7740b57cec5SDimitry Andric MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
7750b57cec5SDimitry Andric isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
776af732203SDimitry Andric MostRecentLocation, getRegion().isBranch()))
7770b57cec5SDimitry Andric MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric
7800b57cec5SDimitry Andric /// Adjust regions and state when \c NewLoc exits a file.
7810b57cec5SDimitry Andric ///
7820b57cec5SDimitry Andric /// If moving from our most recently tracked location to \c NewLoc exits any
7830b57cec5SDimitry Andric /// files, this adjusts our current region stack and creates the file regions
7840b57cec5SDimitry Andric /// for the exited file.
handleFileExit__anone2f8b4240211::CounterCoverageMappingBuilder7850b57cec5SDimitry Andric void handleFileExit(SourceLocation NewLoc) {
7860b57cec5SDimitry Andric if (NewLoc.isInvalid() ||
7870b57cec5SDimitry Andric SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
7880b57cec5SDimitry Andric return;
7890b57cec5SDimitry Andric
7900b57cec5SDimitry Andric // If NewLoc is not in a file that contains MostRecentLocation, walk up to
7910b57cec5SDimitry Andric // find the common ancestor.
7920b57cec5SDimitry Andric SourceLocation LCA = NewLoc;
7930b57cec5SDimitry Andric FileID ParentFile = SM.getFileID(LCA);
7940b57cec5SDimitry Andric while (!isNestedIn(MostRecentLocation, ParentFile)) {
7950b57cec5SDimitry Andric LCA = getIncludeOrExpansionLoc(LCA);
7960b57cec5SDimitry Andric if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
7970b57cec5SDimitry Andric // Since there isn't a common ancestor, no file was exited. We just need
7980b57cec5SDimitry Andric // to adjust our location to the new file.
7990b57cec5SDimitry Andric MostRecentLocation = NewLoc;
8000b57cec5SDimitry Andric return;
8010b57cec5SDimitry Andric }
8020b57cec5SDimitry Andric ParentFile = SM.getFileID(LCA);
8030b57cec5SDimitry Andric }
8040b57cec5SDimitry Andric
8050b57cec5SDimitry Andric llvm::SmallSet<SourceLocation, 8> StartLocs;
8060b57cec5SDimitry Andric Optional<Counter> ParentCounter;
8070b57cec5SDimitry Andric for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
8080b57cec5SDimitry Andric if (!I.hasStartLoc())
8090b57cec5SDimitry Andric continue;
8100b57cec5SDimitry Andric SourceLocation Loc = I.getBeginLoc();
8110b57cec5SDimitry Andric if (!isNestedIn(Loc, ParentFile)) {
8120b57cec5SDimitry Andric ParentCounter = I.getCounter();
8130b57cec5SDimitry Andric break;
8140b57cec5SDimitry Andric }
8150b57cec5SDimitry Andric
8160b57cec5SDimitry Andric while (!SM.isInFileID(Loc, ParentFile)) {
8170b57cec5SDimitry Andric // The most nested region for each start location is the one with the
8180b57cec5SDimitry Andric // correct count. We avoid creating redundant regions by stopping once
8190b57cec5SDimitry Andric // we've seen this region.
820af732203SDimitry Andric if (StartLocs.insert(Loc).second) {
821af732203SDimitry Andric if (I.isBranch())
822af732203SDimitry Andric SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
823af732203SDimitry Andric getEndOfFileOrMacro(Loc), I.isBranch());
824af732203SDimitry Andric else
8250b57cec5SDimitry Andric SourceRegions.emplace_back(I.getCounter(), Loc,
8260b57cec5SDimitry Andric getEndOfFileOrMacro(Loc));
827af732203SDimitry Andric }
8280b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc);
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric I.setStartLoc(getPreciseTokenLocEnd(Loc));
8310b57cec5SDimitry Andric }
8320b57cec5SDimitry Andric
8330b57cec5SDimitry Andric if (ParentCounter) {
8340b57cec5SDimitry Andric // If the file is contained completely by another region and doesn't
8350b57cec5SDimitry Andric // immediately start its own region, the whole file gets a region
8360b57cec5SDimitry Andric // corresponding to the parent.
8370b57cec5SDimitry Andric SourceLocation Loc = MostRecentLocation;
8380b57cec5SDimitry Andric while (isNestedIn(Loc, ParentFile)) {
8390b57cec5SDimitry Andric SourceLocation FileStart = getStartOfFileOrMacro(Loc);
8400b57cec5SDimitry Andric if (StartLocs.insert(FileStart).second) {
8410b57cec5SDimitry Andric SourceRegions.emplace_back(*ParentCounter, FileStart,
8420b57cec5SDimitry Andric getEndOfFileOrMacro(Loc));
8430b57cec5SDimitry Andric assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
8440b57cec5SDimitry Andric }
8450b57cec5SDimitry Andric Loc = getIncludeOrExpansionLoc(Loc);
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric }
8480b57cec5SDimitry Andric
8490b57cec5SDimitry Andric MostRecentLocation = NewLoc;
8500b57cec5SDimitry Andric }
8510b57cec5SDimitry Andric
8520b57cec5SDimitry Andric /// Ensure that \c S is included in the current region.
extendRegion__anone2f8b4240211::CounterCoverageMappingBuilder8530b57cec5SDimitry Andric void extendRegion(const Stmt *S) {
8540b57cec5SDimitry Andric SourceMappingRegion &Region = getRegion();
8550b57cec5SDimitry Andric SourceLocation StartLoc = getStart(S);
8560b57cec5SDimitry Andric
8570b57cec5SDimitry Andric handleFileExit(StartLoc);
8580b57cec5SDimitry Andric if (!Region.hasStartLoc())
8590b57cec5SDimitry Andric Region.setStartLoc(StartLoc);
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric
8620b57cec5SDimitry Andric /// Mark \c S as a terminator, starting a zero region.
terminateRegion__anone2f8b4240211::CounterCoverageMappingBuilder8630b57cec5SDimitry Andric void terminateRegion(const Stmt *S) {
8640b57cec5SDimitry Andric extendRegion(S);
8650b57cec5SDimitry Andric SourceMappingRegion &Region = getRegion();
8660b57cec5SDimitry Andric SourceLocation EndLoc = getEnd(S);
8670b57cec5SDimitry Andric if (!Region.hasEndLoc())
8680b57cec5SDimitry Andric Region.setEndLoc(EndLoc);
8690b57cec5SDimitry Andric pushRegion(Counter::getZero());
870*5f7ddb14SDimitry Andric HasTerminateStmt = true;
8710b57cec5SDimitry Andric }
8720b57cec5SDimitry Andric
8730b57cec5SDimitry Andric /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
findGapAreaBetween__anone2f8b4240211::CounterCoverageMappingBuilder8740b57cec5SDimitry Andric Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
8750b57cec5SDimitry Andric SourceLocation BeforeLoc) {
876*5f7ddb14SDimitry Andric // If AfterLoc is in function-like macro, use the right parenthesis
877*5f7ddb14SDimitry Andric // location.
878*5f7ddb14SDimitry Andric if (AfterLoc.isMacroID()) {
879*5f7ddb14SDimitry Andric FileID FID = SM.getFileID(AfterLoc);
880*5f7ddb14SDimitry Andric const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
881*5f7ddb14SDimitry Andric if (EI->isFunctionMacroExpansion())
882*5f7ddb14SDimitry Andric AfterLoc = EI->getExpansionLocEnd();
883*5f7ddb14SDimitry Andric }
884*5f7ddb14SDimitry Andric
885*5f7ddb14SDimitry Andric size_t StartDepth = locationDepth(AfterLoc);
886*5f7ddb14SDimitry Andric size_t EndDepth = locationDepth(BeforeLoc);
887*5f7ddb14SDimitry Andric while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
888*5f7ddb14SDimitry Andric bool UnnestStart = StartDepth >= EndDepth;
889*5f7ddb14SDimitry Andric bool UnnestEnd = EndDepth >= StartDepth;
890*5f7ddb14SDimitry Andric if (UnnestEnd) {
891*5f7ddb14SDimitry Andric assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
892*5f7ddb14SDimitry Andric BeforeLoc));
893*5f7ddb14SDimitry Andric
894*5f7ddb14SDimitry Andric BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
895*5f7ddb14SDimitry Andric assert(BeforeLoc.isValid());
896*5f7ddb14SDimitry Andric EndDepth--;
897*5f7ddb14SDimitry Andric }
898*5f7ddb14SDimitry Andric if (UnnestStart) {
899*5f7ddb14SDimitry Andric assert(SM.isWrittenInSameFile(AfterLoc,
900*5f7ddb14SDimitry Andric getEndOfFileOrMacro(AfterLoc)));
901*5f7ddb14SDimitry Andric
902*5f7ddb14SDimitry Andric AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
903*5f7ddb14SDimitry Andric assert(AfterLoc.isValid());
904*5f7ddb14SDimitry Andric AfterLoc = getPreciseTokenLocEnd(AfterLoc);
905*5f7ddb14SDimitry Andric assert(AfterLoc.isValid());
906*5f7ddb14SDimitry Andric StartDepth--;
907*5f7ddb14SDimitry Andric }
908*5f7ddb14SDimitry Andric }
909*5f7ddb14SDimitry Andric AfterLoc = getPreciseTokenLocEnd(AfterLoc);
9100b57cec5SDimitry Andric // If the start and end locations of the gap are both within the same macro
9110b57cec5SDimitry Andric // file, the range may not be in source order.
9120b57cec5SDimitry Andric if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
9130b57cec5SDimitry Andric return None;
914*5f7ddb14SDimitry Andric if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
915*5f7ddb14SDimitry Andric !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
9160b57cec5SDimitry Andric return None;
9170b57cec5SDimitry Andric return {{AfterLoc, BeforeLoc}};
9180b57cec5SDimitry Andric }
9190b57cec5SDimitry Andric
9200b57cec5SDimitry Andric /// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
fillGapAreaWithCount__anone2f8b4240211::CounterCoverageMappingBuilder9210b57cec5SDimitry Andric void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
9220b57cec5SDimitry Andric Counter Count) {
9230b57cec5SDimitry Andric if (StartLoc == EndLoc)
9240b57cec5SDimitry Andric return;
9250b57cec5SDimitry Andric assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
9260b57cec5SDimitry Andric handleFileExit(StartLoc);
9270b57cec5SDimitry Andric size_t Index = pushRegion(Count, StartLoc, EndLoc);
9280b57cec5SDimitry Andric getRegion().setGap(true);
9290b57cec5SDimitry Andric handleFileExit(EndLoc);
9300b57cec5SDimitry Andric popRegions(Index);
9310b57cec5SDimitry Andric }
9320b57cec5SDimitry Andric
9330b57cec5SDimitry Andric /// Keep counts of breaks and continues inside loops.
9340b57cec5SDimitry Andric struct BreakContinue {
9350b57cec5SDimitry Andric Counter BreakCount;
9360b57cec5SDimitry Andric Counter ContinueCount;
9370b57cec5SDimitry Andric };
9380b57cec5SDimitry Andric SmallVector<BreakContinue, 8> BreakContinueStack;
9390b57cec5SDimitry Andric
CounterCoverageMappingBuilder__anone2f8b4240211::CounterCoverageMappingBuilder9400b57cec5SDimitry Andric CounterCoverageMappingBuilder(
9410b57cec5SDimitry Andric CoverageMappingModuleGen &CVM,
9420b57cec5SDimitry Andric llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
9430b57cec5SDimitry Andric const LangOptions &LangOpts)
944*5f7ddb14SDimitry Andric : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
9450b57cec5SDimitry Andric
9460b57cec5SDimitry Andric /// Write the mapping data to the output stream
write__anone2f8b4240211::CounterCoverageMappingBuilder9470b57cec5SDimitry Andric void write(llvm::raw_ostream &OS) {
9480b57cec5SDimitry Andric llvm::SmallVector<unsigned, 8> VirtualFileMapping;
9490b57cec5SDimitry Andric gatherFileIDs(VirtualFileMapping);
9500b57cec5SDimitry Andric SourceRegionFilter Filter = emitExpansionRegions();
9510b57cec5SDimitry Andric emitSourceRegions(Filter);
9520b57cec5SDimitry Andric gatherSkippedRegions();
9530b57cec5SDimitry Andric
9540b57cec5SDimitry Andric if (MappingRegions.empty())
9550b57cec5SDimitry Andric return;
9560b57cec5SDimitry Andric
9570b57cec5SDimitry Andric CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
9580b57cec5SDimitry Andric MappingRegions);
9590b57cec5SDimitry Andric Writer.write(OS);
9600b57cec5SDimitry Andric }
9610b57cec5SDimitry Andric
VisitStmt__anone2f8b4240211::CounterCoverageMappingBuilder9620b57cec5SDimitry Andric void VisitStmt(const Stmt *S) {
9630b57cec5SDimitry Andric if (S->getBeginLoc().isValid())
9640b57cec5SDimitry Andric extendRegion(S);
965*5f7ddb14SDimitry Andric const Stmt *LastStmt = nullptr;
966*5f7ddb14SDimitry Andric bool SaveTerminateStmt = HasTerminateStmt;
967*5f7ddb14SDimitry Andric HasTerminateStmt = false;
968*5f7ddb14SDimitry Andric GapRegionCounter = Counter::getZero();
9690b57cec5SDimitry Andric for (const Stmt *Child : S->children())
970*5f7ddb14SDimitry Andric if (Child) {
971*5f7ddb14SDimitry Andric // If last statement contains terminate statements, add a gap area
972*5f7ddb14SDimitry Andric // between the two statements. Skipping attributed statements, because
973*5f7ddb14SDimitry Andric // they don't have valid start location.
974*5f7ddb14SDimitry Andric if (LastStmt && HasTerminateStmt && !dyn_cast<AttributedStmt>(Child)) {
975*5f7ddb14SDimitry Andric auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
976*5f7ddb14SDimitry Andric if (Gap)
977*5f7ddb14SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
978*5f7ddb14SDimitry Andric GapRegionCounter);
979*5f7ddb14SDimitry Andric SaveTerminateStmt = true;
980*5f7ddb14SDimitry Andric HasTerminateStmt = false;
981*5f7ddb14SDimitry Andric }
9820b57cec5SDimitry Andric this->Visit(Child);
983*5f7ddb14SDimitry Andric LastStmt = Child;
984*5f7ddb14SDimitry Andric }
985*5f7ddb14SDimitry Andric if (SaveTerminateStmt)
986*5f7ddb14SDimitry Andric HasTerminateStmt = true;
9870b57cec5SDimitry Andric handleFileExit(getEnd(S));
9880b57cec5SDimitry Andric }
9890b57cec5SDimitry Andric
VisitDecl__anone2f8b4240211::CounterCoverageMappingBuilder9900b57cec5SDimitry Andric void VisitDecl(const Decl *D) {
9910b57cec5SDimitry Andric Stmt *Body = D->getBody();
9920b57cec5SDimitry Andric
9930b57cec5SDimitry Andric // Do not propagate region counts into system headers.
9940b57cec5SDimitry Andric if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
9950b57cec5SDimitry Andric return;
9960b57cec5SDimitry Andric
9970b57cec5SDimitry Andric // Do not visit the artificial children nodes of defaulted methods. The
9980b57cec5SDimitry Andric // lexer may not be able to report back precise token end locations for
9990b57cec5SDimitry Andric // these children nodes (llvm.org/PR39822), and moreover users will not be
10000b57cec5SDimitry Andric // able to see coverage for them.
10010b57cec5SDimitry Andric bool Defaulted = false;
10020b57cec5SDimitry Andric if (auto *Method = dyn_cast<CXXMethodDecl>(D))
10030b57cec5SDimitry Andric Defaulted = Method->isDefaulted();
10040b57cec5SDimitry Andric
10050b57cec5SDimitry Andric propagateCounts(getRegionCounter(Body), Body,
10060b57cec5SDimitry Andric /*VisitChildren=*/!Defaulted);
10070b57cec5SDimitry Andric assert(RegionStack.empty() && "Regions entered but never exited");
10080b57cec5SDimitry Andric }
10090b57cec5SDimitry Andric
VisitReturnStmt__anone2f8b4240211::CounterCoverageMappingBuilder10100b57cec5SDimitry Andric void VisitReturnStmt(const ReturnStmt *S) {
10110b57cec5SDimitry Andric extendRegion(S);
10120b57cec5SDimitry Andric if (S->getRetValue())
10130b57cec5SDimitry Andric Visit(S->getRetValue());
10140b57cec5SDimitry Andric terminateRegion(S);
10150b57cec5SDimitry Andric }
10160b57cec5SDimitry Andric
VisitCoroutineBodyStmt__anone2f8b4240211::CounterCoverageMappingBuilder10175ffd83dbSDimitry Andric void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
10185ffd83dbSDimitry Andric extendRegion(S);
10195ffd83dbSDimitry Andric Visit(S->getBody());
10205ffd83dbSDimitry Andric }
10215ffd83dbSDimitry Andric
VisitCoreturnStmt__anone2f8b4240211::CounterCoverageMappingBuilder10225ffd83dbSDimitry Andric void VisitCoreturnStmt(const CoreturnStmt *S) {
10235ffd83dbSDimitry Andric extendRegion(S);
10245ffd83dbSDimitry Andric if (S->getOperand())
10255ffd83dbSDimitry Andric Visit(S->getOperand());
10265ffd83dbSDimitry Andric terminateRegion(S);
10275ffd83dbSDimitry Andric }
10285ffd83dbSDimitry Andric
VisitCXXThrowExpr__anone2f8b4240211::CounterCoverageMappingBuilder10290b57cec5SDimitry Andric void VisitCXXThrowExpr(const CXXThrowExpr *E) {
10300b57cec5SDimitry Andric extendRegion(E);
10310b57cec5SDimitry Andric if (E->getSubExpr())
10320b57cec5SDimitry Andric Visit(E->getSubExpr());
10330b57cec5SDimitry Andric terminateRegion(E);
10340b57cec5SDimitry Andric }
10350b57cec5SDimitry Andric
VisitGotoStmt__anone2f8b4240211::CounterCoverageMappingBuilder10360b57cec5SDimitry Andric void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
10370b57cec5SDimitry Andric
VisitLabelStmt__anone2f8b4240211::CounterCoverageMappingBuilder10380b57cec5SDimitry Andric void VisitLabelStmt(const LabelStmt *S) {
10390b57cec5SDimitry Andric Counter LabelCount = getRegionCounter(S);
10400b57cec5SDimitry Andric SourceLocation Start = getStart(S);
10410b57cec5SDimitry Andric // We can't extendRegion here or we risk overlapping with our new region.
10420b57cec5SDimitry Andric handleFileExit(Start);
10430b57cec5SDimitry Andric pushRegion(LabelCount, Start);
10440b57cec5SDimitry Andric Visit(S->getSubStmt());
10450b57cec5SDimitry Andric }
10460b57cec5SDimitry Andric
VisitBreakStmt__anone2f8b4240211::CounterCoverageMappingBuilder10470b57cec5SDimitry Andric void VisitBreakStmt(const BreakStmt *S) {
10480b57cec5SDimitry Andric assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
10490b57cec5SDimitry Andric BreakContinueStack.back().BreakCount = addCounters(
10500b57cec5SDimitry Andric BreakContinueStack.back().BreakCount, getRegion().getCounter());
10510b57cec5SDimitry Andric // FIXME: a break in a switch should terminate regions for all preceding
10520b57cec5SDimitry Andric // case statements, not just the most recent one.
10530b57cec5SDimitry Andric terminateRegion(S);
10540b57cec5SDimitry Andric }
10550b57cec5SDimitry Andric
VisitContinueStmt__anone2f8b4240211::CounterCoverageMappingBuilder10560b57cec5SDimitry Andric void VisitContinueStmt(const ContinueStmt *S) {
10570b57cec5SDimitry Andric assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
10580b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount = addCounters(
10590b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount, getRegion().getCounter());
10600b57cec5SDimitry Andric terminateRegion(S);
10610b57cec5SDimitry Andric }
10620b57cec5SDimitry Andric
VisitCallExpr__anone2f8b4240211::CounterCoverageMappingBuilder10630b57cec5SDimitry Andric void VisitCallExpr(const CallExpr *E) {
10640b57cec5SDimitry Andric VisitStmt(E);
10650b57cec5SDimitry Andric
10660b57cec5SDimitry Andric // Terminate the region when we hit a noreturn function.
10670b57cec5SDimitry Andric // (This is helpful dealing with switch statements.)
10680b57cec5SDimitry Andric QualType CalleeType = E->getCallee()->getType();
10690b57cec5SDimitry Andric if (getFunctionExtInfo(*CalleeType).getNoReturn())
10700b57cec5SDimitry Andric terminateRegion(E);
10710b57cec5SDimitry Andric }
10720b57cec5SDimitry Andric
VisitWhileStmt__anone2f8b4240211::CounterCoverageMappingBuilder10730b57cec5SDimitry Andric void VisitWhileStmt(const WhileStmt *S) {
10740b57cec5SDimitry Andric extendRegion(S);
10750b57cec5SDimitry Andric
10760b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
10770b57cec5SDimitry Andric Counter BodyCount = getRegionCounter(S);
10780b57cec5SDimitry Andric
10790b57cec5SDimitry Andric // Handle the body first so that we can get the backedge count.
10800b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue());
10810b57cec5SDimitry Andric extendRegion(S->getBody());
10820b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
10830b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val();
10840b57cec5SDimitry Andric
1085*5f7ddb14SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt;
1086*5f7ddb14SDimitry Andric HasTerminateStmt = false;
1087*5f7ddb14SDimitry Andric
10880b57cec5SDimitry Andric // Go back to handle the condition.
10890b57cec5SDimitry Andric Counter CondCount =
10900b57cec5SDimitry Andric addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
10910b57cec5SDimitry Andric propagateCounts(CondCount, S->getCond());
10920b57cec5SDimitry Andric adjustForOutOfOrderTraversal(getEnd(S));
10930b57cec5SDimitry Andric
10940b57cec5SDimitry Andric // The body count applies to the area immediately after the increment.
1095*5f7ddb14SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
10960b57cec5SDimitry Andric if (Gap)
10970b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
10980b57cec5SDimitry Andric
10990b57cec5SDimitry Andric Counter OutCount =
11000b57cec5SDimitry Andric addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1101*5f7ddb14SDimitry Andric if (OutCount != ParentCount) {
11020b57cec5SDimitry Andric pushRegion(OutCount);
1103*5f7ddb14SDimitry Andric GapRegionCounter = OutCount;
1104*5f7ddb14SDimitry Andric if (BodyHasTerminateStmt)
1105*5f7ddb14SDimitry Andric HasTerminateStmt = true;
1106*5f7ddb14SDimitry Andric }
1107af732203SDimitry Andric
1108af732203SDimitry Andric // Create Branch Region around condition.
1109af732203SDimitry Andric createBranchRegion(S->getCond(), BodyCount,
1110af732203SDimitry Andric subtractCounters(CondCount, BodyCount));
11110b57cec5SDimitry Andric }
11120b57cec5SDimitry Andric
VisitDoStmt__anone2f8b4240211::CounterCoverageMappingBuilder11130b57cec5SDimitry Andric void VisitDoStmt(const DoStmt *S) {
11140b57cec5SDimitry Andric extendRegion(S);
11150b57cec5SDimitry Andric
11160b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
11170b57cec5SDimitry Andric Counter BodyCount = getRegionCounter(S);
11180b57cec5SDimitry Andric
11190b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue());
11200b57cec5SDimitry Andric extendRegion(S->getBody());
11210b57cec5SDimitry Andric Counter BackedgeCount =
11220b57cec5SDimitry Andric propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
11230b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val();
11240b57cec5SDimitry Andric
1125*5f7ddb14SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt;
1126*5f7ddb14SDimitry Andric HasTerminateStmt = false;
1127*5f7ddb14SDimitry Andric
11280b57cec5SDimitry Andric Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
11290b57cec5SDimitry Andric propagateCounts(CondCount, S->getCond());
11300b57cec5SDimitry Andric
11310b57cec5SDimitry Andric Counter OutCount =
11320b57cec5SDimitry Andric addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1133*5f7ddb14SDimitry Andric if (OutCount != ParentCount) {
11340b57cec5SDimitry Andric pushRegion(OutCount);
1135*5f7ddb14SDimitry Andric GapRegionCounter = OutCount;
1136*5f7ddb14SDimitry Andric }
1137af732203SDimitry Andric
1138af732203SDimitry Andric // Create Branch Region around condition.
1139af732203SDimitry Andric createBranchRegion(S->getCond(), BodyCount,
1140af732203SDimitry Andric subtractCounters(CondCount, BodyCount));
1141*5f7ddb14SDimitry Andric
1142*5f7ddb14SDimitry Andric if (BodyHasTerminateStmt)
1143*5f7ddb14SDimitry Andric HasTerminateStmt = true;
11440b57cec5SDimitry Andric }
11450b57cec5SDimitry Andric
VisitForStmt__anone2f8b4240211::CounterCoverageMappingBuilder11460b57cec5SDimitry Andric void VisitForStmt(const ForStmt *S) {
11470b57cec5SDimitry Andric extendRegion(S);
11480b57cec5SDimitry Andric if (S->getInit())
11490b57cec5SDimitry Andric Visit(S->getInit());
11500b57cec5SDimitry Andric
11510b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
11520b57cec5SDimitry Andric Counter BodyCount = getRegionCounter(S);
11530b57cec5SDimitry Andric
11540b57cec5SDimitry Andric // The loop increment may contain a break or continue.
11550b57cec5SDimitry Andric if (S->getInc())
11560b57cec5SDimitry Andric BreakContinueStack.emplace_back();
11570b57cec5SDimitry Andric
11580b57cec5SDimitry Andric // Handle the body first so that we can get the backedge count.
11590b57cec5SDimitry Andric BreakContinueStack.emplace_back();
11600b57cec5SDimitry Andric extendRegion(S->getBody());
11610b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
11620b57cec5SDimitry Andric BreakContinue BodyBC = BreakContinueStack.pop_back_val();
11630b57cec5SDimitry Andric
1164*5f7ddb14SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt;
1165*5f7ddb14SDimitry Andric HasTerminateStmt = false;
1166*5f7ddb14SDimitry Andric
11670b57cec5SDimitry Andric // The increment is essentially part of the body but it needs to include
11680b57cec5SDimitry Andric // the count for all the continue statements.
11690b57cec5SDimitry Andric BreakContinue IncrementBC;
11700b57cec5SDimitry Andric if (const Stmt *Inc = S->getInc()) {
11710b57cec5SDimitry Andric propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
11720b57cec5SDimitry Andric IncrementBC = BreakContinueStack.pop_back_val();
11730b57cec5SDimitry Andric }
11740b57cec5SDimitry Andric
11750b57cec5SDimitry Andric // Go back to handle the condition.
11760b57cec5SDimitry Andric Counter CondCount = addCounters(
11770b57cec5SDimitry Andric addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
11780b57cec5SDimitry Andric IncrementBC.ContinueCount);
11790b57cec5SDimitry Andric if (const Expr *Cond = S->getCond()) {
11800b57cec5SDimitry Andric propagateCounts(CondCount, Cond);
11810b57cec5SDimitry Andric adjustForOutOfOrderTraversal(getEnd(S));
11820b57cec5SDimitry Andric }
11830b57cec5SDimitry Andric
11840b57cec5SDimitry Andric // The body count applies to the area immediately after the increment.
1185*5f7ddb14SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
11860b57cec5SDimitry Andric if (Gap)
11870b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
11880b57cec5SDimitry Andric
11890b57cec5SDimitry Andric Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
11900b57cec5SDimitry Andric subtractCounters(CondCount, BodyCount));
1191*5f7ddb14SDimitry Andric if (OutCount != ParentCount) {
11920b57cec5SDimitry Andric pushRegion(OutCount);
1193*5f7ddb14SDimitry Andric GapRegionCounter = OutCount;
1194*5f7ddb14SDimitry Andric if (BodyHasTerminateStmt)
1195*5f7ddb14SDimitry Andric HasTerminateStmt = true;
1196*5f7ddb14SDimitry Andric }
1197af732203SDimitry Andric
1198af732203SDimitry Andric // Create Branch Region around condition.
1199af732203SDimitry Andric createBranchRegion(S->getCond(), BodyCount,
1200af732203SDimitry Andric subtractCounters(CondCount, BodyCount));
12010b57cec5SDimitry Andric }
12020b57cec5SDimitry Andric
VisitCXXForRangeStmt__anone2f8b4240211::CounterCoverageMappingBuilder12030b57cec5SDimitry Andric void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
12040b57cec5SDimitry Andric extendRegion(S);
12050b57cec5SDimitry Andric if (S->getInit())
12060b57cec5SDimitry Andric Visit(S->getInit());
12070b57cec5SDimitry Andric Visit(S->getLoopVarStmt());
12080b57cec5SDimitry Andric Visit(S->getRangeStmt());
12090b57cec5SDimitry Andric
12100b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
12110b57cec5SDimitry Andric Counter BodyCount = getRegionCounter(S);
12120b57cec5SDimitry Andric
12130b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue());
12140b57cec5SDimitry Andric extendRegion(S->getBody());
12150b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
12160b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val();
12170b57cec5SDimitry Andric
1218*5f7ddb14SDimitry Andric bool BodyHasTerminateStmt = HasTerminateStmt;
1219*5f7ddb14SDimitry Andric HasTerminateStmt = false;
1220*5f7ddb14SDimitry Andric
12210b57cec5SDimitry Andric // The body count applies to the area immediately after the range.
1222*5f7ddb14SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
12230b57cec5SDimitry Andric if (Gap)
12240b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
12250b57cec5SDimitry Andric
12260b57cec5SDimitry Andric Counter LoopCount =
12270b57cec5SDimitry Andric addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
12280b57cec5SDimitry Andric Counter OutCount =
12290b57cec5SDimitry Andric addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1230*5f7ddb14SDimitry Andric if (OutCount != ParentCount) {
12310b57cec5SDimitry Andric pushRegion(OutCount);
1232*5f7ddb14SDimitry Andric GapRegionCounter = OutCount;
1233*5f7ddb14SDimitry Andric if (BodyHasTerminateStmt)
1234*5f7ddb14SDimitry Andric HasTerminateStmt = true;
1235*5f7ddb14SDimitry Andric }
1236af732203SDimitry Andric
1237af732203SDimitry Andric // Create Branch Region around condition.
1238af732203SDimitry Andric createBranchRegion(S->getCond(), BodyCount,
1239af732203SDimitry Andric subtractCounters(LoopCount, BodyCount));
12400b57cec5SDimitry Andric }
12410b57cec5SDimitry Andric
VisitObjCForCollectionStmt__anone2f8b4240211::CounterCoverageMappingBuilder12420b57cec5SDimitry Andric void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
12430b57cec5SDimitry Andric extendRegion(S);
12440b57cec5SDimitry Andric Visit(S->getElement());
12450b57cec5SDimitry Andric
12460b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
12470b57cec5SDimitry Andric Counter BodyCount = getRegionCounter(S);
12480b57cec5SDimitry Andric
12490b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue());
12500b57cec5SDimitry Andric extendRegion(S->getBody());
12510b57cec5SDimitry Andric Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
12520b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val();
12530b57cec5SDimitry Andric
12540b57cec5SDimitry Andric // The body count applies to the area immediately after the collection.
1255*5f7ddb14SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
12560b57cec5SDimitry Andric if (Gap)
12570b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
12580b57cec5SDimitry Andric
12590b57cec5SDimitry Andric Counter LoopCount =
12600b57cec5SDimitry Andric addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
12610b57cec5SDimitry Andric Counter OutCount =
12620b57cec5SDimitry Andric addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1263*5f7ddb14SDimitry Andric if (OutCount != ParentCount) {
12640b57cec5SDimitry Andric pushRegion(OutCount);
1265*5f7ddb14SDimitry Andric GapRegionCounter = OutCount;
1266*5f7ddb14SDimitry Andric }
12670b57cec5SDimitry Andric }
12680b57cec5SDimitry Andric
VisitSwitchStmt__anone2f8b4240211::CounterCoverageMappingBuilder12690b57cec5SDimitry Andric void VisitSwitchStmt(const SwitchStmt *S) {
12700b57cec5SDimitry Andric extendRegion(S);
12710b57cec5SDimitry Andric if (S->getInit())
12720b57cec5SDimitry Andric Visit(S->getInit());
12730b57cec5SDimitry Andric Visit(S->getCond());
12740b57cec5SDimitry Andric
12750b57cec5SDimitry Andric BreakContinueStack.push_back(BreakContinue());
12760b57cec5SDimitry Andric
12770b57cec5SDimitry Andric const Stmt *Body = S->getBody();
12780b57cec5SDimitry Andric extendRegion(Body);
12790b57cec5SDimitry Andric if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
12800b57cec5SDimitry Andric if (!CS->body_empty()) {
12810b57cec5SDimitry Andric // Make a region for the body of the switch. If the body starts with
12820b57cec5SDimitry Andric // a case, that case will reuse this region; otherwise, this covers
12830b57cec5SDimitry Andric // the unreachable code at the beginning of the switch body.
1284480093f4SDimitry Andric size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1285480093f4SDimitry Andric getRegion().setGap(true);
1286*5f7ddb14SDimitry Andric Visit(Body);
12870b57cec5SDimitry Andric
12880b57cec5SDimitry Andric // Set the end for the body of the switch, if it isn't already set.
12890b57cec5SDimitry Andric for (size_t i = RegionStack.size(); i != Index; --i) {
12900b57cec5SDimitry Andric if (!RegionStack[i - 1].hasEndLoc())
12910b57cec5SDimitry Andric RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
12920b57cec5SDimitry Andric }
12930b57cec5SDimitry Andric
12940b57cec5SDimitry Andric popRegions(Index);
12950b57cec5SDimitry Andric }
12960b57cec5SDimitry Andric } else
12970b57cec5SDimitry Andric propagateCounts(Counter::getZero(), Body);
12980b57cec5SDimitry Andric BreakContinue BC = BreakContinueStack.pop_back_val();
12990b57cec5SDimitry Andric
13000b57cec5SDimitry Andric if (!BreakContinueStack.empty())
13010b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount = addCounters(
13020b57cec5SDimitry Andric BreakContinueStack.back().ContinueCount, BC.ContinueCount);
13030b57cec5SDimitry Andric
1304af732203SDimitry Andric Counter ParentCount = getRegion().getCounter();
13050b57cec5SDimitry Andric Counter ExitCount = getRegionCounter(S);
13060b57cec5SDimitry Andric SourceLocation ExitLoc = getEnd(S);
13070b57cec5SDimitry Andric pushRegion(ExitCount);
1308*5f7ddb14SDimitry Andric GapRegionCounter = ExitCount;
13090b57cec5SDimitry Andric
13100b57cec5SDimitry Andric // Ensure that handleFileExit recognizes when the end location is located
13110b57cec5SDimitry Andric // in a different file.
13120b57cec5SDimitry Andric MostRecentLocation = getStart(S);
13130b57cec5SDimitry Andric handleFileExit(ExitLoc);
1314af732203SDimitry Andric
1315af732203SDimitry Andric // Create a Branch Region around each Case. Subtract the case's
1316af732203SDimitry Andric // counter from the Parent counter to track the "False" branch count.
1317af732203SDimitry Andric Counter CaseCountSum;
1318af732203SDimitry Andric bool HasDefaultCase = false;
1319af732203SDimitry Andric const SwitchCase *Case = S->getSwitchCaseList();
1320af732203SDimitry Andric for (; Case; Case = Case->getNextSwitchCase()) {
1321af732203SDimitry Andric HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1322af732203SDimitry Andric CaseCountSum = addCounters(CaseCountSum, getRegionCounter(Case));
1323af732203SDimitry Andric createSwitchCaseRegion(
1324af732203SDimitry Andric Case, getRegionCounter(Case),
1325af732203SDimitry Andric subtractCounters(ParentCount, getRegionCounter(Case)));
1326af732203SDimitry Andric }
1327af732203SDimitry Andric
1328af732203SDimitry Andric // If no explicit default case exists, create a branch region to represent
1329af732203SDimitry Andric // the hidden branch, which will be added later by the CodeGen. This region
1330af732203SDimitry Andric // will be associated with the switch statement's condition.
1331af732203SDimitry Andric if (!HasDefaultCase) {
1332af732203SDimitry Andric Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1333af732203SDimitry Andric Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1334af732203SDimitry Andric createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1335af732203SDimitry Andric }
13360b57cec5SDimitry Andric }
13370b57cec5SDimitry Andric
VisitSwitchCase__anone2f8b4240211::CounterCoverageMappingBuilder13380b57cec5SDimitry Andric void VisitSwitchCase(const SwitchCase *S) {
13390b57cec5SDimitry Andric extendRegion(S);
13400b57cec5SDimitry Andric
13410b57cec5SDimitry Andric SourceMappingRegion &Parent = getRegion();
13420b57cec5SDimitry Andric
13430b57cec5SDimitry Andric Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
13440b57cec5SDimitry Andric // Reuse the existing region if it starts at our label. This is typical of
13450b57cec5SDimitry Andric // the first case in a switch.
13460b57cec5SDimitry Andric if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
13470b57cec5SDimitry Andric Parent.setCounter(Count);
13480b57cec5SDimitry Andric else
13490b57cec5SDimitry Andric pushRegion(Count, getStart(S));
13500b57cec5SDimitry Andric
1351*5f7ddb14SDimitry Andric GapRegionCounter = Count;
1352*5f7ddb14SDimitry Andric
13530b57cec5SDimitry Andric if (const auto *CS = dyn_cast<CaseStmt>(S)) {
13540b57cec5SDimitry Andric Visit(CS->getLHS());
13550b57cec5SDimitry Andric if (const Expr *RHS = CS->getRHS())
13560b57cec5SDimitry Andric Visit(RHS);
13570b57cec5SDimitry Andric }
13580b57cec5SDimitry Andric Visit(S->getSubStmt());
13590b57cec5SDimitry Andric }
13600b57cec5SDimitry Andric
VisitIfStmt__anone2f8b4240211::CounterCoverageMappingBuilder13610b57cec5SDimitry Andric void VisitIfStmt(const IfStmt *S) {
13620b57cec5SDimitry Andric extendRegion(S);
13630b57cec5SDimitry Andric if (S->getInit())
13640b57cec5SDimitry Andric Visit(S->getInit());
13650b57cec5SDimitry Andric
13660b57cec5SDimitry Andric // Extend into the condition before we propagate through it below - this is
13670b57cec5SDimitry Andric // needed to handle macros that generate the "if" but not the condition.
13680b57cec5SDimitry Andric extendRegion(S->getCond());
13690b57cec5SDimitry Andric
13700b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
13710b57cec5SDimitry Andric Counter ThenCount = getRegionCounter(S);
13720b57cec5SDimitry Andric
13730b57cec5SDimitry Andric // Emitting a counter for the condition makes it easier to interpret the
13740b57cec5SDimitry Andric // counter for the body when looking at the coverage.
13750b57cec5SDimitry Andric propagateCounts(ParentCount, S->getCond());
13760b57cec5SDimitry Andric
13770b57cec5SDimitry Andric // The 'then' count applies to the area immediately after the condition.
1378*5f7ddb14SDimitry Andric auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
13790b57cec5SDimitry Andric if (Gap)
13800b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
13810b57cec5SDimitry Andric
13820b57cec5SDimitry Andric extendRegion(S->getThen());
13830b57cec5SDimitry Andric Counter OutCount = propagateCounts(ThenCount, S->getThen());
13840b57cec5SDimitry Andric
13850b57cec5SDimitry Andric Counter ElseCount = subtractCounters(ParentCount, ThenCount);
13860b57cec5SDimitry Andric if (const Stmt *Else = S->getElse()) {
1387*5f7ddb14SDimitry Andric bool ThenHasTerminateStmt = HasTerminateStmt;
1388*5f7ddb14SDimitry Andric HasTerminateStmt = false;
1389*5f7ddb14SDimitry Andric
13900b57cec5SDimitry Andric // The 'else' count applies to the area immediately after the 'then'.
1391*5f7ddb14SDimitry Andric Gap = findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
13920b57cec5SDimitry Andric if (Gap)
13930b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
13940b57cec5SDimitry Andric extendRegion(Else);
13950b57cec5SDimitry Andric OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1396*5f7ddb14SDimitry Andric
1397*5f7ddb14SDimitry Andric if (ThenHasTerminateStmt)
1398*5f7ddb14SDimitry Andric HasTerminateStmt = true;
13990b57cec5SDimitry Andric } else
14000b57cec5SDimitry Andric OutCount = addCounters(OutCount, ElseCount);
14010b57cec5SDimitry Andric
1402*5f7ddb14SDimitry Andric if (OutCount != ParentCount) {
14030b57cec5SDimitry Andric pushRegion(OutCount);
1404*5f7ddb14SDimitry Andric GapRegionCounter = OutCount;
1405*5f7ddb14SDimitry Andric }
1406af732203SDimitry Andric
1407af732203SDimitry Andric // Create Branch Region around condition.
1408af732203SDimitry Andric createBranchRegion(S->getCond(), ThenCount,
1409af732203SDimitry Andric subtractCounters(ParentCount, ThenCount));
14100b57cec5SDimitry Andric }
14110b57cec5SDimitry Andric
VisitCXXTryStmt__anone2f8b4240211::CounterCoverageMappingBuilder14120b57cec5SDimitry Andric void VisitCXXTryStmt(const CXXTryStmt *S) {
14130b57cec5SDimitry Andric extendRegion(S);
14140b57cec5SDimitry Andric // Handle macros that generate the "try" but not the rest.
14150b57cec5SDimitry Andric extendRegion(S->getTryBlock());
14160b57cec5SDimitry Andric
14170b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
14180b57cec5SDimitry Andric propagateCounts(ParentCount, S->getTryBlock());
14190b57cec5SDimitry Andric
14200b57cec5SDimitry Andric for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
14210b57cec5SDimitry Andric Visit(S->getHandler(I));
14220b57cec5SDimitry Andric
14230b57cec5SDimitry Andric Counter ExitCount = getRegionCounter(S);
14240b57cec5SDimitry Andric pushRegion(ExitCount);
14250b57cec5SDimitry Andric }
14260b57cec5SDimitry Andric
VisitCXXCatchStmt__anone2f8b4240211::CounterCoverageMappingBuilder14270b57cec5SDimitry Andric void VisitCXXCatchStmt(const CXXCatchStmt *S) {
14280b57cec5SDimitry Andric propagateCounts(getRegionCounter(S), S->getHandlerBlock());
14290b57cec5SDimitry Andric }
14300b57cec5SDimitry Andric
VisitAbstractConditionalOperator__anone2f8b4240211::CounterCoverageMappingBuilder14310b57cec5SDimitry Andric void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
14320b57cec5SDimitry Andric extendRegion(E);
14330b57cec5SDimitry Andric
14340b57cec5SDimitry Andric Counter ParentCount = getRegion().getCounter();
14350b57cec5SDimitry Andric Counter TrueCount = getRegionCounter(E);
14360b57cec5SDimitry Andric
1437*5f7ddb14SDimitry Andric propagateCounts(ParentCount, E->getCond());
14380b57cec5SDimitry Andric
14390b57cec5SDimitry Andric if (!isa<BinaryConditionalOperator>(E)) {
14400b57cec5SDimitry Andric // The 'then' count applies to the area immediately after the condition.
14410b57cec5SDimitry Andric auto Gap =
14420b57cec5SDimitry Andric findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
14430b57cec5SDimitry Andric if (Gap)
14440b57cec5SDimitry Andric fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
14450b57cec5SDimitry Andric
14460b57cec5SDimitry Andric extendRegion(E->getTrueExpr());
14470b57cec5SDimitry Andric propagateCounts(TrueCount, E->getTrueExpr());
14480b57cec5SDimitry Andric }
14490b57cec5SDimitry Andric
14500b57cec5SDimitry Andric extendRegion(E->getFalseExpr());
14510b57cec5SDimitry Andric propagateCounts(subtractCounters(ParentCount, TrueCount),
14520b57cec5SDimitry Andric E->getFalseExpr());
1453af732203SDimitry Andric
1454af732203SDimitry Andric // Create Branch Region around condition.
1455af732203SDimitry Andric createBranchRegion(E->getCond(), TrueCount,
1456af732203SDimitry Andric subtractCounters(ParentCount, TrueCount));
14570b57cec5SDimitry Andric }
14580b57cec5SDimitry Andric
VisitBinLAnd__anone2f8b4240211::CounterCoverageMappingBuilder14590b57cec5SDimitry Andric void VisitBinLAnd(const BinaryOperator *E) {
14600b57cec5SDimitry Andric extendRegion(E->getLHS());
14610b57cec5SDimitry Andric propagateCounts(getRegion().getCounter(), E->getLHS());
14620b57cec5SDimitry Andric handleFileExit(getEnd(E->getLHS()));
14630b57cec5SDimitry Andric
1464af732203SDimitry Andric // Counter tracks the right hand side of a logical and operator.
14650b57cec5SDimitry Andric extendRegion(E->getRHS());
14660b57cec5SDimitry Andric propagateCounts(getRegionCounter(E), E->getRHS());
1467af732203SDimitry Andric
1468af732203SDimitry Andric // Extract the RHS's Execution Counter.
1469af732203SDimitry Andric Counter RHSExecCnt = getRegionCounter(E);
1470af732203SDimitry Andric
1471af732203SDimitry Andric // Extract the RHS's "True" Instance Counter.
1472af732203SDimitry Andric Counter RHSTrueCnt = getRegionCounter(E->getRHS());
1473af732203SDimitry Andric
1474af732203SDimitry Andric // Extract the Parent Region Counter.
1475af732203SDimitry Andric Counter ParentCnt = getRegion().getCounter();
1476af732203SDimitry Andric
1477af732203SDimitry Andric // Create Branch Region around LHS condition.
1478af732203SDimitry Andric createBranchRegion(E->getLHS(), RHSExecCnt,
1479af732203SDimitry Andric subtractCounters(ParentCnt, RHSExecCnt));
1480af732203SDimitry Andric
1481af732203SDimitry Andric // Create Branch Region around RHS condition.
1482af732203SDimitry Andric createBranchRegion(E->getRHS(), RHSTrueCnt,
1483af732203SDimitry Andric subtractCounters(RHSExecCnt, RHSTrueCnt));
14840b57cec5SDimitry Andric }
14850b57cec5SDimitry Andric
VisitBinLOr__anone2f8b4240211::CounterCoverageMappingBuilder14860b57cec5SDimitry Andric void VisitBinLOr(const BinaryOperator *E) {
14870b57cec5SDimitry Andric extendRegion(E->getLHS());
14880b57cec5SDimitry Andric propagateCounts(getRegion().getCounter(), E->getLHS());
14890b57cec5SDimitry Andric handleFileExit(getEnd(E->getLHS()));
14900b57cec5SDimitry Andric
1491af732203SDimitry Andric // Counter tracks the right hand side of a logical or operator.
14920b57cec5SDimitry Andric extendRegion(E->getRHS());
14930b57cec5SDimitry Andric propagateCounts(getRegionCounter(E), E->getRHS());
1494af732203SDimitry Andric
1495af732203SDimitry Andric // Extract the RHS's Execution Counter.
1496af732203SDimitry Andric Counter RHSExecCnt = getRegionCounter(E);
1497af732203SDimitry Andric
1498af732203SDimitry Andric // Extract the RHS's "False" Instance Counter.
1499af732203SDimitry Andric Counter RHSFalseCnt = getRegionCounter(E->getRHS());
1500af732203SDimitry Andric
1501af732203SDimitry Andric // Extract the Parent Region Counter.
1502af732203SDimitry Andric Counter ParentCnt = getRegion().getCounter();
1503af732203SDimitry Andric
1504af732203SDimitry Andric // Create Branch Region around LHS condition.
1505af732203SDimitry Andric createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
1506af732203SDimitry Andric RHSExecCnt);
1507af732203SDimitry Andric
1508af732203SDimitry Andric // Create Branch Region around RHS condition.
1509af732203SDimitry Andric createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
1510af732203SDimitry Andric RHSFalseCnt);
15110b57cec5SDimitry Andric }
15120b57cec5SDimitry Andric
VisitLambdaExpr__anone2f8b4240211::CounterCoverageMappingBuilder15130b57cec5SDimitry Andric void VisitLambdaExpr(const LambdaExpr *LE) {
15140b57cec5SDimitry Andric // Lambdas are treated as their own functions for now, so we shouldn't
15150b57cec5SDimitry Andric // propagate counts into them.
15160b57cec5SDimitry Andric }
15170b57cec5SDimitry Andric };
15180b57cec5SDimitry Andric
15190b57cec5SDimitry Andric } // end anonymous namespace
15200b57cec5SDimitry Andric
dump(llvm::raw_ostream & OS,StringRef FunctionName,ArrayRef<CounterExpression> Expressions,ArrayRef<CounterMappingRegion> Regions)15210b57cec5SDimitry Andric static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
15220b57cec5SDimitry Andric ArrayRef<CounterExpression> Expressions,
15230b57cec5SDimitry Andric ArrayRef<CounterMappingRegion> Regions) {
15240b57cec5SDimitry Andric OS << FunctionName << ":\n";
15250b57cec5SDimitry Andric CounterMappingContext Ctx(Expressions);
15260b57cec5SDimitry Andric for (const auto &R : Regions) {
15270b57cec5SDimitry Andric OS.indent(2);
15280b57cec5SDimitry Andric switch (R.Kind) {
15290b57cec5SDimitry Andric case CounterMappingRegion::CodeRegion:
15300b57cec5SDimitry Andric break;
15310b57cec5SDimitry Andric case CounterMappingRegion::ExpansionRegion:
15320b57cec5SDimitry Andric OS << "Expansion,";
15330b57cec5SDimitry Andric break;
15340b57cec5SDimitry Andric case CounterMappingRegion::SkippedRegion:
15350b57cec5SDimitry Andric OS << "Skipped,";
15360b57cec5SDimitry Andric break;
15370b57cec5SDimitry Andric case CounterMappingRegion::GapRegion:
15380b57cec5SDimitry Andric OS << "Gap,";
15390b57cec5SDimitry Andric break;
1540af732203SDimitry Andric case CounterMappingRegion::BranchRegion:
1541af732203SDimitry Andric OS << "Branch,";
1542af732203SDimitry Andric break;
15430b57cec5SDimitry Andric }
15440b57cec5SDimitry Andric
15450b57cec5SDimitry Andric OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
15460b57cec5SDimitry Andric << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
15470b57cec5SDimitry Andric Ctx.dump(R.Count, OS);
1548af732203SDimitry Andric
1549af732203SDimitry Andric if (R.Kind == CounterMappingRegion::BranchRegion) {
1550af732203SDimitry Andric OS << ", ";
1551af732203SDimitry Andric Ctx.dump(R.FalseCount, OS);
1552af732203SDimitry Andric }
1553af732203SDimitry Andric
15540b57cec5SDimitry Andric if (R.Kind == CounterMappingRegion::ExpansionRegion)
15550b57cec5SDimitry Andric OS << " (Expanded file = " << R.ExpandedFileID << ")";
15560b57cec5SDimitry Andric OS << "\n";
15570b57cec5SDimitry Andric }
15580b57cec5SDimitry Andric }
15590b57cec5SDimitry Andric
CoverageMappingModuleGen(CodeGenModule & CGM,CoverageSourceInfo & SourceInfo)1560af732203SDimitry Andric CoverageMappingModuleGen::CoverageMappingModuleGen(
1561af732203SDimitry Andric CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
1562af732203SDimitry Andric : CGM(CGM), SourceInfo(SourceInfo) {
1563*5f7ddb14SDimitry Andric CoveragePrefixMap = CGM.getCodeGenOpts().CoveragePrefixMap;
1564*5f7ddb14SDimitry Andric }
1565*5f7ddb14SDimitry Andric
getCurrentDirname()1566*5f7ddb14SDimitry Andric std::string CoverageMappingModuleGen::getCurrentDirname() {
1567*5f7ddb14SDimitry Andric if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty())
1568*5f7ddb14SDimitry Andric return CGM.getCodeGenOpts().CoverageCompilationDir;
1569*5f7ddb14SDimitry Andric
1570*5f7ddb14SDimitry Andric SmallString<256> CWD;
1571*5f7ddb14SDimitry Andric llvm::sys::fs::current_path(CWD);
1572*5f7ddb14SDimitry Andric return CWD.str().str();
1573af732203SDimitry Andric }
1574af732203SDimitry Andric
normalizeFilename(StringRef Filename)1575af732203SDimitry Andric std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
1576af732203SDimitry Andric llvm::SmallString<256> Path(Filename);
1577af732203SDimitry Andric llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1578*5f7ddb14SDimitry Andric for (const auto &Entry : CoveragePrefixMap) {
1579af732203SDimitry Andric if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
1580af732203SDimitry Andric break;
1581af732203SDimitry Andric }
1582af732203SDimitry Andric return Path.str().str();
1583af732203SDimitry Andric }
1584af732203SDimitry Andric
getInstrProfSection(const CodeGenModule & CGM,llvm::InstrProfSectKind SK)15855ffd83dbSDimitry Andric static std::string getInstrProfSection(const CodeGenModule &CGM,
15865ffd83dbSDimitry Andric llvm::InstrProfSectKind SK) {
15875ffd83dbSDimitry Andric return llvm::getInstrProfSectionName(
15885ffd83dbSDimitry Andric SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
15895ffd83dbSDimitry Andric }
15905ffd83dbSDimitry Andric
emitFunctionMappingRecord(const FunctionInfo & Info,uint64_t FilenamesRef)15915ffd83dbSDimitry Andric void CoverageMappingModuleGen::emitFunctionMappingRecord(
15925ffd83dbSDimitry Andric const FunctionInfo &Info, uint64_t FilenamesRef) {
15930b57cec5SDimitry Andric llvm::LLVMContext &Ctx = CGM.getLLVMContext();
15945ffd83dbSDimitry Andric
15955ffd83dbSDimitry Andric // Assign a name to the function record. This is used to merge duplicates.
15965ffd83dbSDimitry Andric std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
15975ffd83dbSDimitry Andric
15985ffd83dbSDimitry Andric // A dummy description for a function included-but-not-used in a TU can be
15995ffd83dbSDimitry Andric // replaced by full description provided by a different TU. The two kinds of
16005ffd83dbSDimitry Andric // descriptions play distinct roles: therefore, assign them different names
16015ffd83dbSDimitry Andric // to prevent `linkonce_odr` merging.
16025ffd83dbSDimitry Andric if (Info.IsUsed)
16035ffd83dbSDimitry Andric FuncRecordName += "u";
16045ffd83dbSDimitry Andric
16055ffd83dbSDimitry Andric // Create the function record type.
16065ffd83dbSDimitry Andric const uint64_t NameHash = Info.NameHash;
16075ffd83dbSDimitry Andric const uint64_t FuncHash = Info.FuncHash;
16085ffd83dbSDimitry Andric const std::string &CoverageMapping = Info.CoverageMapping;
16090b57cec5SDimitry Andric #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
16100b57cec5SDimitry Andric llvm::Type *FunctionRecordTypes[] = {
16110b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc"
16120b57cec5SDimitry Andric };
16135ffd83dbSDimitry Andric auto *FunctionRecordTy =
16140b57cec5SDimitry Andric llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
16150b57cec5SDimitry Andric /*isPacked=*/true);
16160b57cec5SDimitry Andric
16175ffd83dbSDimitry Andric // Create the function record constant.
16180b57cec5SDimitry Andric #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
16190b57cec5SDimitry Andric llvm::Constant *FunctionRecordVals[] = {
16200b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc"
16210b57cec5SDimitry Andric };
16225ffd83dbSDimitry Andric auto *FuncRecordConstant = llvm::ConstantStruct::get(
16235ffd83dbSDimitry Andric FunctionRecordTy, makeArrayRef(FunctionRecordVals));
16245ffd83dbSDimitry Andric
16255ffd83dbSDimitry Andric // Create the function record global.
16265ffd83dbSDimitry Andric auto *FuncRecord = new llvm::GlobalVariable(
16275ffd83dbSDimitry Andric CGM.getModule(), FunctionRecordTy, /*isConstant=*/true,
16285ffd83dbSDimitry Andric llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
16295ffd83dbSDimitry Andric FuncRecordName);
16305ffd83dbSDimitry Andric FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
16315ffd83dbSDimitry Andric FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun));
16325ffd83dbSDimitry Andric FuncRecord->setAlignment(llvm::Align(8));
16335ffd83dbSDimitry Andric if (CGM.supportsCOMDAT())
16345ffd83dbSDimitry Andric FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
16355ffd83dbSDimitry Andric
16365ffd83dbSDimitry Andric // Make sure the data doesn't get deleted.
16375ffd83dbSDimitry Andric CGM.addUsedGlobal(FuncRecord);
16385ffd83dbSDimitry Andric }
16395ffd83dbSDimitry Andric
addFunctionMappingRecord(llvm::GlobalVariable * NamePtr,StringRef NameValue,uint64_t FuncHash,const std::string & CoverageMapping,bool IsUsed)16405ffd83dbSDimitry Andric void CoverageMappingModuleGen::addFunctionMappingRecord(
16415ffd83dbSDimitry Andric llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
16425ffd83dbSDimitry Andric const std::string &CoverageMapping, bool IsUsed) {
16435ffd83dbSDimitry Andric llvm::LLVMContext &Ctx = CGM.getLLVMContext();
16445ffd83dbSDimitry Andric const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
16455ffd83dbSDimitry Andric FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
16465ffd83dbSDimitry Andric
16470b57cec5SDimitry Andric if (!IsUsed)
16480b57cec5SDimitry Andric FunctionNames.push_back(
16490b57cec5SDimitry Andric llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
16500b57cec5SDimitry Andric
16510b57cec5SDimitry Andric if (CGM.getCodeGenOpts().DumpCoverageMapping) {
16520b57cec5SDimitry Andric // Dump the coverage mapping data for this function by decoding the
16530b57cec5SDimitry Andric // encoded data. This allows us to dump the mapping regions which were
16540b57cec5SDimitry Andric // also processed by the CoverageMappingWriter which performs
16550b57cec5SDimitry Andric // additional minimization operations such as reducing the number of
16560b57cec5SDimitry Andric // expressions.
1657*5f7ddb14SDimitry Andric llvm::SmallVector<std::string, 16> FilenameStrs;
16580b57cec5SDimitry Andric std::vector<StringRef> Filenames;
16590b57cec5SDimitry Andric std::vector<CounterExpression> Expressions;
16600b57cec5SDimitry Andric std::vector<CounterMappingRegion> Regions;
1661*5f7ddb14SDimitry Andric FilenameStrs.resize(FileEntries.size() + 1);
1662*5f7ddb14SDimitry Andric FilenameStrs[0] = normalizeFilename(getCurrentDirname());
16630b57cec5SDimitry Andric for (const auto &Entry : FileEntries) {
16640b57cec5SDimitry Andric auto I = Entry.second;
16650b57cec5SDimitry Andric FilenameStrs[I] = normalizeFilename(Entry.first->getName());
16660b57cec5SDimitry Andric }
1667*5f7ddb14SDimitry Andric ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(FilenameStrs);
16680b57cec5SDimitry Andric RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
16690b57cec5SDimitry Andric Expressions, Regions);
16700b57cec5SDimitry Andric if (Reader.read())
16710b57cec5SDimitry Andric return;
16720b57cec5SDimitry Andric dump(llvm::outs(), NameValue, Expressions, Regions);
16730b57cec5SDimitry Andric }
16740b57cec5SDimitry Andric }
16750b57cec5SDimitry Andric
emit()16760b57cec5SDimitry Andric void CoverageMappingModuleGen::emit() {
16770b57cec5SDimitry Andric if (FunctionRecords.empty())
16780b57cec5SDimitry Andric return;
16790b57cec5SDimitry Andric llvm::LLVMContext &Ctx = CGM.getLLVMContext();
16800b57cec5SDimitry Andric auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
16810b57cec5SDimitry Andric
16820b57cec5SDimitry Andric // Create the filenames and merge them with coverage mappings
16830b57cec5SDimitry Andric llvm::SmallVector<std::string, 16> FilenameStrs;
1684*5f7ddb14SDimitry Andric FilenameStrs.resize(FileEntries.size() + 1);
1685*5f7ddb14SDimitry Andric // The first filename is the current working directory.
1686*5f7ddb14SDimitry Andric FilenameStrs[0] = normalizeFilename(getCurrentDirname());
16870b57cec5SDimitry Andric for (const auto &Entry : FileEntries) {
16880b57cec5SDimitry Andric auto I = Entry.second;
16890b57cec5SDimitry Andric FilenameStrs[I] = normalizeFilename(Entry.first->getName());
16900b57cec5SDimitry Andric }
16910b57cec5SDimitry Andric
16925ffd83dbSDimitry Andric std::string Filenames;
16935ffd83dbSDimitry Andric {
16945ffd83dbSDimitry Andric llvm::raw_string_ostream OS(Filenames);
1695*5f7ddb14SDimitry Andric CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
16960b57cec5SDimitry Andric }
16975ffd83dbSDimitry Andric auto *FilenamesVal =
16985ffd83dbSDimitry Andric llvm::ConstantDataArray::getString(Ctx, Filenames, false);
16995ffd83dbSDimitry Andric const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
17000b57cec5SDimitry Andric
17015ffd83dbSDimitry Andric // Emit the function records.
17025ffd83dbSDimitry Andric for (const FunctionInfo &Info : FunctionRecords)
17035ffd83dbSDimitry Andric emitFunctionMappingRecord(Info, FilenamesRef);
17040b57cec5SDimitry Andric
17055ffd83dbSDimitry Andric const unsigned NRecords = 0;
17065ffd83dbSDimitry Andric const size_t FilenamesSize = Filenames.size();
17075ffd83dbSDimitry Andric const unsigned CoverageMappingSize = 0;
17080b57cec5SDimitry Andric llvm::Type *CovDataHeaderTypes[] = {
17090b57cec5SDimitry Andric #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
17100b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc"
17110b57cec5SDimitry Andric };
17120b57cec5SDimitry Andric auto CovDataHeaderTy =
17130b57cec5SDimitry Andric llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
17140b57cec5SDimitry Andric llvm::Constant *CovDataHeaderVals[] = {
17150b57cec5SDimitry Andric #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
17160b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc"
17170b57cec5SDimitry Andric };
17180b57cec5SDimitry Andric auto CovDataHeaderVal = llvm::ConstantStruct::get(
17190b57cec5SDimitry Andric CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
17200b57cec5SDimitry Andric
17210b57cec5SDimitry Andric // Create the coverage data record
17225ffd83dbSDimitry Andric llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
17230b57cec5SDimitry Andric auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
17245ffd83dbSDimitry Andric llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
17250b57cec5SDimitry Andric auto CovDataVal =
17260b57cec5SDimitry Andric llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
17270b57cec5SDimitry Andric auto CovData = new llvm::GlobalVariable(
17285ffd83dbSDimitry Andric CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
17290b57cec5SDimitry Andric CovDataVal, llvm::getCoverageMappingVarName());
17300b57cec5SDimitry Andric
17315ffd83dbSDimitry Andric CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap));
1732a7dea167SDimitry Andric CovData->setAlignment(llvm::Align(8));
17330b57cec5SDimitry Andric
17340b57cec5SDimitry Andric // Make sure the data doesn't get deleted.
17350b57cec5SDimitry Andric CGM.addUsedGlobal(CovData);
17360b57cec5SDimitry Andric // Create the deferred function records array
17370b57cec5SDimitry Andric if (!FunctionNames.empty()) {
17380b57cec5SDimitry Andric auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
17390b57cec5SDimitry Andric FunctionNames.size());
17400b57cec5SDimitry Andric auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
17410b57cec5SDimitry Andric // This variable will *NOT* be emitted to the object file. It is used
17420b57cec5SDimitry Andric // to pass the list of names referenced to codegen.
17430b57cec5SDimitry Andric new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
17440b57cec5SDimitry Andric llvm::GlobalValue::InternalLinkage, NamesArrVal,
17450b57cec5SDimitry Andric llvm::getCoverageUnusedNamesVarName());
17460b57cec5SDimitry Andric }
17470b57cec5SDimitry Andric }
17480b57cec5SDimitry Andric
getFileID(const FileEntry * File)17490b57cec5SDimitry Andric unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
17500b57cec5SDimitry Andric auto It = FileEntries.find(File);
17510b57cec5SDimitry Andric if (It != FileEntries.end())
17520b57cec5SDimitry Andric return It->second;
1753*5f7ddb14SDimitry Andric unsigned FileID = FileEntries.size() + 1;
17540b57cec5SDimitry Andric FileEntries.insert(std::make_pair(File, FileID));
17550b57cec5SDimitry Andric return FileID;
17560b57cec5SDimitry Andric }
17570b57cec5SDimitry Andric
emitCounterMapping(const Decl * D,llvm::raw_ostream & OS)17580b57cec5SDimitry Andric void CoverageMappingGen::emitCounterMapping(const Decl *D,
17590b57cec5SDimitry Andric llvm::raw_ostream &OS) {
17600b57cec5SDimitry Andric assert(CounterMap);
17610b57cec5SDimitry Andric CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
17620b57cec5SDimitry Andric Walker.VisitDecl(D);
17630b57cec5SDimitry Andric Walker.write(OS);
17640b57cec5SDimitry Andric }
17650b57cec5SDimitry Andric
emitEmptyMapping(const Decl * D,llvm::raw_ostream & OS)17660b57cec5SDimitry Andric void CoverageMappingGen::emitEmptyMapping(const Decl *D,
17670b57cec5SDimitry Andric llvm::raw_ostream &OS) {
17680b57cec5SDimitry Andric EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
17690b57cec5SDimitry Andric Walker.VisitDecl(D);
17700b57cec5SDimitry Andric Walker.write(OS);
17710b57cec5SDimitry Andric }
1772