aboutsummaryrefslogtreecommitdiffstats
path: root/include/llvm/ProfileData
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-12-01 14:51:49 -0800
committerStephen Hines <srhines@google.com>2014-12-02 16:08:10 -0800
commit37ed9c199ca639565f6ce88105f9e39e898d82d0 (patch)
tree8fb36d3910e3ee4c4e1b7422f4f017108efc52f5 /include/llvm/ProfileData
parentd2327b22152ced7bc46dc629fc908959e8a52d03 (diff)
downloadexternal_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.zip
external_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.tar.gz
external_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.tar.bz2
Update aosp/master LLVM for rebase to r222494.
Change-Id: Ic787f5e0124df789bd26f3f24680f45e678eef2d
Diffstat (limited to 'include/llvm/ProfileData')
-rw-r--r--include/llvm/ProfileData/CoverageMapping.h448
-rw-r--r--include/llvm/ProfileData/CoverageMappingReader.h209
-rw-r--r--include/llvm/ProfileData/CoverageMappingWriter.h63
-rw-r--r--include/llvm/ProfileData/InstrProfReader.h59
-rw-r--r--include/llvm/ProfileData/InstrProfWriter.h15
-rw-r--r--include/llvm/ProfileData/SampleProf.h248
-rw-r--r--include/llvm/ProfileData/SampleProfReader.h170
-rw-r--r--include/llvm/ProfileData/SampleProfWriter.h110
8 files changed, 1287 insertions, 35 deletions
diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/CoverageMapping.h
new file mode 100644
index 0000000..38fc8ca
--- /dev/null
+++ b/include/llvm/ProfileData/CoverageMapping.h
@@ -0,0 +1,448 @@
+//=-- CoverageMapping.h - Code coverage mapping support ---------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Code coverage mapping data is generated by clang and read by
+// llvm-cov to show code coverage statistics for a file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_H_
+#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/ErrorOr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+namespace llvm {
+class IndexedInstrProfReader;
+namespace coverage {
+
+class ObjectFileCoverageMappingReader;
+
+class CoverageMapping;
+struct CounterExpressions;
+
+enum CoverageMappingVersion { CoverageMappingVersion1 };
+
+/// \brief 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 {
+ enum CounterKind { Zero, CounterValueReference, Expression };
+ static const unsigned EncodingTagBits = 2;
+ static const unsigned EncodingTagMask = 0x3;
+ static const unsigned EncodingCounterTagAndExpansionRegionTagBits =
+ EncodingTagBits + 1;
+
+private:
+ CounterKind Kind;
+ unsigned ID;
+
+ Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {}
+
+public:
+ Counter() : Kind(Zero), ID(0) {}
+
+ 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; }
+
+ bool operator==(const Counter &Other) const {
+ return Kind == Other.Kind && ID == Other.ID;
+ }
+
+ 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.
+ static Counter getZero() { return Counter(); }
+
+ /// \brief Return the counter that corresponds to a specific profile counter.
+ static Counter getCounter(unsigned CounterId) {
+ return Counter(CounterValueReference, CounterId);
+ }
+
+ /// \brief Return the counter that corresponds to a specific
+ /// addition counter expression.
+ static Counter getExpression(unsigned ExpressionId) {
+ return Counter(Expression, ExpressionId);
+ }
+};
+
+/// \brief 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) {}
+};
+
+/// \brief A Counter expression builder is used to construct the
+/// counter expressions. It avoids unecessary duplication
+/// and simplifies algebraic expressions.
+class CounterExpressionBuilder {
+ /// \brief A list of all the counter expressions
+ std::vector<CounterExpression> Expressions;
+ /// \brief A lookup table for the index of a given expression.
+ llvm::DenseMap<CounterExpression, unsigned> ExpressionIndices;
+
+ /// \brief 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);
+
+ /// \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<std::pair<unsigned, int>> &Terms);
+
+ /// \brief Simplifies the given expression tree
+ /// by getting rid of algebraically redundant operations.
+ Counter simplify(Counter ExpressionTree);
+
+public:
+ ArrayRef<CounterExpression> getExpressions() const { return Expressions; }
+
+ /// \brief Return a counter that represents the expression
+ /// that adds LHS and RHS.
+ Counter add(Counter LHS, Counter RHS);
+
+ /// \brief Return a counter that represents the expression
+ /// that subtracts RHS from LHS.
+ Counter subtract(Counter LHS, Counter RHS);
+};
+
+/// \brief A Counter mapping region associates a source range with
+/// a specific counter.
+struct CounterMappingRegion {
+ enum RegionKind {
+ /// \brief A CodeRegion associates some code with a counter
+ CodeRegion,
+
+ /// \brief 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,
+
+ /// \brief A SkippedRegion represents a source range with code that
+ /// was skipped by a preprocessor or similar means.
+ 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)
+ : Count(Count), FileID(FileID), ExpandedFileID(0), LineStart(LineStart),
+ ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
+ Kind(Kind), HasCodeBefore(HasCodeBefore) {}
+
+ inline std::pair<unsigned, unsigned> startLoc() const {
+ return std::pair<unsigned, unsigned>(LineStart, ColumnStart);
+ }
+
+ inline std::pair<unsigned, unsigned> endLoc() const {
+ return std::pair<unsigned, unsigned>(LineEnd, ColumnEnd);
+ }
+
+ bool operator<(const CounterMappingRegion &Other) const {
+ if (FileID != Other.FileID)
+ return FileID < Other.FileID;
+ 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;
+ }
+};
+
+/// \brief Associates a source range with an execution count.
+struct CountedRegion : public CounterMappingRegion {
+ uint64_t ExecutionCount;
+
+ CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
+ : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {}
+};
+
+/// \brief 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 = ArrayRef<uint64_t>())
+ : Expressions(Expressions), CounterValues(CounterValues) {}
+
+ void dump(const Counter &C, llvm::raw_ostream &OS) const;
+ void dump(const Counter &C) const { dump(C, llvm::outs()); }
+
+ /// \brief Return the number of times that a region of code associated with
+ /// this counter was executed.
+ ErrorOr<int64_t> 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<std::string> Filenames;
+ /// \brief Regions in the function along with their counts.
+ std::vector<CountedRegion> CountedRegions;
+ /// \brief The number of times this function was executed.
+ uint64_t ExecutionCount;
+
+ FunctionRecord(StringRef Name, ArrayRef<StringRef> 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<FunctionRecordIterator,
+ std::forward_iterator_tag, FunctionRecord> {
+ ArrayRef<FunctionRecord> Records;
+ ArrayRef<FunctionRecord>::iterator Current;
+ StringRef Filename;
+
+ /// \brief 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;
+ }
+};
+
+/// \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<CoverageSegment> Segments;
+ std::vector<ExpansionRecord> 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<CoverageSegment>::iterator begin() { return Segments.begin(); }
+ std::vector<CoverageSegment>::iterator end() { return Segments.end(); }
+ bool empty() { return Segments.empty(); }
+
+ /// \brief Expansions that can be further processed.
+ std::vector<ExpansionRecord> 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<FunctionRecord> Functions;
+ unsigned MismatchedFunctionCount;
+
+ CoverageMapping() : MismatchedFunctionCount(0) {}
+
+public:
+ /// \brief Load the coverage mapping using the given readers.
+ static ErrorOr<std::unique_ptr<CoverageMapping>>
+ load(ObjectFileCoverageMappingReader &CoverageReader,
+ IndexedInstrProfReader &ProfileReader);
+
+ /// \brief Load the coverage mapping from the given files.
+ static ErrorOr<std::unique_ptr<CoverageMapping>>
+ 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<StringRef> 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<FunctionRecordIterator> getCoveredFunctions() const {
+ return make_range(FunctionRecordIterator(Functions),
+ FunctionRecordIterator());
+ }
+
+ /// \brief Gets all of the functions in a particular file.
+ iterator_range<FunctionRecordIterator>
+ 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<const FunctionRecord *> 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<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_COVERAGEMAPPING_H_
diff --git a/include/llvm/ProfileData/CoverageMappingReader.h b/include/llvm/ProfileData/CoverageMappingReader.h
new file mode 100644
index 0000000..73b0248
--- /dev/null
+++ b/include/llvm/ProfileData/CoverageMappingReader.h
@@ -0,0 +1,209 @@
+//=-- CoverageMappingReader.h - Code coverage mapping reader ------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for reading coverage mapping data for
+// instrumentation based coverage.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PROFILEDATA_COVERAGEMAPPINGREADER_H
+#define LLVM_PROFILEDATA_COVERAGEMAPPINGREADER_H
+
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/FileSystem.h"
+
+#include <iterator>
+
+namespace llvm {
+namespace coverage {
+
+class ObjectFileCoverageMappingReader;
+
+/// \brief Coverage mapping information for a single function.
+struct CoverageMappingRecord {
+ StringRef FunctionName;
+ uint64_t FunctionHash;
+ ArrayRef<StringRef> Filenames;
+ ArrayRef<CounterExpression> Expressions;
+ ArrayRef<CounterMappingRegion> MappingRegions;
+};
+
+/// \brief A file format agnostic iterator over coverage mapping data.
+class CoverageMappingIterator
+ : public std::iterator<std::input_iterator_tag, CoverageMappingRecord> {
+ ObjectFileCoverageMappingReader *Reader;
+ CoverageMappingRecord Record;
+
+ void increment();
+
+public:
+ CoverageMappingIterator() : Reader(nullptr) {}
+ CoverageMappingIterator(ObjectFileCoverageMappingReader *Reader)
+ : Reader(Reader) {
+ increment();
+ }
+
+ CoverageMappingIterator &operator++() {
+ increment();
+ return *this;
+ }
+ bool operator==(const CoverageMappingIterator &RHS) {
+ return Reader == RHS.Reader;
+ }
+ bool operator!=(const CoverageMappingIterator &RHS) {
+ return Reader != RHS.Reader;
+ }
+ CoverageMappingRecord &operator*() { return Record; }
+ CoverageMappingRecord *operator->() { return &Record; }
+};
+
+/// \brief Base class for the raw coverage mapping and filenames data readers.
+class RawCoverageReader {
+protected:
+ StringRef Data;
+
+ /// \brief Return the error code.
+ std::error_code error(std::error_code EC) { return EC; }
+
+ /// \brief Clear the current error code and return a successful one.
+ std::error_code success() { return error(instrprof_error::success); }
+
+ RawCoverageReader(StringRef Data) : Data(Data) {}
+
+ std::error_code readULEB128(uint64_t &Result);
+ std::error_code readIntMax(uint64_t &Result, uint64_t MaxPlus1);
+ std::error_code readSize(uint64_t &Result);
+ std::error_code readString(StringRef &Result);
+};
+
+/// \brief Reader for the raw coverage filenames.
+class RawCoverageFilenamesReader : public RawCoverageReader {
+ std::vector<StringRef> &Filenames;
+
+ RawCoverageFilenamesReader(const RawCoverageFilenamesReader &)
+ LLVM_DELETED_FUNCTION;
+ RawCoverageFilenamesReader &
+ operator=(const RawCoverageFilenamesReader &) LLVM_DELETED_FUNCTION;
+
+public:
+ RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames)
+ : RawCoverageReader(Data), Filenames(Filenames) {}
+
+ std::error_code read();
+};
+
+/// \brief Reader for the raw coverage mapping data.
+class RawCoverageMappingReader : public RawCoverageReader {
+ StringRef FunctionName;
+ ArrayRef<StringRef> TranslationUnitFilenames;
+ std::vector<StringRef> &Filenames;
+ std::vector<CounterExpression> &Expressions;
+ std::vector<CounterMappingRegion> &MappingRegions;
+
+ RawCoverageMappingReader(const RawCoverageMappingReader &)
+ LLVM_DELETED_FUNCTION;
+ RawCoverageMappingReader &
+ operator=(const RawCoverageMappingReader &) LLVM_DELETED_FUNCTION;
+
+public:
+ RawCoverageMappingReader(StringRef FunctionName, StringRef MappingData,
+ ArrayRef<StringRef> TranslationUnitFilenames,
+ std::vector<StringRef> &Filenames,
+ std::vector<CounterExpression> &Expressions,
+ std::vector<CounterMappingRegion> &MappingRegions)
+ : RawCoverageReader(MappingData), FunctionName(FunctionName),
+ TranslationUnitFilenames(TranslationUnitFilenames),
+ Filenames(Filenames), Expressions(Expressions),
+ MappingRegions(MappingRegions) {}
+
+ std::error_code read(CoverageMappingRecord &Record);
+
+private:
+ std::error_code decodeCounter(unsigned Value, Counter &C);
+ std::error_code readCounter(Counter &C);
+ std::error_code
+ readMappingRegionsSubArray(std::vector<CounterMappingRegion> &MappingRegions,
+ unsigned InferredFileID, size_t NumFileIDs);
+};
+
+/// \brief Reader for the coverage mapping data that is emitted by the
+/// frontend and stored in an object file.
+class ObjectFileCoverageMappingReader {
+public:
+ struct ProfileMappingRecord {
+ CoverageMappingVersion Version;
+ StringRef FunctionName;
+ uint64_t FunctionHash;
+ StringRef CoverageMapping;
+ size_t FilenamesBegin;
+ size_t FilenamesSize;
+
+ ProfileMappingRecord(CoverageMappingVersion Version, StringRef FunctionName,
+ uint64_t FunctionHash, StringRef CoverageMapping,
+ size_t FilenamesBegin, size_t FilenamesSize)
+ : Version(Version), FunctionName(FunctionName),
+ FunctionHash(FunctionHash), CoverageMapping(CoverageMapping),
+ FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
+ };
+
+private:
+ std::error_code LastError;
+ object::OwningBinary<object::ObjectFile> Object;
+ std::vector<StringRef> Filenames;
+ std::vector<ProfileMappingRecord> MappingRecords;
+ size_t CurrentRecord;
+ std::vector<StringRef> FunctionsFilenames;
+ std::vector<CounterExpression> Expressions;
+ std::vector<CounterMappingRegion> MappingRegions;
+
+ ObjectFileCoverageMappingReader(const ObjectFileCoverageMappingReader &)
+ LLVM_DELETED_FUNCTION;
+ ObjectFileCoverageMappingReader &
+ operator=(const ObjectFileCoverageMappingReader &) LLVM_DELETED_FUNCTION;
+
+ /// \brief Set the current error_code and return same.
+ std::error_code error(std::error_code EC) {
+ LastError = EC;
+ return EC;
+ }
+
+ /// \brief Clear the current error code and return a successful one.
+ std::error_code success() { return error(instrprof_error::success); }
+
+public:
+ ObjectFileCoverageMappingReader(StringRef FileName);
+ ObjectFileCoverageMappingReader(
+ std::unique_ptr<MemoryBuffer> &ObjectBuffer,
+ sys::fs::file_magic Type = sys::fs::file_magic::unknown);
+
+ std::error_code readHeader();
+ std::error_code readNextRecord(CoverageMappingRecord &Record);
+
+ /// Iterator over profile data.
+ CoverageMappingIterator begin() { return CoverageMappingIterator(this); }
+ CoverageMappingIterator end() { return CoverageMappingIterator(); }
+
+ /// \brief Return true if the reader has finished reading the profile data.
+ bool isEOF() { return LastError == instrprof_error::eof; }
+ /// \brief Return true if the reader encountered an error reading profiling
+ /// data.
+ bool hasError() { return LastError && !isEOF(); }
+ /// \brief Get the current error code.
+ std::error_code getError() { return LastError; }
+};
+
+} // end namespace coverage
+} // end namespace llvm
+
+#endif
diff --git a/include/llvm/ProfileData/CoverageMappingWriter.h b/include/llvm/ProfileData/CoverageMappingWriter.h
new file mode 100644
index 0000000..cf16140
--- /dev/null
+++ b/include/llvm/ProfileData/CoverageMappingWriter.h
@@ -0,0 +1,63 @@
+//=-- CoverageMappingWriter.h - Code coverage mapping writer ------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for writing coverage mapping data for
+// instrumentation based coverage.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PROFILEDATA_COVERAGEMAPPINGWRITER_H
+#define LLVM_PROFILEDATA_COVERAGEMAPPINGWRITER_H
+
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace coverage {
+
+/// \brief Writer of the filenames section for the instrumentation
+/// based code coverage.
+class CoverageFilenamesSectionWriter {
+ ArrayRef<StringRef> Filenames;
+
+public:
+ CoverageFilenamesSectionWriter(ArrayRef<StringRef> Filenames)
+ : Filenames(Filenames) {}
+
+ /// \brief Write encoded filenames to the given output stream.
+ void write(raw_ostream &OS);
+};
+
+/// \brief Writer for instrumentation based coverage mapping data.
+class CoverageMappingWriter {
+ ArrayRef<unsigned> VirtualFileMapping;
+ ArrayRef<CounterExpression> Expressions;
+ MutableArrayRef<CounterMappingRegion> MappingRegions;
+
+public:
+ CoverageMappingWriter(ArrayRef<unsigned> VirtualFileMapping,
+ ArrayRef<CounterExpression> Expressions,
+ MutableArrayRef<CounterMappingRegion> MappingRegions)
+ : VirtualFileMapping(VirtualFileMapping), Expressions(Expressions),
+ MappingRegions(MappingRegions) {}
+
+ CoverageMappingWriter(ArrayRef<CounterExpression> Expressions,
+ MutableArrayRef<CounterMappingRegion> MappingRegions)
+ : Expressions(Expressions), MappingRegions(MappingRegions) {}
+
+ /// \brief Write encoded coverage mapping data to the given output stream.
+ void write(raw_ostream &OS);
+};
+
+} // end namespace coverage
+} // end namespace llvm
+
+#endif
diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h
index 7a5a71d..38c5310 100644
--- a/include/llvm/ProfileData/InstrProfReader.h
+++ b/include/llvm/ProfileData/InstrProfReader.h
@@ -12,12 +12,13 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_PROFILEDATA_INSTRPROF_READER_H_
-#define LLVM_PROFILEDATA_INSTRPROF_READER_H_
+#ifndef LLVM_PROFILEDATA_INSTRPROFREADER_H
+#define LLVM_PROFILEDATA_INSTRPROFREADER_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/EndianStream.h"
@@ -94,8 +95,7 @@ public:
/// Factory method to create an appropriately typed reader for the given
/// instrprof file.
- static std::error_code create(std::string Path,
- std::unique_ptr<InstrProfReader> &Result);
+ static ErrorOr<std::unique_ptr<InstrProfReader>> create(std::string Path);
};
/// Reader for the simple text based instrprof format.
@@ -120,7 +120,7 @@ private:
LLVM_DELETED_FUNCTION;
public:
TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_)
- : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, '#') {}
+ : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {}
/// Read the header.
std::error_code readHeader() override { return success(); }
@@ -206,12 +206,17 @@ enum class HashT : uint32_t;
/// Trait for lookups into the on-disk hash table for the binary instrprof
/// format.
class InstrProfLookupTrait {
- std::vector<uint64_t> CountBuffer;
+ std::vector<uint64_t> DataBuffer;
IndexedInstrProf::HashT HashType;
public:
InstrProfLookupTrait(IndexedInstrProf::HashT HashType) : HashType(HashType) {}
- typedef InstrProfRecord data_type;
+ struct data_type {
+ data_type(StringRef Name, ArrayRef<uint64_t> Data)
+ : Name(Name), Data(Data) {}
+ StringRef Name;
+ ArrayRef<uint64_t> Data;
+ };
typedef StringRef internal_key_type;
typedef StringRef external_key_type;
typedef uint64_t hash_value_type;
@@ -234,25 +239,20 @@ public:
return StringRef((const char *)D, N);
}
- InstrProfRecord ReadData(StringRef K, const unsigned char *D, offset_type N) {
- if (N < 2 * sizeof(uint64_t) || N % sizeof(uint64_t)) {
+ data_type ReadData(StringRef K, const unsigned char *D, offset_type N) {
+ DataBuffer.clear();
+ if (N % sizeof(uint64_t))
// The data is corrupt, don't try to read it.
- CountBuffer.clear();
- return InstrProfRecord("", 0, CountBuffer);
- }
+ return data_type("", DataBuffer);
using namespace support;
-
- // The first stored value is the hash.
- uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
- // Each counter follows.
- unsigned NumCounters = N / sizeof(uint64_t) - 1;
- CountBuffer.clear();
- CountBuffer.reserve(NumCounters - 1);
- for (unsigned I = 0; I < NumCounters; ++I)
- CountBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
-
- return InstrProfRecord(K, Hash, CountBuffer);
+ // We just treat the data as opaque here. It's simpler to handle in
+ // IndexedInstrProfReader.
+ unsigned NumEntries = N / sizeof(uint64_t);
+ DataBuffer.reserve(NumEntries);
+ for (unsigned I = 0; I < NumEntries; ++I)
+ DataBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
+ return data_type(K, DataBuffer);
}
};
typedef OnDiskIterableChainedHashTable<InstrProfLookupTrait>
@@ -267,7 +267,11 @@ private:
std::unique_ptr<InstrProfReaderIndex> Index;
/// Iterator over the profile data.
InstrProfReaderIndex::data_iterator RecordIterator;
- /// The maximal execution count among all fucntions.
+ /// Offset into our current data set.
+ size_t CurrentOffset;
+ /// The file format version of the profile data.
+ uint64_t FormatVersion;
+ /// The maximal execution count among all functions.
uint64_t MaxFunctionCount;
IndexedInstrProfReader(const IndexedInstrProfReader &) LLVM_DELETED_FUNCTION;
@@ -275,8 +279,7 @@ private:
LLVM_DELETED_FUNCTION;
public:
IndexedInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
- : DataBuffer(std::move(DataBuffer)), Index(nullptr),
- RecordIterator(InstrProfReaderIndex::data_iterator()) {}
+ : DataBuffer(std::move(DataBuffer)), Index(nullptr), CurrentOffset(0) {}
/// Return true if the given buffer is in an indexed instrprof format.
static bool hasFormat(const MemoryBuffer &DataBuffer);
@@ -287,7 +290,7 @@ public:
std::error_code readNextRecord(InstrProfRecord &Record) override;
/// Fill Counts with the profile data for the given function name.
- std::error_code getFunctionCounts(StringRef FuncName, uint64_t &FuncHash,
+ std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
std::vector<uint64_t> &Counts);
/// Return the maximum of all known function counts.
uint64_t getMaximumFunctionCount() { return MaxFunctionCount; }
@@ -299,4 +302,4 @@ public:
} // end namespace llvm
-#endif // LLVM_PROFILEDATA_INSTRPROF_READER_H_
+#endif
diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h
index 6e68bee..e76f668 100644
--- a/include/llvm/ProfileData/InstrProfWriter.h
+++ b/include/llvm/ProfileData/InstrProfWriter.h
@@ -12,10 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_PROFILEDATA_INSTRPROF_WRITER_H_
-#define LLVM_PROFILEDATA_INSTRPROF_WRITER_H_
+#ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H
+#define LLVM_PROFILEDATA_INSTRPROFWRITER_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/DataTypes.h"
@@ -28,13 +29,13 @@ namespace llvm {
/// Writer for instrumentation based profile data.
class InstrProfWriter {
public:
- struct CounterData {
- uint64_t Hash;
- std::vector<uint64_t> Counts;
- };
+ typedef SmallDenseMap<uint64_t, std::vector<uint64_t>, 1> CounterData;
private:
StringMap<CounterData> FunctionData;
+ uint64_t MaxFunctionCount;
public:
+ InstrProfWriter() : MaxFunctionCount(0) {}
+
/// Add function counts for the given function. If there are already counts
/// for this function and the hash and number of counts match, each counter is
/// summed.
@@ -47,4 +48,4 @@ public:
} // end namespace llvm
-#endif // LLVM_PROFILE_INSTRPROF_WRITER_H_
+#endif
diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h
new file mode 100644
index 0000000..5c70b31
--- /dev/null
+++ b/include/llvm/ProfileData/SampleProf.h
@@ -0,0 +1,248 @@
+//=-- SampleProf.h - Sampling profiling format support --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains common definitions used in the reading and writing of
+// sample profile data.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H_
+#define LLVM_PROFILEDATA_SAMPLEPROF_H_
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <system_error>
+
+namespace llvm {
+
+const std::error_category &sampleprof_category();
+
+enum class sampleprof_error {
+ success = 0,
+ bad_magic,
+ unsupported_version,
+ too_large,
+ truncated,
+ malformed,
+ unrecognized_format
+};
+
+inline std::error_code make_error_code(sampleprof_error E) {
+ return std::error_code(static_cast<int>(E), sampleprof_category());
+}
+
+} // end namespace llvm
+
+namespace std {
+template <>
+struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
+}
+
+namespace llvm {
+
+namespace sampleprof {
+
+static inline uint64_t SPMagic() {
+ return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) |
+ uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) |
+ uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) |
+ uint64_t('2') << (64 - 56) | uint64_t(0xff);
+}
+
+static inline uint64_t SPVersion() { return 100; }
+
+/// \brief Represents the relative location of an instruction.
+///
+/// Instruction locations are specified by the line offset from the
+/// beginning of the function (marked by the line where the function
+/// header is) and the discriminator value within that line.
+///
+/// The discriminator value is useful to distinguish instructions
+/// that are on the same line but belong to different basic blocks
+/// (e.g., the two post-increment instructions in "if (p) x++; else y++;").
+struct LineLocation {
+ LineLocation(int L, unsigned D) : LineOffset(L), Discriminator(D) {}
+ int LineOffset;
+ unsigned Discriminator;
+};
+
+} // End namespace sampleprof
+
+template <> struct DenseMapInfo<sampleprof::LineLocation> {
+ typedef DenseMapInfo<int> OffsetInfo;
+ typedef DenseMapInfo<unsigned> DiscriminatorInfo;
+ static inline sampleprof::LineLocation getEmptyKey() {
+ return sampleprof::LineLocation(OffsetInfo::getEmptyKey(),
+ DiscriminatorInfo::getEmptyKey());
+ }
+ static inline sampleprof::LineLocation getTombstoneKey() {
+ return sampleprof::LineLocation(OffsetInfo::getTombstoneKey(),
+ DiscriminatorInfo::getTombstoneKey());
+ }
+ static inline unsigned getHashValue(sampleprof::LineLocation Val) {
+ return DenseMapInfo<std::pair<int, unsigned>>::getHashValue(
+ std::pair<int, unsigned>(Val.LineOffset, Val.Discriminator));
+ }
+ static inline bool isEqual(sampleprof::LineLocation LHS,
+ sampleprof::LineLocation RHS) {
+ return LHS.LineOffset == RHS.LineOffset &&
+ LHS.Discriminator == RHS.Discriminator;
+ }
+};
+
+namespace sampleprof {
+
+/// \brief Representation of a single sample record.
+///
+/// A sample record is represented by a positive integer value, which
+/// indicates how frequently was the associated line location executed.
+///
+/// Additionally, if the associated location contains a function call,
+/// the record will hold a list of all the possible called targets. For
+/// direct calls, this will be the exact function being invoked. For
+/// indirect calls (function pointers, virtual table dispatch), this
+/// will be a list of one or more functions.
+class SampleRecord {
+public:
+ typedef StringMap<unsigned> CallTargetMap;
+
+ SampleRecord() : NumSamples(0), CallTargets() {}
+
+ /// \brief Increment the number of samples for this record by \p S.
+ ///
+ /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
+ /// around unsigned integers.
+ void addSamples(unsigned S) {
+ if (NumSamples <= std::numeric_limits<unsigned>::max() - S)
+ NumSamples += S;
+ else
+ NumSamples = std::numeric_limits<unsigned>::max();
+ }
+
+ /// \brief Add called function \p F with samples \p S.
+ ///
+ /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
+ /// around unsigned integers.
+ void addCalledTarget(StringRef F, unsigned S) {
+ unsigned &TargetSamples = CallTargets[F];
+ if (TargetSamples <= std::numeric_limits<unsigned>::max() - S)
+ TargetSamples += S;
+ else
+ TargetSamples = std::numeric_limits<unsigned>::max();
+ }
+
+ /// \brief Return true if this sample record contains function calls.
+ bool hasCalls() const { return CallTargets.size() > 0; }
+
+ unsigned getSamples() const { return NumSamples; }
+ const CallTargetMap &getCallTargets() const { return CallTargets; }
+
+ /// \brief Merge the samples in \p Other into this record.
+ void merge(const SampleRecord &Other) {
+ addSamples(Other.getSamples());
+ for (const auto &I : Other.getCallTargets())
+ addCalledTarget(I.first(), I.second);
+ }
+
+private:
+ unsigned NumSamples;
+ CallTargetMap CallTargets;
+};
+
+typedef DenseMap<LineLocation, SampleRecord> BodySampleMap;
+
+/// \brief Representation of the samples collected for a function.
+///
+/// This data structure contains all the collected samples for the body
+/// of a function. Each sample corresponds to a LineLocation instance
+/// within the body of the function.
+class FunctionSamples {
+public:
+ FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
+ void print(raw_ostream &OS = dbgs());
+ void addTotalSamples(unsigned Num) { TotalSamples += Num; }
+ void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
+ void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
+ assert(LineOffset >= 0);
+ // When dealing with instruction weights, we use the value
+ // zero to indicate the absence of a sample. If we read an
+ // actual zero from the profile file, use the value 1 to
+ // avoid the confusion later on.
+ if (Num == 0)
+ Num = 1;
+ BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num);
+ }
+ void addCalledTargetSamples(int LineOffset, unsigned Discriminator,
+ std::string FName, unsigned Num) {
+ assert(LineOffset >= 0);
+ BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName,
+ Num);
+ }
+
+ /// \brief Return the sample record at the given location.
+ /// Each location is specified by \p LineOffset and \p Discriminator.
+ SampleRecord &sampleRecordAt(const LineLocation &Loc) {
+ return BodySamples[Loc];
+ }
+
+ /// \brief Return the number of samples collected at the given location.
+ /// Each location is specified by \p LineOffset and \p Discriminator.
+ unsigned samplesAt(int LineOffset, unsigned Discriminator) {
+ return sampleRecordAt(LineLocation(LineOffset, Discriminator)).getSamples();
+ }
+
+ bool empty() const { return BodySamples.empty(); }
+
+ /// \brief Return the total number of samples collected inside the function.
+ unsigned getTotalSamples() const { return TotalSamples; }
+
+ /// \brief Return the total number of samples collected at the head of the
+ /// function.
+ unsigned getHeadSamples() const { return TotalHeadSamples; }
+
+ /// \brief Return all the samples collected in the body of the function.
+ const BodySampleMap &getBodySamples() const { return BodySamples; }
+
+ /// \brief Merge the samples in \p Other into this one.
+ void merge(const FunctionSamples &Other) {
+ addTotalSamples(Other.getTotalSamples());
+ addHeadSamples(Other.getHeadSamples());
+ for (const auto &I : Other.getBodySamples()) {
+ const LineLocation &Loc = I.first;
+ const SampleRecord &Rec = I.second;
+ sampleRecordAt(Loc).merge(Rec);
+ }
+ }
+
+private:
+ /// \brief Total number of samples collected inside this function.
+ ///
+ /// Samples are cumulative, they include all the samples collected
+ /// inside this function and all its inlined callees.
+ unsigned TotalSamples;
+
+ /// \brief Total number of samples collected at the head of the function.
+ unsigned TotalHeadSamples;
+
+ /// \brief Map instruction locations to collected samples.
+ ///
+ /// Each entry in this map contains the number of samples
+ /// collected at the corresponding line offset. All line locations
+ /// are an offset from the start of the function.
+ BodySampleMap BodySamples;
+};
+
+} // End namespace sampleprof
+
+} // End namespace llvm
+
+#endif // LLVM_PROFILEDATA_SAMPLEPROF_H_
diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h
new file mode 100644
index 0000000..c20b815
--- /dev/null
+++ b/include/llvm/ProfileData/SampleProfReader.h
@@ -0,0 +1,170 @@
+//===- SampleProfReader.h - Read LLVM sample profile data -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains definitions needed for reading sample profiles.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_PROFILEDATA_SAMPLEPROFREADER_H
+#define LLVM_PROFILEDATA_SAMPLEPROFREADER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ProfileData/SampleProf.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+namespace sampleprof {
+
+/// \brief Sample-based profile reader.
+///
+/// Each profile contains sample counts for all the functions
+/// executed. Inside each function, statements are annotated with the
+/// collected samples on all the instructions associated with that
+/// statement.
+///
+/// For this to produce meaningful data, the program needs to be
+/// compiled with some debug information (at minimum, line numbers:
+/// -gline-tables-only). Otherwise, it will be impossible to match IR
+/// instructions to the line numbers collected by the profiler.
+///
+/// From the profile file, we are interested in collecting the
+/// following information:
+///
+/// * A list of functions included in the profile (mangled names).
+///
+/// * For each function F:
+/// 1. The total number of samples collected in F.
+///
+/// 2. The samples collected at each line in F. To provide some
+/// protection against source code shuffling, line numbers should
+/// be relative to the start of the function.
+///
+/// The reader supports two file formats: text and binary. The text format
+/// is useful for debugging and testing, while the binary format is more
+/// compact. They can both be used interchangeably.
+class SampleProfileReader {
+public:
+ SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
+ : Profiles(0), Ctx(C), Buffer(std::move(B)) {}
+
+ virtual ~SampleProfileReader() {}
+
+ /// \brief Read and validate the file header.
+ virtual std::error_code readHeader() = 0;
+
+ /// \brief Read sample profiles from the associated file.
+ virtual std::error_code read() = 0;
+
+ /// \brief Print the profile for \p FName on stream \p OS.
+ void dumpFunctionProfile(StringRef FName, raw_ostream &OS = dbgs());
+
+ /// \brief Print all the profiles on stream \p OS.
+ void dump(raw_ostream &OS = dbgs());
+
+ /// \brief Return the samples collected for function \p F.
+ FunctionSamples *getSamplesFor(const Function &F) {
+ return &Profiles[F.getName()];
+ }
+
+ /// \brief Return all the profiles.
+ StringMap<FunctionSamples> &getProfiles() { return Profiles; }
+
+ /// \brief Report a parse error message.
+ void reportParseError(int64_t LineNumber, Twine Msg) const {
+ Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
+ LineNumber, Msg));
+ }
+
+ /// \brief Create a sample profile reader appropriate to the file format.
+ static ErrorOr<std::unique_ptr<SampleProfileReader>>
+ create(StringRef Filename, LLVMContext &C);
+
+protected:
+ /// \brief Map every function to its associated profile.
+ ///
+ /// The profile of every function executed at runtime is collected
+ /// in the structure FunctionSamples. This maps function objects
+ /// to their corresponding profiles.
+ StringMap<FunctionSamples> Profiles;
+
+ /// \brief LLVM context used to emit diagnostics.
+ LLVMContext &Ctx;
+
+ /// \brief Memory buffer holding the profile file.
+ std::unique_ptr<MemoryBuffer> Buffer;
+};
+
+class SampleProfileReaderText : public SampleProfileReader {
+public:
+ SampleProfileReaderText(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
+ : SampleProfileReader(std::move(B), C) {}
+
+ /// \brief Read and validate the file header.
+ std::error_code readHeader() override { return sampleprof_error::success; }
+
+ /// \brief Read sample profiles from the associated file.
+ std::error_code read() override;
+};
+
+class SampleProfileReaderBinary : public SampleProfileReader {
+public:
+ SampleProfileReaderBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
+ : SampleProfileReader(std::move(B), C), Data(nullptr), End(nullptr) {}
+
+ /// \brief Read and validate the file header.
+ std::error_code readHeader() override;
+
+ /// \brief Read sample profiles from the associated file.
+ std::error_code read() override;
+
+ /// \brief Return true if \p Buffer is in the format supported by this class.
+ static bool hasFormat(const MemoryBuffer &Buffer);
+
+protected:
+ /// \brief Read a numeric value of type T from the profile.
+ ///
+ /// If an error occurs during decoding, a diagnostic message is emitted and
+ /// EC is set.
+ ///
+ /// \returns the read value.
+ template <typename T> ErrorOr<T> readNumber();
+
+ /// \brief Read a string from the profile.
+ ///
+ /// If an error occurs during decoding, a diagnostic message is emitted and
+ /// EC is set.
+ ///
+ /// \returns the read value.
+ ErrorOr<StringRef> readString();
+
+ /// \brief Return true if we've reached the end of file.
+ bool at_eof() const { return Data >= End; }
+
+ /// \brief Points to the current location in the buffer.
+ const uint8_t *Data;
+
+ /// \brief Points to the end of the buffer.
+ const uint8_t *End;
+};
+
+} // End namespace sampleprof
+
+} // End namespace llvm
+
+#endif // LLVM_PROFILEDATA_SAMPLEPROFREADER_H
diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h
new file mode 100644
index 0000000..302a82d
--- /dev/null
+++ b/include/llvm/ProfileData/SampleProfWriter.h
@@ -0,0 +1,110 @@
+//===- SampleProfWriter.h - Write LLVM sample profile data ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains definitions needed for writing sample profiles.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
+#define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/ProfileData/SampleProf.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+namespace sampleprof {
+
+enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC };
+
+/// \brief Sample-based profile writer. Base class.
+class SampleProfileWriter {
+public:
+ SampleProfileWriter(StringRef Filename, std::error_code &EC,
+ sys::fs::OpenFlags Flags)
+ : OS(Filename, EC, Flags) {}
+ virtual ~SampleProfileWriter() {}
+
+ /// \brief Write sample profiles in \p S for function \p FName.
+ ///
+ /// \returns true if the file was updated successfully. False, otherwise.
+ virtual bool write(StringRef FName, const FunctionSamples &S) = 0;
+
+ /// \brief Write sample profiles in \p S for function \p F.
+ bool write(const Function &F, const FunctionSamples &S) {
+ return write(F.getName(), S);
+ }
+
+ /// \brief Write all the sample profiles for all the functions in \p M.
+ ///
+ /// \returns true if the file was updated successfully. False, otherwise.
+ bool write(const Module &M, StringMap<FunctionSamples> &P) {
+ for (const auto &F : M) {
+ StringRef Name = F.getName();
+ if (!write(Name, P[Name]))
+ return false;
+ }
+ return true;
+ }
+
+ /// \brief Write all the sample profiles in the given map of samples.
+ ///
+ /// \returns true if the file was updated successfully. False, otherwise.
+ bool write(StringMap<FunctionSamples> &ProfileMap) {
+ for (auto &I : ProfileMap) {
+ StringRef FName = I.first();
+ FunctionSamples &Profile = I.second;
+ if (!write(FName, Profile))
+ return false;
+ }
+ return true;
+ }
+
+ /// \brief Profile writer factory. Create a new writer based on the value of
+ /// \p Format.
+ static ErrorOr<std::unique_ptr<SampleProfileWriter>>
+ create(StringRef Filename, SampleProfileFormat Format);
+
+protected:
+ /// \brief Output stream where to emit the profile to.
+ raw_fd_ostream OS;
+};
+
+/// \brief Sample-based profile writer (text format).
+class SampleProfileWriterText : public SampleProfileWriter {
+public:
+ SampleProfileWriterText(StringRef F, std::error_code &EC)
+ : SampleProfileWriter(F, EC, sys::fs::F_Text) {}
+
+ bool write(StringRef FName, const FunctionSamples &S) override;
+ bool write(const Module &M, StringMap<FunctionSamples> &P) {
+ return SampleProfileWriter::write(M, P);
+ }
+};
+
+/// \brief Sample-based profile writer (binary format).
+class SampleProfileWriterBinary : public SampleProfileWriter {
+public:
+ SampleProfileWriterBinary(StringRef F, std::error_code &EC);
+
+ bool write(StringRef F, const FunctionSamples &S) override;
+ bool write(const Module &M, StringMap<FunctionSamples> &P) {
+ return SampleProfileWriter::write(M, P);
+ }
+};
+
+} // End namespace sampleprof
+
+} // End namespace llvm
+
+#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H