39 #include <system_error> 44 using namespace coverage;
46 #define DEBUG_TYPE "coverage-mapping" 49 auto It = ExpressionIndices.find(E);
50 if (It != ExpressionIndices.end())
52 unsigned I = Expressions.size();
53 Expressions.push_back(E);
54 ExpressionIndices[
E] =
I;
58 void CounterExpressionBuilder::extractTerms(
Counter C,
int Factor,
68 extractTerms(
E.LHS, Factor, Terms);
75 Counter CounterExpressionBuilder::simplify(
Counter ExpressionTree) {
78 extractTerms(ExpressionTree, +1, Terms);
82 if (Terms.
size() == 0)
86 llvm::sort(Terms, [](
const Term &LHS,
const Term &RHS) {
87 return LHS.CounterID < RHS.CounterID;
91 auto Prev = Terms.
begin();
92 for (
auto I = Prev + 1,
E = Terms.
end();
I !=
E; ++
I) {
93 if (
I->CounterID == Prev->CounterID) {
94 Prev->Factor +=
I->Factor;
105 for (
auto T : Terms) {
108 for (
int I = 0;
I <
T.Factor; ++
I)
117 for (
auto T : Terms) {
120 for (
int I = 0;
I < -
T.Factor; ++
I)
156 if (CounterValues.empty())
163 OS <<
'[' << *Value <<
']';
190 void FunctionRecordIterator::skipOtherFiles() {
191 while (Current != Records.end() && !Filename.empty() &&
192 Filename != Current->Filenames[0])
194 if (Current == Records.end())
198 Error CoverageMapping::loadFunctionRecord(
202 if (OrigFuncName.
empty())
212 std::vector<uint64_t> Counts;
220 return make_error<InstrProfError>(IPE);
249 if (!RecordProvenance[FilenamesHash].insert(
hash_value(OrigFuncName)).second)
252 Functions.push_back(std::move(Function));
257 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
259 auto Coverage = std::unique_ptr<CoverageMapping>(
new CoverageMapping());
261 for (
const auto &CoverageReader : CoverageReaders) {
262 for (
auto RecordOrErr : *CoverageReader) {
263 if (
Error E = RecordOrErr.takeError())
265 const auto &Record = *RecordOrErr;
266 if (
Error E = Coverage->loadFunctionRecord(Record, ProfileReader))
271 return std::move(Coverage);
278 if (
Error E = ProfileReaderOrErr.takeError())
280 auto ProfileReader = std::move(ProfileReaderOrErr.get());
286 if (std::error_code EC = CovMappingBufOrErr.getError())
289 auto CoverageReaderOrErr =
291 if (
Error E = CoverageReaderOrErr.takeError())
293 Readers.push_back(std::move(CoverageReaderOrErr.get()));
294 Buffers.
push_back(std::move(CovMappingBufOrErr.get()));
296 return load(Readers, *ProfileReader);
305 class FunctionInstantiationSetCollector {
306 using MapT = std::map<LineColPair, std::vector<const FunctionRecord *>>;
307 MapT InstantiatedFunctions;
312 while (
I !=
E &&
I->FileID != FileID)
314 assert(
I !=
E &&
"function does not cover the given file");
315 auto &Functions = InstantiatedFunctions[
I->startLoc()];
316 Functions.push_back(&Function);
319 MapT::iterator
begin() {
return InstantiatedFunctions.
begin(); }
320 MapT::iterator
end() {
return InstantiatedFunctions.
end(); }
323 class SegmentBuilder {
324 std::vector<CoverageSegment> &Segments;
327 SegmentBuilder(std::vector<CoverageSegment> &Segments) : Segments(Segments) {}
334 bool IsRegionEntry,
bool EmitSkippedRegion =
false) {
335 bool HasCount = !EmitSkippedRegion &&
339 if (!Segments.empty() && !IsRegionEntry && !EmitSkippedRegion) {
340 const auto &Last = Segments.back();
341 if (Last.HasCount == HasCount && Last.Count == Region.
ExecutionCount &&
347 Segments.emplace_back(StartLoc.first, StartLoc.second,
351 Segments.emplace_back(StartLoc.first, StartLoc.second, IsRegionEntry);
354 const auto &Last = Segments.back();
355 dbgs() <<
"Segment at " << Last.Line <<
":" << Last.Col
356 <<
" (count = " << Last.Count <<
")" 357 << (Last.IsRegionEntry ?
", RegionEntry" :
"")
358 << (!Last.HasCount ?
", Skipped" :
"")
359 << (Last.IsGapRegion ?
", Gap" :
"") <<
"\n";
369 unsigned FirstCompletedRegion) {
372 auto CompletedRegionsIt = ActiveRegions.
begin() + FirstCompletedRegion;
373 std::stable_sort(CompletedRegionsIt, ActiveRegions.
end(),
375 return L->
endLoc() < R->endLoc();
379 for (
unsigned I = FirstCompletedRegion + 1,
E = ActiveRegions.
size();
I <
E;
381 const auto *CompletedRegion = ActiveRegions[
I];
382 assert((!Loc || CompletedRegion->endLoc() <= *Loc) &&
383 "Completed region ends after start of new region");
385 const auto *PrevCompletedRegion = ActiveRegions[
I - 1];
386 auto CompletedSegmentLoc = PrevCompletedRegion->endLoc();
389 if (Loc && CompletedSegmentLoc == *Loc)
394 if (CompletedSegmentLoc == CompletedRegion->endLoc())
398 for (
unsigned J =
I + 1; J <
E; ++J)
399 if (CompletedRegion->endLoc() == ActiveRegions[J]->endLoc())
400 CompletedRegion = ActiveRegions[J];
402 startSegment(*CompletedRegion, CompletedSegmentLoc,
false);
405 auto Last = ActiveRegions.
back();
406 if (FirstCompletedRegion && Last->endLoc() != *Loc) {
409 startSegment(*ActiveRegions[FirstCompletedRegion - 1], Last->endLoc(),
411 }
else if (!FirstCompletedRegion && (!Loc || *Loc != Last->endLoc())) {
414 startSegment(*Last, Last->endLoc(),
false,
true);
418 ActiveRegions.
erase(CompletedRegionsIt, ActiveRegions.
end());
422 for (
const auto &CR :
enumerate(Regions)) {
423 auto CurStartLoc = CR.value().startLoc();
426 auto CompletedRegions =
427 std::stable_partition(ActiveRegions.
begin(), ActiveRegions.
end(),
429 return !(Region->
endLoc() <= CurStartLoc);
431 if (CompletedRegions != ActiveRegions.
end()) {
432 unsigned FirstCompletedRegion =
433 std::distance(ActiveRegions.
begin(), CompletedRegions);
434 completeRegionsUntil(CurStartLoc, FirstCompletedRegion);
440 if (CurStartLoc == CR.value().endLoc()) {
443 const bool Skipped = (CR.index() + 1) == Regions.
size();
444 startSegment(ActiveRegions.
empty() ? CR.value() : *ActiveRegions.
back(),
445 CurStartLoc, !GapRegion, Skipped);
448 if (CR.index() + 1 == Regions.
size() ||
449 CurStartLoc != Regions[CR.index() + 1].startLoc()) {
452 startSegment(CR.value(), CurStartLoc, !GapRegion);
460 if (!ActiveRegions.
empty())
461 completeRegionsUntil(
None, 0);
481 "Unexpected order of region kind values");
491 auto Active = Regions.
begin();
492 auto End = Regions.
end();
493 for (
auto I = Regions.
begin() + 1;
I != End; ++
I) {
494 if (Active->startLoc() !=
I->startLoc() ||
495 Active->endLoc() !=
I->endLoc()) {
514 if (
I->Kind == Active->Kind)
515 Active->ExecutionCount +=
I->ExecutionCount;
517 return Regions.
drop_back(std::distance(++Active, End));
522 static std::vector<CoverageSegment>
524 std::vector<CoverageSegment> Segments;
525 SegmentBuilder Builder(Segments);
527 sortNestedRegions(Regions);
531 dbgs() <<
"Combined regions:\n";
532 for (
const auto &CR : CombinedRegions)
533 dbgs() <<
" " << CR.LineStart <<
":" << CR.ColumnStart <<
" -> " 534 << CR.LineEnd <<
":" << CR.ColumnEnd
535 <<
" (count=" << CR.ExecutionCount <<
")\n";
538 Builder.buildSegmentsImpl(CombinedRegions);
541 for (
unsigned I = 1,
E = Segments.size();
I <
E; ++
I) {
542 const auto &L = Segments[
I - 1];
543 const auto &R = Segments[
I];
544 if (!(L.Line < R.Line) && !(L.Line == R.Line && L.Col < R.Col)) {
546 <<
" followed by " << R.Line <<
":" << R.Col <<
"\n");
547 assert(
false &&
"Coverage segments not unique or sorted");
559 std::vector<StringRef> Filenames;
560 for (
const auto &
Function : getCoveredFunctions())
561 Filenames.insert(Filenames.end(),
Function.Filenames.
begin(),
564 auto Last = std::unique(Filenames.begin(), Filenames.end());
565 Filenames.erase(Last, Filenames.end());
574 FilenameEquivalence[
I] =
true;
575 return FilenameEquivalence;
583 IsNotExpandedFile[CR.ExpandedFileID] =
false;
584 int I = IsNotExpandedFile.find_first();
595 if (I && SourceFile == Function.
Filenames[*I])
606 std::vector<CountedRegion> Regions;
608 for (
const auto &
Function : Functions) {
611 for (
const auto &CR :
Function.CountedRegions)
612 if (FileIDs.test(CR.FileID)) {
613 Regions.push_back(CR);
615 FileCoverage.Expansions.emplace_back(CR,
Function);
619 LLVM_DEBUG(
dbgs() <<
"Emitting segments for file: " << Filename <<
"\n");
620 FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
625 std::vector<InstantiationGroup>
627 FunctionInstantiationSetCollector InstantiationSetCollector;
628 for (
const auto &
Function : Functions) {
632 InstantiationSetCollector.insert(
Function, *MainFileID);
635 std::vector<InstantiationGroup> Result;
636 for (
auto &InstantiationSet : InstantiationSetCollector) {
638 InstantiationSet.first.second,
639 std::move(InstantiationSet.second)};
640 Result.emplace_back(std::move(IG));
652 std::vector<CountedRegion> Regions;
654 if (CR.FileID == *MainFileID) {
655 Regions.push_back(CR);
657 FunctionCoverage.Expansions.emplace_back(CR, Function);
662 FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
664 return FunctionCoverage;
671 std::vector<CountedRegion> Regions;
673 if (CR.FileID == Expansion.
FileID) {
674 Regions.push_back(CR);
676 ExpansionCoverage.Expansions.emplace_back(CR, Expansion.
Function);
680 << Expansion.
FileID <<
"\n");
681 ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
683 return ExpansionCoverage;
686 LineCoverageStats::LineCoverageStats(
689 : ExecutionCount(0), HasMultipleRegions(
false), Mapped(
false), Line(Line),
690 LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
692 unsigned MinRegionCount = 0;
694 return !S->
IsGapRegion && S->HasCount && S->IsRegionEntry;
696 for (
unsigned I = 0;
I < LineSegments.
size() && MinRegionCount < 2; ++
I)
697 if (isStartOfRegion(LineSegments[
I]))
700 bool StartOfSkippedRegion = !LineSegments.
empty() &&
704 HasMultipleRegions = MinRegionCount > 1;
706 !StartOfSkippedRegion &&
707 ((WrappedSegment && WrappedSegment->
HasCount) || (MinRegionCount > 0));
715 ExecutionCount = WrappedSegment->
Count;
718 for (
const auto *
LS : LineSegments)
719 if (isStartOfRegion(
LS))
720 ExecutionCount =
std::max(ExecutionCount,
LS->Count);
724 if (Next == CD.end()) {
730 WrappedSegment = Segments.back();
732 while (Next != CD.end() && Next->Line == Line)
733 Segments.push_back(&*Next++);
744 return "End of File";
746 return "No coverage data found";
748 return "Unsupported coverage format version";
750 return "Truncated coverage data";
752 return "Malformed coverage data";
763 const char *
name()
const noexcept
override {
return "llvm.coveragemap"; }
764 std::string message(
int IE)
const override {
const T & front() const
front - Get the first element.
const_iterator end(StringRef path)
Get end iterator over path.
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
This class represents lattice values for constants.
static Counter getZero()
Return the counter that represents the number zero.
void setCounts(ArrayRef< uint64_t > Counts)
static instrprof_error take(Error E)
Consume an Error and return the raw enum value contained within it.
void push_back(const T &Elt)
LineColPair endLoc() const
static SmallBitVector gatherFileIDs(StringRef SourceFile, const FunctionRecord &Function)
void pushRegion(CounterMappingRegion Region, uint64_t Count)
A Counter expression is a value that represents an arithmetic operation with two counters.
Error takeError()
Take ownership of the stored error.
ArrayRef< CounterMappingRegion > MappingRegions
CoverageData getCoverageForFile(StringRef Filename) const
Get the coverage for a particular file.
Iterator over Functions, optionally filtered to a single file.
A GapRegion is like a CodeRegion, but its count is only set as the line execution count when its the ...
ArrayRef< CounterExpression > Expressions
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
An iterator over the LineCoverageStats objects for lines described by a CoverageData instance...
friend const_iterator begin(StringRef path, Style style)
Get begin iterator over path.
Tagged union holding either a T or a Error.
block placement Basic Block Placement Stats
StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, StringRef FileName="<unknown>")
Given a PGO function name, remove the filename prefix and return the original (static) function name...
std::pair< unsigned, unsigned > LineColPair
void dump(const Counter &C, raw_ostream &OS) const
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const
empty - Check if the string is empty.
Coverage information to be processed or displayed.
static Expected< std::unique_ptr< CoverageMapping > > load(ArrayRef< std::unique_ptr< CoverageMappingReader >> CoverageReaders, IndexedInstrProfReader &ProfileReader)
Load the coverage mapping using the given readers.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
hash_code hash_value(const APFloat &Arg)
See friend declarations above.
Counter add(Counter LHS, Counter RHS)
Return a counter that represents the expression that adds LHS and RHS.
const std::error_category & coveragemap_category()
The execution count information starting at a point in a file.
ArrayRef< StringRef > Filenames
friend const_iterator end(StringRef path)
Get end iterator over path.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Coverage mapping information for a single function.
size_t size() const
size - Get the array size.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
An instantiation group contains a FunctionRecord list, such that each record corresponds to a distinc...
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
A CodeRegion associates some code with a counter.
A Counter mapping context is used to connect the counters, expressions and the obtained counter value...
bool IsRegionEntry
Whether this enters a new region or returns to a previous count.
static ManagedStatic< _object_error_category > error_category
LineColPair startLoc() const
static ManagedStatic< CoverageMappingErrorCategoryType > ErrorCategory
Associates a source range with an execution count.
iterator erase(const_iterator CI)
void consumeError(Error Err)
Consume a Error without doing anything.
MutableArrayRef< T > drop_back(size_t N=1) const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Counter subtract(Counter LHS, Counter RHS)
Return a counter that represents the expression that subtracts RHS from LHS.
CoverageData getCoverageForFunction(const FunctionRecord &Function) const
Get the coverage for a particular function.
void sort(IteratorTy Start, IteratorTy End)
Code coverage information for a single function.
static ErrorSuccess success()
Create a success value.
static std::string getCoverageMapErrString(coveragemap_error Err)
Coverage statistics for a single line.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
static bool isExpansion(const CountedRegion &R, unsigned FileID)
uint64_t Count
The execution count, or zero if no count was recorded.
bool HasCount
When false, the segment was uninstrumented or skipped.
static Expected< std::unique_ptr< BinaryCoverageReader > > create(std::unique_ptr< MemoryBuffer > &ObjectBuffer, StringRef Arch)
An ExpansionRegion represents a file expansion region that associates a source range with the expansi...
A SkippedRegion represents a source range with code that was skipped by a preprocessor or similar mea...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
The mapping of profile information to coverage data.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, int64_t FileSize=-1, bool RequiresNullTerminator=true)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
std::vector< InstantiationGroup > getInstantiationGroups(StringRef Filename) const
Get the list of function instantiation groups in a particular file.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
std::string message() const override
Return the error message as a string.
void emplace_back(ArgTypes &&... Args)
unsigned getExpressionID() const
CounterKind getKind() const
LLVM_NODISCARD bool empty() const
static Optional< unsigned > findMainViewFileID(const FunctionRecord &Function)
Return the ID of the file where the definition of the function is located.
Expected< int64_t > evaluate(const Counter &C) const
Return the number of times that a region of code associated with this counter was executed...
std::vector< CountedRegion > CountedRegions
Regions in the function along with their counts.
std::string Name
Raw function name.
unsigned FileID
The abstract file this expansion covers.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool IsGapRegion
Whether this enters a gap region.
unsigned getCounterID() const
LLVM Value Representation.
std::vector< std::string > Filenames
Associated files.
Lightweight error class with error context and mandatory checking.
This class implements an extremely fast bulk output stream that can only output to a stream...
StringRef - Represent a constant reference to a string, i.e.
Reader for the indexed binary instrprof format.
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
static Counter getExpression(unsigned ExpressionId)
Return the counter that corresponds to a specific addition counter expression.
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const
Get the coverage for an expansion within a coverage set.
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, const Twine &RemappingPath="")
Factory method to create an indexed reader.
A Counter is an abstract value that describes how to compute the execution count for a region of code...
LineCoverageIterator & operator++()
static Counter getCounter(unsigned CounterId)
Return the counter that corresponds to a specific profile counter.
const FunctionRecord & Function
Coverage for the expansion.
bool empty() const
empty - Check if the array is empty.
std::vector< StringRef > getUniqueSourceFiles() const
Returns a lexicographically sorted, unique list of files that are covered.
detail::enumerator< R > enumerate(R &&TheRange)
Given an input range, returns a new range whose values are are pair (A,B) such that A is the 0-based ...
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector< uint64_t > &Counts)
Fill Counts with the profile data for the given function name.
Coverage information for a macro expansion or #included file.