X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FProfileData%2FCoverageMapping.h;h=61aad3b3bc3dbf0fa072577319368201580d57e1;hb=a378f917aff9d43c75b22415567a1d9dc6e4914f;hp=428b5d1328a32ae94b9d5260bf2841dc3fb5bb45;hpb=74a60259a595b8e5804dd0bf29fc9b2b84de3049;p=oota-llvm.git diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/CoverageMapping.h index 428b5d1328a..61aad3b3bc3 100644 --- a/include/llvm/ProfileData/CoverageMapping.h +++ b/include/llvm/ProfileData/CoverageMapping.h @@ -16,13 +16,21 @@ #define LLVM_PROFILEDATA_COVERAGEMAPPING_H_ #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/raw_ostream.h" #include namespace llvm { +class IndexedInstrProfReader; namespace coverage { +class ObjectFileCoverageMappingReader; + +class CoverageMapping; struct CounterExpressions; enum CoverageMappingVersion { CoverageMappingVersion1 }; @@ -55,8 +63,16 @@ public: unsigned getExpressionID() const { return ID; } - bool operator==(const Counter &Other) const { - return Kind == Other.Kind && ID == Other.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); } /// \brief Return the counter that represents the number zero. @@ -83,10 +99,6 @@ struct CounterExpression { CounterExpression(ExprKind Kind, Counter LHS, Counter RHS) : Kind(Kind), LHS(LHS), RHS(RHS) {} - - bool operator==(const CounterExpression &Other) const { - return Kind == Other.Kind && LHS == Other.LHS && RHS == Other.RHS; - } }; /// \brief A Counter expression builder is used to construct the @@ -94,9 +106,9 @@ struct CounterExpression { /// and simplifies algebraic expressions. class CounterExpressionBuilder { /// \brief A list of all the counter expressions - llvm::SmallVector Expressions; - /// \brief An array of terms used in expression simplification. - llvm::SmallVector Terms; + std::vector Expressions; + /// \brief A lookup table for the index of a given expression. + llvm::DenseMap ExpressionIndices; /// \brief Return the counter which corresponds to the given expression. /// @@ -105,18 +117,19 @@ class CounterExpressionBuilder { /// expression is added to the builder's collection of expressions. Counter get(const CounterExpression &E); - /// \brief Convert the expression tree represented by a counter - /// into a polynomial in the form of K1Counter1 + .. + KNCounterN - /// where K1 .. KN are integer constants that are stored in the Terms array. - void extractTerms(Counter C, int Sign = 1); + /// \brief 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> &Terms); /// \brief Simplifies the given expression tree /// by getting rid of algebraically redundant operations. Counter simplify(Counter ExpressionTree); public: - CounterExpressionBuilder(unsigned NumCounterValues); - ArrayRef getExpressions() const { return Expressions; } /// \brief Return a counter that represents the expression @@ -145,31 +158,40 @@ struct CounterMappingRegion { SkippedRegion }; - static const unsigned EncodingHasCodeBeforeBits = 1; - Counter Count; unsigned FileID, ExpandedFileID; unsigned LineStart, ColumnStart, LineEnd, ColumnEnd; RegionKind Kind; - /// \brief A flag that is set to true when there is already code before - /// this region on the same line. - /// This is useful to accurately compute the execution counts for a line. - bool HasCodeBefore; CounterMappingRegion(Counter Count, unsigned FileID, unsigned LineStart, unsigned ColumnStart, unsigned LineEnd, - unsigned ColumnEnd, bool HasCodeBefore = false, - RegionKind Kind = CodeRegion) + unsigned ColumnEnd, RegionKind Kind = CodeRegion) : Count(Count), FileID(FileID), ExpandedFileID(0), LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd), - Kind(Kind), HasCodeBefore(HasCodeBefore) {} + Kind(Kind) {} + + inline std::pair startLoc() const { + return std::pair(LineStart, ColumnStart); + } + + inline std::pair endLoc() const { + return std::pair(LineEnd, ColumnEnd); + } bool operator<(const CounterMappingRegion &Other) const { if (FileID != Other.FileID) return FileID < Other.FileID; - if (LineStart == Other.LineStart) - return ColumnStart < Other.ColumnStart; - return LineStart < Other.LineStart; + return startLoc() < Other.startLoc(); + } + + bool contains(const CounterMappingRegion &Other) const { + if (FileID != Other.FileID) + return false; + if (startLoc() > Other.startLoc()) + return false; + if (endLoc() < Other.endLoc()) + return false; + return true; } }; @@ -193,14 +215,232 @@ public: : Expressions(Expressions), CounterValues(CounterValues) {} void dump(const Counter &C, llvm::raw_ostream &OS) const; - void dump(const Counter &C) const { dump(C, llvm::outs()); } + void dump(const Counter &C) const { dump(C, dbgs()); } /// \brief Return the number of times that a region of code associated with /// this counter was executed. ErrorOr evaluate(const Counter &C) const; }; +/// \brief Code coverage information for a single function. +struct FunctionRecord { + /// \brief Raw function name. + std::string Name; + /// \brief Associated files. + std::vector Filenames; + /// \brief Regions in the function along with their counts. + std::vector CountedRegions; + /// \brief The number of times this function was executed. + uint64_t ExecutionCount; + + FunctionRecord(StringRef Name, ArrayRef Filenames, + uint64_t ExecutionCount) + : Name(Name), Filenames(Filenames.begin(), Filenames.end()), + ExecutionCount(ExecutionCount) {} +}; + +/// \brief Iterator over Functions, optionally filtered to a single file. +class FunctionRecordIterator + : public iterator_facade_base { + ArrayRef Records; + ArrayRef::iterator Current; + StringRef Filename; + + /// \brief Skip records whose primary file is not \c Filename. + void skipOtherFiles(); + +public: + FunctionRecordIterator(ArrayRef 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; + } +}; + +/// \brief 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 { + /// \brief The abstract file this expansion covers. + unsigned FileID; + /// \brief The region that expands to this record. + const CountedRegion &Region; + /// \brief Coverage for the expansion. + const FunctionRecord &Function; + + ExpansionRecord(const CountedRegion &Region, + const FunctionRecord &Function) + : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {} +}; + +/// \brief 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 { + /// \brief The line where this segment begins. + unsigned Line; + /// \brief The column where this segment begins. + unsigned Col; + /// \brief The execution count, or zero if no count was recorded. + uint64_t Count; + /// \brief When false, the segment was uninstrumented or skipped. + bool HasCount; + /// \brief Whether this enters a new region or returns to a previous count. + bool IsRegionEntry; + + CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry) + : Line(Line), Col(Col), Count(0), HasCount(false), + IsRegionEntry(IsRegionEntry) {} + void setCount(uint64_t NewCount) { + Count = NewCount; + HasCount = true; + } + void addCount(uint64_t NewCount) { setCount(Count + NewCount); } +}; + +/// \brief 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 { + std::string Filename; + std::vector Segments; + std::vector Expansions; + friend class CoverageMapping; + +public: + CoverageData() {} + + CoverageData(StringRef Filename) : Filename(Filename) {} + + CoverageData(CoverageData &&RHS) + : Filename(std::move(RHS.Filename)), Segments(std::move(RHS.Segments)), + Expansions(std::move(RHS.Expansions)) {} + + /// \brief Get the name of the file this data covers. + StringRef getFilename() { return Filename; } + + std::vector::iterator begin() { return Segments.begin(); } + std::vector::iterator end() { return Segments.end(); } + bool empty() { return Segments.empty(); } + + /// \brief Expansions that can be further processed. + std::vector getExpansions() { return Expansions; } +}; + +/// \brief 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 { + std::vector Functions; + unsigned MismatchedFunctionCount; + + CoverageMapping() : MismatchedFunctionCount(0) {} + +public: + /// \brief Load the coverage mapping using the given readers. + static ErrorOr> + load(ObjectFileCoverageMappingReader &CoverageReader, + IndexedInstrProfReader &ProfileReader); + + /// \brief Load the coverage mapping from the given files. + static ErrorOr> + load(StringRef ObjectFilename, StringRef ProfileFilename); + + /// \brief 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() { return MismatchedFunctionCount; } + + /// \brief Returns the list of files that are covered. + std::vector getUniqueSourceFiles() const; + + /// \brief 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); + + /// \brief Gets all of the functions covered by this profile. + iterator_range getCoveredFunctions() const { + return make_range(FunctionRecordIterator(Functions), + FunctionRecordIterator()); + } + + /// \brief Gets all of the functions in a particular file. + iterator_range + getCoveredFunctions(StringRef Filename) const { + return make_range(FunctionRecordIterator(Functions, Filename), + FunctionRecordIterator()); + } + + /// \brief Get the list of function instantiations in the file. + /// + /// Fucntions that are instantiated more than once, such as C++ template + /// specializations, have distinct coverage records for each instantiation. + std::vector getInstantiations(StringRef Filename); + + /// \brief Get the coverage for a particular function. + CoverageData getCoverageForFunction(const FunctionRecord &Function); + + /// \brief Get the coverage for an expansion within a coverage set. + CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion); +}; + } // end namespace coverage + +/// \brief Provide DenseMapInfo for CounterExpression +template<> struct DenseMapInfo { + 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( + 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_COVERAGEMAPPING_H_