diff options
| author | vvvv <[email protected]> | 2024-02-06 20:01:22 +0300 |
|---|---|---|
| committer | vvvv <[email protected]> | 2024-02-06 20:22:16 +0300 |
| commit | 0203b7a9a40828bb2bd4c32029b79ff0ea3d1f8f (patch) | |
| tree | e630d0d5bd0bd29fc8c2d2842ed2cfde781b993a /contrib/libs/llvm16/include/llvm/ProfileData/Coverage/CoverageMapping.h | |
| parent | ba27db76d99d12a4f1c06960b5449423218614c4 (diff) | |
llvm16 targets
Diffstat (limited to 'contrib/libs/llvm16/include/llvm/ProfileData/Coverage/CoverageMapping.h')
| -rw-r--r-- | contrib/libs/llvm16/include/llvm/ProfileData/Coverage/CoverageMapping.h | 1089 |
1 files changed, 1089 insertions, 0 deletions
diff --git a/contrib/libs/llvm16/include/llvm/ProfileData/Coverage/CoverageMapping.h b/contrib/libs/llvm16/include/llvm/ProfileData/Coverage/CoverageMapping.h new file mode 100644 index 00000000000..952456cb92b --- /dev/null +++ b/contrib/libs/llvm16/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -0,0 +1,1089 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- CoverageMapping.h - Code coverage mapping support --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Code coverage mapping data is generated by clang and read by +// llvm-cov to show code coverage statistics for a file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H +#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/BuildID.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstdint> +#include <iterator> +#include <memory> +#include <string> +#include <system_error> +#include <tuple> +#include <utility> +#include <vector> + +namespace llvm { + +class IndexedInstrProfReader; + +namespace object { +class BuildIDFetcher; +} // namespace object + +namespace coverage { + +class CoverageMappingReader; +struct CoverageMappingRecord; + +enum class coveragemap_error { + success = 0, + eof, + no_data_found, + unsupported_version, + truncated, + malformed, + decompression_failed, + invalid_or_missing_arch_specifier +}; + +const std::error_category &coveragemap_category(); + +inline std::error_code make_error_code(coveragemap_error E) { + return std::error_code(static_cast<int>(E), coveragemap_category()); +} + +class CoverageMapError : public ErrorInfo<CoverageMapError> { +public: + CoverageMapError(coveragemap_error Err) : Err(Err) { + assert(Err != coveragemap_error::success && "Not an error"); + } + + std::string message() const override; + + void log(raw_ostream &OS) const override { OS << message(); } + + std::error_code convertToErrorCode() const override { + return make_error_code(Err); + } + + coveragemap_error get() const { return Err; } + + static char ID; + +private: + coveragemap_error Err; +}; + +/// A Counter is an abstract value that describes how to compute the +/// execution count for a region of code using the collected profile count data. +struct Counter { + /// The CounterExpression kind (Add or Subtract) is encoded in bit 0 next to + /// the CounterKind. This means CounterKind has to leave bit 0 free. + enum CounterKind { Zero, CounterValueReference, Expression }; + static const unsigned EncodingTagBits = 2; + static const unsigned EncodingTagMask = 0x3; + static const unsigned EncodingCounterTagAndExpansionRegionTagBits = + EncodingTagBits + 1; + +private: + CounterKind Kind = Zero; + unsigned ID = 0; + + Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {} + +public: + Counter() = default; + + CounterKind getKind() const { return Kind; } + + bool isZero() const { return Kind == Zero; } + + bool isExpression() const { return Kind == Expression; } + + unsigned getCounterID() const { return ID; } + + unsigned getExpressionID() const { return ID; } + + friend bool operator==(const Counter &LHS, const Counter &RHS) { + return LHS.Kind == RHS.Kind && LHS.ID == RHS.ID; + } + + friend bool operator!=(const Counter &LHS, const Counter &RHS) { + return !(LHS == RHS); + } + + friend bool operator<(const Counter &LHS, const Counter &RHS) { + return std::tie(LHS.Kind, LHS.ID) < std::tie(RHS.Kind, RHS.ID); + } + + /// Return the counter that represents the number zero. + static Counter getZero() { return Counter(); } + + /// Return the counter that corresponds to a specific profile counter. + static Counter getCounter(unsigned CounterId) { + return Counter(CounterValueReference, CounterId); + } + + /// Return the counter that corresponds to a specific addition counter + /// expression. + static Counter getExpression(unsigned ExpressionId) { + return Counter(Expression, ExpressionId); + } +}; + +/// A Counter expression is a value that represents an arithmetic operation +/// with two counters. +struct CounterExpression { + enum ExprKind { Subtract, Add }; + ExprKind Kind; + Counter LHS, RHS; + + CounterExpression(ExprKind Kind, Counter LHS, Counter RHS) + : Kind(Kind), LHS(LHS), RHS(RHS) {} +}; + +/// A Counter expression builder is used to construct the counter expressions. +/// It avoids unnecessary duplication and simplifies algebraic expressions. +class CounterExpressionBuilder { + /// A list of all the counter expressions + std::vector<CounterExpression> Expressions; + + /// A lookup table for the index of a given expression. + DenseMap<CounterExpression, unsigned> ExpressionIndices; + + /// Return the counter which corresponds to the given expression. + /// + /// If the given expression is already stored in the builder, a counter + /// that references that expression is returned. Otherwise, the given + /// expression is added to the builder's collection of expressions. + Counter get(const CounterExpression &E); + + /// Represents a term in a counter expression tree. + struct Term { + unsigned CounterID; + int Factor; + + Term(unsigned CounterID, int Factor) + : CounterID(CounterID), Factor(Factor) {} + }; + + /// Gather the terms of the expression tree for processing. + /// + /// This collects each addition and subtraction referenced by the counter into + /// a sequence that can be sorted and combined to build a simplified counter + /// expression. + void extractTerms(Counter C, int Sign, SmallVectorImpl<Term> &Terms); + + /// Simplifies the given expression tree + /// by getting rid of algebraically redundant operations. + Counter simplify(Counter ExpressionTree); + +public: + ArrayRef<CounterExpression> getExpressions() const { return Expressions; } + + /// Return a counter that represents the expression that adds LHS and RHS. + Counter add(Counter LHS, Counter RHS, bool Simplify = true); + + /// Return a counter that represents the expression that subtracts RHS from + /// LHS. + Counter subtract(Counter LHS, Counter RHS, bool Simplify = true); +}; + +using LineColPair = std::pair<unsigned, unsigned>; + +/// A Counter mapping region associates a source range with a specific counter. +struct CounterMappingRegion { + enum RegionKind { + /// A CodeRegion associates some code with a counter + CodeRegion, + + /// An ExpansionRegion represents a file expansion region that associates + /// a source range with the expansion of a virtual source file, such as + /// for a macro instantiation or #include file. + ExpansionRegion, + + /// A SkippedRegion represents a source range with code that was skipped + /// by a preprocessor or similar means. + SkippedRegion, + + /// A GapRegion is like a CodeRegion, but its count is only set as the + /// line execution count when its the only region in the line. + GapRegion, + + /// A BranchRegion represents leaf-level boolean expressions and is + /// associated with two counters, each representing the number of times the + /// expression evaluates to true or false. + BranchRegion + }; + + /// Primary Counter that is also used for Branch Regions (TrueCount). + Counter Count; + + /// Secondary Counter used for Branch Regions (FalseCount). + Counter FalseCount; + + unsigned FileID, ExpandedFileID; + unsigned LineStart, ColumnStart, LineEnd, ColumnEnd; + RegionKind Kind; + + CounterMappingRegion(Counter Count, unsigned FileID, unsigned ExpandedFileID, + unsigned LineStart, unsigned ColumnStart, + unsigned LineEnd, unsigned ColumnEnd, RegionKind Kind) + : Count(Count), FileID(FileID), ExpandedFileID(ExpandedFileID), + LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd), + ColumnEnd(ColumnEnd), Kind(Kind) {} + + CounterMappingRegion(Counter Count, Counter FalseCount, unsigned FileID, + unsigned ExpandedFileID, unsigned LineStart, + unsigned ColumnStart, unsigned LineEnd, + unsigned ColumnEnd, RegionKind Kind) + : Count(Count), FalseCount(FalseCount), FileID(FileID), + ExpandedFileID(ExpandedFileID), LineStart(LineStart), + ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd), + Kind(Kind) {} + + static CounterMappingRegion + makeRegion(Counter Count, unsigned FileID, unsigned LineStart, + unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { + return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart, + LineEnd, ColumnEnd, CodeRegion); + } + + static CounterMappingRegion + makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart, + unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { + return CounterMappingRegion(Counter(), FileID, ExpandedFileID, LineStart, + ColumnStart, LineEnd, ColumnEnd, + ExpansionRegion); + } + + static CounterMappingRegion + makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart, + unsigned LineEnd, unsigned ColumnEnd) { + return CounterMappingRegion(Counter(), FileID, 0, LineStart, ColumnStart, + LineEnd, ColumnEnd, SkippedRegion); + } + + static CounterMappingRegion + makeGapRegion(Counter Count, unsigned FileID, unsigned LineStart, + unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { + return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart, + LineEnd, (1U << 31) | ColumnEnd, GapRegion); + } + + static CounterMappingRegion + makeBranchRegion(Counter Count, Counter FalseCount, unsigned FileID, + unsigned LineStart, unsigned ColumnStart, unsigned LineEnd, + unsigned ColumnEnd) { + return CounterMappingRegion(Count, FalseCount, FileID, 0, LineStart, + ColumnStart, LineEnd, ColumnEnd, BranchRegion); + } + + inline LineColPair startLoc() const { + return LineColPair(LineStart, ColumnStart); + } + + inline LineColPair endLoc() const { return LineColPair(LineEnd, ColumnEnd); } +}; + +/// Associates a source range with an execution count. +struct CountedRegion : public CounterMappingRegion { + uint64_t ExecutionCount; + uint64_t FalseExecutionCount; + bool Folded; + + CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount) + : CounterMappingRegion(R), ExecutionCount(ExecutionCount), + FalseExecutionCount(0), Folded(false) {} + + CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount, + uint64_t FalseExecutionCount) + : CounterMappingRegion(R), ExecutionCount(ExecutionCount), + FalseExecutionCount(FalseExecutionCount), Folded(false) {} +}; + +/// A Counter mapping context is used to connect the counters, expressions +/// and the obtained counter values. +class CounterMappingContext { + ArrayRef<CounterExpression> Expressions; + ArrayRef<uint64_t> CounterValues; + +public: + CounterMappingContext(ArrayRef<CounterExpression> Expressions, + ArrayRef<uint64_t> CounterValues = std::nullopt) + : Expressions(Expressions), CounterValues(CounterValues) {} + + void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; } + + void dump(const Counter &C, raw_ostream &OS) const; + void dump(const Counter &C) const { dump(C, dbgs()); } + + /// Return the number of times that a region of code associated with this + /// counter was executed. + Expected<int64_t> evaluate(const Counter &C) const; + + unsigned getMaxCounterID(const Counter &C) const; +}; + +/// Code coverage information for a single function. +struct FunctionRecord { + /// Raw function name. + std::string Name; + /// Mapping from FileID (i.e. vector index) to filename. Used to support + /// macro expansions within a function in which the macro and function are + /// defined in separate files. + /// + /// TODO: Uniquing filenames across all function records may be a performance + /// optimization. + std::vector<std::string> Filenames; + /// Regions in the function along with their counts. + std::vector<CountedRegion> CountedRegions; + /// Branch Regions in the function along with their counts. + std::vector<CountedRegion> CountedBranchRegions; + /// The number of times this function was executed. + uint64_t ExecutionCount = 0; + + FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames) + : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {} + + FunctionRecord(FunctionRecord &&FR) = default; + FunctionRecord &operator=(FunctionRecord &&) = default; + + void pushRegion(CounterMappingRegion Region, uint64_t Count, + uint64_t FalseCount) { + if (Region.Kind == CounterMappingRegion::BranchRegion) { + CountedBranchRegions.emplace_back(Region, Count, FalseCount); + // If both counters are hard-coded to zero, then this region represents a + // constant-folded branch. + if (Region.Count.isZero() && Region.FalseCount.isZero()) + CountedBranchRegions.back().Folded = true; + return; + } + if (CountedRegions.empty()) + ExecutionCount = Count; + CountedRegions.emplace_back(Region, Count, FalseCount); + } +}; + +/// Iterator over Functions, optionally filtered to a single file. +class FunctionRecordIterator + : public iterator_facade_base<FunctionRecordIterator, + std::forward_iterator_tag, FunctionRecord> { + ArrayRef<FunctionRecord> Records; + ArrayRef<FunctionRecord>::iterator Current; + StringRef Filename; + + /// Skip records whose primary file is not \c Filename. + void skipOtherFiles(); + +public: + FunctionRecordIterator(ArrayRef<FunctionRecord> Records_, + StringRef Filename = "") + : Records(Records_), Current(Records.begin()), Filename(Filename) { + skipOtherFiles(); + } + + FunctionRecordIterator() : Current(Records.begin()) {} + + bool operator==(const FunctionRecordIterator &RHS) const { + return Current == RHS.Current && Filename == RHS.Filename; + } + + const FunctionRecord &operator*() const { return *Current; } + + FunctionRecordIterator &operator++() { + assert(Current != Records.end() && "incremented past end"); + ++Current; + skipOtherFiles(); + return *this; + } +}; + +/// Coverage information for a macro expansion or #included file. +/// +/// When covered code has pieces that can be expanded for more detail, such as a +/// preprocessor macro use and its definition, these are represented as +/// expansions whose coverage can be looked up independently. +struct ExpansionRecord { + /// The abstract file this expansion covers. + unsigned FileID; + /// The region that expands to this record. + const CountedRegion &Region; + /// Coverage for the expansion. + const FunctionRecord &Function; + + ExpansionRecord(const CountedRegion &Region, + const FunctionRecord &Function) + : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {} +}; + +/// The execution count information starting at a point in a file. +/// +/// A sequence of CoverageSegments gives execution counts for a file in format +/// that's simple to iterate through for processing. +struct CoverageSegment { + /// The line where this segment begins. + unsigned Line; + /// The column where this segment begins. + unsigned Col; + /// The execution count, or zero if no count was recorded. + uint64_t Count; + /// When false, the segment was uninstrumented or skipped. + bool HasCount; + /// Whether this enters a new region or returns to a previous count. + bool IsRegionEntry; + /// Whether this enters a gap region. + bool IsGapRegion; + + CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry) + : Line(Line), Col(Col), Count(0), HasCount(false), + IsRegionEntry(IsRegionEntry), IsGapRegion(false) {} + + CoverageSegment(unsigned Line, unsigned Col, uint64_t Count, + bool IsRegionEntry, bool IsGapRegion = false, + bool IsBranchRegion = false) + : Line(Line), Col(Col), Count(Count), HasCount(true), + IsRegionEntry(IsRegionEntry), IsGapRegion(IsGapRegion) {} + + friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) { + return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry, + L.IsGapRegion) == std::tie(R.Line, R.Col, R.Count, + R.HasCount, R.IsRegionEntry, + R.IsGapRegion); + } +}; + +/// An instantiation group contains a \c FunctionRecord list, such that each +/// record corresponds to a distinct instantiation of the same function. +/// +/// Note that it's possible for a function to have more than one instantiation +/// (consider C++ template specializations or static inline functions). +class InstantiationGroup { + friend class CoverageMapping; + + unsigned Line; + unsigned Col; + std::vector<const FunctionRecord *> Instantiations; + + InstantiationGroup(unsigned Line, unsigned Col, + std::vector<const FunctionRecord *> Instantiations) + : Line(Line), Col(Col), Instantiations(std::move(Instantiations)) {} + +public: + InstantiationGroup(const InstantiationGroup &) = delete; + InstantiationGroup(InstantiationGroup &&) = default; + + /// Get the number of instantiations in this group. + size_t size() const { return Instantiations.size(); } + + /// Get the line where the common function was defined. + unsigned getLine() const { return Line; } + + /// Get the column where the common function was defined. + unsigned getColumn() const { return Col; } + + /// Check if the instantiations in this group have a common mangled name. + bool hasName() const { + for (unsigned I = 1, E = Instantiations.size(); I < E; ++I) + if (Instantiations[I]->Name != Instantiations[0]->Name) + return false; + return true; + } + + /// Get the common mangled name for instantiations in this group. + StringRef getName() const { + assert(hasName() && "Instantiations don't have a shared name"); + return Instantiations[0]->Name; + } + + /// Get the total execution count of all instantiations in this group. + uint64_t getTotalExecutionCount() const { + uint64_t Count = 0; + for (const FunctionRecord *F : Instantiations) + Count += F->ExecutionCount; + return Count; + } + + /// Get the instantiations in this group. + ArrayRef<const FunctionRecord *> getInstantiations() const { + return Instantiations; + } +}; + +/// Coverage information to be processed or displayed. +/// +/// This represents the coverage of an entire file, expansion, or function. It +/// provides a sequence of CoverageSegments to iterate through, as well as the +/// list of expansions that can be further processed. +class CoverageData { + friend class CoverageMapping; + + std::string Filename; + std::vector<CoverageSegment> Segments; + std::vector<ExpansionRecord> Expansions; + std::vector<CountedRegion> BranchRegions; + +public: + CoverageData() = default; + + CoverageData(StringRef Filename) : Filename(Filename) {} + + /// Get the name of the file this data covers. + StringRef getFilename() const { return Filename; } + + /// Get an iterator over the coverage segments for this object. The segments + /// are guaranteed to be uniqued and sorted by location. + std::vector<CoverageSegment>::const_iterator begin() const { + return Segments.begin(); + } + + std::vector<CoverageSegment>::const_iterator end() const { + return Segments.end(); + } + + bool empty() const { return Segments.empty(); } + + /// Expansions that can be further processed. + ArrayRef<ExpansionRecord> getExpansions() const { return Expansions; } + + /// Branches that can be further processed. + ArrayRef<CountedRegion> getBranches() const { return BranchRegions; } +}; + +/// The mapping of profile information to coverage data. +/// +/// This is the main interface to get coverage information, using a profile to +/// fill out execution counts. +class CoverageMapping { + DenseMap<size_t, DenseSet<size_t>> RecordProvenance; + std::vector<FunctionRecord> Functions; + DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices; + std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches; + + CoverageMapping() = default; + + // Load coverage records from readers. + static Error loadFromReaders( + ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, + IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage); + + // Load coverage records from file. + static Error + loadFromFile(StringRef Filename, StringRef Arch, StringRef CompilationDir, + IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage, + bool &DataFound, + SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr); + + /// Add a function record corresponding to \p Record. + Error loadFunctionRecord(const CoverageMappingRecord &Record, + IndexedInstrProfReader &ProfileReader); + + /// Look up the indices for function records which are at least partially + /// defined in the specified file. This is guaranteed to return a superset of + /// such records: extra records not in the file may be included if there is + /// a hash collision on the filename. Clients must be robust to collisions. + ArrayRef<unsigned> + getImpreciseRecordIndicesForFilename(StringRef Filename) const; + +public: + CoverageMapping(const CoverageMapping &) = delete; + CoverageMapping &operator=(const CoverageMapping &) = delete; + + /// Load the coverage mapping using the given readers. + static Expected<std::unique_ptr<CoverageMapping>> + load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, + IndexedInstrProfReader &ProfileReader); + + /// Load the coverage mapping from the given object files and profile. If + /// \p Arches is non-empty, it must specify an architecture for each object. + /// Ignores non-instrumented object files unless all are not instrumented. + static Expected<std::unique_ptr<CoverageMapping>> + load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename, + ArrayRef<StringRef> Arches = std::nullopt, StringRef CompilationDir = "", + const object::BuildIDFetcher *BIDFetcher = nullptr); + + /// The number of functions that couldn't have their profiles mapped. + /// + /// This is a count of functions whose profile is out of date or otherwise + /// can't be associated with any coverage information. + unsigned getMismatchedCount() const { return FuncHashMismatches.size(); } + + /// A hash mismatch occurs when a profile record for a symbol does not have + /// the same hash as a coverage mapping record for the same symbol. This + /// returns a list of hash mismatches, where each mismatch is a pair of the + /// symbol name and its coverage mapping hash. + ArrayRef<std::pair<std::string, uint64_t>> getHashMismatches() const { + return FuncHashMismatches; + } + + /// Returns a lexicographically sorted, unique list of files that are + /// covered. + std::vector<StringRef> getUniqueSourceFiles() const; + + /// Get the coverage for a particular file. + /// + /// The given filename must be the name as recorded in the coverage + /// information. That is, only names returned from getUniqueSourceFiles will + /// yield a result. + CoverageData getCoverageForFile(StringRef Filename) const; + + /// Get the coverage for a particular function. + CoverageData getCoverageForFunction(const FunctionRecord &Function) const; + + /// Get the coverage for an expansion within a coverage set. + CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const; + + /// Gets all of the functions covered by this profile. + iterator_range<FunctionRecordIterator> getCoveredFunctions() const { + return make_range(FunctionRecordIterator(Functions), + FunctionRecordIterator()); + } + + /// Gets all of the functions in a particular file. + iterator_range<FunctionRecordIterator> + getCoveredFunctions(StringRef Filename) const { + return make_range(FunctionRecordIterator(Functions, Filename), + FunctionRecordIterator()); + } + + /// Get the list of function instantiation groups in a particular file. + /// + /// Every instantiation group in a program is attributed to exactly one file: + /// the file in which the definition for the common function begins. + std::vector<InstantiationGroup> + getInstantiationGroups(StringRef Filename) const; +}; + +/// Coverage statistics for a single line. +class LineCoverageStats { + uint64_t ExecutionCount; + bool HasMultipleRegions; + bool Mapped; + unsigned Line; + ArrayRef<const CoverageSegment *> LineSegments; + const CoverageSegment *WrappedSegment; + + friend class LineCoverageIterator; + LineCoverageStats() = default; + +public: + LineCoverageStats(ArrayRef<const CoverageSegment *> LineSegments, + const CoverageSegment *WrappedSegment, unsigned Line); + + uint64_t getExecutionCount() const { return ExecutionCount; } + + bool hasMultipleRegions() const { return HasMultipleRegions; } + + bool isMapped() const { return Mapped; } + + unsigned getLine() const { return Line; } + + ArrayRef<const CoverageSegment *> getLineSegments() const { + return LineSegments; + } + + const CoverageSegment *getWrappedSegment() const { return WrappedSegment; } +}; + +/// An iterator over the \c LineCoverageStats objects for lines described by +/// a \c CoverageData instance. +class LineCoverageIterator + : public iterator_facade_base<LineCoverageIterator, + std::forward_iterator_tag, + const LineCoverageStats> { +public: + LineCoverageIterator(const CoverageData &CD) + : LineCoverageIterator(CD, CD.begin()->Line) {} + + LineCoverageIterator(const CoverageData &CD, unsigned Line) + : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false), + Line(Line) { + this->operator++(); + } + + bool operator==(const LineCoverageIterator &R) const { + return &CD == &R.CD && Next == R.Next && Ended == R.Ended; + } + + const LineCoverageStats &operator*() const { return Stats; } + + LineCoverageIterator &operator++(); + + LineCoverageIterator getEnd() const { + auto EndIt = *this; + EndIt.Next = CD.end(); + EndIt.Ended = true; + return EndIt; + } + +private: + const CoverageData &CD; + const CoverageSegment *WrappedSegment; + std::vector<CoverageSegment>::const_iterator Next; + bool Ended; + unsigned Line; + SmallVector<const CoverageSegment *, 4> Segments; + LineCoverageStats Stats; +}; + +/// Get a \c LineCoverageIterator range for the lines described by \p CD. +static inline iterator_range<LineCoverageIterator> +getLineCoverageStats(const coverage::CoverageData &CD) { + auto Begin = LineCoverageIterator(CD); + auto End = Begin.getEnd(); + return make_range(Begin, End); +} + +// Coverage mappping data (V2) has the following layout: +// IPSK_covmap: +// [CoverageMapFileHeader] +// [ArrayStart] +// [CovMapFunctionRecordV2] +// [CovMapFunctionRecordV2] +// ... +// [ArrayEnd] +// [Encoded Filenames and Region Mapping Data] +// +// Coverage mappping data (V3) has the following layout: +// IPSK_covmap: +// [CoverageMapFileHeader] +// [Encoded Filenames] +// IPSK_covfun: +// [ArrayStart] +// odr_name_1: [CovMapFunctionRecordV3] +// odr_name_2: [CovMapFunctionRecordV3] +// ... +// [ArrayEnd] +// +// Both versions of the coverage mapping format encode the same information, +// but the V3 format does so more compactly by taking advantage of linkonce_odr +// semantics (it allows exactly 1 function record per name reference). + +/// This namespace defines accessors shared by different versions of coverage +/// mapping records. +namespace accessors { + +/// Return the structural hash associated with the function. +template <class FuncRecordTy, support::endianness Endian> +uint64_t getFuncHash(const FuncRecordTy *Record) { + return support::endian::byte_swap<uint64_t, Endian>(Record->FuncHash); +} + +/// Return the coverage map data size for the function. +template <class FuncRecordTy, support::endianness Endian> +uint64_t getDataSize(const FuncRecordTy *Record) { + return support::endian::byte_swap<uint32_t, Endian>(Record->DataSize); +} + +/// Return the function lookup key. The value is considered opaque. +template <class FuncRecordTy, support::endianness Endian> +uint64_t getFuncNameRef(const FuncRecordTy *Record) { + return support::endian::byte_swap<uint64_t, Endian>(Record->NameRef); +} + +/// Return the PGO name of the function. Used for formats in which the name is +/// a hash. +template <class FuncRecordTy, support::endianness Endian> +Error getFuncNameViaRef(const FuncRecordTy *Record, + InstrProfSymtab &ProfileNames, StringRef &FuncName) { + uint64_t NameRef = getFuncNameRef<FuncRecordTy, Endian>(Record); + FuncName = ProfileNames.getFuncName(NameRef); + return Error::success(); +} + +/// Read coverage mapping out-of-line, from \p MappingBuf. This is used when the +/// coverage mapping is attached to the file header, instead of to the function +/// record. +template <class FuncRecordTy, support::endianness Endian> +StringRef getCoverageMappingOutOfLine(const FuncRecordTy *Record, + const char *MappingBuf) { + return {MappingBuf, size_t(getDataSize<FuncRecordTy, Endian>(Record))}; +} + +/// Advance to the next out-of-line coverage mapping and its associated +/// function record. +template <class FuncRecordTy, support::endianness Endian> +std::pair<const char *, const FuncRecordTy *> +advanceByOneOutOfLine(const FuncRecordTy *Record, const char *MappingBuf) { + return {MappingBuf + getDataSize<FuncRecordTy, Endian>(Record), Record + 1}; +} + +} // end namespace accessors + +LLVM_PACKED_START +template <class IntPtrT> +struct CovMapFunctionRecordV1 { + using ThisT = CovMapFunctionRecordV1<IntPtrT>; + +#define COVMAP_V1 +#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; +#include "llvm/ProfileData/InstrProfData.inc" +#undef COVMAP_V1 + CovMapFunctionRecordV1() = delete; + + template <support::endianness Endian> uint64_t getFuncHash() const { + return accessors::getFuncHash<ThisT, Endian>(this); + } + + template <support::endianness Endian> uint64_t getDataSize() const { + return accessors::getDataSize<ThisT, Endian>(this); + } + + /// Return function lookup key. The value is consider opaque. + template <support::endianness Endian> IntPtrT getFuncNameRef() const { + return support::endian::byte_swap<IntPtrT, Endian>(NamePtr); + } + + /// Return the PGO name of the function. + template <support::endianness Endian> + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { + IntPtrT NameRef = getFuncNameRef<Endian>(); + uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize); + FuncName = ProfileNames.getFuncName(NameRef, NameS); + if (NameS && FuncName.empty()) + return make_error<CoverageMapError>(coveragemap_error::malformed); + return Error::success(); + } + + template <support::endianness Endian> + std::pair<const char *, const ThisT *> + advanceByOne(const char *MappingBuf) const { + return accessors::advanceByOneOutOfLine<ThisT, Endian>(this, MappingBuf); + } + + template <support::endianness Endian> uint64_t getFilenamesRef() const { + llvm_unreachable("V1 function format does not contain a filenames ref"); + } + + template <support::endianness Endian> + StringRef getCoverageMapping(const char *MappingBuf) const { + return accessors::getCoverageMappingOutOfLine<ThisT, Endian>(this, + MappingBuf); + } +}; + +struct CovMapFunctionRecordV2 { + using ThisT = CovMapFunctionRecordV2; + +#define COVMAP_V2 +#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; +#include "llvm/ProfileData/InstrProfData.inc" +#undef COVMAP_V2 + CovMapFunctionRecordV2() = delete; + + template <support::endianness Endian> uint64_t getFuncHash() const { + return accessors::getFuncHash<ThisT, Endian>(this); + } + + template <support::endianness Endian> uint64_t getDataSize() const { + return accessors::getDataSize<ThisT, Endian>(this); + } + + template <support::endianness Endian> uint64_t getFuncNameRef() const { + return accessors::getFuncNameRef<ThisT, Endian>(this); + } + + template <support::endianness Endian> + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { + return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames, + FuncName); + } + + template <support::endianness Endian> + std::pair<const char *, const ThisT *> + advanceByOne(const char *MappingBuf) const { + return accessors::advanceByOneOutOfLine<ThisT, Endian>(this, MappingBuf); + } + + template <support::endianness Endian> uint64_t getFilenamesRef() const { + llvm_unreachable("V2 function format does not contain a filenames ref"); + } + + template <support::endianness Endian> + StringRef getCoverageMapping(const char *MappingBuf) const { + return accessors::getCoverageMappingOutOfLine<ThisT, Endian>(this, + MappingBuf); + } +}; + +struct CovMapFunctionRecordV3 { + using ThisT = CovMapFunctionRecordV3; + +#define COVMAP_V3 +#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; +#include "llvm/ProfileData/InstrProfData.inc" +#undef COVMAP_V3 + CovMapFunctionRecordV3() = delete; + + template <support::endianness Endian> uint64_t getFuncHash() const { + return accessors::getFuncHash<ThisT, Endian>(this); + } + + template <support::endianness Endian> uint64_t getDataSize() const { + return accessors::getDataSize<ThisT, Endian>(this); + } + + template <support::endianness Endian> uint64_t getFuncNameRef() const { + return accessors::getFuncNameRef<ThisT, Endian>(this); + } + + template <support::endianness Endian> + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { + return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames, + FuncName); + } + + /// Get the filename set reference. + template <support::endianness Endian> uint64_t getFilenamesRef() const { + return support::endian::byte_swap<uint64_t, Endian>(FilenamesRef); + } + + /// Read the inline coverage mapping. Ignore the buffer parameter, it is for + /// out-of-line coverage mapping data only. + template <support::endianness Endian> + StringRef getCoverageMapping(const char *) const { + return StringRef(&CoverageMapping, getDataSize<Endian>()); + } + + // Advance to the next inline coverage mapping and its associated function + // record. Ignore the out-of-line coverage mapping buffer. + template <support::endianness Endian> + std::pair<const char *, const CovMapFunctionRecordV3 *> + advanceByOne(const char *) const { + assert(isAddrAligned(Align(8), this) && "Function record not aligned"); + const char *Next = ((const char *)this) + sizeof(CovMapFunctionRecordV3) - + sizeof(char) + getDataSize<Endian>(); + // Each function record has an alignment of 8, so we need to adjust + // alignment before reading the next record. + Next += offsetToAlignedAddr(Next, Align(8)); + return {nullptr, reinterpret_cast<const CovMapFunctionRecordV3 *>(Next)}; + } +}; + +// Per module coverage mapping data header, i.e. CoverageMapFileHeader +// documented above. +struct CovMapHeader { +#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name; +#include "llvm/ProfileData/InstrProfData.inc" + template <support::endianness Endian> uint32_t getNRecords() const { + return support::endian::byte_swap<uint32_t, Endian>(NRecords); + } + + template <support::endianness Endian> uint32_t getFilenamesSize() const { + return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize); + } + + template <support::endianness Endian> uint32_t getCoverageSize() const { + return support::endian::byte_swap<uint32_t, Endian>(CoverageSize); + } + + template <support::endianness Endian> uint32_t getVersion() const { + return support::endian::byte_swap<uint32_t, Endian>(Version); + } +}; + +LLVM_PACKED_END + +enum CovMapVersion { + Version1 = 0, + // Function's name reference from CovMapFuncRecord is changed from raw + // name string pointer to MD5 to support name section compression. Name + // section is also compressed. + Version2 = 1, + // A new interpretation of the columnEnd field is added in order to mark + // regions as gap areas. + Version3 = 2, + // Function records are named, uniqued, and moved to a dedicated section. + Version4 = 3, + // Branch regions referring to two counters are added + Version5 = 4, + // Compilation directory is stored separately and combined with relative + // filenames to produce an absolute file path. + Version6 = 5, + // The current version is Version6. + CurrentVersion = INSTR_PROF_COVMAP_VERSION +}; + +template <int CovMapVersion, class IntPtrT> struct CovMapTraits { + using CovMapFuncRecordType = CovMapFunctionRecordV3; + using NameRefType = uint64_t; +}; + +template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version3, IntPtrT> { + using CovMapFuncRecordType = CovMapFunctionRecordV2; + using NameRefType = uint64_t; +}; + +template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version2, IntPtrT> { + using CovMapFuncRecordType = CovMapFunctionRecordV2; + using NameRefType = uint64_t; +}; + +template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version1, IntPtrT> { + using CovMapFuncRecordType = CovMapFunctionRecordV1<IntPtrT>; + using NameRefType = IntPtrT; +}; + +} // end namespace coverage + +/// Provide DenseMapInfo for CounterExpression +template<> struct DenseMapInfo<coverage::CounterExpression> { + static inline coverage::CounterExpression getEmptyKey() { + using namespace coverage; + + return CounterExpression(CounterExpression::ExprKind::Subtract, + Counter::getCounter(~0U), + Counter::getCounter(~0U)); + } + + static inline coverage::CounterExpression getTombstoneKey() { + using namespace coverage; + + return CounterExpression(CounterExpression::ExprKind::Add, + Counter::getCounter(~0U), + Counter::getCounter(~0U)); + } + + static unsigned getHashValue(const coverage::CounterExpression &V) { + return static_cast<unsigned>( + hash_combine(V.Kind, V.LHS.getKind(), V.LHS.getCounterID(), + V.RHS.getKind(), V.RHS.getCounterID())); + } + + static bool isEqual(const coverage::CounterExpression &LHS, + const coverage::CounterExpression &RHS) { + return LHS.Kind == RHS.Kind && LHS.LHS == RHS.LHS && LHS.RHS == RHS.RHS; + } +}; + +} // end namespace llvm + +#endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |
