aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CoverageMappingGen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CoverageMappingGen.cpp')
-rw-r--r--lib/CodeGen/CoverageMappingGen.cpp153
1 files changed, 72 insertions, 81 deletions
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 89a30dc7040c..2d8446463594 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -35,14 +35,14 @@ void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
namespace {
-/// \brief A region of source code that can be mapped to a counter.
+/// A region of source code that can be mapped to a counter.
class SourceMappingRegion {
Counter Count;
- /// \brief The region's starting location.
+ /// The region's starting location.
Optional<SourceLocation> LocStart;
- /// \brief The region's ending location.
+ /// The region's ending location.
Optional<SourceLocation> LocEnd;
/// Whether this region should be emitted after its parent is emitted.
@@ -74,7 +74,10 @@ public:
bool hasEndLoc() const { return LocEnd.hasValue(); }
- void setEndLoc(SourceLocation Loc) { LocEnd = Loc; }
+ void setEndLoc(SourceLocation Loc) {
+ assert(Loc.isValid() && "Setting an invalid end location");
+ LocEnd = Loc;
+ }
SourceLocation getEndLoc() const {
assert(LocEnd && "Region has no end location");
@@ -123,7 +126,7 @@ struct SpellingRegion {
}
};
-/// \brief Provides the common functionality for the different
+/// Provides the common functionality for the different
/// coverage mapping region builders.
class CoverageMappingBuilder {
public:
@@ -132,17 +135,17 @@ public:
const LangOptions &LangOpts;
private:
- /// \brief Map of clang's FileIDs to IDs used for coverage mapping.
+ /// Map of clang's FileIDs to IDs used for coverage mapping.
llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
FileIDMapping;
public:
- /// \brief The coverage mapping regions for this function
+ /// The coverage mapping regions for this function
llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
- /// \brief The source mapping regions for this function.
+ /// The source mapping regions for this function.
std::vector<SourceMappingRegion> SourceRegions;
- /// \brief A set of regions which can be used as a filter.
+ /// A set of regions which can be used as a filter.
///
/// It is produced by emitExpansionRegions() and is used in
/// emitSourceRegions() to suppress producing code regions if
@@ -154,7 +157,7 @@ public:
const LangOptions &LangOpts)
: CVM(CVM), SM(SM), LangOpts(LangOpts) {}
- /// \brief Return the precise end location for the given token.
+ /// Return the precise end location for the given token.
SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
// We avoid getLocForEndOfToken here, because it doesn't do what we want for
// macro locations, which we just treat as expanded files.
@@ -163,14 +166,14 @@ public:
return Loc.getLocWithOffset(TokLen);
}
- /// \brief Return the start location of an included file or expanded macro.
+ /// Return the start location of an included file or expanded macro.
SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
if (Loc.isMacroID())
return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
return SM.getLocForStartOfFile(SM.getFileID(Loc));
}
- /// \brief Return the end location of an included file or expanded macro.
+ /// Return the end location of an included file or expanded macro.
SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
if (Loc.isMacroID())
return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
@@ -178,18 +181,18 @@ public:
return SM.getLocForEndOfFile(SM.getFileID(Loc));
}
- /// \brief Find out where the current file is included or macro is expanded.
+ /// Find out where the current file is included or macro is expanded.
SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
- return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).first
+ return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
: SM.getIncludeLoc(SM.getFileID(Loc));
}
- /// \brief Return true if \c Loc is a location in a built-in macro.
+ /// Return true if \c Loc is a location in a built-in macro.
bool isInBuiltin(SourceLocation Loc) {
return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
}
- /// \brief Check whether \c Loc is included or expanded from \c Parent.
+ /// Check whether \c Loc is included or expanded from \c Parent.
bool isNestedIn(SourceLocation Loc, FileID Parent) {
do {
Loc = getIncludeOrExpansionLoc(Loc);
@@ -199,23 +202,23 @@ public:
return true;
}
- /// \brief Get the start of \c S ignoring macro arguments and builtin macros.
+ /// Get the start of \c S ignoring macro arguments and builtin macros.
SourceLocation getStart(const Stmt *S) {
SourceLocation Loc = S->getLocStart();
while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
- Loc = SM.getImmediateExpansionRange(Loc).first;
+ Loc = SM.getImmediateExpansionRange(Loc).getBegin();
return Loc;
}
- /// \brief Get the end of \c S ignoring macro arguments and builtin macros.
+ /// Get the end of \c S ignoring macro arguments and builtin macros.
SourceLocation getEnd(const Stmt *S) {
SourceLocation Loc = S->getLocEnd();
while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
- Loc = SM.getImmediateExpansionRange(Loc).first;
+ Loc = SM.getImmediateExpansionRange(Loc).getBegin();
return getPreciseTokenLocEnd(Loc);
}
- /// \brief Find the set of files we have regions for and assign IDs
+ /// Find the set of files we have regions for and assign IDs
///
/// Fills \c Mapping with the virtual file mapping needed to write out
/// coverage and collects the necessary file information to emit source and
@@ -255,7 +258,7 @@ public:
}
}
- /// \brief Get the coverage mapping file ID for \c Loc.
+ /// Get the coverage mapping file ID for \c Loc.
///
/// If such file id doesn't exist, return None.
Optional<unsigned> getCoverageFileID(SourceLocation Loc) {
@@ -265,7 +268,7 @@ public:
return None;
}
- /// \brief Gather all the regions that were skipped by the preprocessor
+ /// Gather all the regions that were skipped by the preprocessor
/// using the constructs like #if.
void gatherSkippedRegions() {
/// An array of the minimum lineStarts and the maximum lineEnds
@@ -295,14 +298,14 @@ public:
auto Region = CounterMappingRegion::makeSkipped(
*CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd);
// Make sure that we only collect the regions that are inside
- // the souce code of this function.
+ // the source code of this function.
if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
Region.LineEnd <= FileLineRanges[*CovFileID].second)
MappingRegions.push_back(Region);
}
}
- /// \brief Generate the coverage counter mapping regions from collected
+ /// Generate the coverage counter mapping regions from collected
/// source regions.
void emitSourceRegions(const SourceRegionFilter &Filter) {
for (const auto &Region : SourceRegions) {
@@ -347,7 +350,7 @@ public:
}
}
- /// \brief Generate expansion regions for each virtual file we've seen.
+ /// Generate expansion regions for each virtual file we've seen.
SourceRegionFilter emitExpansionRegions() {
SourceRegionFilter Filter;
for (const auto &FM : FileIDMapping) {
@@ -377,7 +380,7 @@ public:
}
};
-/// \brief Creates unreachable coverage regions for the functions that
+/// Creates unreachable coverage regions for the functions that
/// are not emitted.
struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
@@ -411,7 +414,7 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
SourceRegions.emplace_back(Counter(), Start, End);
}
- /// \brief Write the mapping data to the output stream
+ /// Write the mapping data to the output stream
void write(llvm::raw_ostream &OS) {
SmallVector<unsigned, 16> FileIDMapping;
gatherFileIDs(FileIDMapping);
@@ -425,15 +428,15 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
}
};
-/// \brief A StmtVisitor that creates coverage mapping regions which map
+/// A StmtVisitor that creates coverage mapping regions which map
/// from the source code locations to the PGO counters.
struct CounterCoverageMappingBuilder
: public CoverageMappingBuilder,
public ConstStmtVisitor<CounterCoverageMappingBuilder> {
- /// \brief The map of statements to count values.
+ /// The map of statements to count values.
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
- /// \brief A stack of currently live regions.
+ /// A stack of currently live regions.
std::vector<SourceMappingRegion> RegionStack;
/// The currently deferred region: its end location and count can be set once
@@ -442,7 +445,7 @@ struct CounterCoverageMappingBuilder
CounterExpressionBuilder Builder;
- /// \brief A location in the most recently visited file or macro.
+ /// A location in the most recently visited file or macro.
///
/// This is used to adjust the active source regions appropriately when
/// expressions cross file or macro boundaries.
@@ -451,12 +454,12 @@ struct CounterCoverageMappingBuilder
/// Location of the last terminated region.
Optional<std::pair<SourceLocation, size_t>> LastTerminatedRegion;
- /// \brief Return a counter for the subtraction of \c RHS from \c LHS
+ /// Return a counter for the subtraction of \c RHS from \c LHS
Counter subtractCounters(Counter LHS, Counter RHS) {
return Builder.subtract(LHS, RHS);
}
- /// \brief Return a counter for the sum of \c LHS and \c RHS.
+ /// Return a counter for the sum of \c LHS and \c RHS.
Counter addCounters(Counter LHS, Counter RHS) {
return Builder.add(LHS, RHS);
}
@@ -465,14 +468,14 @@ struct CounterCoverageMappingBuilder
return addCounters(addCounters(C1, C2), C3);
}
- /// \brief Return the region counter for the given statement.
+ /// Return the region counter for the given statement.
///
/// This should only be called on statements that have a dedicated counter.
Counter getRegionCounter(const Stmt *S) {
return Counter::getCounter(CounterMap[S]);
}
- /// \brief Push a region onto the stack.
+ /// Push a region onto the stack.
///
/// Returns the index on the stack where the region was pushed. This can be
/// used with popRegions to exit a "scope", ending the region that was pushed.
@@ -549,7 +552,7 @@ struct CounterCoverageMappingBuilder
completeDeferred(Count, DeferredEndLoc);
}
- /// \brief Pop regions from the stack into the function's list of regions.
+ /// Pop regions from the stack into the function's list of regions.
///
/// Adds all regions from \c ParentIndex to the top of the stack to the
/// function's \c SourceRegions.
@@ -616,13 +619,13 @@ struct CounterCoverageMappingBuilder
assert(!ParentOfDeferredRegion && "Deferred region with no parent");
}
- /// \brief Return the currently active region.
+ /// Return the currently active region.
SourceMappingRegion &getRegion() {
assert(!RegionStack.empty() && "statement has no region");
return RegionStack.back();
}
- /// \brief Propagate counts through the children of \c S.
+ /// Propagate counts through the children of \c S.
Counter propagateCounts(Counter TopCount, const Stmt *S) {
SourceLocation StartLoc = getStart(S);
SourceLocation EndLoc = getEnd(S);
@@ -639,7 +642,7 @@ struct CounterCoverageMappingBuilder
return ExitCount;
}
- /// \brief Check whether a region with bounds \c StartLoc and \c EndLoc
+ /// Check whether a region with bounds \c StartLoc and \c EndLoc
/// is already added to \c SourceRegions.
bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc) {
return SourceRegions.rend() !=
@@ -650,7 +653,7 @@ struct CounterCoverageMappingBuilder
});
}
- /// \brief Adjust the most recently visited location to \c EndLoc.
+ /// Adjust the most recently visited location to \c EndLoc.
///
/// This should be used after visiting any statements in non-source order.
void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
@@ -667,7 +670,7 @@ struct CounterCoverageMappingBuilder
MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
}
- /// \brief Adjust regions and state when \c NewLoc exits a file.
+ /// Adjust regions and state when \c NewLoc exits a file.
///
/// If moving from our most recently tracked location to \c NewLoc exits any
/// files, this adjusts our current region stack and creates the file regions
@@ -734,7 +737,7 @@ struct CounterCoverageMappingBuilder
MostRecentLocation = NewLoc;
}
- /// \brief Ensure that \c S is included in the current region.
+ /// Ensure that \c S is included in the current region.
void extendRegion(const Stmt *S) {
SourceMappingRegion &Region = getRegion();
SourceLocation StartLoc = getStart(S);
@@ -746,7 +749,7 @@ struct CounterCoverageMappingBuilder
completeDeferred(Region.getCounter(), StartLoc);
}
- /// \brief Mark \c S as a terminator, starting a zero region.
+ /// Mark \c S as a terminator, starting a zero region.
void terminateRegion(const Stmt *S) {
extendRegion(S);
SourceMappingRegion &Region = getRegion();
@@ -791,7 +794,7 @@ struct CounterCoverageMappingBuilder
popRegions(Index);
}
- /// \brief Keep counts of breaks and continues inside loops.
+ /// Keep counts of breaks and continues inside loops.
struct BreakContinue {
Counter BreakCount;
Counter ContinueCount;
@@ -805,7 +808,7 @@ struct CounterCoverageMappingBuilder
: CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
DeferredRegion(None) {}
- /// \brief Write the mapping data to the output stream
+ /// Write the mapping data to the output stream
void write(llvm::raw_ostream &OS) {
llvm::SmallVector<unsigned, 8> VirtualFileMapping;
gatherFileIDs(VirtualFileMapping);
@@ -831,22 +834,6 @@ struct CounterCoverageMappingBuilder
handleFileExit(getEnd(S));
}
- /// Determine whether the final deferred region emitted in \p Body should be
- /// discarded.
- static bool discardFinalDeferredRegionInDecl(Stmt *Body) {
- if (auto *CS = dyn_cast<CompoundStmt>(Body)) {
- Stmt *LastStmt = CS->body_back();
- if (auto *IfElse = dyn_cast<IfStmt>(LastStmt)) {
- if (auto *Else = dyn_cast_or_null<CompoundStmt>(IfElse->getElse()))
- LastStmt = Else->body_back();
- else
- LastStmt = IfElse->getElse();
- }
- return dyn_cast_or_null<ReturnStmt>(LastStmt);
- }
- return false;
- }
-
void VisitDecl(const Decl *D) {
assert(!DeferredRegion && "Deferred region never completed");
@@ -856,17 +843,13 @@ struct CounterCoverageMappingBuilder
if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
return;
- Counter ExitCount = propagateCounts(getRegionCounter(Body), Body);
+ propagateCounts(getRegionCounter(Body), Body);
assert(RegionStack.empty() && "Regions entered but never exited");
- if (DeferredRegion) {
- // Complete (or discard) any deferred regions introduced by the last
- // statement.
- if (discardFinalDeferredRegionInDecl(Body))
- DeferredRegion = None;
- else
- popRegions(completeDeferred(ExitCount, getEnd(Body)));
- }
+ // Discard the last uncompleted deferred region in a decl, if one exists.
+ // This prevents lines at the end of a function containing only whitespace
+ // or closing braces from being marked as uncovered.
+ DeferredRegion = None;
}
void VisitReturnStmt(const ReturnStmt *S) {
@@ -889,6 +872,7 @@ struct CounterCoverageMappingBuilder
Counter LabelCount = getRegionCounter(S);
SourceLocation Start = getStart(S);
completeTopLevelDeferredRegion(LabelCount, Start);
+ completeDeferred(LabelCount, Start);
// We can't extendRegion here or we risk overlapping with our new region.
handleFileExit(Start);
pushRegion(LabelCount, Start);
@@ -979,20 +963,28 @@ struct CounterCoverageMappingBuilder
Counter ParentCount = getRegion().getCounter();
Counter BodyCount = getRegionCounter(S);
+ // The loop increment may contain a break or continue.
+ if (S->getInc())
+ BreakContinueStack.emplace_back();
+
// Handle the body first so that we can get the backedge count.
- BreakContinueStack.push_back(BreakContinue());
+ BreakContinueStack.emplace_back();
extendRegion(S->getBody());
Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
- BreakContinue BC = BreakContinueStack.pop_back_val();
+ BreakContinue BodyBC = BreakContinueStack.pop_back_val();
// The increment is essentially part of the body but it needs to include
// the count for all the continue statements.
- if (const Stmt *Inc = S->getInc())
- propagateCounts(addCounters(BackedgeCount, BC.ContinueCount), Inc);
+ BreakContinue IncrementBC;
+ if (const Stmt *Inc = S->getInc()) {
+ propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
+ IncrementBC = BreakContinueStack.pop_back_val();
+ }
// Go back to handle the condition.
- Counter CondCount =
- addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
+ Counter CondCount = addCounters(
+ addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
+ IncrementBC.ContinueCount);
if (const Expr *Cond = S->getCond()) {
propagateCounts(CondCount, Cond);
adjustForOutOfOrderTraversal(getEnd(S));
@@ -1004,8 +996,8 @@ struct CounterCoverageMappingBuilder
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
- Counter OutCount =
- addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
+ Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
+ subtractCounters(CondCount, BodyCount));
if (OutCount != ParentCount)
pushRegion(OutCount);
}
@@ -1361,8 +1353,7 @@ void CoverageMappingModuleGen::emit() {
// and coverage mappings is a multiple of 8.
if (size_t Rem = OS.str().size() % 8) {
CoverageMappingSize += 8 - Rem;
- for (size_t I = 0, S = 8 - Rem; I < S; ++I)
- OS << '\0';
+ OS.write_zeros(8 - Rem);
}
auto *FilenamesAndMappingsVal =
llvm::ConstantDataArray::getString(Ctx, OS.str(), false);