mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
Retry^2 "[ProfileData] (llvm) Use Error in InstrProf and Coverage, NFC"
Transition InstrProf and Coverage over to the stricter Error/Expected interface. Changes since the initial commit: - Address undefined-var-template warning. - Fix error message printing in llvm-profdata. - Check errors in loadTestingFormat() + annotateAllFunctions(). - Defer error handling in InstrProfIterator to InstrProfReader. Differential Revision: http://reviews.llvm.org/D19901 llvm-svn: 269694
This commit is contained in:
parent
5730660c55
commit
511487a013
@ -23,13 +23,13 @@
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
|
||||
namespace llvm {
|
||||
namespace coverage {
|
||||
|
||||
enum class coveragemap_error {
|
||||
success = 0,
|
||||
eof,
|
||||
@ -38,14 +38,20 @@ enum class coveragemap_error {
|
||||
truncated,
|
||||
malformed
|
||||
};
|
||||
} // end of coverage namespace.
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct is_error_code_enum<llvm::coverage::coveragemap_error> : std::true_type {
|
||||
class CoverageMapError : public ProfErrorInfoBase<coveragemap_error> {
|
||||
public:
|
||||
CoverageMapError(coveragemap_error Err)
|
||||
: ProfErrorInfoBase<coveragemap_error>(Err) {}
|
||||
|
||||
std::string message() const override;
|
||||
};
|
||||
}
|
||||
|
||||
} // end of coverage namespace.
|
||||
|
||||
template <> char ProfErrorInfoBase<coverage::coveragemap_error>::ID;
|
||||
|
||||
} // end of llvm namespace
|
||||
|
||||
namespace llvm {
|
||||
class IndexedInstrProfReader;
|
||||
@ -265,7 +271,7 @@ public:
|
||||
|
||||
/// \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;
|
||||
Expected<int64_t> evaluate(const Counter &C) const;
|
||||
};
|
||||
|
||||
/// \brief Code coverage information for a single function.
|
||||
@ -415,12 +421,12 @@ class CoverageMapping {
|
||||
|
||||
public:
|
||||
/// \brief Load the coverage mapping using the given readers.
|
||||
static ErrorOr<std::unique_ptr<CoverageMapping>>
|
||||
static Expected<std::unique_ptr<CoverageMapping>>
|
||||
load(CoverageMappingReader &CoverageReader,
|
||||
IndexedInstrProfReader &ProfileReader);
|
||||
|
||||
/// \brief Load the coverage mapping from the given files.
|
||||
static ErrorOr<std::unique_ptr<CoverageMapping>>
|
||||
static Expected<std::unique_ptr<CoverageMapping>>
|
||||
load(StringRef ObjectFilename, StringRef ProfileFilename,
|
||||
StringRef Arch = StringRef());
|
||||
|
||||
@ -501,14 +507,13 @@ template <class IntPtrT> struct CovMapFunctionRecordV1 {
|
||||
}
|
||||
// Return the PGO name of the function */
|
||||
template <support::endianness Endian>
|
||||
std::error_code getFuncName(InstrProfSymtab &ProfileNames,
|
||||
StringRef &FuncName) const {
|
||||
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 coveragemap_error::malformed;
|
||||
return std::error_code();
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
@ -530,11 +535,10 @@ struct CovMapFunctionRecord {
|
||||
}
|
||||
// Return the PGO name of the function */
|
||||
template <support::endianness Endian>
|
||||
std::error_code getFuncName(InstrProfSymtab &ProfileNames,
|
||||
StringRef &FuncName) const {
|
||||
Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
|
||||
uint64_t NameRef = getFuncNameRef<Endian>();
|
||||
FuncName = ProfileNames.getFuncName(NameRef);
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
|
||||
class CoverageMappingReader {
|
||||
public:
|
||||
virtual std::error_code readNextRecord(CoverageMappingRecord &Record) = 0;
|
||||
virtual Error readNextRecord(CoverageMappingRecord &Record) = 0;
|
||||
CoverageMappingIterator begin() { return CoverageMappingIterator(this); }
|
||||
CoverageMappingIterator end() { return CoverageMappingIterator(); }
|
||||
virtual ~CoverageMappingReader() {}
|
||||
@ -82,10 +82,10 @@ protected:
|
||||
|
||||
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);
|
||||
Error readULEB128(uint64_t &Result);
|
||||
Error readIntMax(uint64_t &Result, uint64_t MaxPlus1);
|
||||
Error readSize(uint64_t &Result);
|
||||
Error readString(StringRef &Result);
|
||||
};
|
||||
|
||||
/// \brief Reader for the raw coverage filenames.
|
||||
@ -100,7 +100,7 @@ public:
|
||||
RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames)
|
||||
: RawCoverageReader(Data), Filenames(Filenames) {}
|
||||
|
||||
std::error_code read();
|
||||
Error read();
|
||||
};
|
||||
|
||||
/// \brief Reader for the raw coverage mapping data.
|
||||
@ -125,12 +125,12 @@ public:
|
||||
Filenames(Filenames), Expressions(Expressions),
|
||||
MappingRegions(MappingRegions) {}
|
||||
|
||||
std::error_code read();
|
||||
Error read();
|
||||
|
||||
private:
|
||||
std::error_code decodeCounter(unsigned Value, Counter &C);
|
||||
std::error_code readCounter(Counter &C);
|
||||
std::error_code
|
||||
Error decodeCounter(unsigned Value, Counter &C);
|
||||
Error readCounter(Counter &C);
|
||||
Error
|
||||
readMappingRegionsSubArray(std::vector<CounterMappingRegion> &MappingRegions,
|
||||
unsigned InferredFileID, size_t NumFileIDs);
|
||||
};
|
||||
@ -170,11 +170,11 @@ private:
|
||||
BinaryCoverageReader() : CurrentRecord(0) {}
|
||||
|
||||
public:
|
||||
static ErrorOr<std::unique_ptr<BinaryCoverageReader>>
|
||||
static Expected<std::unique_ptr<BinaryCoverageReader>>
|
||||
create(std::unique_ptr<MemoryBuffer> &ObjectBuffer,
|
||||
StringRef Arch);
|
||||
|
||||
std::error_code readNextRecord(CoverageMappingRecord &Record) override;
|
||||
Error readNextRecord(CoverageMappingRecord &Record) override;
|
||||
};
|
||||
|
||||
} // end namespace coverage
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "llvm/ProfileData/ProfileCommon.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MD5.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cstdint>
|
||||
@ -204,20 +203,17 @@ StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName,
|
||||
/// third field is the uncompressed strings; otherwise it is the
|
||||
/// compressed string. When the string compression is off, the
|
||||
/// second field will have value zero.
|
||||
std::error_code
|
||||
collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
|
||||
bool doCompression, std::string &Result);
|
||||
Error collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
|
||||
bool doCompression, std::string &Result);
|
||||
/// Produce \c Result string with the same format described above. The input
|
||||
/// is vector of PGO function name variables that are referenced.
|
||||
std::error_code
|
||||
collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars,
|
||||
std::string &Result, bool doCompression = true);
|
||||
Error collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars,
|
||||
std::string &Result, bool doCompression = true);
|
||||
class InstrProfSymtab;
|
||||
/// \c NameStrings is a string composed of one of more sub-strings encoded in
|
||||
/// the format described above. The substrings are seperated by 0 or more zero
|
||||
/// bytes. This method decodes the string and populates the \c Symtab.
|
||||
std::error_code readPGOFuncNameStrings(StringRef NameStrings,
|
||||
InstrProfSymtab &Symtab);
|
||||
Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab);
|
||||
|
||||
enum InstrProfValueKind : uint32_t {
|
||||
#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value,
|
||||
@ -284,6 +280,27 @@ inline std::error_code make_error_code(instrprof_error E) {
|
||||
return std::error_code(static_cast<int>(E), instrprof_category());
|
||||
}
|
||||
|
||||
class InstrProfError : public ProfErrorInfoBase<instrprof_error> {
|
||||
public:
|
||||
InstrProfError(instrprof_error Err)
|
||||
: ProfErrorInfoBase<instrprof_error>(Err) {}
|
||||
|
||||
std::string message() const override;
|
||||
|
||||
/// Consume an Error and return the raw enum value contained within it. The
|
||||
/// Error must either be a success value, or contain a single InstrProfError.
|
||||
static instrprof_error take(Error E) {
|
||||
auto Err = instrprof_error::success;
|
||||
handleAllErrors(std::move(E), [&Err](const InstrProfError &IPE) {
|
||||
assert(Err == instrprof_error::success && "Multiple errors encountered");
|
||||
Err = IPE.get();
|
||||
});
|
||||
return Err;
|
||||
}
|
||||
};
|
||||
|
||||
template <> char ProfErrorInfoBase<instrprof_error>::ID;
|
||||
|
||||
class SoftInstrProfErrors {
|
||||
/// Count the number of soft instrprof_errors encountered and keep track of
|
||||
/// the first such error for reporting purposes.
|
||||
@ -309,6 +326,11 @@ public:
|
||||
NumCountMismatches(0), NumCounterOverflows(0),
|
||||
NumValueSiteCountMismatches(0) {}
|
||||
|
||||
~SoftInstrProfErrors() {
|
||||
assert(FirstError == instrprof_error::success &&
|
||||
"Unchecked soft error encountered");
|
||||
}
|
||||
|
||||
/// Track a soft error (\p IE) and increment its associated counter.
|
||||
void addError(instrprof_error IE);
|
||||
|
||||
@ -326,8 +348,15 @@ public:
|
||||
return NumValueSiteCountMismatches;
|
||||
}
|
||||
|
||||
/// Return an error code for the first encountered error.
|
||||
std::error_code getError() const { return make_error_code(FirstError); }
|
||||
/// Return the first encountered error and reset FirstError to a success
|
||||
/// value.
|
||||
Error takeError() {
|
||||
if (FirstError == instrprof_error::success)
|
||||
return Error::success();
|
||||
auto E = make_error<InstrProfError>(FirstError);
|
||||
FirstError = instrprof_error::success;
|
||||
return E;
|
||||
}
|
||||
};
|
||||
|
||||
namespace object {
|
||||
@ -372,14 +401,14 @@ public:
|
||||
/// only initialize the symtab with reference to the data and
|
||||
/// the section base address. The decompression will be delayed
|
||||
/// until before it is used. See also \c create(StringRef) method.
|
||||
std::error_code create(object::SectionRef &Section);
|
||||
Error create(object::SectionRef &Section);
|
||||
/// This interface is used by reader of CoverageMapping test
|
||||
/// format.
|
||||
inline std::error_code create(StringRef D, uint64_t BaseAddr);
|
||||
inline Error create(StringRef D, uint64_t BaseAddr);
|
||||
/// \c NameStrings is a string composed of one of more sub-strings
|
||||
/// encoded in the format described in \c collectPGOFuncNameStrings.
|
||||
/// This method is a wrapper to \c readPGOFuncNameStrings method.
|
||||
inline std::error_code create(StringRef NameStrings);
|
||||
inline Error create(StringRef NameStrings);
|
||||
/// A wrapper interface to populate the PGO symtab with functions
|
||||
/// decls from module \c M. This interface is used by transformation
|
||||
/// passes such as indirect function call promotion. Variable \c InLTO
|
||||
@ -424,13 +453,13 @@ public:
|
||||
inline StringRef getNameData() const { return Data; }
|
||||
};
|
||||
|
||||
std::error_code InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) {
|
||||
Error InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) {
|
||||
Data = D;
|
||||
Address = BaseAddr;
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code InstrProfSymtab::create(StringRef NameStrings) {
|
||||
Error InstrProfSymtab::create(StringRef NameStrings) {
|
||||
return readPGOFuncNameStrings(NameStrings, *this);
|
||||
}
|
||||
|
||||
@ -572,7 +601,7 @@ struct InstrProfRecord {
|
||||
}
|
||||
|
||||
/// Get the error contained within the record's soft error counter.
|
||||
std::error_code getError() const { return SIPE.getError(); }
|
||||
Error takeError() { return SIPE.takeError(); }
|
||||
|
||||
private:
|
||||
std::vector<InstrProfValueSiteRecord> IndirectCallSites;
|
||||
@ -869,9 +898,4 @@ struct Header {
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct is_error_code_enum<llvm::instrprof_error> : std::true_type {};
|
||||
}
|
||||
|
||||
#endif // LLVM_PROFILEDATA_INSTRPROF_H
|
||||
|
@ -322,16 +322,15 @@ typedef struct ValueProfData {
|
||||
static std::unique_ptr<ValueProfData>
|
||||
serializeFrom(const InstrProfRecord &Record);
|
||||
/*!
|
||||
* Check the integrity of the record. Return the error code when
|
||||
* an error is detected, otherwise return instrprof_error::success.
|
||||
* Check the integrity of the record.
|
||||
*/
|
||||
instrprof_error checkIntegrity();
|
||||
Error checkIntegrity();
|
||||
/*!
|
||||
* Return a pointer to \c ValueProfileData instance ready to be read.
|
||||
* All data in the instance are properly byte swapped. The input
|
||||
* data is assumed to be in little endian order.
|
||||
*/
|
||||
static ErrorOr<std::unique_ptr<ValueProfData>>
|
||||
static Expected<std::unique_ptr<ValueProfData>>
|
||||
getValueProfData(const unsigned char *SrcBuffer,
|
||||
const unsigned char *const SrcBufferEnd,
|
||||
support::endianness SrcDataEndianness);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/Support/EndianStream.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/OnDiskHashTable.h"
|
||||
@ -51,16 +50,16 @@ public:
|
||||
/// Base class and interface for reading profiling data of any known instrprof
|
||||
/// format. Provides an iterator over InstrProfRecords.
|
||||
class InstrProfReader {
|
||||
std::error_code LastError;
|
||||
instrprof_error LastError;
|
||||
|
||||
public:
|
||||
InstrProfReader() : LastError(instrprof_error::success), Symtab() {}
|
||||
virtual ~InstrProfReader() {}
|
||||
|
||||
/// Read the header. Required before reading first record.
|
||||
virtual std::error_code readHeader() = 0;
|
||||
virtual Error readHeader() = 0;
|
||||
/// Read a single record.
|
||||
virtual std::error_code readNextRecord(InstrProfRecord &Record) = 0;
|
||||
virtual Error readNextRecord(InstrProfRecord &Record) = 0;
|
||||
/// Iterator over profile data.
|
||||
InstrProfIterator begin() { return InstrProfIterator(this); }
|
||||
InstrProfIterator end() { return InstrProfIterator(); }
|
||||
@ -80,28 +79,35 @@ public:
|
||||
|
||||
protected:
|
||||
std::unique_ptr<InstrProfSymtab> Symtab;
|
||||
/// Set the current std::error_code and return same.
|
||||
std::error_code error(std::error_code EC) {
|
||||
LastError = EC;
|
||||
return EC;
|
||||
/// Set the current error and return same.
|
||||
Error error(instrprof_error Err) {
|
||||
LastError = Err;
|
||||
if (Err == instrprof_error::success)
|
||||
return Error::success();
|
||||
return make_error<InstrProfError>(Err);
|
||||
}
|
||||
Error error(Error E) { return error(InstrProfError::take(std::move(E))); }
|
||||
|
||||
/// Clear the current error code and return a successful one.
|
||||
std::error_code success() { return error(instrprof_error::success); }
|
||||
/// Clear the current error and return a successful one.
|
||||
Error success() { return error(instrprof_error::success); }
|
||||
|
||||
public:
|
||||
/// Return true if the reader has finished reading the profile data.
|
||||
bool isEOF() { return LastError == instrprof_error::eof; }
|
||||
/// Return true if the reader encountered an error reading profiling data.
|
||||
bool hasError() { return LastError && !isEOF(); }
|
||||
/// Get the current error code.
|
||||
std::error_code getError() { return LastError; }
|
||||
bool hasError() { return LastError != instrprof_error::success && !isEOF(); }
|
||||
/// Get the current error.
|
||||
Error getError() {
|
||||
if (hasError())
|
||||
return make_error<InstrProfError>(LastError);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Factory method to create an appropriately typed reader for the given
|
||||
/// instrprof file.
|
||||
static ErrorOr<std::unique_ptr<InstrProfReader>> create(std::string Path);
|
||||
static Expected<std::unique_ptr<InstrProfReader>> create(std::string Path);
|
||||
|
||||
static ErrorOr<std::unique_ptr<InstrProfReader>>
|
||||
static Expected<std::unique_ptr<InstrProfReader>>
|
||||
create(std::unique_ptr<MemoryBuffer> Buffer);
|
||||
};
|
||||
|
||||
@ -123,7 +129,7 @@ private:
|
||||
|
||||
TextInstrProfReader(const TextInstrProfReader &) = delete;
|
||||
TextInstrProfReader &operator=(const TextInstrProfReader &) = delete;
|
||||
std::error_code readValueProfileData(InstrProfRecord &Record);
|
||||
Error readValueProfileData(InstrProfRecord &Record);
|
||||
|
||||
public:
|
||||
TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_)
|
||||
@ -136,9 +142,9 @@ public:
|
||||
bool isIRLevelProfile() const override { return IsIRLevelProfile; }
|
||||
|
||||
/// Read the header.
|
||||
std::error_code readHeader() override;
|
||||
Error readHeader() override;
|
||||
/// Read a single record.
|
||||
std::error_code readNextRecord(InstrProfRecord &Record) override;
|
||||
Error readNextRecord(InstrProfRecord &Record) override;
|
||||
|
||||
InstrProfSymtab &getSymtab() override {
|
||||
assert(Symtab.get());
|
||||
@ -185,8 +191,8 @@ public:
|
||||
: DataBuffer(std::move(DataBuffer)) { }
|
||||
|
||||
static bool hasFormat(const MemoryBuffer &DataBuffer);
|
||||
std::error_code readHeader() override;
|
||||
std::error_code readNextRecord(InstrProfRecord &Record) override;
|
||||
Error readHeader() override;
|
||||
Error readNextRecord(InstrProfRecord &Record) override;
|
||||
bool isIRLevelProfile() const override {
|
||||
return (Version & VARIANT_MASK_IR_PROF) != 0;
|
||||
}
|
||||
@ -197,9 +203,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::error_code createSymtab(InstrProfSymtab &Symtab);
|
||||
std::error_code readNextHeader(const char *CurrentPos);
|
||||
std::error_code readHeader(const RawInstrProf::Header &Header);
|
||||
Error createSymtab(InstrProfSymtab &Symtab);
|
||||
Error readNextHeader(const char *CurrentPos);
|
||||
Error readHeader(const RawInstrProf::Header &Header);
|
||||
template <class IntT> IntT swap(IntT Int) const {
|
||||
return ShouldSwapBytes ? sys::getSwappedBytes(Int) : Int;
|
||||
}
|
||||
@ -216,10 +222,10 @@ private:
|
||||
inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) {
|
||||
return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
|
||||
}
|
||||
std::error_code readName(InstrProfRecord &Record);
|
||||
std::error_code readFuncHash(InstrProfRecord &Record);
|
||||
std::error_code readRawCounts(InstrProfRecord &Record);
|
||||
std::error_code readValueProfilingData(InstrProfRecord &Record);
|
||||
Error readName(InstrProfRecord &Record);
|
||||
Error readFuncHash(InstrProfRecord &Record);
|
||||
Error readRawCounts(InstrProfRecord &Record);
|
||||
Error readValueProfilingData(InstrProfRecord &Record);
|
||||
bool atEnd() const { return Data == DataEnd; }
|
||||
void advanceData() {
|
||||
Data++;
|
||||
@ -300,9 +306,9 @@ public:
|
||||
struct InstrProfReaderIndexBase {
|
||||
// Read all the profile records with the same key pointed to the current
|
||||
// iterator.
|
||||
virtual std::error_code getRecords(ArrayRef<InstrProfRecord> &Data) = 0;
|
||||
virtual Error getRecords(ArrayRef<InstrProfRecord> &Data) = 0;
|
||||
// Read all the profile records with the key equal to FuncName
|
||||
virtual std::error_code getRecords(StringRef FuncName,
|
||||
virtual Error getRecords(StringRef FuncName,
|
||||
ArrayRef<InstrProfRecord> &Data) = 0;
|
||||
virtual void advanceToNextKey() = 0;
|
||||
virtual bool atEnd() const = 0;
|
||||
@ -330,9 +336,9 @@ public:
|
||||
const unsigned char *const Base,
|
||||
IndexedInstrProf::HashT HashType, uint64_t Version);
|
||||
|
||||
std::error_code getRecords(ArrayRef<InstrProfRecord> &Data) override;
|
||||
std::error_code getRecords(StringRef FuncName,
|
||||
ArrayRef<InstrProfRecord> &Data) override;
|
||||
Error getRecords(ArrayRef<InstrProfRecord> &Data) override;
|
||||
Error getRecords(StringRef FuncName,
|
||||
ArrayRef<InstrProfRecord> &Data) override;
|
||||
void advanceToNextKey() override { RecordIterator++; }
|
||||
bool atEnd() const override {
|
||||
return RecordIterator == HashTable->data_end();
|
||||
@ -379,27 +385,27 @@ public:
|
||||
static bool hasFormat(const MemoryBuffer &DataBuffer);
|
||||
|
||||
/// Read the file header.
|
||||
std::error_code readHeader() override;
|
||||
Error readHeader() override;
|
||||
/// Read a single record.
|
||||
std::error_code readNextRecord(InstrProfRecord &Record) override;
|
||||
Error readNextRecord(InstrProfRecord &Record) override;
|
||||
|
||||
/// Return the pointer to InstrProfRecord associated with FuncName
|
||||
/// and FuncHash
|
||||
ErrorOr<InstrProfRecord> getInstrProfRecord(StringRef FuncName,
|
||||
uint64_t FuncHash);
|
||||
Expected<InstrProfRecord> getInstrProfRecord(StringRef FuncName,
|
||||
uint64_t FuncHash);
|
||||
|
||||
/// Fill Counts with the profile data for the given function name.
|
||||
std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
|
||||
std::vector<uint64_t> &Counts);
|
||||
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
|
||||
std::vector<uint64_t> &Counts);
|
||||
|
||||
/// Return the maximum of all known function counts.
|
||||
uint64_t getMaximumFunctionCount() { return Summary->getMaxFunctionCount(); }
|
||||
|
||||
/// Factory method to create an indexed reader.
|
||||
static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
|
||||
static Expected<std::unique_ptr<IndexedInstrProfReader>>
|
||||
create(std::string Path);
|
||||
|
||||
static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
|
||||
static Expected<std::unique_ptr<IndexedInstrProfReader>>
|
||||
create(std::unique_ptr<MemoryBuffer> Buffer);
|
||||
|
||||
// Used for testing purpose only.
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
/// 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. Optionally scale counts by \p Weight.
|
||||
std::error_code addRecord(InstrProfRecord &&I, uint64_t Weight = 1);
|
||||
Error addRecord(InstrProfRecord &&I, uint64_t Weight = 1);
|
||||
/// Write the profile to \c OS
|
||||
void write(raw_fd_ostream &OS);
|
||||
/// Write the profile in text format to \c OS
|
||||
@ -58,13 +58,15 @@ public:
|
||||
std::unique_ptr<MemoryBuffer> writeBuffer();
|
||||
|
||||
/// Set the ProfileKind. Report error if mixing FE and IR level profiles.
|
||||
std::error_code setIsIRLevelProfile(bool IsIRLevel) {
|
||||
Error setIsIRLevelProfile(bool IsIRLevel) {
|
||||
if (ProfileKind == PF_Unknown) {
|
||||
ProfileKind = IsIRLevel ? PF_IRLevel: PF_FE;
|
||||
return instrprof_error::success;
|
||||
return Error::success();
|
||||
}
|
||||
return (IsIRLevel == (ProfileKind == PF_IRLevel)) ?
|
||||
instrprof_error::success : instrprof_error::unsupported_version;
|
||||
return (IsIRLevel == (ProfileKind == PF_IRLevel))
|
||||
? Error::success()
|
||||
: make_error<InstrProfError>(
|
||||
instrprof_error::unsupported_version);
|
||||
}
|
||||
|
||||
// Internal interface for testing purpose only.
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
@ -36,6 +37,29 @@ class Metadata;
|
||||
class MDTuple;
|
||||
class MDNode;
|
||||
|
||||
template <typename ErrT>
|
||||
class ProfErrorInfoBase : public ErrorInfo<ProfErrorInfoBase<ErrT>> {
|
||||
public:
|
||||
ProfErrorInfoBase(ErrT Err) : Err(Err) {
|
||||
assert(Err != ErrT::success && "Not an error");
|
||||
}
|
||||
|
||||
virtual std::string message() const override = 0;
|
||||
|
||||
void log(raw_ostream &OS) const override { OS << message(); }
|
||||
|
||||
std::error_code convertToErrorCode() const override {
|
||||
return make_error_code(Err);
|
||||
}
|
||||
|
||||
ErrT get() const { return Err; }
|
||||
|
||||
static char ID;
|
||||
|
||||
protected:
|
||||
ErrT Err;
|
||||
};
|
||||
|
||||
inline const char *getHotSectionPrefix() { return ".hot"; }
|
||||
inline const char *getUnlikelySectionPrefix() { return ".unlikely"; }
|
||||
|
||||
|
@ -143,28 +143,30 @@ void CounterMappingContext::dump(const Counter &C,
|
||||
}
|
||||
if (CounterValues.empty())
|
||||
return;
|
||||
ErrorOr<int64_t> Value = evaluate(C);
|
||||
if (!Value)
|
||||
Expected<int64_t> Value = evaluate(C);
|
||||
if (auto E = Value.takeError()) {
|
||||
llvm::consumeError(std::move(E));
|
||||
return;
|
||||
}
|
||||
OS << '[' << *Value << ']';
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
|
||||
Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
|
||||
switch (C.getKind()) {
|
||||
case Counter::Zero:
|
||||
return 0;
|
||||
case Counter::CounterValueReference:
|
||||
if (C.getCounterID() >= CounterValues.size())
|
||||
return make_error_code(errc::argument_out_of_domain);
|
||||
return errorCodeToError(errc::argument_out_of_domain);
|
||||
return CounterValues[C.getCounterID()];
|
||||
case Counter::Expression: {
|
||||
if (C.getExpressionID() >= Expressions.size())
|
||||
return make_error_code(errc::argument_out_of_domain);
|
||||
return errorCodeToError(errc::argument_out_of_domain);
|
||||
const auto &E = Expressions[C.getExpressionID()];
|
||||
ErrorOr<int64_t> LHS = evaluate(E.LHS);
|
||||
Expected<int64_t> LHS = evaluate(E.LHS);
|
||||
if (!LHS)
|
||||
return LHS;
|
||||
ErrorOr<int64_t> RHS = evaluate(E.RHS);
|
||||
Expected<int64_t> RHS = evaluate(E.RHS);
|
||||
if (!RHS)
|
||||
return RHS;
|
||||
return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS;
|
||||
@ -181,7 +183,7 @@ void FunctionRecordIterator::skipOtherFiles() {
|
||||
*this = FunctionRecordIterator();
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<CoverageMapping>>
|
||||
Expected<std::unique_ptr<CoverageMapping>>
|
||||
CoverageMapping::load(CoverageMappingReader &CoverageReader,
|
||||
IndexedInstrProfReader &ProfileReader) {
|
||||
auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
|
||||
@ -191,13 +193,14 @@ CoverageMapping::load(CoverageMappingReader &CoverageReader,
|
||||
CounterMappingContext Ctx(Record.Expressions);
|
||||
|
||||
Counts.clear();
|
||||
if (std::error_code EC = ProfileReader.getFunctionCounts(
|
||||
if (Error E = ProfileReader.getFunctionCounts(
|
||||
Record.FunctionName, Record.FunctionHash, Counts)) {
|
||||
if (EC == instrprof_error::hash_mismatch) {
|
||||
instrprof_error IPE = InstrProfError::take(std::move(E));
|
||||
if (IPE == instrprof_error::hash_mismatch) {
|
||||
Coverage->MismatchedFunctionCount++;
|
||||
continue;
|
||||
} else if (EC != instrprof_error::unknown_function)
|
||||
return EC;
|
||||
} else if (IPE != instrprof_error::unknown_function)
|
||||
return make_error<InstrProfError>(IPE);
|
||||
Counts.assign(Record.MappingRegions.size(), 0);
|
||||
}
|
||||
Ctx.setCounts(Counts);
|
||||
@ -212,9 +215,11 @@ CoverageMapping::load(CoverageMappingReader &CoverageReader,
|
||||
getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
|
||||
FunctionRecord Function(OrigFuncName, Record.Filenames);
|
||||
for (const auto &Region : Record.MappingRegions) {
|
||||
ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
|
||||
if (!ExecutionCount)
|
||||
Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
|
||||
if (auto E = ExecutionCount.takeError()) {
|
||||
llvm::consumeError(std::move(E));
|
||||
break;
|
||||
}
|
||||
Function.pushRegion(Region, *ExecutionCount);
|
||||
}
|
||||
if (Function.CountedRegions.size() != Record.MappingRegions.size()) {
|
||||
@ -228,20 +233,20 @@ CoverageMapping::load(CoverageMappingReader &CoverageReader,
|
||||
return std::move(Coverage);
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<CoverageMapping>>
|
||||
Expected<std::unique_ptr<CoverageMapping>>
|
||||
CoverageMapping::load(StringRef ObjectFilename, StringRef ProfileFilename,
|
||||
StringRef Arch) {
|
||||
auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
|
||||
if (std::error_code EC = CounterMappingBuff.getError())
|
||||
return EC;
|
||||
return errorCodeToError(EC);
|
||||
auto CoverageReaderOrErr =
|
||||
BinaryCoverageReader::create(CounterMappingBuff.get(), Arch);
|
||||
if (std::error_code EC = CoverageReaderOrErr.getError())
|
||||
return EC;
|
||||
if (Error E = CoverageReaderOrErr.takeError())
|
||||
return std::move(E);
|
||||
auto CoverageReader = std::move(CoverageReaderOrErr.get());
|
||||
auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename);
|
||||
if (auto EC = ProfileReaderOrErr.getError())
|
||||
return EC;
|
||||
if (Error E = ProfileReaderOrErr.takeError())
|
||||
return std::move(E);
|
||||
auto ProfileReader = std::move(ProfileReaderOrErr.get());
|
||||
return load(*CoverageReader, *ProfileReader);
|
||||
}
|
||||
@ -533,27 +538,34 @@ CoverageMapping::getCoverageForExpansion(const ExpansionRecord &Expansion) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string getCoverageMapErrString(coveragemap_error Err) {
|
||||
switch (Err) {
|
||||
case coveragemap_error::success:
|
||||
return "Success";
|
||||
case coveragemap_error::eof:
|
||||
return "End of File";
|
||||
case coveragemap_error::no_data_found:
|
||||
return "No coverage data found";
|
||||
case coveragemap_error::unsupported_version:
|
||||
return "Unsupported coverage format version";
|
||||
case coveragemap_error::truncated:
|
||||
return "Truncated coverage data";
|
||||
case coveragemap_error::malformed:
|
||||
return "Malformed coverage data";
|
||||
}
|
||||
llvm_unreachable("A value of coveragemap_error has no message.");
|
||||
}
|
||||
|
||||
class CoverageMappingErrorCategoryType : public std::error_category {
|
||||
const char *name() const LLVM_NOEXCEPT override { return "llvm.coveragemap"; }
|
||||
std::string message(int IE) const override {
|
||||
auto E = static_cast<coveragemap_error>(IE);
|
||||
switch (E) {
|
||||
case coveragemap_error::success:
|
||||
return "Success";
|
||||
case coveragemap_error::eof:
|
||||
return "End of File";
|
||||
case coveragemap_error::no_data_found:
|
||||
return "No coverage data found";
|
||||
case coveragemap_error::unsupported_version:
|
||||
return "Unsupported coverage format version";
|
||||
case coveragemap_error::truncated:
|
||||
return "Truncated coverage data";
|
||||
case coveragemap_error::malformed:
|
||||
return "Malformed coverage data";
|
||||
}
|
||||
llvm_unreachable("A value of coveragemap_error has no message.");
|
||||
return getCoverageMapErrString(static_cast<coveragemap_error>(IE));
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
std::string CoverageMapError::message() const {
|
||||
return getCoverageMapErrString(Err);
|
||||
}
|
||||
|
||||
static ManagedStatic<CoverageMappingErrorCategoryType> ErrorCategory;
|
||||
@ -561,3 +573,5 @@ static ManagedStatic<CoverageMappingErrorCategoryType> ErrorCategory;
|
||||
const std::error_category &llvm::coverage::coveragemap_category() {
|
||||
return *ErrorCategory;
|
||||
}
|
||||
|
||||
template <> char ProfErrorInfoBase<coveragemap_error>::ID = 0;
|
||||
|
@ -31,49 +31,54 @@ using namespace object;
|
||||
void CoverageMappingIterator::increment() {
|
||||
// Check if all the records were read or if an error occurred while reading
|
||||
// the next record.
|
||||
if (Reader->readNextRecord(Record))
|
||||
*this = CoverageMappingIterator();
|
||||
if (auto E = Reader->readNextRecord(Record)) {
|
||||
handleAllErrors(std::move(E), [&](const CoverageMapError &CME) {
|
||||
if (CME.get() == coveragemap_error::eof)
|
||||
*this = CoverageMappingIterator();
|
||||
else
|
||||
llvm_unreachable("Unexpected error in coverage mapping iterator");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code RawCoverageReader::readULEB128(uint64_t &Result) {
|
||||
Error RawCoverageReader::readULEB128(uint64_t &Result) {
|
||||
if (Data.size() < 1)
|
||||
return coveragemap_error::truncated;
|
||||
return make_error<CoverageMapError>(coveragemap_error::truncated);
|
||||
unsigned N = 0;
|
||||
Result = decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
|
||||
if (N > Data.size())
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
Data = Data.substr(N);
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code RawCoverageReader::readIntMax(uint64_t &Result,
|
||||
uint64_t MaxPlus1) {
|
||||
Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) {
|
||||
if (auto Err = readULEB128(Result))
|
||||
return Err;
|
||||
if (Result >= MaxPlus1)
|
||||
return coveragemap_error::malformed;
|
||||
return std::error_code();
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code RawCoverageReader::readSize(uint64_t &Result) {
|
||||
Error RawCoverageReader::readSize(uint64_t &Result) {
|
||||
if (auto Err = readULEB128(Result))
|
||||
return Err;
|
||||
// Sanity check the number.
|
||||
if (Result > Data.size())
|
||||
return coveragemap_error::malformed;
|
||||
return std::error_code();
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code RawCoverageReader::readString(StringRef &Result) {
|
||||
Error RawCoverageReader::readString(StringRef &Result) {
|
||||
uint64_t Length;
|
||||
if (auto Err = readSize(Length))
|
||||
return Err;
|
||||
Result = Data.substr(0, Length);
|
||||
Data = Data.substr(Length);
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code RawCoverageFilenamesReader::read() {
|
||||
Error RawCoverageFilenamesReader::read() {
|
||||
uint64_t NumFilenames;
|
||||
if (auto Err = readSize(NumFilenames))
|
||||
return Err;
|
||||
@ -83,19 +88,18 @@ std::error_code RawCoverageFilenamesReader::read() {
|
||||
return Err;
|
||||
Filenames.push_back(Filename);
|
||||
}
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value,
|
||||
Counter &C) {
|
||||
Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) {
|
||||
auto Tag = Value & Counter::EncodingTagMask;
|
||||
switch (Tag) {
|
||||
case Counter::Zero:
|
||||
C = Counter::getZero();
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
case Counter::CounterValueReference:
|
||||
C = Counter::getCounter(Value >> Counter::EncodingTagBits);
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -105,25 +109,25 @@ std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value,
|
||||
case CounterExpression::Add: {
|
||||
auto ID = Value >> Counter::EncodingTagBits;
|
||||
if (ID >= Expressions.size())
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
Expressions[ID].Kind = CounterExpression::ExprKind(Tag);
|
||||
C = Counter::getExpression(ID);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
}
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code RawCoverageMappingReader::readCounter(Counter &C) {
|
||||
Error RawCoverageMappingReader::readCounter(Counter &C) {
|
||||
uint64_t EncodedCounter;
|
||||
if (auto Err =
|
||||
readIntMax(EncodedCounter, std::numeric_limits<unsigned>::max()))
|
||||
return Err;
|
||||
if (auto Err = decodeCounter(EncodedCounter, C))
|
||||
return Err;
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static const unsigned EncodingExpansionRegionBit = 1
|
||||
@ -132,7 +136,7 @@ static const unsigned EncodingExpansionRegionBit = 1
|
||||
/// \brief Read the sub-array of regions for the given inferred file id.
|
||||
/// \param NumFileIDs the number of file ids that are defined for this
|
||||
/// function.
|
||||
std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(
|
||||
Error RawCoverageMappingReader::readMappingRegionsSubArray(
|
||||
std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID,
|
||||
size_t NumFileIDs) {
|
||||
uint64_t NumRegions;
|
||||
@ -160,7 +164,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(
|
||||
ExpandedFileID = EncodedCounterAndRegion >>
|
||||
Counter::EncodingCounterTagAndExpansionRegionTagBits;
|
||||
if (ExpandedFileID >= NumFileIDs)
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
} else {
|
||||
switch (EncodedCounterAndRegion >>
|
||||
Counter::EncodingCounterTagAndExpansionRegionTagBits) {
|
||||
@ -171,7 +175,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(
|
||||
Kind = CounterMappingRegion::SkippedRegion;
|
||||
break;
|
||||
default:
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,7 +188,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(
|
||||
if (auto Err = readULEB128(ColumnStart))
|
||||
return Err;
|
||||
if (ColumnStart > std::numeric_limits<unsigned>::max())
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max()))
|
||||
return Err;
|
||||
if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max()))
|
||||
@ -218,10 +222,10 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(
|
||||
C, InferredFileID, ExpandedFileID, LineStart, ColumnStart,
|
||||
LineStart + NumLines, ColumnEnd, Kind));
|
||||
}
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code RawCoverageMappingReader::read() {
|
||||
Error RawCoverageMappingReader::read() {
|
||||
|
||||
// Read the virtual file mapping.
|
||||
llvm::SmallVector<unsigned, 8> VirtualFileMapping;
|
||||
@ -287,14 +291,14 @@ std::error_code RawCoverageMappingReader::read() {
|
||||
}
|
||||
}
|
||||
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::error_code InstrProfSymtab::create(SectionRef &Section) {
|
||||
if (auto Err = Section.getContents(Data))
|
||||
return Err;
|
||||
Error InstrProfSymtab::create(SectionRef &Section) {
|
||||
if (auto EC = Section.getContents(Data))
|
||||
return errorCodeToError(EC);
|
||||
Address = Section.getAddress();
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) {
|
||||
@ -312,11 +316,10 @@ struct CovMapFuncRecordReader {
|
||||
// a module. \p Buf is a reference to the buffer pointer pointing
|
||||
// to the \c CovHeader of coverage mapping data associated with
|
||||
// the module.
|
||||
virtual std::error_code readFunctionRecords(const char *&Buf,
|
||||
const char *End) = 0;
|
||||
virtual Error readFunctionRecords(const char *&Buf, const char *End) = 0;
|
||||
virtual ~CovMapFuncRecordReader() {}
|
||||
template <class IntPtrT, support::endianness Endian>
|
||||
static ErrorOr<std::unique_ptr<CovMapFuncRecordReader>>
|
||||
static Expected<std::unique_ptr<CovMapFuncRecordReader>>
|
||||
get(coverage::CovMapVersion Version, InstrProfSymtab &P,
|
||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
|
||||
std::vector<StringRef> &F);
|
||||
@ -344,11 +347,10 @@ public:
|
||||
: ProfileNames(P), Filenames(F), Records(R) {}
|
||||
~VersionedCovMapFuncRecordReader() override {}
|
||||
|
||||
std::error_code readFunctionRecords(const char *&Buf,
|
||||
const char *End) override {
|
||||
Error readFunctionRecords(const char *&Buf, const char *End) override {
|
||||
using namespace support;
|
||||
if (Buf + sizeof(CovMapHeader) > End)
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
auto CovHeader = reinterpret_cast<const coverage::CovMapHeader *>(Buf);
|
||||
uint32_t NRecords = CovHeader->getNRecords<Endian>();
|
||||
uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>();
|
||||
@ -363,7 +365,7 @@ public:
|
||||
|
||||
// Get the filenames.
|
||||
if (Buf + FilenamesSize > End)
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
size_t FilenamesBegin = Filenames.size();
|
||||
RawCoverageFilenamesReader Reader(StringRef(Buf, FilenamesSize), Filenames);
|
||||
if (auto Err = Reader.read())
|
||||
@ -376,7 +378,7 @@ public:
|
||||
const char *CovEnd = Buf;
|
||||
|
||||
if (Buf > End)
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
// Each coverage map has an alignment of 8, so we need to adjust alignment
|
||||
// before reading the next map.
|
||||
Buf += alignmentAdjustment(Buf, 8);
|
||||
@ -389,7 +391,7 @@ public:
|
||||
|
||||
// Now use that to read the coverage data.
|
||||
if (CovBuf + DataSize > CovEnd)
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
auto Mapping = StringRef(CovBuf, DataSize);
|
||||
CovBuf += DataSize;
|
||||
|
||||
@ -403,21 +405,20 @@ public:
|
||||
}
|
||||
|
||||
StringRef FuncName;
|
||||
if (std::error_code EC =
|
||||
CFR->template getFuncName<Endian>(ProfileNames, FuncName))
|
||||
return EC;
|
||||
if (Error E = CFR->template getFuncName<Endian>(ProfileNames, FuncName))
|
||||
return E;
|
||||
Records.push_back(BinaryCoverageReader::ProfileMappingRecord(
|
||||
Version, FuncName, FuncHash, Mapping, FilenamesBegin,
|
||||
Filenames.size() - FilenamesBegin));
|
||||
CFR++;
|
||||
}
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
template <class IntPtrT, support::endianness Endian>
|
||||
ErrorOr<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
||||
Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
||||
coverage::CovMapVersion Version, InstrProfSymtab &P,
|
||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
|
||||
std::vector<StringRef> &F) {
|
||||
@ -428,8 +429,8 @@ ErrorOr<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
||||
CovMapVersion::Version1, IntPtrT, Endian>>(P, R, F);
|
||||
case CovMapVersion::Version2:
|
||||
// Decompress the name data.
|
||||
if (auto EC = P.create(P.getNameData()))
|
||||
return EC;
|
||||
if (Error E = P.create(P.getNameData()))
|
||||
return std::move(E);
|
||||
return llvm::make_unique<VersionedCovMapFuncRecordReader<
|
||||
CovMapVersion::Version2, IntPtrT, Endian>>(P, R, F);
|
||||
}
|
||||
@ -437,7 +438,7 @@ ErrorOr<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
||||
}
|
||||
|
||||
template <typename T, support::endianness Endian>
|
||||
static std::error_code readCoverageMappingData(
|
||||
static Error readCoverageMappingData(
|
||||
InstrProfSymtab &ProfileNames, StringRef Data,
|
||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
|
||||
std::vector<StringRef> &Filenames) {
|
||||
@ -447,89 +448,90 @@ static std::error_code readCoverageMappingData(
|
||||
reinterpret_cast<const coverage::CovMapHeader *>(Data.data());
|
||||
CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>();
|
||||
if (Version > coverage::CovMapVersion::CurrentVersion)
|
||||
return coveragemap_error::unsupported_version;
|
||||
ErrorOr<std::unique_ptr<CovMapFuncRecordReader>> ReaderErrorOr =
|
||||
return make_error<CoverageMapError>(coveragemap_error::unsupported_version);
|
||||
Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected =
|
||||
CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records,
|
||||
Filenames);
|
||||
if (auto EC = ReaderErrorOr.getError())
|
||||
return EC;
|
||||
auto Reader = std::move(ReaderErrorOr.get());
|
||||
if (Error E = ReaderExpected.takeError())
|
||||
return E;
|
||||
auto Reader = std::move(ReaderExpected.get());
|
||||
for (const char *Buf = Data.data(), *End = Buf + Data.size(); Buf < End;) {
|
||||
if (std::error_code EC = Reader->readFunctionRecords(Buf, End))
|
||||
return EC;
|
||||
if (Error E = Reader->readFunctionRecords(Buf, End))
|
||||
return E;
|
||||
}
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
static const char *TestingFormatMagic = "llvmcovmtestdata";
|
||||
|
||||
static std::error_code loadTestingFormat(StringRef Data,
|
||||
InstrProfSymtab &ProfileNames,
|
||||
StringRef &CoverageMapping,
|
||||
uint8_t &BytesInAddress,
|
||||
support::endianness &Endian) {
|
||||
static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames,
|
||||
StringRef &CoverageMapping,
|
||||
uint8_t &BytesInAddress,
|
||||
support::endianness &Endian) {
|
||||
BytesInAddress = 8;
|
||||
Endian = support::endianness::little;
|
||||
|
||||
Data = Data.substr(StringRef(TestingFormatMagic).size());
|
||||
if (Data.size() < 1)
|
||||
return coveragemap_error::truncated;
|
||||
return make_error<CoverageMapError>(coveragemap_error::truncated);
|
||||
unsigned N = 0;
|
||||
auto ProfileNamesSize =
|
||||
decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
|
||||
if (N > Data.size())
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
Data = Data.substr(N);
|
||||
if (Data.size() < 1)
|
||||
return coveragemap_error::truncated;
|
||||
return make_error<CoverageMapError>(coveragemap_error::truncated);
|
||||
N = 0;
|
||||
uint64_t Address =
|
||||
decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
|
||||
if (N > Data.size())
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
Data = Data.substr(N);
|
||||
if (Data.size() < ProfileNamesSize)
|
||||
return coveragemap_error::malformed;
|
||||
ProfileNames.create(Data.substr(0, ProfileNamesSize), Address);
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address))
|
||||
return E;
|
||||
CoverageMapping = Data.substr(ProfileNamesSize);
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static ErrorOr<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) {
|
||||
static Expected<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) {
|
||||
StringRef FoundName;
|
||||
for (const auto &Section : OF.sections()) {
|
||||
if (auto EC = Section.getName(FoundName))
|
||||
return EC;
|
||||
return errorCodeToError(EC);
|
||||
if (FoundName == Name)
|
||||
return Section;
|
||||
}
|
||||
return coveragemap_error::no_data_found;
|
||||
return make_error<CoverageMapError>(coveragemap_error::no_data_found);
|
||||
}
|
||||
|
||||
static std::error_code
|
||||
loadBinaryFormat(MemoryBufferRef ObjectBuffer, InstrProfSymtab &ProfileNames,
|
||||
StringRef &CoverageMapping, uint8_t &BytesInAddress,
|
||||
support::endianness &Endian, StringRef Arch) {
|
||||
static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer,
|
||||
InstrProfSymtab &ProfileNames,
|
||||
StringRef &CoverageMapping,
|
||||
uint8_t &BytesInAddress,
|
||||
support::endianness &Endian, StringRef Arch) {
|
||||
auto BinOrErr = object::createBinary(ObjectBuffer);
|
||||
if (!BinOrErr)
|
||||
return errorToErrorCode(BinOrErr.takeError());
|
||||
return BinOrErr.takeError();
|
||||
auto Bin = std::move(BinOrErr.get());
|
||||
std::unique_ptr<ObjectFile> OF;
|
||||
if (auto *Universal = dyn_cast<object::MachOUniversalBinary>(Bin.get())) {
|
||||
// If we have a universal binary, try to look up the object for the
|
||||
// appropriate architecture.
|
||||
auto ObjectFileOrErr = Universal->getObjectForArch(Arch);
|
||||
if (std::error_code EC = ObjectFileOrErr.getError())
|
||||
return EC;
|
||||
if (auto EC = ObjectFileOrErr.getError())
|
||||
return errorCodeToError(EC);
|
||||
OF = std::move(ObjectFileOrErr.get());
|
||||
} else if (isa<object::ObjectFile>(Bin.get())) {
|
||||
// For any other object file, upcast and take ownership.
|
||||
OF.reset(cast<object::ObjectFile>(Bin.release()));
|
||||
// If we've asked for a particular arch, make sure they match.
|
||||
if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch())
|
||||
return object_error::arch_not_found;
|
||||
return errorCodeToError(object_error::arch_not_found);
|
||||
} else
|
||||
// We can only handle object files.
|
||||
return coveragemap_error::malformed;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
|
||||
// The coverage uses native pointer sizes for the object it's written in.
|
||||
BytesInAddress = OF->getBytesInAddress();
|
||||
@ -538,23 +540,23 @@ loadBinaryFormat(MemoryBufferRef ObjectBuffer, InstrProfSymtab &ProfileNames,
|
||||
|
||||
// Look for the sections that we are interested in.
|
||||
auto NamesSection = lookupSection(*OF, getInstrProfNameSectionName(false));
|
||||
if (auto EC = NamesSection.getError())
|
||||
return EC;
|
||||
if (auto E = NamesSection.takeError())
|
||||
return E;
|
||||
auto CoverageSection =
|
||||
lookupSection(*OF, getInstrProfCoverageSectionName(false));
|
||||
if (auto EC = CoverageSection.getError())
|
||||
return EC;
|
||||
if (auto E = CoverageSection.takeError())
|
||||
return E;
|
||||
|
||||
// Get the contents of the given sections.
|
||||
if (std::error_code EC = CoverageSection->getContents(CoverageMapping))
|
||||
return EC;
|
||||
if (std::error_code EC = ProfileNames.create(*NamesSection))
|
||||
return EC;
|
||||
if (auto EC = CoverageSection->getContents(CoverageMapping))
|
||||
return errorCodeToError(EC);
|
||||
if (Error E = ProfileNames.create(*NamesSection))
|
||||
return E;
|
||||
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<BinaryCoverageReader>>
|
||||
Expected<std::unique_ptr<BinaryCoverageReader>>
|
||||
BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer,
|
||||
StringRef Arch) {
|
||||
std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader());
|
||||
@ -562,44 +564,44 @@ BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer,
|
||||
StringRef Coverage;
|
||||
uint8_t BytesInAddress;
|
||||
support::endianness Endian;
|
||||
std::error_code EC;
|
||||
Error E;
|
||||
consumeError(std::move(E));
|
||||
if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic))
|
||||
// This is a special format used for testing.
|
||||
EC = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames,
|
||||
Coverage, BytesInAddress, Endian);
|
||||
E = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames,
|
||||
Coverage, BytesInAddress, Endian);
|
||||
else
|
||||
EC = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames,
|
||||
Coverage, BytesInAddress, Endian, Arch);
|
||||
if (EC)
|
||||
return EC;
|
||||
E = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames,
|
||||
Coverage, BytesInAddress, Endian, Arch);
|
||||
if (E)
|
||||
return std::move(E);
|
||||
|
||||
if (BytesInAddress == 4 && Endian == support::endianness::little)
|
||||
EC = readCoverageMappingData<uint32_t, support::endianness::little>(
|
||||
E = readCoverageMappingData<uint32_t, support::endianness::little>(
|
||||
Reader->ProfileNames, Coverage, Reader->MappingRecords,
|
||||
Reader->Filenames);
|
||||
else if (BytesInAddress == 4 && Endian == support::endianness::big)
|
||||
EC = readCoverageMappingData<uint32_t, support::endianness::big>(
|
||||
E = readCoverageMappingData<uint32_t, support::endianness::big>(
|
||||
Reader->ProfileNames, Coverage, Reader->MappingRecords,
|
||||
Reader->Filenames);
|
||||
else if (BytesInAddress == 8 && Endian == support::endianness::little)
|
||||
EC = readCoverageMappingData<uint64_t, support::endianness::little>(
|
||||
E = readCoverageMappingData<uint64_t, support::endianness::little>(
|
||||
Reader->ProfileNames, Coverage, Reader->MappingRecords,
|
||||
Reader->Filenames);
|
||||
else if (BytesInAddress == 8 && Endian == support::endianness::big)
|
||||
EC = readCoverageMappingData<uint64_t, support::endianness::big>(
|
||||
E = readCoverageMappingData<uint64_t, support::endianness::big>(
|
||||
Reader->ProfileNames, Coverage, Reader->MappingRecords,
|
||||
Reader->Filenames);
|
||||
else
|
||||
return coveragemap_error::malformed;
|
||||
if (EC)
|
||||
return EC;
|
||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||
if (E)
|
||||
return std::move(E);
|
||||
return std::move(Reader);
|
||||
}
|
||||
|
||||
std::error_code
|
||||
BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
|
||||
Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
|
||||
if (CurrentRecord >= MappingRecords.size())
|
||||
return coveragemap_error::eof;
|
||||
return make_error<CoverageMapError>(coveragemap_error::eof);
|
||||
|
||||
FunctionsFilenames.clear();
|
||||
Expressions.clear();
|
||||
@ -619,5 +621,5 @@ BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
|
||||
Record.MappingRegions = MappingRegions;
|
||||
|
||||
++CurrentRecord;
|
||||
return std::error_code();
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -27,47 +27,50 @@
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
std::string getInstrProfErrString(instrprof_error Err) {
|
||||
switch (Err) {
|
||||
case instrprof_error::success:
|
||||
return "Success";
|
||||
case instrprof_error::eof:
|
||||
return "End of File";
|
||||
case instrprof_error::unrecognized_format:
|
||||
return "Unrecognized instrumentation profile encoding format";
|
||||
case instrprof_error::bad_magic:
|
||||
return "Invalid instrumentation profile data (bad magic)";
|
||||
case instrprof_error::bad_header:
|
||||
return "Invalid instrumentation profile data (file header is corrupt)";
|
||||
case instrprof_error::unsupported_version:
|
||||
return "Unsupported instrumentation profile format version";
|
||||
case instrprof_error::unsupported_hash_type:
|
||||
return "Unsupported instrumentation profile hash type";
|
||||
case instrprof_error::too_large:
|
||||
return "Too much profile data";
|
||||
case instrprof_error::truncated:
|
||||
return "Truncated profile data";
|
||||
case instrprof_error::malformed:
|
||||
return "Malformed instrumentation profile data";
|
||||
case instrprof_error::unknown_function:
|
||||
return "No profile data available for function";
|
||||
case instrprof_error::hash_mismatch:
|
||||
return "Function control flow change detected (hash mismatch)";
|
||||
case instrprof_error::count_mismatch:
|
||||
return "Function basic block count change detected (counter mismatch)";
|
||||
case instrprof_error::counter_overflow:
|
||||
return "Counter overflow";
|
||||
case instrprof_error::value_site_count_mismatch:
|
||||
return "Function value site count change detected (counter mismatch)";
|
||||
case instrprof_error::compress_failed:
|
||||
return "Failed to compress data (zlib)";
|
||||
case instrprof_error::uncompress_failed:
|
||||
return "Failed to uncompress data (zlib)";
|
||||
}
|
||||
llvm_unreachable("A value of instrprof_error has no message.");
|
||||
}
|
||||
|
||||
class InstrProfErrorCategoryType : public std::error_category {
|
||||
const char *name() const LLVM_NOEXCEPT override { return "llvm.instrprof"; }
|
||||
std::string message(int IE) const override {
|
||||
instrprof_error E = static_cast<instrprof_error>(IE);
|
||||
switch (E) {
|
||||
case instrprof_error::success:
|
||||
return "Success";
|
||||
case instrprof_error::eof:
|
||||
return "End of File";
|
||||
case instrprof_error::unrecognized_format:
|
||||
return "Unrecognized instrumentation profile encoding format";
|
||||
case instrprof_error::bad_magic:
|
||||
return "Invalid instrumentation profile data (bad magic)";
|
||||
case instrprof_error::bad_header:
|
||||
return "Invalid instrumentation profile data (file header is corrupt)";
|
||||
case instrprof_error::unsupported_version:
|
||||
return "Unsupported instrumentation profile format version";
|
||||
case instrprof_error::unsupported_hash_type:
|
||||
return "Unsupported instrumentation profile hash type";
|
||||
case instrprof_error::too_large:
|
||||
return "Too much profile data";
|
||||
case instrprof_error::truncated:
|
||||
return "Truncated profile data";
|
||||
case instrprof_error::malformed:
|
||||
return "Malformed instrumentation profile data";
|
||||
case instrprof_error::unknown_function:
|
||||
return "No profile data available for function";
|
||||
case instrprof_error::hash_mismatch:
|
||||
return "Function control flow change detected (hash mismatch)";
|
||||
case instrprof_error::count_mismatch:
|
||||
return "Function basic block count change detected (counter mismatch)";
|
||||
case instrprof_error::counter_overflow:
|
||||
return "Counter overflow";
|
||||
case instrprof_error::value_site_count_mismatch:
|
||||
return "Function value site count change detected (counter mismatch)";
|
||||
case instrprof_error::compress_failed:
|
||||
return "Failed to compress data (zlib)";
|
||||
case instrprof_error::uncompress_failed:
|
||||
return "Failed to uncompress data (zlib)";
|
||||
}
|
||||
llvm_unreachable("A value of instrprof_error has no message.");
|
||||
return getInstrProfErrString(static_cast<instrprof_error>(IE));
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -105,6 +108,12 @@ void SoftInstrProfErrors::addError(instrprof_error IE) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string InstrProfError::message() const {
|
||||
return getInstrProfErrString(Err);
|
||||
}
|
||||
|
||||
template <> char ProfErrorInfoBase<instrprof_error>::ID = 0;
|
||||
|
||||
std::string getPGOFuncName(StringRef RawFuncName,
|
||||
GlobalValue::LinkageTypes Linkage,
|
||||
StringRef FileName,
|
||||
@ -214,9 +223,8 @@ void InstrProfSymtab::create(Module &M, bool InLTO) {
|
||||
finalizeSymtab();
|
||||
}
|
||||
|
||||
std::error_code
|
||||
collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
|
||||
bool doCompression, std::string &Result) {
|
||||
Error collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
|
||||
bool doCompression, std::string &Result) {
|
||||
assert(NameStrs.size() && "No name data to emit");
|
||||
|
||||
uint8_t Header[16], *P = Header;
|
||||
@ -238,11 +246,12 @@ collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
|
||||
unsigned HeaderLen = P - &Header[0];
|
||||
Result.append(HeaderStr, HeaderLen);
|
||||
Result += InputStr;
|
||||
return make_error_code(instrprof_error::success);
|
||||
return Error::success();
|
||||
};
|
||||
|
||||
if (!doCompression)
|
||||
if (!doCompression) {
|
||||
return WriteStringToResult(0, UncompressedNameStrings);
|
||||
}
|
||||
|
||||
SmallVector<char, 128> CompressedNameStrings;
|
||||
zlib::Status Success =
|
||||
@ -250,7 +259,7 @@ collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
|
||||
zlib::BestSizeCompression);
|
||||
|
||||
if (Success != zlib::StatusOK)
|
||||
return make_error_code(instrprof_error::compress_failed);
|
||||
return make_error<InstrProfError>(instrprof_error::compress_failed);
|
||||
|
||||
return WriteStringToResult(
|
||||
CompressedNameStrings.size(),
|
||||
@ -264,9 +273,8 @@ StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar) {
|
||||
return NameStr;
|
||||
}
|
||||
|
||||
std::error_code
|
||||
collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars,
|
||||
std::string &Result, bool doCompression) {
|
||||
Error collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars,
|
||||
std::string &Result, bool doCompression) {
|
||||
std::vector<std::string> NameStrs;
|
||||
for (auto *NameVar : NameVars) {
|
||||
NameStrs.push_back(getPGOFuncNameVarInitializer(NameVar));
|
||||
@ -275,8 +283,7 @@ collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars,
|
||||
NameStrs, zlib::isAvailable() && doCompression, Result);
|
||||
}
|
||||
|
||||
std::error_code readPGOFuncNameStrings(StringRef NameStrings,
|
||||
InstrProfSymtab &Symtab) {
|
||||
Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) {
|
||||
const uint8_t *P = reinterpret_cast<const uint8_t *>(NameStrings.data());
|
||||
const uint8_t *EndP = reinterpret_cast<const uint8_t *>(NameStrings.data() +
|
||||
NameStrings.size());
|
||||
@ -294,7 +301,7 @@ std::error_code readPGOFuncNameStrings(StringRef NameStrings,
|
||||
CompressedSize);
|
||||
if (zlib::uncompress(CompressedNameStrings, UncompressedNameStrings,
|
||||
UncompressedSize) != zlib::StatusOK)
|
||||
return make_error_code(instrprof_error::uncompress_failed);
|
||||
return make_error<InstrProfError>(instrprof_error::uncompress_failed);
|
||||
P += CompressedSize;
|
||||
NameStrings = StringRef(UncompressedNameStrings.data(),
|
||||
UncompressedNameStrings.size());
|
||||
@ -313,7 +320,7 @@ std::error_code readPGOFuncNameStrings(StringRef NameStrings,
|
||||
P++;
|
||||
}
|
||||
Symtab.finalizeSymtab();
|
||||
return make_error_code(instrprof_error::success);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void InstrProfValueSiteRecord::merge(SoftInstrProfErrors &SIPE,
|
||||
@ -577,45 +584,45 @@ static std::unique_ptr<ValueProfData> allocValueProfData(uint32_t TotalSize) {
|
||||
ValueProfData());
|
||||
}
|
||||
|
||||
instrprof_error ValueProfData::checkIntegrity() {
|
||||
Error ValueProfData::checkIntegrity() {
|
||||
if (NumValueKinds > IPVK_Last + 1)
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
// Total size needs to be mulltiple of quadword size.
|
||||
if (TotalSize % sizeof(uint64_t))
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
|
||||
ValueProfRecord *VR = getFirstValueProfRecord(this);
|
||||
for (uint32_t K = 0; K < this->NumValueKinds; K++) {
|
||||
if (VR->Kind > IPVK_Last)
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
VR = getValueProfRecordNext(VR);
|
||||
if ((char *)VR - (char *)this > (ptrdiff_t)TotalSize)
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
}
|
||||
return instrprof_error::success;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<ValueProfData>>
|
||||
Expected<std::unique_ptr<ValueProfData>>
|
||||
ValueProfData::getValueProfData(const unsigned char *D,
|
||||
const unsigned char *const BufferEnd,
|
||||
support::endianness Endianness) {
|
||||
using namespace support;
|
||||
if (D + sizeof(ValueProfData) > BufferEnd)
|
||||
return instrprof_error::truncated;
|
||||
return make_error<InstrProfError>(instrprof_error::truncated);
|
||||
|
||||
const unsigned char *Header = D;
|
||||
uint32_t TotalSize = swapToHostOrder<uint32_t>(Header, Endianness);
|
||||
if (D + TotalSize > BufferEnd)
|
||||
return instrprof_error::too_large;
|
||||
return make_error<InstrProfError>(instrprof_error::too_large);
|
||||
|
||||
std::unique_ptr<ValueProfData> VPD = allocValueProfData(TotalSize);
|
||||
memcpy(VPD.get(), D, TotalSize);
|
||||
// Byte swap.
|
||||
VPD->swapBytesToHost(Endianness);
|
||||
|
||||
instrprof_error EC = VPD->checkIntegrity();
|
||||
if (EC != instrprof_error::success)
|
||||
return EC;
|
||||
Error E = VPD->checkIntegrity();
|
||||
if (E)
|
||||
return std::move(E);
|
||||
|
||||
return std::move(VPD);
|
||||
}
|
||||
|
@ -18,33 +18,33 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
static Expected<std::unique_ptr<MemoryBuffer>>
|
||||
setupMemoryBuffer(std::string Path) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(Path);
|
||||
if (std::error_code EC = BufferOrErr.getError())
|
||||
return EC;
|
||||
return errorCodeToError(EC);
|
||||
return std::move(BufferOrErr.get());
|
||||
}
|
||||
|
||||
static std::error_code initializeReader(InstrProfReader &Reader) {
|
||||
static Error initializeReader(InstrProfReader &Reader) {
|
||||
return Reader.readHeader();
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<InstrProfReader>>
|
||||
Expected<std::unique_ptr<InstrProfReader>>
|
||||
InstrProfReader::create(std::string Path) {
|
||||
// Set up the buffer to read.
|
||||
auto BufferOrError = setupMemoryBuffer(Path);
|
||||
if (std::error_code EC = BufferOrError.getError())
|
||||
return EC;
|
||||
if (Error E = BufferOrError.takeError())
|
||||
return std::move(E);
|
||||
return InstrProfReader::create(std::move(BufferOrError.get()));
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<InstrProfReader>>
|
||||
Expected<std::unique_ptr<InstrProfReader>>
|
||||
InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
|
||||
// Sanity check the buffer.
|
||||
if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
|
||||
return instrprof_error::too_large;
|
||||
return make_error<InstrProfError>(instrprof_error::too_large);
|
||||
|
||||
std::unique_ptr<InstrProfReader> Result;
|
||||
// Create the reader.
|
||||
@ -57,46 +57,49 @@ InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
|
||||
else if (TextInstrProfReader::hasFormat(*Buffer))
|
||||
Result.reset(new TextInstrProfReader(std::move(Buffer)));
|
||||
else
|
||||
return instrprof_error::unrecognized_format;
|
||||
return make_error<InstrProfError>(instrprof_error::unrecognized_format);
|
||||
|
||||
// Initialize the reader and return the result.
|
||||
if (std::error_code EC = initializeReader(*Result))
|
||||
return EC;
|
||||
if (Error E = initializeReader(*Result))
|
||||
return std::move(E);
|
||||
|
||||
return std::move(Result);
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
|
||||
Expected<std::unique_ptr<IndexedInstrProfReader>>
|
||||
IndexedInstrProfReader::create(std::string Path) {
|
||||
// Set up the buffer to read.
|
||||
auto BufferOrError = setupMemoryBuffer(Path);
|
||||
if (std::error_code EC = BufferOrError.getError())
|
||||
return EC;
|
||||
if (Error E = BufferOrError.takeError())
|
||||
return std::move(E);
|
||||
return IndexedInstrProfReader::create(std::move(BufferOrError.get()));
|
||||
}
|
||||
|
||||
|
||||
ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
|
||||
Expected<std::unique_ptr<IndexedInstrProfReader>>
|
||||
IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
|
||||
// Sanity check the buffer.
|
||||
if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
|
||||
return instrprof_error::too_large;
|
||||
return make_error<InstrProfError>(instrprof_error::too_large);
|
||||
|
||||
// Create the reader.
|
||||
if (!IndexedInstrProfReader::hasFormat(*Buffer))
|
||||
return instrprof_error::bad_magic;
|
||||
return make_error<InstrProfError>(instrprof_error::bad_magic);
|
||||
auto Result = llvm::make_unique<IndexedInstrProfReader>(std::move(Buffer));
|
||||
|
||||
// Initialize the reader and return the result.
|
||||
if (std::error_code EC = initializeReader(*Result))
|
||||
return EC;
|
||||
if (Error E = initializeReader(*Result))
|
||||
return std::move(E);
|
||||
|
||||
return std::move(Result);
|
||||
}
|
||||
|
||||
void InstrProfIterator::Increment() {
|
||||
if (Reader->readNextRecord(Record))
|
||||
if (auto E = Reader->readNextRecord(Record)) {
|
||||
// Handle errors in the reader.
|
||||
InstrProfError::take(std::move(E));
|
||||
*this = InstrProfIterator();
|
||||
}
|
||||
}
|
||||
|
||||
bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
|
||||
@ -112,7 +115,7 @@ bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
|
||||
// Read the profile variant flag from the header: ":FE" means this is a FE
|
||||
// generated profile. ":IR" means this is an IR level profile. Other strings
|
||||
// with a leading ':' will be reported an error format.
|
||||
std::error_code TextInstrProfReader::readHeader() {
|
||||
Error TextInstrProfReader::readHeader() {
|
||||
Symtab.reset(new InstrProfSymtab());
|
||||
bool IsIRInstr = false;
|
||||
if (!Line->startswith(":")) {
|
||||
@ -125,14 +128,14 @@ std::error_code TextInstrProfReader::readHeader() {
|
||||
else if (Str.equals_lower("fe"))
|
||||
IsIRInstr = false;
|
||||
else
|
||||
return instrprof_error::bad_header;
|
||||
return error(instrprof_error::bad_header);
|
||||
|
||||
++Line;
|
||||
IsIRLevelProfile = IsIRInstr;
|
||||
return success();
|
||||
}
|
||||
|
||||
std::error_code
|
||||
Error
|
||||
TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
|
||||
|
||||
#define CHECK_LINE_END(Line) \
|
||||
@ -196,7 +199,7 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
|
||||
#undef VP_READ_ADVANCE
|
||||
}
|
||||
|
||||
std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
|
||||
Error TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
|
||||
// Skip empty lines and comments.
|
||||
while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
|
||||
++Line;
|
||||
@ -238,8 +241,8 @@ std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
|
||||
}
|
||||
|
||||
// Check if value profile data exists and read it if so.
|
||||
if (std::error_code EC = readValueProfileData(Record))
|
||||
return EC;
|
||||
if (Error E = readValueProfileData(Record))
|
||||
return E;
|
||||
|
||||
// This is needed to avoid two pass parsing because llvm-profdata
|
||||
// does dumping while reading.
|
||||
@ -258,7 +261,7 @@ bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
|
||||
Error RawInstrProfReader<IntPtrT>::readHeader() {
|
||||
if (!hasFormat(*DataBuffer))
|
||||
return error(instrprof_error::bad_magic);
|
||||
if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header))
|
||||
@ -270,26 +273,25 @@ std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code
|
||||
RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
|
||||
Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
|
||||
const char *End = DataBuffer->getBufferEnd();
|
||||
// Skip zero padding between profiles.
|
||||
while (CurrentPos != End && *CurrentPos == 0)
|
||||
++CurrentPos;
|
||||
// If there's nothing left, we're done.
|
||||
if (CurrentPos == End)
|
||||
return instrprof_error::eof;
|
||||
return make_error<InstrProfError>(instrprof_error::eof);
|
||||
// If there isn't enough space for another header, this is probably just
|
||||
// garbage at the end of the file.
|
||||
if (CurrentPos + sizeof(RawInstrProf::Header) > End)
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
// The writer ensures each profile is padded to start at an aligned address.
|
||||
if (reinterpret_cast<size_t>(CurrentPos) % alignOf<uint64_t>())
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
// The magic should have the same byte order as in the previous header.
|
||||
uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
|
||||
if (Magic != swap(RawInstrProf::getMagic<IntPtrT>()))
|
||||
return instrprof_error::bad_magic;
|
||||
return make_error<InstrProfError>(instrprof_error::bad_magic);
|
||||
|
||||
// There's another profile to read, so we need to process the header.
|
||||
auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos);
|
||||
@ -297,11 +299,9 @@ RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code
|
||||
RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
|
||||
std::error_code EC = Symtab.create(StringRef(NamesStart, NamesSize));
|
||||
if (EC)
|
||||
return EC;
|
||||
Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
|
||||
if (Error E = Symtab.create(StringRef(NamesStart, NamesSize)))
|
||||
return error(std::move(E));
|
||||
for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
|
||||
const IntPtrT FPtr = swap(I->FunctionPointer);
|
||||
if (!FPtr)
|
||||
@ -313,8 +313,8 @@ RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code
|
||||
RawInstrProfReader<IntPtrT>::readHeader(const RawInstrProf::Header &Header) {
|
||||
Error RawInstrProfReader<IntPtrT>::readHeader(
|
||||
const RawInstrProf::Header &Header) {
|
||||
Version = swap(Header.Version);
|
||||
if (GET_VERSION(Version) != RawInstrProf::Version)
|
||||
return error(instrprof_error::unsupported_version);
|
||||
@ -346,28 +346,27 @@ RawInstrProfReader<IntPtrT>::readHeader(const RawInstrProf::Header &Header) {
|
||||
ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
|
||||
|
||||
std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>();
|
||||
if (auto EC = createSymtab(*NewSymtab.get()))
|
||||
return EC;
|
||||
if (Error E = createSymtab(*NewSymtab.get()))
|
||||
return E;
|
||||
|
||||
Symtab = std::move(NewSymtab);
|
||||
return success();
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code RawInstrProfReader<IntPtrT>::readName(InstrProfRecord &Record) {
|
||||
Error RawInstrProfReader<IntPtrT>::readName(InstrProfRecord &Record) {
|
||||
Record.Name = getName(Data->NameRef);
|
||||
return success();
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code RawInstrProfReader<IntPtrT>::readFuncHash(
|
||||
InstrProfRecord &Record) {
|
||||
Error RawInstrProfReader<IntPtrT>::readFuncHash(InstrProfRecord &Record) {
|
||||
Record.Hash = swap(Data->FuncHash);
|
||||
return success();
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code RawInstrProfReader<IntPtrT>::readRawCounts(
|
||||
Error RawInstrProfReader<IntPtrT>::readRawCounts(
|
||||
InstrProfRecord &Record) {
|
||||
uint32_t NumCounters = swap(Data->NumCounters);
|
||||
IntPtrT CounterPtr = Data->CounterPtr;
|
||||
@ -394,8 +393,8 @@ std::error_code RawInstrProfReader<IntPtrT>::readRawCounts(
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code
|
||||
RawInstrProfReader<IntPtrT>::readValueProfilingData(InstrProfRecord &Record) {
|
||||
Error RawInstrProfReader<IntPtrT>::readValueProfilingData(
|
||||
InstrProfRecord &Record) {
|
||||
|
||||
Record.clearValueData();
|
||||
CurValueDataSize = 0;
|
||||
@ -407,13 +406,13 @@ RawInstrProfReader<IntPtrT>::readValueProfilingData(InstrProfRecord &Record) {
|
||||
if (!NumValueKinds)
|
||||
return success();
|
||||
|
||||
ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
|
||||
Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
|
||||
ValueProfData::getValueProfData(
|
||||
ValueDataStart, (const unsigned char *)DataBuffer->getBufferEnd(),
|
||||
getDataEndianness());
|
||||
|
||||
if (VDataPtrOrErr.getError())
|
||||
return VDataPtrOrErr.getError();
|
||||
if (Error E = VDataPtrOrErr.takeError())
|
||||
return E;
|
||||
|
||||
// Note that besides deserialization, this also performs the conversion for
|
||||
// indirect call targets. The function pointers from the raw profile are
|
||||
@ -424,28 +423,27 @@ RawInstrProfReader<IntPtrT>::readValueProfilingData(InstrProfRecord &Record) {
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
std::error_code
|
||||
RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
|
||||
Error RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
|
||||
if (atEnd())
|
||||
// At this point, ValueDataStart field points to the next header.
|
||||
if (std::error_code EC = readNextHeader(getNextHeaderPos()))
|
||||
return EC;
|
||||
if (Error E = readNextHeader(getNextHeaderPos()))
|
||||
return E;
|
||||
|
||||
// Read name ad set it in Record.
|
||||
if (std::error_code EC = readName(Record))
|
||||
return EC;
|
||||
if (Error E = readName(Record))
|
||||
return E;
|
||||
|
||||
// Read FuncHash and set it in Record.
|
||||
if (std::error_code EC = readFuncHash(Record))
|
||||
return EC;
|
||||
if (Error E = readFuncHash(Record))
|
||||
return E;
|
||||
|
||||
// Read raw counts and set Record.
|
||||
if (std::error_code EC = readRawCounts(Record))
|
||||
return EC;
|
||||
if (Error E = readRawCounts(Record))
|
||||
return E;
|
||||
|
||||
// Read value data and set Record.
|
||||
if (std::error_code EC = readValueProfilingData(Record))
|
||||
return EC;
|
||||
if (Error E = readValueProfilingData(Record))
|
||||
return E;
|
||||
|
||||
// Iterate.
|
||||
advanceData();
|
||||
@ -467,10 +465,10 @@ typedef InstrProfLookupTrait::offset_type offset_type;
|
||||
|
||||
bool InstrProfLookupTrait::readValueProfilingData(
|
||||
const unsigned char *&D, const unsigned char *const End) {
|
||||
ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
|
||||
Expected<std::unique_ptr<ValueProfData>> VDataPtrOrErr =
|
||||
ValueProfData::getValueProfData(D, End, ValueProfDataEndianness);
|
||||
|
||||
if (VDataPtrOrErr.getError())
|
||||
if (VDataPtrOrErr.takeError())
|
||||
return false;
|
||||
|
||||
VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr);
|
||||
@ -526,31 +524,31 @@ data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
|
||||
}
|
||||
|
||||
template <typename HashTableImpl>
|
||||
std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
|
||||
Error InstrProfReaderIndex<HashTableImpl>::getRecords(
|
||||
StringRef FuncName, ArrayRef<InstrProfRecord> &Data) {
|
||||
auto Iter = HashTable->find(FuncName);
|
||||
if (Iter == HashTable->end())
|
||||
return instrprof_error::unknown_function;
|
||||
return make_error<InstrProfError>(instrprof_error::unknown_function);
|
||||
|
||||
Data = (*Iter);
|
||||
if (Data.empty())
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
|
||||
return instrprof_error::success;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
template <typename HashTableImpl>
|
||||
std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords(
|
||||
Error InstrProfReaderIndex<HashTableImpl>::getRecords(
|
||||
ArrayRef<InstrProfRecord> &Data) {
|
||||
if (atEnd())
|
||||
return instrprof_error::eof;
|
||||
return make_error<InstrProfError>(instrprof_error::eof);
|
||||
|
||||
Data = *RecordIterator;
|
||||
|
||||
if (Data.empty())
|
||||
return instrprof_error::malformed;
|
||||
return make_error<InstrProfError>(instrprof_error::malformed);
|
||||
|
||||
return instrprof_error::success;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
template <typename HashTableImpl>
|
||||
@ -609,7 +607,7 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version,
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code IndexedInstrProfReader::readHeader() {
|
||||
Error IndexedInstrProfReader::readHeader() {
|
||||
const unsigned char *Start =
|
||||
(const unsigned char *)DataBuffer->getBufferStart();
|
||||
const unsigned char *Cur = Start;
|
||||
@ -661,13 +659,13 @@ InstrProfSymtab &IndexedInstrProfReader::getSymtab() {
|
||||
return *Symtab.get();
|
||||
}
|
||||
|
||||
ErrorOr<InstrProfRecord>
|
||||
Expected<InstrProfRecord>
|
||||
IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName,
|
||||
uint64_t FuncHash) {
|
||||
ArrayRef<InstrProfRecord> Data;
|
||||
std::error_code EC = Index->getRecords(FuncName, Data);
|
||||
if (EC != instrprof_error::success)
|
||||
return EC;
|
||||
Error Err = Index->getRecords(FuncName, Data);
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
// Found it. Look for counters with the right hash.
|
||||
for (unsigned I = 0, E = Data.size(); I < E; ++I) {
|
||||
// Check for a match and fill the vector if there is one.
|
||||
@ -678,26 +676,25 @@ IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName,
|
||||
return error(instrprof_error::hash_mismatch);
|
||||
}
|
||||
|
||||
std::error_code
|
||||
IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
|
||||
std::vector<uint64_t> &Counts) {
|
||||
ErrorOr<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
|
||||
if (std::error_code EC = Record.getError())
|
||||
return EC;
|
||||
Error IndexedInstrProfReader::getFunctionCounts(StringRef FuncName,
|
||||
uint64_t FuncHash,
|
||||
std::vector<uint64_t> &Counts) {
|
||||
Expected<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
|
||||
if (Error E = Record.takeError())
|
||||
return error(std::move(E));
|
||||
|
||||
Counts = Record.get().Counts;
|
||||
return success();
|
||||
}
|
||||
|
||||
std::error_code IndexedInstrProfReader::readNextRecord(
|
||||
InstrProfRecord &Record) {
|
||||
Error IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
|
||||
static unsigned RecordIndex = 0;
|
||||
|
||||
ArrayRef<InstrProfRecord> Data;
|
||||
|
||||
std::error_code EC = Index->getRecords(Data);
|
||||
if (EC != instrprof_error::success)
|
||||
return error(EC);
|
||||
Error E = Index->getRecords(Data);
|
||||
if (E)
|
||||
return error(std::move(E));
|
||||
|
||||
Record = Data[RecordIndex++];
|
||||
if (RecordIndex >= Data.size()) {
|
||||
|
@ -156,8 +156,7 @@ void InstrProfWriter::setOutputSparse(bool Sparse) {
|
||||
this->Sparse = Sparse;
|
||||
}
|
||||
|
||||
std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
|
||||
uint64_t Weight) {
|
||||
Error InstrProfWriter::addRecord(InstrProfRecord &&I, uint64_t Weight) {
|
||||
auto &ProfileDataMap = FunctionData[I.Name];
|
||||
|
||||
bool NewFunc;
|
||||
@ -180,7 +179,7 @@ std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
|
||||
|
||||
Dest.sortValueData();
|
||||
|
||||
return Dest.getError();
|
||||
return Dest.takeError();
|
||||
}
|
||||
|
||||
bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) {
|
||||
|
@ -374,9 +374,9 @@ void InstrProfiling::emitNameData() {
|
||||
return;
|
||||
|
||||
std::string CompressedNameStr;
|
||||
if (auto EC = collectPGOFuncNameStrings(ReferencedNames, CompressedNameStr,
|
||||
if (Error E = collectPGOFuncNameStrings(ReferencedNames, CompressedNameStr,
|
||||
DoNameCompression)) {
|
||||
llvm::report_fatal_error(EC.message(), false);
|
||||
llvm::report_fatal_error(toString(std::move(E)), false);
|
||||
}
|
||||
|
||||
auto &Ctx = M->getContext();
|
||||
|
@ -582,23 +582,28 @@ void PGOUseFunc::setEdgeCount(DirectEdges &Edges, uint64_t Value) {
|
||||
// Return true if the profile are successfully read, and false on errors.
|
||||
bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader) {
|
||||
auto &Ctx = M->getContext();
|
||||
ErrorOr<InstrProfRecord> Result =
|
||||
Expected<InstrProfRecord> Result =
|
||||
PGOReader->getInstrProfRecord(FuncInfo.FuncName, FuncInfo.FunctionHash);
|
||||
if (std::error_code EC = Result.getError()) {
|
||||
if (EC == instrprof_error::unknown_function) {
|
||||
NumOfPGOMissing++;
|
||||
if (NoPGOWarnMissing)
|
||||
return false;
|
||||
} else if (EC == instrprof_error::hash_mismatch ||
|
||||
EC == llvm::instrprof_error::malformed) {
|
||||
NumOfPGOMismatch++;
|
||||
if (NoPGOWarnMismatch)
|
||||
return false;
|
||||
}
|
||||
if (Error E = Result.takeError()) {
|
||||
handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
|
||||
auto Err = IPE.get();
|
||||
bool SkipWarning = false;
|
||||
if (Err == instrprof_error::unknown_function) {
|
||||
NumOfPGOMissing++;
|
||||
SkipWarning = NoPGOWarnMissing;
|
||||
} else if (Err == instrprof_error::hash_mismatch ||
|
||||
Err == instrprof_error::malformed) {
|
||||
NumOfPGOMismatch++;
|
||||
SkipWarning = NoPGOWarnMismatch;
|
||||
}
|
||||
|
||||
std::string Msg = EC.message() + std::string(" ") + F.getName().str();
|
||||
Ctx.diagnose(
|
||||
DiagnosticInfoPGOProfile(M->getName().data(), Msg, DS_Warning));
|
||||
if (SkipWarning)
|
||||
return;
|
||||
|
||||
std::string Msg = IPE.message() + std::string(" ") + F.getName().str();
|
||||
Ctx.diagnose(
|
||||
DiagnosticInfoPGOProfile(M->getName().data(), Msg, DS_Warning));
|
||||
});
|
||||
return false;
|
||||
}
|
||||
ProfileRecord = std::move(Result.get());
|
||||
@ -854,9 +859,11 @@ static bool annotateAllFunctions(
|
||||
auto &Ctx = M.getContext();
|
||||
// Read the counter array from file.
|
||||
auto ReaderOrErr = IndexedInstrProfReader::create(ProfileFileName);
|
||||
if (std::error_code EC = ReaderOrErr.getError()) {
|
||||
Ctx.diagnose(
|
||||
DiagnosticInfoPGOProfile(ProfileFileName.data(), EC.message()));
|
||||
if (Error E = ReaderOrErr.takeError()) {
|
||||
handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
|
||||
Ctx.diagnose(
|
||||
DiagnosticInfoPGOProfile(ProfileFileName.data(), EI.message()));
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -210,10 +210,9 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
|
||||
errs() << "warning: profile data may be out of date - object is newer\n";
|
||||
auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename,
|
||||
CoverageArch);
|
||||
if (std::error_code EC = CoverageOrErr.getError()) {
|
||||
if (Error E = CoverageOrErr.takeError()) {
|
||||
colored_ostream(errs(), raw_ostream::RED)
|
||||
<< "error: Failed to load coverage: " << EC.message();
|
||||
errs() << "\n";
|
||||
<< "error: Failed to load coverage: " << toString(std::move(E)) << "\n";
|
||||
return nullptr;
|
||||
}
|
||||
auto Coverage = std::move(CoverageOrErr.get());
|
||||
|
@ -47,38 +47,50 @@ static void exitWithError(const Twine &Message, StringRef Whence = "",
|
||||
::exit(1);
|
||||
}
|
||||
|
||||
static void exitWithErrorCode(const std::error_code &Error,
|
||||
StringRef Whence = "") {
|
||||
if (Error.category() == instrprof_category()) {
|
||||
instrprof_error instrError = static_cast<instrprof_error>(Error.value());
|
||||
if (instrError == instrprof_error::unrecognized_format) {
|
||||
// Hint for common error of forgetting -sample for sample profiles.
|
||||
exitWithError(Error.message(), Whence,
|
||||
"Perhaps you forgot to use the -sample option?");
|
||||
}
|
||||
static void exitWithError(Error E, StringRef Whence = "") {
|
||||
if (E.isA<InstrProfError>()) {
|
||||
handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
|
||||
instrprof_error instrError = IPE.get();
|
||||
StringRef Hint = "";
|
||||
if (instrError == instrprof_error::unrecognized_format) {
|
||||
// Hint for common error of forgetting -sample for sample profiles.
|
||||
Hint = "Perhaps you forgot to use the -sample option?";
|
||||
}
|
||||
exitWithError(IPE.message(), Whence, Hint);
|
||||
});
|
||||
}
|
||||
exitWithError(Error.message(), Whence);
|
||||
|
||||
exitWithError(toString(std::move(E)), Whence);
|
||||
}
|
||||
|
||||
static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {
|
||||
exitWithError(EC.message(), Whence);
|
||||
}
|
||||
|
||||
namespace {
|
||||
enum ProfileKinds { instr, sample };
|
||||
}
|
||||
|
||||
static void handleMergeWriterError(std::error_code &Error,
|
||||
StringRef WhenceFile = "",
|
||||
static void handleMergeWriterError(Error E, StringRef WhenceFile = "",
|
||||
StringRef WhenceFunction = "",
|
||||
bool ShowHint = true) {
|
||||
if (!WhenceFile.empty())
|
||||
errs() << WhenceFile << ": ";
|
||||
if (!WhenceFunction.empty())
|
||||
errs() << WhenceFunction << ": ";
|
||||
errs() << Error.message() << "\n";
|
||||
|
||||
auto IPE = instrprof_error::success;
|
||||
E = handleErrors(std::move(E),
|
||||
[&IPE](std::unique_ptr<InstrProfError> E) -> Error {
|
||||
IPE = E->get();
|
||||
return Error(std::move(E));
|
||||
});
|
||||
errs() << toString(std::move(E)) << "\n";
|
||||
|
||||
if (ShowHint) {
|
||||
StringRef Hint = "";
|
||||
if (Error.category() == instrprof_category()) {
|
||||
instrprof_error instrError = static_cast<instrprof_error>(Error.value());
|
||||
switch (instrError) {
|
||||
if (IPE != instrprof_error::success) {
|
||||
switch (IPE) {
|
||||
case instrprof_error::hash_mismatch:
|
||||
case instrprof_error::count_mismatch:
|
||||
case instrprof_error::value_site_count_mismatch:
|
||||
@ -120,11 +132,11 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
|
||||
exitWithErrorCode(EC, OutputFilename);
|
||||
|
||||
InstrProfWriter Writer(OutputSparse);
|
||||
SmallSet<std::error_code, 4> WriterErrorCodes;
|
||||
SmallSet<instrprof_error, 4> WriterErrorCodes;
|
||||
for (const auto &Input : Inputs) {
|
||||
auto ReaderOrErr = InstrProfReader::create(Input.Filename);
|
||||
if (std::error_code ec = ReaderOrErr.getError())
|
||||
exitWithErrorCode(ec, Input.Filename);
|
||||
if (Error E = ReaderOrErr.takeError())
|
||||
exitWithError(std::move(E), Input.Filename);
|
||||
|
||||
auto Reader = std::move(ReaderOrErr.get());
|
||||
bool IsIRProfile = Reader->isIRLevelProfile();
|
||||
@ -132,14 +144,16 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
|
||||
exitWithError("Merge IR generated profile with Clang generated profile.");
|
||||
|
||||
for (auto &I : *Reader) {
|
||||
if (std::error_code EC = Writer.addRecord(std::move(I), Input.Weight)) {
|
||||
if (Error E = Writer.addRecord(std::move(I), Input.Weight)) {
|
||||
// Only show hint the first time an error occurs.
|
||||
bool firstTime = WriterErrorCodes.insert(EC).second;
|
||||
handleMergeWriterError(EC, Input.Filename, I.Name, firstTime);
|
||||
instrprof_error IPE = InstrProfError::take(std::move(E));
|
||||
bool firstTime = WriterErrorCodes.insert(IPE).second;
|
||||
handleMergeWriterError(make_error<InstrProfError>(IPE), Input.Filename,
|
||||
I.Name, firstTime);
|
||||
}
|
||||
}
|
||||
if (Reader->hasError())
|
||||
exitWithErrorCode(Reader->getError(), Input.Filename);
|
||||
exitWithError(Reader->getError(), Input.Filename);
|
||||
}
|
||||
if (OutputFormat == PF_Text)
|
||||
Writer.writeText(Output);
|
||||
@ -187,7 +201,7 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs,
|
||||
sampleprof_error Result = ProfileMap[FName].merge(Samples, Input.Weight);
|
||||
if (Result != sampleprof_error::success) {
|
||||
std::error_code EC = make_error_code(Result);
|
||||
handleMergeWriterError(EC, Input.Filename, FName);
|
||||
handleMergeWriterError(errorCodeToError(EC), Input.Filename, FName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -268,8 +282,8 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
|
||||
Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990};
|
||||
}
|
||||
InstrProfSummary PS(Cutoffs);
|
||||
if (std::error_code EC = ReaderOrErr.getError())
|
||||
exitWithErrorCode(EC, Filename);
|
||||
if (Error E = ReaderOrErr.takeError())
|
||||
exitWithError(std::move(E), Filename);
|
||||
|
||||
auto Reader = std::move(ReaderOrErr.get());
|
||||
bool IsIRInstr = Reader->isIRLevelProfile();
|
||||
@ -335,7 +349,7 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
|
||||
}
|
||||
|
||||
if (Reader->hasError())
|
||||
exitWithErrorCode(Reader->getError(), Filename);
|
||||
exitWithError(Reader->getError(), Filename);
|
||||
|
||||
if (ShowCounts && TextFormat)
|
||||
return 0;
|
||||
|
@ -20,11 +20,11 @@
|
||||
using namespace llvm;
|
||||
using namespace coverage;
|
||||
|
||||
static ::testing::AssertionResult NoError(std::error_code EC) {
|
||||
if (!EC)
|
||||
static ::testing::AssertionResult NoError(Error E) {
|
||||
if (!E)
|
||||
return ::testing::AssertionSuccess();
|
||||
return ::testing::AssertionFailure() << "error " << EC.value()
|
||||
<< ": " << EC.message();
|
||||
return ::testing::AssertionFailure() << "error: " << toString(std::move(E))
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
@ -70,14 +70,14 @@ struct CoverageMappingReaderMock : CoverageMappingReader {
|
||||
CoverageMappingReaderMock(ArrayRef<OutputFunctionCoverageData> Functions)
|
||||
: Functions(Functions) {}
|
||||
|
||||
std::error_code readNextRecord(CoverageMappingRecord &Record) override {
|
||||
Error readNextRecord(CoverageMappingRecord &Record) override {
|
||||
if (Functions.empty())
|
||||
return coveragemap_error::eof;
|
||||
return make_error<CoverageMapError>(coveragemap_error::eof);
|
||||
|
||||
Functions.front().fillCoverageMappingRecord(Record);
|
||||
Functions = Functions.slice(1);
|
||||
|
||||
return coveragemap_error::success;
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
@ -190,7 +190,7 @@ struct CoverageMappingTest : ::testing::Test {
|
||||
void readProfCounts() {
|
||||
auto Profile = ProfileWriter.writeBuffer();
|
||||
auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile));
|
||||
ASSERT_TRUE(NoError(ReaderOrErr.getError()));
|
||||
ASSERT_TRUE(NoError(ReaderOrErr.takeError()));
|
||||
ProfileReader = std::move(ReaderOrErr.get());
|
||||
}
|
||||
|
||||
@ -200,7 +200,7 @@ struct CoverageMappingTest : ::testing::Test {
|
||||
|
||||
CoverageMappingReaderMock CovReader(OutputFunctions);
|
||||
auto CoverageOrErr = CoverageMapping::load(CovReader, *ProfileReader);
|
||||
ASSERT_TRUE(NoError(CoverageOrErr.getError()));
|
||||
ASSERT_TRUE(NoError(CoverageOrErr.takeError()));
|
||||
LoadedCoverage = std::move(CoverageOrErr.get());
|
||||
}
|
||||
};
|
||||
|
@ -19,19 +19,24 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static ::testing::AssertionResult NoError(std::error_code EC) {
|
||||
if (!EC)
|
||||
static ::testing::AssertionResult NoError(Error E) {
|
||||
if (!E)
|
||||
return ::testing::AssertionSuccess();
|
||||
return ::testing::AssertionFailure() << "error " << EC.value()
|
||||
<< ": " << EC.message();
|
||||
return ::testing::AssertionFailure() << "error: " << toString(std::move(E))
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
static ::testing::AssertionResult ErrorEquals(std::error_code Expected,
|
||||
std::error_code Found) {
|
||||
static ::testing::AssertionResult ErrorEquals(instrprof_error Expected,
|
||||
Error E) {
|
||||
instrprof_error Found;
|
||||
std::string FoundMsg;
|
||||
handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
|
||||
Found = IPE.get();
|
||||
FoundMsg = IPE.message();
|
||||
});
|
||||
if (Expected == Found)
|
||||
return ::testing::AssertionSuccess();
|
||||
return ::testing::AssertionFailure() << "error " << Found.value()
|
||||
<< ": " << Found.message();
|
||||
return ::testing::AssertionFailure() << "error: " << FoundMsg << "\n";
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -44,7 +49,7 @@ struct InstrProfTest : ::testing::Test {
|
||||
|
||||
void readProfile(std::unique_ptr<MemoryBuffer> Profile) {
|
||||
auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile));
|
||||
ASSERT_TRUE(NoError(ReaderOrErr.getError()));
|
||||
ASSERT_TRUE(NoError(ReaderOrErr.takeError()));
|
||||
Reader = std::move(ReaderOrErr.get());
|
||||
}
|
||||
};
|
||||
@ -90,23 +95,23 @@ TEST_P(MaybeSparseInstrProfTest, get_instr_prof_record) {
|
||||
auto Profile = Writer.writeBuffer();
|
||||
readProfile(std::move(Profile));
|
||||
|
||||
ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("foo", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("foo", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
ASSERT_EQ(2U, R->Counts.size());
|
||||
ASSERT_EQ(1U, R->Counts[0]);
|
||||
ASSERT_EQ(2U, R->Counts[1]);
|
||||
|
||||
R = Reader->getInstrProfRecord("foo", 0x1235);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
ASSERT_EQ(2U, R->Counts.size());
|
||||
ASSERT_EQ(3U, R->Counts[0]);
|
||||
ASSERT_EQ(4U, R->Counts[1]);
|
||||
|
||||
R = Reader->getInstrProfRecord("foo", 0x5678);
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.getError()));
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.takeError()));
|
||||
|
||||
R = Reader->getInstrProfRecord("bar", 0x1234);
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.getError()));
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.takeError()));
|
||||
}
|
||||
|
||||
TEST_P(MaybeSparseInstrProfTest, get_function_counts) {
|
||||
@ -128,12 +133,11 @@ TEST_P(MaybeSparseInstrProfTest, get_function_counts) {
|
||||
ASSERT_EQ(3U, Counts[0]);
|
||||
ASSERT_EQ(4U, Counts[1]);
|
||||
|
||||
std::error_code EC;
|
||||
EC = Reader->getFunctionCounts("foo", 0x5678, Counts);
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, EC));
|
||||
Error E1 = Reader->getFunctionCounts("foo", 0x5678, Counts);
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, std::move(E1)));
|
||||
|
||||
EC = Reader->getFunctionCounts("bar", 0x1234, Counts);
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, EC));
|
||||
Error E2 = Reader->getFunctionCounts("bar", 0x1234, Counts);
|
||||
ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, std::move(E2)));
|
||||
}
|
||||
|
||||
// Profile data is copied from general.proftext
|
||||
@ -235,8 +239,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) {
|
||||
auto Profile = Writer.writeBuffer();
|
||||
readProfile(std::move(Profile));
|
||||
|
||||
ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget));
|
||||
ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
|
||||
ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
|
||||
@ -266,8 +270,8 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) {
|
||||
NoError(Writer.addRecord(std::move(Record)));
|
||||
auto Profile = Writer.writeBuffer();
|
||||
readProfile(std::move(Profile));
|
||||
ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
|
||||
LLVMContext Ctx;
|
||||
std::unique_ptr<Module> M(new Module("MyModule", Ctx));
|
||||
@ -378,8 +382,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) {
|
||||
auto Profile = Writer.writeBuffer();
|
||||
readProfile(std::move(Profile));
|
||||
|
||||
ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget));
|
||||
ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
|
||||
ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
|
||||
@ -431,8 +435,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) {
|
||||
// Set big endian input.
|
||||
Reader->setValueProfDataEndianness(support::big);
|
||||
|
||||
ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget));
|
||||
ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
|
||||
ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
|
||||
@ -513,8 +517,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
|
||||
auto Profile = Writer.writeBuffer();
|
||||
readProfile(std::move(Profile));
|
||||
|
||||
ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
ASSERT_EQ(5U, R->getNumValueSites(IPVK_IndirectCallTarget));
|
||||
ASSERT_EQ(4U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
|
||||
ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
|
||||
@ -566,23 +570,27 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) {
|
||||
|
||||
InstrProfRecord Record1("foo", 0x1234, {1});
|
||||
auto Result1 = Writer.addRecord(std::move(Record1));
|
||||
ASSERT_EQ(Result1, instrprof_error::success);
|
||||
ASSERT_EQ(InstrProfError::take(std::move(Result1)),
|
||||
instrprof_error::success);
|
||||
|
||||
// Verify counter overflow.
|
||||
InstrProfRecord Record2("foo", 0x1234, {Max});
|
||||
auto Result2 = Writer.addRecord(std::move(Record2));
|
||||
ASSERT_EQ(Result2, instrprof_error::counter_overflow);
|
||||
ASSERT_EQ(InstrProfError::take(std::move(Result2)),
|
||||
instrprof_error::counter_overflow);
|
||||
|
||||
InstrProfRecord Record3(bar, 0x9012, {8});
|
||||
auto Result3 = Writer.addRecord(std::move(Record3));
|
||||
ASSERT_EQ(Result3, instrprof_error::success);
|
||||
ASSERT_EQ(InstrProfError::take(std::move(Result3)),
|
||||
instrprof_error::success);
|
||||
|
||||
InstrProfRecord Record4("baz", 0x5678, {3, 4});
|
||||
Record4.reserveSites(IPVK_IndirectCallTarget, 1);
|
||||
InstrProfValueData VD4[] = {{uint64_t(bar), 1}};
|
||||
Record4.addValueData(IPVK_IndirectCallTarget, 0, VD4, 1, nullptr);
|
||||
auto Result4 = Writer.addRecord(std::move(Record4));
|
||||
ASSERT_EQ(Result4, instrprof_error::success);
|
||||
ASSERT_EQ(InstrProfError::take(std::move(Result4)),
|
||||
instrprof_error::success);
|
||||
|
||||
// Verify value data counter overflow.
|
||||
InstrProfRecord Record5("baz", 0x5678, {5, 6});
|
||||
@ -590,19 +598,21 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) {
|
||||
InstrProfValueData VD5[] = {{uint64_t(bar), Max}};
|
||||
Record5.addValueData(IPVK_IndirectCallTarget, 0, VD5, 1, nullptr);
|
||||
auto Result5 = Writer.addRecord(std::move(Record5));
|
||||
ASSERT_EQ(Result5, instrprof_error::counter_overflow);
|
||||
ASSERT_EQ(InstrProfError::take(std::move(Result5)),
|
||||
instrprof_error::counter_overflow);
|
||||
|
||||
auto Profile = Writer.writeBuffer();
|
||||
readProfile(std::move(Profile));
|
||||
|
||||
// Verify saturation of counts.
|
||||
ErrorOr<InstrProfRecord> ReadRecord1 =
|
||||
Expected<InstrProfRecord> ReadRecord1 =
|
||||
Reader->getInstrProfRecord("foo", 0x1234);
|
||||
ASSERT_TRUE(NoError(ReadRecord1.getError()));
|
||||
ASSERT_TRUE(NoError(ReadRecord1.takeError()));
|
||||
ASSERT_EQ(Max, ReadRecord1->Counts[0]);
|
||||
|
||||
ErrorOr<InstrProfRecord> ReadRecord2 =
|
||||
Expected<InstrProfRecord> ReadRecord2 =
|
||||
Reader->getInstrProfRecord("baz", 0x5678);
|
||||
ASSERT_TRUE(bool(ReadRecord2));
|
||||
ASSERT_EQ(1U, ReadRecord2->getNumValueSites(IPVK_IndirectCallTarget));
|
||||
std::unique_ptr<InstrProfValueData[]> VD =
|
||||
ReadRecord2->getValueForSite(IPVK_IndirectCallTarget, 0);
|
||||
@ -647,8 +657,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge_site_trunc) {
|
||||
auto Profile = Writer.writeBuffer();
|
||||
readProfile(std::move(Profile));
|
||||
|
||||
ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.getError()));
|
||||
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
|
||||
ASSERT_TRUE(NoError(R.takeError()));
|
||||
std::unique_ptr<InstrProfValueData[]> VD(
|
||||
R->getValueForSite(IPVK_IndirectCallTarget, 0));
|
||||
ASSERT_EQ(2U, R->getNumValueSites(IPVK_IndirectCallTarget));
|
||||
|
Loading…
Reference in New Issue
Block a user