mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-07-27 07:23:56 +00:00
Initial Commit
This commit is contained in:
1066
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/Coverage/CoverageMapping.h
vendored
Normal file
1066
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/Coverage/CoverageMapping.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,245 @@
|
||||
//===- CoverageMappingReader.h - Code coverage mapping reader ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for reading coverage mapping data for
|
||||
// instrumentation based coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGREADER_H
|
||||
#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGREADER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace coverage {
|
||||
|
||||
class CoverageMappingReader;
|
||||
|
||||
/// Coverage mapping information for a single function.
|
||||
struct CoverageMappingRecord {
|
||||
StringRef FunctionName;
|
||||
uint64_t FunctionHash;
|
||||
ArrayRef<StringRef> Filenames;
|
||||
ArrayRef<CounterExpression> Expressions;
|
||||
ArrayRef<CounterMappingRegion> MappingRegions;
|
||||
};
|
||||
|
||||
/// A file format agnostic iterator over coverage mapping data.
|
||||
class CoverageMappingIterator {
|
||||
CoverageMappingReader *Reader;
|
||||
CoverageMappingRecord Record;
|
||||
coveragemap_error ReadErr;
|
||||
|
||||
void increment();
|
||||
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = CoverageMappingRecord;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
CoverageMappingIterator()
|
||||
: Reader(nullptr), ReadErr(coveragemap_error::success) {}
|
||||
|
||||
CoverageMappingIterator(CoverageMappingReader *Reader)
|
||||
: Reader(Reader), ReadErr(coveragemap_error::success) {
|
||||
increment();
|
||||
}
|
||||
|
||||
~CoverageMappingIterator() {
|
||||
if (ReadErr != coveragemap_error::success)
|
||||
llvm_unreachable("Unexpected error in coverage mapping iterator");
|
||||
}
|
||||
|
||||
CoverageMappingIterator &operator++() {
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const CoverageMappingIterator &RHS) const {
|
||||
return Reader == RHS.Reader;
|
||||
}
|
||||
bool operator!=(const CoverageMappingIterator &RHS) const {
|
||||
return Reader != RHS.Reader;
|
||||
}
|
||||
Expected<CoverageMappingRecord &> operator*() {
|
||||
if (ReadErr != coveragemap_error::success) {
|
||||
auto E = make_error<CoverageMapError>(ReadErr);
|
||||
ReadErr = coveragemap_error::success;
|
||||
return std::move(E);
|
||||
}
|
||||
return Record;
|
||||
}
|
||||
Expected<CoverageMappingRecord *> operator->() {
|
||||
if (ReadErr != coveragemap_error::success) {
|
||||
auto E = make_error<CoverageMapError>(ReadErr);
|
||||
ReadErr = coveragemap_error::success;
|
||||
return std::move(E);
|
||||
}
|
||||
return &Record;
|
||||
}
|
||||
};
|
||||
|
||||
class CoverageMappingReader {
|
||||
public:
|
||||
virtual ~CoverageMappingReader() = default;
|
||||
|
||||
virtual Error readNextRecord(CoverageMappingRecord &Record) = 0;
|
||||
CoverageMappingIterator begin() { return CoverageMappingIterator(this); }
|
||||
CoverageMappingIterator end() { return CoverageMappingIterator(); }
|
||||
};
|
||||
|
||||
/// Base class for the raw coverage mapping and filenames data readers.
|
||||
class RawCoverageReader {
|
||||
protected:
|
||||
StringRef Data;
|
||||
|
||||
RawCoverageReader(StringRef Data) : Data(Data) {}
|
||||
|
||||
Error readULEB128(uint64_t &Result);
|
||||
Error readIntMax(uint64_t &Result, uint64_t MaxPlus1);
|
||||
Error readSize(uint64_t &Result);
|
||||
Error readString(StringRef &Result);
|
||||
};
|
||||
|
||||
/// Checks if the given coverage mapping data is exported for
|
||||
/// an unused function.
|
||||
class RawCoverageMappingDummyChecker : public RawCoverageReader {
|
||||
public:
|
||||
RawCoverageMappingDummyChecker(StringRef MappingData)
|
||||
: RawCoverageReader(MappingData) {}
|
||||
|
||||
Expected<bool> isDummy();
|
||||
};
|
||||
|
||||
/// Reader for the raw coverage mapping data.
|
||||
class RawCoverageMappingReader : public RawCoverageReader {
|
||||
ArrayRef<std::string> &TranslationUnitFilenames;
|
||||
std::vector<StringRef> &Filenames;
|
||||
std::vector<CounterExpression> &Expressions;
|
||||
std::vector<CounterMappingRegion> &MappingRegions;
|
||||
|
||||
public:
|
||||
RawCoverageMappingReader(StringRef MappingData,
|
||||
ArrayRef<std::string> &TranslationUnitFilenames,
|
||||
std::vector<StringRef> &Filenames,
|
||||
std::vector<CounterExpression> &Expressions,
|
||||
std::vector<CounterMappingRegion> &MappingRegions)
|
||||
: RawCoverageReader(MappingData),
|
||||
TranslationUnitFilenames(TranslationUnitFilenames),
|
||||
Filenames(Filenames), Expressions(Expressions),
|
||||
MappingRegions(MappingRegions) {}
|
||||
RawCoverageMappingReader(const RawCoverageMappingReader &) = delete;
|
||||
RawCoverageMappingReader &
|
||||
operator=(const RawCoverageMappingReader &) = delete;
|
||||
|
||||
Error read();
|
||||
|
||||
private:
|
||||
Error decodeCounter(unsigned Value, Counter &C);
|
||||
Error readCounter(Counter &C);
|
||||
Error
|
||||
readMappingRegionsSubArray(std::vector<CounterMappingRegion> &MappingRegions,
|
||||
unsigned InferredFileID, size_t NumFileIDs);
|
||||
};
|
||||
|
||||
/// Reader for the coverage mapping data that is emitted by the
|
||||
/// frontend and stored in an object file.
|
||||
class BinaryCoverageReader : public CoverageMappingReader {
|
||||
public:
|
||||
struct ProfileMappingRecord {
|
||||
CovMapVersion Version;
|
||||
StringRef FunctionName;
|
||||
uint64_t FunctionHash;
|
||||
StringRef CoverageMapping;
|
||||
size_t FilenamesBegin;
|
||||
size_t FilenamesSize;
|
||||
|
||||
ProfileMappingRecord(CovMapVersion Version, StringRef FunctionName,
|
||||
uint64_t FunctionHash, StringRef CoverageMapping,
|
||||
size_t FilenamesBegin, size_t FilenamesSize)
|
||||
: Version(Version), FunctionName(FunctionName),
|
||||
FunctionHash(FunctionHash), CoverageMapping(CoverageMapping),
|
||||
FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
|
||||
};
|
||||
|
||||
using FuncRecordsStorage = std::unique_ptr<MemoryBuffer>;
|
||||
|
||||
private:
|
||||
std::vector<std::string> Filenames;
|
||||
std::vector<ProfileMappingRecord> MappingRecords;
|
||||
InstrProfSymtab ProfileNames;
|
||||
size_t CurrentRecord = 0;
|
||||
std::vector<StringRef> FunctionsFilenames;
|
||||
std::vector<CounterExpression> Expressions;
|
||||
std::vector<CounterMappingRegion> MappingRegions;
|
||||
|
||||
// Used to tie the lifetimes of coverage function records to the lifetime of
|
||||
// this BinaryCoverageReader instance. Needed to support the format change in
|
||||
// D69471, which can split up function records into multiple sections on ELF.
|
||||
FuncRecordsStorage FuncRecords;
|
||||
|
||||
BinaryCoverageReader(FuncRecordsStorage &&FuncRecords)
|
||||
: FuncRecords(std::move(FuncRecords)) {}
|
||||
|
||||
public:
|
||||
BinaryCoverageReader(const BinaryCoverageReader &) = delete;
|
||||
BinaryCoverageReader &operator=(const BinaryCoverageReader &) = delete;
|
||||
|
||||
static Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
|
||||
create(MemoryBufferRef ObjectBuffer, StringRef Arch,
|
||||
SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
|
||||
StringRef CompilationDir = "");
|
||||
|
||||
static Expected<std::unique_ptr<BinaryCoverageReader>>
|
||||
createCoverageReaderFromBuffer(StringRef Coverage,
|
||||
FuncRecordsStorage &&FuncRecords,
|
||||
InstrProfSymtab &&ProfileNames,
|
||||
uint8_t BytesInAddress,
|
||||
support::endianness Endian,
|
||||
StringRef CompilationDir = "");
|
||||
|
||||
Error readNextRecord(CoverageMappingRecord &Record) override;
|
||||
};
|
||||
|
||||
/// Reader for the raw coverage filenames.
|
||||
class RawCoverageFilenamesReader : public RawCoverageReader {
|
||||
std::vector<std::string> &Filenames;
|
||||
StringRef CompilationDir;
|
||||
|
||||
// Read an uncompressed sequence of filenames.
|
||||
Error readUncompressed(CovMapVersion Version, uint64_t NumFilenames);
|
||||
|
||||
public:
|
||||
RawCoverageFilenamesReader(StringRef Data,
|
||||
std::vector<std::string> &Filenames,
|
||||
StringRef CompilationDir = "")
|
||||
: RawCoverageReader(Data), Filenames(Filenames),
|
||||
CompilationDir(CompilationDir) {}
|
||||
RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) = delete;
|
||||
RawCoverageFilenamesReader &
|
||||
operator=(const RawCoverageFilenamesReader &) = delete;
|
||||
|
||||
Error read(CovMapVersion Version);
|
||||
};
|
||||
|
||||
} // end namespace coverage
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGREADER_H
|
@@ -0,0 +1,61 @@
|
||||
//===- CoverageMappingWriter.h - Code coverage mapping writer ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for writing coverage mapping data for
|
||||
// instrumentation based coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGWRITER_H
|
||||
#define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGWRITER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
namespace coverage {
|
||||
|
||||
/// Writer of the filenames section for the instrumentation
|
||||
/// based code coverage.
|
||||
class CoverageFilenamesSectionWriter {
|
||||
ArrayRef<std::string> Filenames;
|
||||
|
||||
public:
|
||||
CoverageFilenamesSectionWriter(ArrayRef<std::string> Filenames);
|
||||
|
||||
/// Write encoded filenames to the given output stream. If \p Compress is
|
||||
/// true, attempt to compress the filenames.
|
||||
void write(raw_ostream &OS, bool Compress = true);
|
||||
};
|
||||
|
||||
/// Writer for instrumentation based coverage mapping data.
|
||||
class CoverageMappingWriter {
|
||||
ArrayRef<unsigned> VirtualFileMapping;
|
||||
ArrayRef<CounterExpression> Expressions;
|
||||
MutableArrayRef<CounterMappingRegion> MappingRegions;
|
||||
|
||||
public:
|
||||
CoverageMappingWriter(ArrayRef<unsigned> VirtualFileMapping,
|
||||
ArrayRef<CounterExpression> Expressions,
|
||||
MutableArrayRef<CounterMappingRegion> MappingRegions)
|
||||
: VirtualFileMapping(VirtualFileMapping), Expressions(Expressions),
|
||||
MappingRegions(MappingRegions) {}
|
||||
|
||||
/// Write encoded coverage mapping data to the given output stream.
|
||||
void write(raw_ostream &OS);
|
||||
};
|
||||
|
||||
} // end namespace coverage
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPINGWRITER_H
|
323
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/GCOV.h
vendored
Normal file
323
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/GCOV.h
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
//===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header provides the interface to read and write coverage files that
|
||||
// use 'gcov' format.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_GCOV_H
|
||||
#define LLVM_PROFILEDATA_GCOV_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/DataExtractor.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class GCOVFunction;
|
||||
class GCOVBlock;
|
||||
|
||||
namespace GCOV {
|
||||
|
||||
enum GCOVVersion { V304, V407, V408, V800, V900, V1200 };
|
||||
|
||||
/// A struct for passing gcov options between functions.
|
||||
struct Options {
|
||||
Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L,
|
||||
bool M, bool N, bool R, bool T, bool X, std::string SourcePrefix)
|
||||
: AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
|
||||
PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L),
|
||||
Demangle(M), NoOutput(N), RelativeOnly(R), UseStdout(T),
|
||||
HashFilenames(X), SourcePrefix(std::move(SourcePrefix)) {}
|
||||
|
||||
bool AllBlocks;
|
||||
bool BranchInfo;
|
||||
bool BranchCount;
|
||||
bool FuncCoverage;
|
||||
bool PreservePaths;
|
||||
bool UncondBranch;
|
||||
bool Intermediate;
|
||||
bool LongFileNames;
|
||||
bool Demangle;
|
||||
bool NoOutput;
|
||||
bool RelativeOnly;
|
||||
bool UseStdout;
|
||||
bool HashFilenames;
|
||||
std::string SourcePrefix;
|
||||
};
|
||||
|
||||
} // end namespace GCOV
|
||||
|
||||
/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
|
||||
/// read operations.
|
||||
class GCOVBuffer {
|
||||
public:
|
||||
GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
|
||||
~GCOVBuffer() { consumeError(cursor.takeError()); }
|
||||
|
||||
/// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
|
||||
bool readGCNOFormat() {
|
||||
StringRef buf = Buffer->getBuffer();
|
||||
StringRef magic = buf.substr(0, 4);
|
||||
if (magic == "gcno") {
|
||||
de = DataExtractor(buf.substr(4), false, 0);
|
||||
} else if (magic == "oncg") {
|
||||
de = DataExtractor(buf.substr(4), true, 0);
|
||||
} else {
|
||||
errs() << "unexpected magic: " << magic << "\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
|
||||
bool readGCDAFormat() {
|
||||
StringRef buf = Buffer->getBuffer();
|
||||
StringRef magic = buf.substr(0, 4);
|
||||
if (magic == "gcda") {
|
||||
de = DataExtractor(buf.substr(4), false, 0);
|
||||
} else if (magic == "adcg") {
|
||||
de = DataExtractor(buf.substr(4), true, 0);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readGCOVVersion - Read GCOV version.
|
||||
bool readGCOVVersion(GCOV::GCOVVersion &version) {
|
||||
std::string str(de.getBytes(cursor, 4));
|
||||
if (str.size() != 4)
|
||||
return false;
|
||||
if (de.isLittleEndian())
|
||||
std::reverse(str.begin(), str.end());
|
||||
int ver = str[0] >= 'A'
|
||||
? (str[0] - 'A') * 100 + (str[1] - '0') * 10 + str[2] - '0'
|
||||
: (str[0] - '0') * 10 + str[2] - '0';
|
||||
if (ver >= 120) {
|
||||
this->version = version = GCOV::V1200;
|
||||
return true;
|
||||
} else if (ver >= 90) {
|
||||
// PR gcov-profile/84846, r269678
|
||||
this->version = version = GCOV::V900;
|
||||
return true;
|
||||
} else if (ver >= 80) {
|
||||
// PR gcov-profile/48463
|
||||
this->version = version = GCOV::V800;
|
||||
return true;
|
||||
} else if (ver >= 48) {
|
||||
// r189778: the exit block moved from the last to the second.
|
||||
this->version = version = GCOV::V408;
|
||||
return true;
|
||||
} else if (ver >= 47) {
|
||||
// r173147: split checksum into cfg checksum and line checksum.
|
||||
this->version = version = GCOV::V407;
|
||||
return true;
|
||||
} else if (ver >= 34) {
|
||||
this->version = version = GCOV::V304;
|
||||
return true;
|
||||
}
|
||||
errs() << "unexpected version: " << str << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t getWord() { return de.getU32(cursor); }
|
||||
StringRef getString() {
|
||||
uint32_t len;
|
||||
if (!readInt(len) || len == 0)
|
||||
return {};
|
||||
return de.getBytes(cursor, len * 4).split('\0').first;
|
||||
}
|
||||
|
||||
bool readInt(uint32_t &Val) {
|
||||
if (cursor.tell() + 4 > de.size()) {
|
||||
Val = 0;
|
||||
errs() << "unexpected end of memory buffer: " << cursor.tell() << "\n";
|
||||
return false;
|
||||
}
|
||||
Val = de.getU32(cursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readInt64(uint64_t &Val) {
|
||||
uint32_t Lo, Hi;
|
||||
if (!readInt(Lo) || !readInt(Hi))
|
||||
return false;
|
||||
Val = ((uint64_t)Hi << 32) | Lo;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readString(StringRef &str) {
|
||||
uint32_t len;
|
||||
if (!readInt(len) || len == 0)
|
||||
return false;
|
||||
if (version >= GCOV::V1200)
|
||||
str = de.getBytes(cursor, len).drop_back();
|
||||
else
|
||||
str = de.getBytes(cursor, len * 4).split('\0').first;
|
||||
return bool(cursor);
|
||||
}
|
||||
|
||||
DataExtractor de{ArrayRef<uint8_t>{}, false, 0};
|
||||
DataExtractor::Cursor cursor{0};
|
||||
|
||||
private:
|
||||
MemoryBuffer *Buffer;
|
||||
GCOV::GCOVVersion version{};
|
||||
};
|
||||
|
||||
/// GCOVFile - Collects coverage information for one pair of coverage file
|
||||
/// (.gcno and .gcda).
|
||||
class GCOVFile {
|
||||
public:
|
||||
GCOVFile() = default;
|
||||
|
||||
bool readGCNO(GCOVBuffer &Buffer);
|
||||
bool readGCDA(GCOVBuffer &Buffer);
|
||||
GCOV::GCOVVersion getVersion() const { return version; }
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
std::vector<std::string> filenames;
|
||||
StringMap<unsigned> filenameToIdx;
|
||||
|
||||
public:
|
||||
bool GCNOInitialized = false;
|
||||
GCOV::GCOVVersion version{};
|
||||
uint32_t checksum = 0;
|
||||
StringRef cwd;
|
||||
SmallVector<std::unique_ptr<GCOVFunction>, 16> functions;
|
||||
std::map<uint32_t, GCOVFunction *> identToFunction;
|
||||
uint32_t runCount = 0;
|
||||
uint32_t programCount = 0;
|
||||
|
||||
using iterator = pointee_iterator<
|
||||
SmallVectorImpl<std::unique_ptr<GCOVFunction>>::const_iterator>;
|
||||
iterator begin() const { return iterator(functions.begin()); }
|
||||
iterator end() const { return iterator(functions.end()); }
|
||||
};
|
||||
|
||||
struct GCOVArc {
|
||||
GCOVArc(GCOVBlock &src, GCOVBlock &dst, uint32_t flags)
|
||||
: src(src), dst(dst), flags(flags) {}
|
||||
bool onTree() const;
|
||||
|
||||
GCOVBlock &src;
|
||||
GCOVBlock &dst;
|
||||
uint32_t flags;
|
||||
uint64_t count = 0;
|
||||
uint64_t cycleCount = 0;
|
||||
};
|
||||
|
||||
/// GCOVFunction - Collects function information.
|
||||
class GCOVFunction {
|
||||
public:
|
||||
using BlockIterator = pointee_iterator<
|
||||
SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
|
||||
|
||||
GCOVFunction(GCOVFile &file) : file(file) {}
|
||||
|
||||
StringRef getName(bool demangle) const;
|
||||
StringRef getFilename() const;
|
||||
uint64_t getEntryCount() const;
|
||||
GCOVBlock &getExitBlock() const;
|
||||
|
||||
iterator_range<BlockIterator> blocksRange() const {
|
||||
return make_range(blocks.begin(), blocks.end());
|
||||
}
|
||||
|
||||
uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred);
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
GCOVFile &file;
|
||||
uint32_t ident = 0;
|
||||
uint32_t linenoChecksum;
|
||||
uint32_t cfgChecksum = 0;
|
||||
uint32_t startLine = 0;
|
||||
uint32_t startColumn = 0;
|
||||
uint32_t endLine = 0;
|
||||
uint32_t endColumn = 0;
|
||||
uint8_t artificial = 0;
|
||||
StringRef Name;
|
||||
mutable SmallString<0> demangled;
|
||||
unsigned srcIdx;
|
||||
SmallVector<std::unique_ptr<GCOVBlock>, 0> blocks;
|
||||
SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs;
|
||||
DenseSet<const GCOVBlock *> visited;
|
||||
};
|
||||
|
||||
/// GCOVBlock - Collects block information.
|
||||
class GCOVBlock {
|
||||
public:
|
||||
using EdgeIterator = SmallVectorImpl<GCOVArc *>::const_iterator;
|
||||
using BlockVector = SmallVector<const GCOVBlock *, 1>;
|
||||
using BlockVectorLists = SmallVector<BlockVector, 4>;
|
||||
using Edges = SmallVector<GCOVArc *, 4>;
|
||||
|
||||
GCOVBlock(uint32_t N) : number(N) {}
|
||||
|
||||
void addLine(uint32_t N) { lines.push_back(N); }
|
||||
uint32_t getLastLine() const { return lines.back(); }
|
||||
uint64_t getCount() const { return count; }
|
||||
|
||||
void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
|
||||
|
||||
void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); }
|
||||
|
||||
iterator_range<EdgeIterator> srcs() const {
|
||||
return make_range(pred.begin(), pred.end());
|
||||
}
|
||||
|
||||
iterator_range<EdgeIterator> dsts() const {
|
||||
return make_range(succ.begin(), succ.end());
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
static uint64_t
|
||||
augmentOneCycle(GCOVBlock *src,
|
||||
std::vector<std::pair<GCOVBlock *, size_t>> &stack);
|
||||
static uint64_t getCyclesCount(const BlockVector &blocks);
|
||||
static uint64_t getLineCount(const BlockVector &Blocks);
|
||||
|
||||
public:
|
||||
uint32_t number;
|
||||
uint64_t count = 0;
|
||||
SmallVector<GCOVArc *, 2> pred;
|
||||
SmallVector<GCOVArc *, 2> succ;
|
||||
SmallVector<uint32_t, 4> lines;
|
||||
bool traversable = false;
|
||||
GCOVArc *incoming = nullptr;
|
||||
};
|
||||
|
||||
void gcovOneInput(const GCOV::Options &options, StringRef filename,
|
||||
StringRef gcno, StringRef gcda, GCOVFile &file);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_GCOV_H
|
1179
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProf.h
vendored
Normal file
1179
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProf.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
178
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProfCorrelator.h
vendored
Normal file
178
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProfCorrelator.h
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
//===- InstrProfCorrelator.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This file defines InstrProfCorrelator used to generate PGO profiles from
|
||||
// raw profile data and debug info.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
|
||||
#define LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// InstrProfCorrelator - A base class used to create raw instrumentation data
|
||||
/// to their functions.
|
||||
class InstrProfCorrelator {
|
||||
public:
|
||||
static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
|
||||
get(StringRef DebugInfoFilename);
|
||||
|
||||
/// Construct a ProfileData vector used to correlate raw instrumentation data
|
||||
/// to their functions.
|
||||
virtual Error correlateProfileData() = 0;
|
||||
|
||||
/// Return the number of ProfileData elements.
|
||||
llvm::Optional<size_t> getDataSize() const;
|
||||
|
||||
/// Return a pointer to the names string that this class constructs.
|
||||
const char *getNamesPointer() const { return Names.c_str(); }
|
||||
|
||||
/// Return the number of bytes in the names string.
|
||||
size_t getNamesSize() const { return Names.size(); }
|
||||
|
||||
/// Return the size of the counters section in bytes.
|
||||
uint64_t getCountersSectionSize() const {
|
||||
return Ctx->CountersSectionEnd - Ctx->CountersSectionStart;
|
||||
}
|
||||
|
||||
static const char *FunctionNameAttributeName;
|
||||
static const char *CFGHashAttributeName;
|
||||
static const char *NumCountersAttributeName;
|
||||
|
||||
enum InstrProfCorrelatorKind { CK_32Bit, CK_64Bit };
|
||||
InstrProfCorrelatorKind getKind() const { return Kind; }
|
||||
virtual ~InstrProfCorrelator() = default;
|
||||
|
||||
protected:
|
||||
struct Context {
|
||||
static llvm::Expected<std::unique_ptr<Context>>
|
||||
get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj);
|
||||
std::unique_ptr<MemoryBuffer> Buffer;
|
||||
/// The address range of the __llvm_prf_cnts section.
|
||||
uint64_t CountersSectionStart;
|
||||
uint64_t CountersSectionEnd;
|
||||
/// True if target and host have different endian orders.
|
||||
bool ShouldSwapBytes;
|
||||
};
|
||||
const std::unique_ptr<InstrProfCorrelator::Context> Ctx;
|
||||
|
||||
InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr<Context> Ctx)
|
||||
: Ctx(std::move(Ctx)), Kind(K) {}
|
||||
|
||||
std::string Names;
|
||||
std::vector<std::string> NamesVec;
|
||||
|
||||
private:
|
||||
static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
|
||||
get(std::unique_ptr<MemoryBuffer> Buffer);
|
||||
|
||||
const InstrProfCorrelatorKind Kind;
|
||||
};
|
||||
|
||||
/// InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template
|
||||
/// pointer type so that the ProfileData vector can be materialized.
|
||||
template <class IntPtrT>
|
||||
class InstrProfCorrelatorImpl : public InstrProfCorrelator {
|
||||
public:
|
||||
InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx);
|
||||
static bool classof(const InstrProfCorrelator *C);
|
||||
|
||||
/// Return a pointer to the underlying ProfileData vector that this class
|
||||
/// constructs.
|
||||
const RawInstrProf::ProfileData<IntPtrT> *getDataPointer() const {
|
||||
return Data.empty() ? nullptr : Data.data();
|
||||
}
|
||||
|
||||
/// Return the number of ProfileData elements.
|
||||
size_t getDataSize() const { return Data.size(); }
|
||||
|
||||
static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
|
||||
get(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
|
||||
const object::ObjectFile &Obj);
|
||||
|
||||
protected:
|
||||
std::vector<RawInstrProf::ProfileData<IntPtrT>> Data;
|
||||
|
||||
Error correlateProfileData() override;
|
||||
virtual void correlateProfileDataImpl() = 0;
|
||||
|
||||
void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset,
|
||||
IntPtrT FunctionPtr, uint32_t NumCounters);
|
||||
|
||||
private:
|
||||
InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
|
||||
std::unique_ptr<InstrProfCorrelator::Context> Ctx)
|
||||
: InstrProfCorrelator(Kind, std::move(Ctx)){};
|
||||
llvm::DenseSet<IntPtrT> CounterOffsets;
|
||||
|
||||
// Byte-swap the value if necessary.
|
||||
template <class T> T maybeSwap(T Value) const {
|
||||
return Ctx->ShouldSwapBytes ? sys::getSwappedBytes(Value) : Value;
|
||||
}
|
||||
};
|
||||
|
||||
/// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes
|
||||
/// DWARF debug info as input to correlate profiles.
|
||||
template <class IntPtrT>
|
||||
class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
|
||||
public:
|
||||
DwarfInstrProfCorrelator(std::unique_ptr<DWARFContext> DICtx,
|
||||
std::unique_ptr<InstrProfCorrelator::Context> Ctx)
|
||||
: InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)),
|
||||
DICtx(std::move(DICtx)) {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<DWARFContext> DICtx;
|
||||
|
||||
/// Return the address of the object that the provided DIE symbolizes.
|
||||
llvm::Optional<uint64_t> getLocation(const DWARFDie &Die) const;
|
||||
|
||||
/// Returns true if the provided DIE symbolizes an instrumentation probe
|
||||
/// symbol.
|
||||
static bool isDIEOfProbe(const DWARFDie &Die);
|
||||
|
||||
/// Iterate over DWARF DIEs to find those that symbolize instrumentation
|
||||
/// probes and construct the ProfileData vector and Names string.
|
||||
///
|
||||
/// Here is some example DWARF for an instrumentation probe we are looking
|
||||
/// for:
|
||||
/// \code
|
||||
/// DW_TAG_subprogram
|
||||
/// DW_AT_low_pc (0x0000000000000000)
|
||||
/// DW_AT_high_pc (0x0000000000000014)
|
||||
/// DW_AT_name ("foo")
|
||||
/// DW_TAG_variable
|
||||
/// DW_AT_name ("__profc_foo")
|
||||
/// DW_AT_location (DW_OP_addr 0x0)
|
||||
/// DW_TAG_LLVM_annotation
|
||||
/// DW_AT_name ("Function Name")
|
||||
/// DW_AT_const_value ("foo")
|
||||
/// DW_TAG_LLVM_annotation
|
||||
/// DW_AT_name ("CFG Hash")
|
||||
/// DW_AT_const_value (12345678)
|
||||
/// DW_TAG_LLVM_annotation
|
||||
/// DW_AT_name ("Num Counters")
|
||||
/// DW_AT_const_value (2)
|
||||
/// NULL
|
||||
/// NULL
|
||||
/// \endcode
|
||||
void correlateProfileDataImpl() override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
|
650
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProfReader.h
vendored
Normal file
650
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProfReader.h
vendored
Normal file
@@ -0,0 +1,650 @@
|
||||
//===- InstrProfReader.h - Instrumented profiling readers -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for reading profiling data for instrumentation
|
||||
// based PGO and coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_INSTRPROFREADER_H
|
||||
#define LLVM_PROFILEDATA_INSTRPROFREADER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/IR/ProfileSummary.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/ProfileData/InstrProfCorrelator.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/OnDiskHashTable.h"
|
||||
#include "llvm/Support/SwapByteOrder.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class InstrProfReader;
|
||||
|
||||
/// A file format agnostic iterator over profiling data.
|
||||
class InstrProfIterator {
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = NamedInstrProfRecord;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
private:
|
||||
InstrProfReader *Reader = nullptr;
|
||||
value_type Record;
|
||||
|
||||
void Increment();
|
||||
|
||||
public:
|
||||
InstrProfIterator() = default;
|
||||
InstrProfIterator(InstrProfReader *Reader) : Reader(Reader) { Increment(); }
|
||||
|
||||
InstrProfIterator &operator++() { Increment(); return *this; }
|
||||
bool operator==(const InstrProfIterator &RHS) const {
|
||||
return Reader == RHS.Reader;
|
||||
}
|
||||
bool operator!=(const InstrProfIterator &RHS) const {
|
||||
return Reader != RHS.Reader;
|
||||
}
|
||||
value_type &operator*() { return Record; }
|
||||
value_type *operator->() { return &Record; }
|
||||
};
|
||||
|
||||
/// Base class and interface for reading profiling data of any known instrprof
|
||||
/// format. Provides an iterator over NamedInstrProfRecords.
|
||||
class InstrProfReader {
|
||||
instrprof_error LastError = instrprof_error::success;
|
||||
std::string LastErrorMsg;
|
||||
|
||||
public:
|
||||
InstrProfReader() = default;
|
||||
virtual ~InstrProfReader() = default;
|
||||
|
||||
/// Read the header. Required before reading first record.
|
||||
virtual Error readHeader() = 0;
|
||||
|
||||
/// Read a single record.
|
||||
virtual Error readNextRecord(NamedInstrProfRecord &Record) = 0;
|
||||
|
||||
/// Print binary ids on stream OS.
|
||||
virtual Error printBinaryIds(raw_ostream &OS) { return success(); };
|
||||
|
||||
/// Iterator over profile data.
|
||||
InstrProfIterator begin() { return InstrProfIterator(this); }
|
||||
InstrProfIterator end() { return InstrProfIterator(); }
|
||||
|
||||
virtual bool isIRLevelProfile() const = 0;
|
||||
|
||||
virtual bool hasCSIRLevelProfile() const = 0;
|
||||
|
||||
virtual bool instrEntryBBEnabled() const = 0;
|
||||
|
||||
/// Return true if we must provide debug info to create PGO profiles.
|
||||
virtual bool useDebugInfoCorrelate() const { return false; }
|
||||
|
||||
/// Return true if the profile has single byte counters representing coverage.
|
||||
virtual bool hasSingleByteCoverage() const = 0;
|
||||
|
||||
/// Return true if the profile only instruments function entries.
|
||||
virtual bool functionEntryOnly() const = 0;
|
||||
|
||||
/// Returns a BitsetEnum describing the attributes of the profile. To check
|
||||
/// individual attributes prefer using the helpers above.
|
||||
virtual InstrProfKind getProfileKind() const = 0;
|
||||
|
||||
/// Return the PGO symtab. There are three different readers:
|
||||
/// Raw, Text, and Indexed profile readers. The first two types
|
||||
/// of readers are used only by llvm-profdata tool, while the indexed
|
||||
/// profile reader is also used by llvm-cov tool and the compiler (
|
||||
/// backend or frontend). Since creating PGO symtab can create
|
||||
/// significant runtime and memory overhead (as it touches data
|
||||
/// for the whole program), InstrProfSymtab for the indexed profile
|
||||
/// reader should be created on demand and it is recommended to be
|
||||
/// only used for dumping purpose with llvm-proftool, not with the
|
||||
/// compiler.
|
||||
virtual InstrProfSymtab &getSymtab() = 0;
|
||||
|
||||
/// Compute the sum of counts and return in Sum.
|
||||
void accumulateCounts(CountSumOrPercent &Sum, bool IsCS);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<InstrProfSymtab> Symtab;
|
||||
|
||||
/// Set the current error and return same.
|
||||
Error error(instrprof_error Err, const std::string &ErrMsg = "") {
|
||||
LastError = Err;
|
||||
LastErrorMsg = ErrMsg;
|
||||
if (Err == instrprof_error::success)
|
||||
return Error::success();
|
||||
return make_error<InstrProfError>(Err, ErrMsg);
|
||||
}
|
||||
|
||||
Error error(Error &&E) {
|
||||
handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
|
||||
LastError = IPE.get();
|
||||
LastErrorMsg = IPE.getMessage();
|
||||
});
|
||||
return make_error<InstrProfError>(LastError, LastErrorMsg);
|
||||
}
|
||||
|
||||
/// 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 != instrprof_error::success && !isEOF(); }
|
||||
|
||||
/// Get the current error.
|
||||
Error getError() {
|
||||
if (hasError())
|
||||
return make_error<InstrProfError>(LastError, LastErrorMsg);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Factory method to create an appropriately typed reader for the given
|
||||
/// instrprof file.
|
||||
static Expected<std::unique_ptr<InstrProfReader>>
|
||||
create(const Twine &Path, const InstrProfCorrelator *Correlator = nullptr);
|
||||
|
||||
static Expected<std::unique_ptr<InstrProfReader>>
|
||||
create(std::unique_ptr<MemoryBuffer> Buffer,
|
||||
const InstrProfCorrelator *Correlator = nullptr);
|
||||
};
|
||||
|
||||
/// Reader for the simple text based instrprof format.
|
||||
///
|
||||
/// This format is a simple text format that's suitable for test data. Records
|
||||
/// are separated by one or more blank lines, and record fields are separated by
|
||||
/// new lines.
|
||||
///
|
||||
/// Each record consists of a function name, a function hash, a number of
|
||||
/// counters, and then each counter value, in that order.
|
||||
class TextInstrProfReader : public InstrProfReader {
|
||||
private:
|
||||
/// The profile data file contents.
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer;
|
||||
/// Iterator over the profile data.
|
||||
line_iterator Line;
|
||||
/// The attributes of the current profile.
|
||||
InstrProfKind ProfileKind = InstrProfKind::Unknown;
|
||||
|
||||
Error readValueProfileData(InstrProfRecord &Record);
|
||||
|
||||
public:
|
||||
TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_)
|
||||
: DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {}
|
||||
TextInstrProfReader(const TextInstrProfReader &) = delete;
|
||||
TextInstrProfReader &operator=(const TextInstrProfReader &) = delete;
|
||||
|
||||
/// Return true if the given buffer is in text instrprof format.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
|
||||
bool isIRLevelProfile() const override {
|
||||
return static_cast<bool>(ProfileKind & InstrProfKind::IR);
|
||||
}
|
||||
|
||||
bool hasCSIRLevelProfile() const override {
|
||||
return static_cast<bool>(ProfileKind & InstrProfKind::CS);
|
||||
}
|
||||
|
||||
bool instrEntryBBEnabled() const override {
|
||||
return static_cast<bool>(ProfileKind & InstrProfKind::BB);
|
||||
}
|
||||
|
||||
bool hasSingleByteCoverage() const override {
|
||||
return static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage);
|
||||
}
|
||||
|
||||
bool functionEntryOnly() const override {
|
||||
return static_cast<bool>(ProfileKind & InstrProfKind::FunctionEntryOnly);
|
||||
}
|
||||
|
||||
InstrProfKind getProfileKind() const override { return ProfileKind; }
|
||||
|
||||
/// Read the header.
|
||||
Error readHeader() override;
|
||||
|
||||
/// Read a single record.
|
||||
Error readNextRecord(NamedInstrProfRecord &Record) override;
|
||||
|
||||
InstrProfSymtab &getSymtab() override {
|
||||
assert(Symtab.get());
|
||||
return *Symtab.get();
|
||||
}
|
||||
};
|
||||
|
||||
/// Reader for the raw instrprof binary format from runtime.
|
||||
///
|
||||
/// This format is a raw memory dump of the instrumentation-based profiling data
|
||||
/// from the runtime. It has no index.
|
||||
///
|
||||
/// Templated on the unsigned type whose size matches pointers on the platform
|
||||
/// that wrote the profile.
|
||||
template <class IntPtrT>
|
||||
class RawInstrProfReader : public InstrProfReader {
|
||||
private:
|
||||
/// The profile data file contents.
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer;
|
||||
/// If available, this hold the ProfileData array used to correlate raw
|
||||
/// instrumentation data to their functions.
|
||||
const InstrProfCorrelatorImpl<IntPtrT> *Correlator;
|
||||
bool ShouldSwapBytes;
|
||||
// The value of the version field of the raw profile data header. The lower 56
|
||||
// bits specifies the format version and the most significant 8 bits specify
|
||||
// the variant types of the profile.
|
||||
uint64_t Version;
|
||||
uint64_t CountersDelta;
|
||||
uint64_t NamesDelta;
|
||||
const RawInstrProf::ProfileData<IntPtrT> *Data;
|
||||
const RawInstrProf::ProfileData<IntPtrT> *DataEnd;
|
||||
const char *CountersStart;
|
||||
const char *CountersEnd;
|
||||
const char *NamesStart;
|
||||
const char *NamesEnd;
|
||||
// After value profile is all read, this pointer points to
|
||||
// the header of next profile data (if exists)
|
||||
const uint8_t *ValueDataStart;
|
||||
uint32_t ValueKindLast;
|
||||
uint32_t CurValueDataSize;
|
||||
|
||||
uint64_t BinaryIdsSize;
|
||||
const uint8_t *BinaryIdsStart;
|
||||
|
||||
public:
|
||||
RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer,
|
||||
const InstrProfCorrelator *Correlator)
|
||||
: DataBuffer(std::move(DataBuffer)),
|
||||
Correlator(dyn_cast_or_null<const InstrProfCorrelatorImpl<IntPtrT>>(
|
||||
Correlator)) {}
|
||||
RawInstrProfReader(const RawInstrProfReader &) = delete;
|
||||
RawInstrProfReader &operator=(const RawInstrProfReader &) = delete;
|
||||
|
||||
static bool hasFormat(const MemoryBuffer &DataBuffer);
|
||||
Error readHeader() override;
|
||||
Error readNextRecord(NamedInstrProfRecord &Record) override;
|
||||
Error printBinaryIds(raw_ostream &OS) override;
|
||||
|
||||
bool isIRLevelProfile() const override {
|
||||
return (Version & VARIANT_MASK_IR_PROF) != 0;
|
||||
}
|
||||
|
||||
bool hasCSIRLevelProfile() const override {
|
||||
return (Version & VARIANT_MASK_CSIR_PROF) != 0;
|
||||
}
|
||||
|
||||
bool instrEntryBBEnabled() const override {
|
||||
return (Version & VARIANT_MASK_INSTR_ENTRY) != 0;
|
||||
}
|
||||
|
||||
bool useDebugInfoCorrelate() const override {
|
||||
return (Version & VARIANT_MASK_DBG_CORRELATE) != 0;
|
||||
}
|
||||
|
||||
bool hasSingleByteCoverage() const override {
|
||||
return (Version & VARIANT_MASK_BYTE_COVERAGE) != 0;
|
||||
}
|
||||
|
||||
bool functionEntryOnly() const override {
|
||||
return (Version & VARIANT_MASK_FUNCTION_ENTRY_ONLY) != 0;
|
||||
}
|
||||
|
||||
/// Returns a BitsetEnum describing the attributes of the raw instr profile.
|
||||
InstrProfKind getProfileKind() const override;
|
||||
|
||||
InstrProfSymtab &getSymtab() override {
|
||||
assert(Symtab.get());
|
||||
return *Symtab.get();
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
}
|
||||
|
||||
support::endianness getDataEndianness() const {
|
||||
support::endianness HostEndian = getHostEndianness();
|
||||
if (!ShouldSwapBytes)
|
||||
return HostEndian;
|
||||
if (HostEndian == support::little)
|
||||
return support::big;
|
||||
else
|
||||
return support::little;
|
||||
}
|
||||
|
||||
inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) {
|
||||
return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
|
||||
}
|
||||
|
||||
Error readName(NamedInstrProfRecord &Record);
|
||||
Error readFuncHash(NamedInstrProfRecord &Record);
|
||||
Error readRawCounts(InstrProfRecord &Record);
|
||||
Error readValueProfilingData(InstrProfRecord &Record);
|
||||
bool atEnd() const { return Data == DataEnd; }
|
||||
|
||||
void advanceData() {
|
||||
// `CountersDelta` is a constant zero when using debug info correlation.
|
||||
if (!Correlator) {
|
||||
// The initial CountersDelta is the in-memory address difference between
|
||||
// the data and counts sections:
|
||||
// start(__llvm_prf_cnts) - start(__llvm_prf_data)
|
||||
// As we advance to the next record, we maintain the correct CountersDelta
|
||||
// with respect to the next record.
|
||||
CountersDelta -= sizeof(*Data);
|
||||
}
|
||||
Data++;
|
||||
ValueDataStart += CurValueDataSize;
|
||||
}
|
||||
|
||||
const char *getNextHeaderPos() const {
|
||||
assert(atEnd());
|
||||
return (const char *)ValueDataStart;
|
||||
}
|
||||
|
||||
StringRef getName(uint64_t NameRef) const {
|
||||
return Symtab->getFuncName(swap(NameRef));
|
||||
}
|
||||
|
||||
int getCounterTypeSize() const {
|
||||
return hasSingleByteCoverage() ? sizeof(uint8_t) : sizeof(uint64_t);
|
||||
}
|
||||
};
|
||||
|
||||
using RawInstrProfReader32 = RawInstrProfReader<uint32_t>;
|
||||
using RawInstrProfReader64 = RawInstrProfReader<uint64_t>;
|
||||
|
||||
namespace IndexedInstrProf {
|
||||
|
||||
enum class HashT : uint32_t;
|
||||
|
||||
} // end namespace IndexedInstrProf
|
||||
|
||||
/// Trait for lookups into the on-disk hash table for the binary instrprof
|
||||
/// format.
|
||||
class InstrProfLookupTrait {
|
||||
std::vector<NamedInstrProfRecord> DataBuffer;
|
||||
IndexedInstrProf::HashT HashType;
|
||||
unsigned FormatVersion;
|
||||
// Endianness of the input value profile data.
|
||||
// It should be LE by default, but can be changed
|
||||
// for testing purpose.
|
||||
support::endianness ValueProfDataEndianness = support::little;
|
||||
|
||||
public:
|
||||
InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion)
|
||||
: HashType(HashType), FormatVersion(FormatVersion) {}
|
||||
|
||||
using data_type = ArrayRef<NamedInstrProfRecord>;
|
||||
|
||||
using internal_key_type = StringRef;
|
||||
using external_key_type = StringRef;
|
||||
using hash_value_type = uint64_t;
|
||||
using offset_type = uint64_t;
|
||||
|
||||
static bool EqualKey(StringRef A, StringRef B) { return A == B; }
|
||||
static StringRef GetInternalKey(StringRef K) { return K; }
|
||||
static StringRef GetExternalKey(StringRef K) { return K; }
|
||||
|
||||
hash_value_type ComputeHash(StringRef K);
|
||||
|
||||
static std::pair<offset_type, offset_type>
|
||||
ReadKeyDataLength(const unsigned char *&D) {
|
||||
using namespace support;
|
||||
|
||||
offset_type KeyLen = endian::readNext<offset_type, little, unaligned>(D);
|
||||
offset_type DataLen = endian::readNext<offset_type, little, unaligned>(D);
|
||||
return std::make_pair(KeyLen, DataLen);
|
||||
}
|
||||
|
||||
StringRef ReadKey(const unsigned char *D, offset_type N) {
|
||||
return StringRef((const char *)D, N);
|
||||
}
|
||||
|
||||
bool readValueProfilingData(const unsigned char *&D,
|
||||
const unsigned char *const End);
|
||||
data_type ReadData(StringRef K, const unsigned char *D, offset_type N);
|
||||
|
||||
// Used for testing purpose only.
|
||||
void setValueProfDataEndianness(support::endianness Endianness) {
|
||||
ValueProfDataEndianness = Endianness;
|
||||
}
|
||||
};
|
||||
|
||||
struct InstrProfReaderIndexBase {
|
||||
virtual ~InstrProfReaderIndexBase() = default;
|
||||
|
||||
// Read all the profile records with the same key pointed to the current
|
||||
// iterator.
|
||||
virtual Error getRecords(ArrayRef<NamedInstrProfRecord> &Data) = 0;
|
||||
|
||||
// Read all the profile records with the key equal to FuncName
|
||||
virtual Error getRecords(StringRef FuncName,
|
||||
ArrayRef<NamedInstrProfRecord> &Data) = 0;
|
||||
virtual void advanceToNextKey() = 0;
|
||||
virtual bool atEnd() const = 0;
|
||||
virtual void setValueProfDataEndianness(support::endianness Endianness) = 0;
|
||||
virtual uint64_t getVersion() const = 0;
|
||||
virtual bool isIRLevelProfile() const = 0;
|
||||
virtual bool hasCSIRLevelProfile() const = 0;
|
||||
virtual bool instrEntryBBEnabled() const = 0;
|
||||
virtual bool hasSingleByteCoverage() const = 0;
|
||||
virtual bool functionEntryOnly() const = 0;
|
||||
virtual InstrProfKind getProfileKind() const = 0;
|
||||
virtual Error populateSymtab(InstrProfSymtab &) = 0;
|
||||
};
|
||||
|
||||
using OnDiskHashTableImplV3 =
|
||||
OnDiskIterableChainedHashTable<InstrProfLookupTrait>;
|
||||
|
||||
template <typename HashTableImpl>
|
||||
class InstrProfReaderItaniumRemapper;
|
||||
|
||||
template <typename HashTableImpl>
|
||||
class InstrProfReaderIndex : public InstrProfReaderIndexBase {
|
||||
private:
|
||||
std::unique_ptr<HashTableImpl> HashTable;
|
||||
typename HashTableImpl::data_iterator RecordIterator;
|
||||
uint64_t FormatVersion;
|
||||
|
||||
friend class InstrProfReaderItaniumRemapper<HashTableImpl>;
|
||||
|
||||
public:
|
||||
InstrProfReaderIndex(const unsigned char *Buckets,
|
||||
const unsigned char *const Payload,
|
||||
const unsigned char *const Base,
|
||||
IndexedInstrProf::HashT HashType, uint64_t Version);
|
||||
~InstrProfReaderIndex() override = default;
|
||||
|
||||
Error getRecords(ArrayRef<NamedInstrProfRecord> &Data) override;
|
||||
Error getRecords(StringRef FuncName,
|
||||
ArrayRef<NamedInstrProfRecord> &Data) override;
|
||||
void advanceToNextKey() override { RecordIterator++; }
|
||||
|
||||
bool atEnd() const override {
|
||||
return RecordIterator == HashTable->data_end();
|
||||
}
|
||||
|
||||
void setValueProfDataEndianness(support::endianness Endianness) override {
|
||||
HashTable->getInfoObj().setValueProfDataEndianness(Endianness);
|
||||
}
|
||||
|
||||
uint64_t getVersion() const override { return GET_VERSION(FormatVersion); }
|
||||
|
||||
bool isIRLevelProfile() const override {
|
||||
return (FormatVersion & VARIANT_MASK_IR_PROF) != 0;
|
||||
}
|
||||
|
||||
bool hasCSIRLevelProfile() const override {
|
||||
return (FormatVersion & VARIANT_MASK_CSIR_PROF) != 0;
|
||||
}
|
||||
|
||||
bool instrEntryBBEnabled() const override {
|
||||
return (FormatVersion & VARIANT_MASK_INSTR_ENTRY) != 0;
|
||||
}
|
||||
|
||||
bool hasSingleByteCoverage() const override {
|
||||
return (FormatVersion & VARIANT_MASK_BYTE_COVERAGE) != 0;
|
||||
}
|
||||
|
||||
bool functionEntryOnly() const override {
|
||||
return (FormatVersion & VARIANT_MASK_FUNCTION_ENTRY_ONLY) != 0;
|
||||
}
|
||||
|
||||
InstrProfKind getProfileKind() const override;
|
||||
|
||||
Error populateSymtab(InstrProfSymtab &Symtab) override {
|
||||
return Symtab.create(HashTable->keys());
|
||||
}
|
||||
};
|
||||
|
||||
/// Name matcher supporting fuzzy matching of symbol names to names in profiles.
|
||||
class InstrProfReaderRemapper {
|
||||
public:
|
||||
virtual ~InstrProfReaderRemapper() = default;
|
||||
virtual Error populateRemappings() { return Error::success(); }
|
||||
virtual Error getRecords(StringRef FuncName,
|
||||
ArrayRef<NamedInstrProfRecord> &Data) = 0;
|
||||
};
|
||||
|
||||
/// Reader for the indexed binary instrprof format.
|
||||
class IndexedInstrProfReader : public InstrProfReader {
|
||||
private:
|
||||
/// The profile data file contents.
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer;
|
||||
/// The profile remapping file contents.
|
||||
std::unique_ptr<MemoryBuffer> RemappingBuffer;
|
||||
/// The index into the profile data.
|
||||
std::unique_ptr<InstrProfReaderIndexBase> Index;
|
||||
/// The profile remapping file contents.
|
||||
std::unique_ptr<InstrProfReaderRemapper> Remapper;
|
||||
/// Profile summary data.
|
||||
std::unique_ptr<ProfileSummary> Summary;
|
||||
/// Context sensitive profile summary data.
|
||||
std::unique_ptr<ProfileSummary> CS_Summary;
|
||||
// Index to the current record in the record array.
|
||||
unsigned RecordIndex;
|
||||
|
||||
// Read the profile summary. Return a pointer pointing to one byte past the
|
||||
// end of the summary data if it exists or the input \c Cur.
|
||||
// \c UseCS indicates whether to use the context-sensitive profile summary.
|
||||
const unsigned char *readSummary(IndexedInstrProf::ProfVersion Version,
|
||||
const unsigned char *Cur, bool UseCS);
|
||||
|
||||
public:
|
||||
IndexedInstrProfReader(
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer,
|
||||
std::unique_ptr<MemoryBuffer> RemappingBuffer = nullptr)
|
||||
: DataBuffer(std::move(DataBuffer)),
|
||||
RemappingBuffer(std::move(RemappingBuffer)), RecordIndex(0) {}
|
||||
IndexedInstrProfReader(const IndexedInstrProfReader &) = delete;
|
||||
IndexedInstrProfReader &operator=(const IndexedInstrProfReader &) = delete;
|
||||
|
||||
/// Return the profile version.
|
||||
uint64_t getVersion() const { return Index->getVersion(); }
|
||||
bool isIRLevelProfile() const override { return Index->isIRLevelProfile(); }
|
||||
bool hasCSIRLevelProfile() const override {
|
||||
return Index->hasCSIRLevelProfile();
|
||||
}
|
||||
|
||||
bool instrEntryBBEnabled() const override {
|
||||
return Index->instrEntryBBEnabled();
|
||||
}
|
||||
|
||||
bool hasSingleByteCoverage() const override {
|
||||
return Index->hasSingleByteCoverage();
|
||||
}
|
||||
|
||||
bool functionEntryOnly() const override { return Index->functionEntryOnly(); }
|
||||
|
||||
/// Returns a BitsetEnum describing the attributes of the indexed instr
|
||||
/// profile.
|
||||
InstrProfKind getProfileKind() const override {
|
||||
return Index->getProfileKind();
|
||||
}
|
||||
|
||||
/// Return true if the given buffer is in an indexed instrprof format.
|
||||
static bool hasFormat(const MemoryBuffer &DataBuffer);
|
||||
|
||||
/// Read the file header.
|
||||
Error readHeader() override;
|
||||
/// Read a single record.
|
||||
Error readNextRecord(NamedInstrProfRecord &Record) override;
|
||||
|
||||
/// Return the NamedInstrProfRecord associated with FuncName and FuncHash
|
||||
Expected<InstrProfRecord> getInstrProfRecord(StringRef FuncName,
|
||||
uint64_t FuncHash);
|
||||
|
||||
/// Fill Counts with the profile data for the given function name.
|
||||
Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
|
||||
std::vector<uint64_t> &Counts);
|
||||
|
||||
/// Return the maximum of all known function counts.
|
||||
/// \c UseCS indicates whether to use the context-sensitive count.
|
||||
uint64_t getMaximumFunctionCount(bool UseCS) {
|
||||
if (UseCS) {
|
||||
assert(CS_Summary && "No context sensitive profile summary");
|
||||
return CS_Summary->getMaxFunctionCount();
|
||||
} else {
|
||||
assert(Summary && "No profile summary");
|
||||
return Summary->getMaxFunctionCount();
|
||||
}
|
||||
}
|
||||
|
||||
/// Factory method to create an indexed reader.
|
||||
static Expected<std::unique_ptr<IndexedInstrProfReader>>
|
||||
create(const Twine &Path, const Twine &RemappingPath = "");
|
||||
|
||||
static Expected<std::unique_ptr<IndexedInstrProfReader>>
|
||||
create(std::unique_ptr<MemoryBuffer> Buffer,
|
||||
std::unique_ptr<MemoryBuffer> RemappingBuffer = nullptr);
|
||||
|
||||
// Used for testing purpose only.
|
||||
void setValueProfDataEndianness(support::endianness Endianness) {
|
||||
Index->setValueProfDataEndianness(Endianness);
|
||||
}
|
||||
|
||||
// See description in the base class. This interface is designed
|
||||
// to be used by llvm-profdata (for dumping). Avoid using this when
|
||||
// the client is the compiler.
|
||||
InstrProfSymtab &getSymtab() override;
|
||||
|
||||
/// Return the profile summary.
|
||||
/// \c UseCS indicates whether to use the context-sensitive summary.
|
||||
ProfileSummary &getSummary(bool UseCS) {
|
||||
if (UseCS) {
|
||||
assert(CS_Summary && "No context sensitive summary");
|
||||
return *(CS_Summary.get());
|
||||
} else {
|
||||
assert(Summary && "No profile summary");
|
||||
return *(Summary.get());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_INSTRPROFREADER_H
|
134
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProfWriter.h
vendored
Normal file
134
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/InstrProfWriter.h
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
//===- InstrProfWriter.h - Instrumented profiling writer --------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for writing profiling data for instrumentation
|
||||
// based PGO and coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H
|
||||
#define LLVM_PROFILEDATA_INSTRPROFWRITER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Writer for instrumentation based profile data.
|
||||
class InstrProfRecordWriterTrait;
|
||||
class ProfOStream;
|
||||
class raw_fd_ostream;
|
||||
|
||||
class InstrProfWriter {
|
||||
public:
|
||||
using ProfilingData = SmallDenseMap<uint64_t, InstrProfRecord>;
|
||||
|
||||
private:
|
||||
bool Sparse;
|
||||
StringMap<ProfilingData> FunctionData;
|
||||
// An enum describing the attributes of the profile.
|
||||
InstrProfKind ProfileKind = InstrProfKind::Unknown;
|
||||
// Use raw pointer here for the incomplete type object.
|
||||
InstrProfRecordWriterTrait *InfoObj;
|
||||
|
||||
public:
|
||||
InstrProfWriter(bool Sparse = false);
|
||||
~InstrProfWriter();
|
||||
|
||||
StringMap<ProfilingData> &getProfileData() { return FunctionData; }
|
||||
|
||||
/// 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.
|
||||
void addRecord(NamedInstrProfRecord &&I, uint64_t Weight,
|
||||
function_ref<void(Error)> Warn);
|
||||
void addRecord(NamedInstrProfRecord &&I, function_ref<void(Error)> Warn) {
|
||||
addRecord(std::move(I), 1, Warn);
|
||||
}
|
||||
|
||||
/// Merge existing function counts from the given writer.
|
||||
void mergeRecordsFromWriter(InstrProfWriter &&IPW,
|
||||
function_ref<void(Error)> Warn);
|
||||
|
||||
/// Write the profile to \c OS
|
||||
Error write(raw_fd_ostream &OS);
|
||||
|
||||
/// Write the profile in text format to \c OS
|
||||
Error writeText(raw_fd_ostream &OS);
|
||||
|
||||
Error validateRecord(const InstrProfRecord &Func);
|
||||
|
||||
/// Write \c Record in text format to \c OS
|
||||
static void writeRecordInText(StringRef Name, uint64_t Hash,
|
||||
const InstrProfRecord &Counters,
|
||||
InstrProfSymtab &Symtab, raw_fd_ostream &OS);
|
||||
|
||||
/// Write the profile, returning the raw data. For testing.
|
||||
std::unique_ptr<MemoryBuffer> writeBuffer();
|
||||
|
||||
/// Update the attributes of the current profile from the attributes
|
||||
/// specified. An error is returned if IR and FE profiles are mixed.
|
||||
Error mergeProfileKind(const InstrProfKind Other) {
|
||||
// If the kind is unset, this is the first profile we are merging so just
|
||||
// set it to the given type.
|
||||
if (ProfileKind == InstrProfKind::Unknown) {
|
||||
ProfileKind = Other;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// Returns true if merging should fail assuming A and B are incompatible.
|
||||
auto testIncompatible = [&](InstrProfKind A, InstrProfKind B) {
|
||||
return (static_cast<bool>(ProfileKind & A) &&
|
||||
static_cast<bool>(Other & B)) ||
|
||||
(static_cast<bool>(ProfileKind & B) &&
|
||||
static_cast<bool>(Other & A));
|
||||
};
|
||||
|
||||
// Check if the profiles are in-compatible. Clang frontend profiles can't be
|
||||
// merged with other profile types.
|
||||
if (static_cast<bool>((ProfileKind & InstrProfKind::FE) ^
|
||||
(Other & InstrProfKind::FE))) {
|
||||
return make_error<InstrProfError>(instrprof_error::unsupported_version);
|
||||
}
|
||||
if (testIncompatible(InstrProfKind::FunctionEntryOnly, InstrProfKind::BB)) {
|
||||
return make_error<InstrProfError>(
|
||||
instrprof_error::unsupported_version,
|
||||
"cannot merge FunctionEntryOnly profiles and BB profiles together");
|
||||
}
|
||||
|
||||
// Now we update the profile type with the bits that are set.
|
||||
ProfileKind |= Other;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// Internal interface for testing purpose only.
|
||||
void setValueProfDataEndianness(support::endianness Endianness);
|
||||
void setOutputSparse(bool Sparse);
|
||||
// Compute the overlap b/w this object and Other. Program level result is
|
||||
// stored in Overlap and function level result is stored in FuncLevelOverlap.
|
||||
void overlapRecord(NamedInstrProfRecord &&Other, OverlapStats &Overlap,
|
||||
OverlapStats &FuncLevelOverlap,
|
||||
const OverlapFuncFilters &FuncFilter);
|
||||
|
||||
private:
|
||||
void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I,
|
||||
uint64_t Weight, function_ref<void(Error)> Warn);
|
||||
bool shouldEncodeData(const ProfilingData &PD);
|
||||
|
||||
Error writeImpl(ProfOStream &OS);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_INSTRPROFWRITER_H
|
111
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/ProfileCommon.h
vendored
Normal file
111
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/ProfileCommon.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
//===- ProfileCommon.h - Common profiling APIs. -----------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains data structures and functions common to both instrumented
|
||||
// and sample profiling.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_PROFILECOMMON_H
|
||||
#define LLVM_PROFILEDATA_PROFILECOMMON_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/IR/ProfileSummary.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/ProfileData/SampleProf.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace sampleprof {
|
||||
|
||||
class FunctionSamples;
|
||||
|
||||
} // end namespace sampleprof
|
||||
|
||||
inline const char *getHotSectionPrefix() { return "hot"; }
|
||||
inline const char *getUnlikelySectionPrefix() { return "unlikely"; }
|
||||
|
||||
class ProfileSummaryBuilder {
|
||||
private:
|
||||
/// We keep track of the number of times a count (block count or samples)
|
||||
/// appears in the profile. The map is kept sorted in the descending order of
|
||||
/// counts.
|
||||
std::map<uint64_t, uint32_t, std::greater<uint64_t>> CountFrequencies;
|
||||
std::vector<uint32_t> DetailedSummaryCutoffs;
|
||||
|
||||
protected:
|
||||
SummaryEntryVector DetailedSummary;
|
||||
uint64_t TotalCount = 0;
|
||||
uint64_t MaxCount = 0;
|
||||
uint64_t MaxFunctionCount = 0;
|
||||
uint32_t NumCounts = 0;
|
||||
uint32_t NumFunctions = 0;
|
||||
|
||||
ProfileSummaryBuilder(std::vector<uint32_t> Cutoffs)
|
||||
: DetailedSummaryCutoffs(std::move(Cutoffs)) {}
|
||||
~ProfileSummaryBuilder() = default;
|
||||
|
||||
inline void addCount(uint64_t Count);
|
||||
void computeDetailedSummary();
|
||||
|
||||
public:
|
||||
/// A vector of useful cutoff values for detailed summary.
|
||||
static const ArrayRef<uint32_t> DefaultCutoffs;
|
||||
|
||||
/// Find the summary entry for a desired percentile of counts.
|
||||
static const ProfileSummaryEntry &
|
||||
getEntryForPercentile(const SummaryEntryVector &DS, uint64_t Percentile);
|
||||
static uint64_t getHotCountThreshold(const SummaryEntryVector &DS);
|
||||
static uint64_t getColdCountThreshold(const SummaryEntryVector &DS);
|
||||
};
|
||||
|
||||
class InstrProfSummaryBuilder final : public ProfileSummaryBuilder {
|
||||
uint64_t MaxInternalBlockCount = 0;
|
||||
|
||||
inline void addEntryCount(uint64_t Count);
|
||||
inline void addInternalCount(uint64_t Count);
|
||||
|
||||
public:
|
||||
InstrProfSummaryBuilder(std::vector<uint32_t> Cutoffs)
|
||||
: ProfileSummaryBuilder(std::move(Cutoffs)) {}
|
||||
|
||||
void addRecord(const InstrProfRecord &);
|
||||
std::unique_ptr<ProfileSummary> getSummary();
|
||||
};
|
||||
|
||||
class SampleProfileSummaryBuilder final : public ProfileSummaryBuilder {
|
||||
public:
|
||||
SampleProfileSummaryBuilder(std::vector<uint32_t> Cutoffs)
|
||||
: ProfileSummaryBuilder(std::move(Cutoffs)) {}
|
||||
|
||||
void addRecord(const sampleprof::FunctionSamples &FS,
|
||||
bool isCallsiteSample = false);
|
||||
std::unique_ptr<ProfileSummary>
|
||||
computeSummaryForProfiles(const sampleprof::SampleProfileMap &Profiles);
|
||||
std::unique_ptr<ProfileSummary> getSummary();
|
||||
};
|
||||
|
||||
/// This is called when a count is seen in the profile.
|
||||
void ProfileSummaryBuilder::addCount(uint64_t Count) {
|
||||
TotalCount += Count;
|
||||
if (Count > MaxCount)
|
||||
MaxCount = Count;
|
||||
NumCounts++;
|
||||
CountFrequencies[Count]++;
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_PROFILECOMMON_H
|
43
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/RawMemProfReader.h
vendored
Normal file
43
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/RawMemProfReader.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
|
||||
#define LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
|
||||
//===- MemProfReader.h - Instrumented memory profiling reader ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for reading MemProf profiling data.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace memprof {
|
||||
|
||||
class RawMemProfReader {
|
||||
public:
|
||||
RawMemProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
|
||||
: DataBuffer(std::move(DataBuffer)) {}
|
||||
// Prints aggregate counts for each raw profile parsed from the DataBuffer.
|
||||
void printSummaries(raw_ostream &OS) const;
|
||||
|
||||
// Return true if the \p DataBuffer starts with magic bytes indicating it is
|
||||
// a raw binary memprof profile.
|
||||
static bool hasFormat(const MemoryBuffer &DataBuffer);
|
||||
|
||||
// Create a RawMemProfReader after sanity checking the contents of the file at
|
||||
// \p Path.
|
||||
static Expected<std::unique_ptr<RawMemProfReader>> create(const Twine &Path);
|
||||
|
||||
private:
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer;
|
||||
};
|
||||
|
||||
} // namespace memprof
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
|
1279
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/SampleProf.h
vendored
Normal file
1279
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/SampleProf.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
903
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/SampleProfReader.h
vendored
Normal file
903
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/SampleProfReader.h
vendored
Normal file
@@ -0,0 +1,903 @@
|
||||
//===- SampleProfReader.h - Read LLVM sample profile data -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains definitions needed for reading sample profiles.
|
||||
//
|
||||
// NOTE: If you are making changes to this file format, please remember
|
||||
// to document them in the Clang documentation at
|
||||
// tools/clang/docs/UsersManual.rst.
|
||||
//
|
||||
// Text format
|
||||
// -----------
|
||||
//
|
||||
// Sample profiles are written as ASCII text. The file is divided into
|
||||
// sections, which correspond to each of the functions executed at runtime.
|
||||
// Each section has the following format
|
||||
//
|
||||
// function1:total_samples:total_head_samples
|
||||
// offset1[.discriminator]: number_of_samples [fn1:num fn2:num ... ]
|
||||
// offset2[.discriminator]: number_of_samples [fn3:num fn4:num ... ]
|
||||
// ...
|
||||
// offsetN[.discriminator]: number_of_samples [fn5:num fn6:num ... ]
|
||||
// offsetA[.discriminator]: fnA:num_of_total_samples
|
||||
// offsetA1[.discriminator]: number_of_samples [fn7:num fn8:num ... ]
|
||||
// ...
|
||||
// !CFGChecksum: num
|
||||
// !Attribute: flags
|
||||
//
|
||||
// This is a nested tree in which the indentation represents the nesting level
|
||||
// of the inline stack. There are no blank lines in the file. And the spacing
|
||||
// within a single line is fixed. Additional spaces will result in an error
|
||||
// while reading the file.
|
||||
//
|
||||
// Any line starting with the '#' character is completely ignored.
|
||||
//
|
||||
// Inlined calls are represented with indentation. The Inline stack is a
|
||||
// stack of source locations in which the top of the stack represents the
|
||||
// leaf function, and the bottom of the stack represents the actual
|
||||
// symbol to which the instruction belongs.
|
||||
//
|
||||
// Function names must be mangled in order for the profile loader to
|
||||
// match them in the current translation unit. The two numbers in the
|
||||
// function header specify how many total samples were accumulated in the
|
||||
// function (first number), and the total number of samples accumulated
|
||||
// in the prologue of the function (second number). This head sample
|
||||
// count provides an indicator of how frequently the function is invoked.
|
||||
//
|
||||
// There are three types of lines in the function body.
|
||||
//
|
||||
// * Sampled line represents the profile information of a source location.
|
||||
// * Callsite line represents the profile information of a callsite.
|
||||
// * Metadata line represents extra metadata of the function.
|
||||
//
|
||||
// Each sampled line may contain several items. Some are optional (marked
|
||||
// below):
|
||||
//
|
||||
// a. Source line offset. This number represents the line number
|
||||
// in the function where the sample was collected. The line number is
|
||||
// always relative to the line where symbol of the function is
|
||||
// defined. So, if the function has its header at line 280, the offset
|
||||
// 13 is at line 293 in the file.
|
||||
//
|
||||
// Note that this offset should never be a negative number. This could
|
||||
// happen in cases like macros. The debug machinery will register the
|
||||
// line number at the point of macro expansion. So, if the macro was
|
||||
// expanded in a line before the start of the function, the profile
|
||||
// converter should emit a 0 as the offset (this means that the optimizers
|
||||
// will not be able to associate a meaningful weight to the instructions
|
||||
// in the macro).
|
||||
//
|
||||
// b. [OPTIONAL] Discriminator. This is used if the sampled program
|
||||
// was compiled with DWARF discriminator support
|
||||
// (http://wiki.dwarfstd.org/index.php?title=Path_Discriminators).
|
||||
// DWARF discriminators are unsigned integer values that allow the
|
||||
// compiler to distinguish between multiple execution paths on the
|
||||
// same source line location.
|
||||
//
|
||||
// For example, consider the line of code ``if (cond) foo(); else bar();``.
|
||||
// If the predicate ``cond`` is true 80% of the time, then the edge
|
||||
// into function ``foo`` should be considered to be taken most of the
|
||||
// time. But both calls to ``foo`` and ``bar`` are at the same source
|
||||
// line, so a sample count at that line is not sufficient. The
|
||||
// compiler needs to know which part of that line is taken more
|
||||
// frequently.
|
||||
//
|
||||
// This is what discriminators provide. In this case, the calls to
|
||||
// ``foo`` and ``bar`` will be at the same line, but will have
|
||||
// different discriminator values. This allows the compiler to correctly
|
||||
// set edge weights into ``foo`` and ``bar``.
|
||||
//
|
||||
// c. Number of samples. This is an integer quantity representing the
|
||||
// number of samples collected by the profiler at this source
|
||||
// location.
|
||||
//
|
||||
// d. [OPTIONAL] Potential call targets and samples. If present, this
|
||||
// line contains a call instruction. This models both direct and
|
||||
// number of samples. For example,
|
||||
//
|
||||
// 130: 7 foo:3 bar:2 baz:7
|
||||
//
|
||||
// The above means that at relative line offset 130 there is a call
|
||||
// instruction that calls one of ``foo()``, ``bar()`` and ``baz()``,
|
||||
// with ``baz()`` being the relatively more frequently called target.
|
||||
//
|
||||
// Each callsite line may contain several items. Some are optional.
|
||||
//
|
||||
// a. Source line offset. This number represents the line number of the
|
||||
// callsite that is inlined in the profiled binary.
|
||||
//
|
||||
// b. [OPTIONAL] Discriminator. Same as the discriminator for sampled line.
|
||||
//
|
||||
// c. Number of samples. This is an integer quantity representing the
|
||||
// total number of samples collected for the inlined instance at this
|
||||
// callsite
|
||||
//
|
||||
// Metadata line can occur in lines with one indent only, containing extra
|
||||
// information for the top-level function. Furthermore, metadata can only
|
||||
// occur after all the body samples and callsite samples.
|
||||
// Each metadata line may contain a particular type of metadata, marked by
|
||||
// the starting characters annotated with !. We process each metadata line
|
||||
// independently, hence each metadata line has to form an independent piece
|
||||
// of information that does not require cross-line reference.
|
||||
// We support the following types of metadata:
|
||||
//
|
||||
// a. CFG Checksum (a.k.a. function hash):
|
||||
// !CFGChecksum: 12345
|
||||
// b. CFG Checksum (see ContextAttributeMask):
|
||||
// !Attribute: 1
|
||||
//
|
||||
//
|
||||
// Binary format
|
||||
// -------------
|
||||
//
|
||||
// This is a more compact encoding. Numbers are encoded as ULEB128 values
|
||||
// and all strings are encoded in a name table. The file is organized in
|
||||
// the following sections:
|
||||
//
|
||||
// MAGIC (uint64_t)
|
||||
// File identifier computed by function SPMagic() (0x5350524f463432ff)
|
||||
//
|
||||
// VERSION (uint32_t)
|
||||
// File format version number computed by SPVersion()
|
||||
//
|
||||
// SUMMARY
|
||||
// TOTAL_COUNT (uint64_t)
|
||||
// Total number of samples in the profile.
|
||||
// MAX_COUNT (uint64_t)
|
||||
// Maximum value of samples on a line.
|
||||
// MAX_FUNCTION_COUNT (uint64_t)
|
||||
// Maximum number of samples at function entry (head samples).
|
||||
// NUM_COUNTS (uint64_t)
|
||||
// Number of lines with samples.
|
||||
// NUM_FUNCTIONS (uint64_t)
|
||||
// Number of functions with samples.
|
||||
// NUM_DETAILED_SUMMARY_ENTRIES (size_t)
|
||||
// Number of entries in detailed summary
|
||||
// DETAILED_SUMMARY
|
||||
// A list of detailed summary entry. Each entry consists of
|
||||
// CUTOFF (uint32_t)
|
||||
// Required percentile of total sample count expressed as a fraction
|
||||
// multiplied by 1000000.
|
||||
// MIN_COUNT (uint64_t)
|
||||
// The minimum number of samples required to reach the target
|
||||
// CUTOFF.
|
||||
// NUM_COUNTS (uint64_t)
|
||||
// Number of samples to get to the desired percentile.
|
||||
//
|
||||
// NAME TABLE
|
||||
// SIZE (uint32_t)
|
||||
// Number of entries in the name table.
|
||||
// NAMES
|
||||
// A NUL-separated list of SIZE strings.
|
||||
//
|
||||
// FUNCTION BODY (one for each uninlined function body present in the profile)
|
||||
// HEAD_SAMPLES (uint64_t) [only for top-level functions]
|
||||
// Total number of samples collected at the head (prologue) of the
|
||||
// function.
|
||||
// NOTE: This field should only be present for top-level functions
|
||||
// (i.e., not inlined into any caller). Inlined function calls
|
||||
// have no prologue, so they don't need this.
|
||||
// NAME_IDX (uint32_t)
|
||||
// Index into the name table indicating the function name.
|
||||
// SAMPLES (uint64_t)
|
||||
// Total number of samples collected in this function.
|
||||
// NRECS (uint32_t)
|
||||
// Total number of sampling records this function's profile.
|
||||
// BODY RECORDS
|
||||
// A list of NRECS entries. Each entry contains:
|
||||
// OFFSET (uint32_t)
|
||||
// Line offset from the start of the function.
|
||||
// DISCRIMINATOR (uint32_t)
|
||||
// Discriminator value (see description of discriminators
|
||||
// in the text format documentation above).
|
||||
// SAMPLES (uint64_t)
|
||||
// Number of samples collected at this location.
|
||||
// NUM_CALLS (uint32_t)
|
||||
// Number of non-inlined function calls made at this location. In the
|
||||
// case of direct calls, this number will always be 1. For indirect
|
||||
// calls (virtual functions and function pointers) this will
|
||||
// represent all the actual functions called at runtime.
|
||||
// CALL_TARGETS
|
||||
// A list of NUM_CALLS entries for each called function:
|
||||
// NAME_IDX (uint32_t)
|
||||
// Index into the name table with the callee name.
|
||||
// SAMPLES (uint64_t)
|
||||
// Number of samples collected at the call site.
|
||||
// NUM_INLINED_FUNCTIONS (uint32_t)
|
||||
// Number of callees inlined into this function.
|
||||
// INLINED FUNCTION RECORDS
|
||||
// A list of NUM_INLINED_FUNCTIONS entries describing each of the inlined
|
||||
// callees.
|
||||
// OFFSET (uint32_t)
|
||||
// Line offset from the start of the function.
|
||||
// DISCRIMINATOR (uint32_t)
|
||||
// Discriminator value (see description of discriminators
|
||||
// in the text format documentation above).
|
||||
// FUNCTION BODY
|
||||
// A FUNCTION BODY entry describing the inlined function.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILEDATA_SAMPLEPROFREADER_H
|
||||
#define LLVM_PROFILEDATA_SAMPLEPROFREADER_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/IR/DiagnosticInfo.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/ProfileSummary.h"
|
||||
#include "llvm/ProfileData/GCOV.h"
|
||||
#include "llvm/ProfileData/SampleProf.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Discriminator.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/SymbolRemappingReader.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
class Twine;
|
||||
|
||||
namespace sampleprof {
|
||||
|
||||
class SampleProfileReader;
|
||||
|
||||
/// SampleProfileReaderItaniumRemapper remaps the profile data from a
|
||||
/// sample profile data reader, by applying a provided set of equivalences
|
||||
/// between components of the symbol names in the profile.
|
||||
class SampleProfileReaderItaniumRemapper {
|
||||
public:
|
||||
SampleProfileReaderItaniumRemapper(std::unique_ptr<MemoryBuffer> B,
|
||||
std::unique_ptr<SymbolRemappingReader> SRR,
|
||||
SampleProfileReader &R)
|
||||
: Buffer(std::move(B)), Remappings(std::move(SRR)), Reader(R) {
|
||||
assert(Remappings && "Remappings cannot be nullptr");
|
||||
}
|
||||
|
||||
/// Create a remapper from the given remapping file. The remapper will
|
||||
/// be used for profile read in by Reader.
|
||||
static ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
|
||||
create(const std::string Filename, SampleProfileReader &Reader,
|
||||
LLVMContext &C);
|
||||
|
||||
/// Create a remapper from the given Buffer. The remapper will
|
||||
/// be used for profile read in by Reader.
|
||||
static ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
|
||||
create(std::unique_ptr<MemoryBuffer> &B, SampleProfileReader &Reader,
|
||||
LLVMContext &C);
|
||||
|
||||
/// Apply remappings to the profile read by Reader.
|
||||
void applyRemapping(LLVMContext &Ctx);
|
||||
|
||||
bool hasApplied() { return RemappingApplied; }
|
||||
|
||||
/// Insert function name into remapper.
|
||||
void insert(StringRef FunctionName) { Remappings->insert(FunctionName); }
|
||||
|
||||
/// Query whether there is equivalent in the remapper which has been
|
||||
/// inserted.
|
||||
bool exist(StringRef FunctionName) {
|
||||
return Remappings->lookup(FunctionName);
|
||||
}
|
||||
|
||||
/// Return the equivalent name in the profile for \p FunctionName if
|
||||
/// it exists.
|
||||
Optional<StringRef> lookUpNameInProfile(StringRef FunctionName);
|
||||
|
||||
private:
|
||||
// The buffer holding the content read from remapping file.
|
||||
std::unique_ptr<MemoryBuffer> Buffer;
|
||||
std::unique_ptr<SymbolRemappingReader> Remappings;
|
||||
// Map remapping key to the name in the profile. By looking up the
|
||||
// key in the remapper, a given new name can be mapped to the
|
||||
// canonical name using the NameMap.
|
||||
DenseMap<SymbolRemappingReader::Key, StringRef> NameMap;
|
||||
// The Reader the remapper is servicing.
|
||||
SampleProfileReader &Reader;
|
||||
// Indicate whether remapping has been applied to the profile read
|
||||
// by Reader -- by calling applyRemapping.
|
||||
bool RemappingApplied = false;
|
||||
};
|
||||
|
||||
/// Sample-based profile reader.
|
||||
///
|
||||
/// Each profile contains sample counts for all the functions
|
||||
/// executed. Inside each function, statements are annotated with the
|
||||
/// collected samples on all the instructions associated with that
|
||||
/// statement.
|
||||
///
|
||||
/// For this to produce meaningful data, the program needs to be
|
||||
/// compiled with some debug information (at minimum, line numbers:
|
||||
/// -gline-tables-only). Otherwise, it will be impossible to match IR
|
||||
/// instructions to the line numbers collected by the profiler.
|
||||
///
|
||||
/// From the profile file, we are interested in collecting the
|
||||
/// following information:
|
||||
///
|
||||
/// * A list of functions included in the profile (mangled names).
|
||||
///
|
||||
/// * For each function F:
|
||||
/// 1. The total number of samples collected in F.
|
||||
///
|
||||
/// 2. The samples collected at each line in F. To provide some
|
||||
/// protection against source code shuffling, line numbers should
|
||||
/// be relative to the start of the function.
|
||||
///
|
||||
/// The reader supports two file formats: text and binary. The text format
|
||||
/// is useful for debugging and testing, while the binary format is more
|
||||
/// compact and I/O efficient. They can both be used interchangeably.
|
||||
class SampleProfileReader {
|
||||
public:
|
||||
SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
|
||||
SampleProfileFormat Format = SPF_None)
|
||||
: Profiles(0), Ctx(C), Buffer(std::move(B)), Format(Format) {}
|
||||
|
||||
virtual ~SampleProfileReader() = default;
|
||||
|
||||
/// Read and validate the file header.
|
||||
virtual std::error_code readHeader() = 0;
|
||||
|
||||
/// Set the bits for FS discriminators. Parameter Pass specify the sequence
|
||||
/// number, Pass == i is for the i-th round of adding FS discriminators.
|
||||
/// Pass == 0 is for using base discriminators.
|
||||
void setDiscriminatorMaskedBitFrom(FSDiscriminatorPass P) {
|
||||
MaskedBitFrom = getFSPassBitEnd(P);
|
||||
}
|
||||
|
||||
/// Get the bitmask the discriminators: For FS profiles, return the bit
|
||||
/// mask for this pass. For non FS profiles, return (unsigned) -1.
|
||||
uint32_t getDiscriminatorMask() const {
|
||||
if (!ProfileIsFS)
|
||||
return 0xFFFFFFFF;
|
||||
assert((MaskedBitFrom != 0) && "MaskedBitFrom is not set properly");
|
||||
return getN1Bits(MaskedBitFrom);
|
||||
}
|
||||
|
||||
/// The interface to read sample profiles from the associated file.
|
||||
std::error_code read() {
|
||||
if (std::error_code EC = readImpl())
|
||||
return EC;
|
||||
if (Remapper)
|
||||
Remapper->applyRemapping(Ctx);
|
||||
FunctionSamples::UseMD5 = useMD5();
|
||||
return sampleprof_error::success;
|
||||
}
|
||||
|
||||
/// The implementation to read sample profiles from the associated file.
|
||||
virtual std::error_code readImpl() = 0;
|
||||
|
||||
/// Print the profile for \p FContext on stream \p OS.
|
||||
void dumpFunctionProfile(SampleContext FContext, raw_ostream &OS = dbgs());
|
||||
|
||||
/// Collect functions with definitions in Module M. For reader which
|
||||
/// support loading function profiles on demand, return true when the
|
||||
/// reader has been given a module. Always return false for reader
|
||||
/// which doesn't support loading function profiles on demand.
|
||||
virtual bool collectFuncsFromModule() { return false; }
|
||||
|
||||
/// Print all the profiles on stream \p OS.
|
||||
void dump(raw_ostream &OS = dbgs());
|
||||
|
||||
/// Return the samples collected for function \p F.
|
||||
FunctionSamples *getSamplesFor(const Function &F) {
|
||||
// The function name may have been updated by adding suffix. Call
|
||||
// a helper to (optionally) strip off suffixes so that we can
|
||||
// match against the original function name in the profile.
|
||||
StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
|
||||
return getSamplesFor(CanonName);
|
||||
}
|
||||
|
||||
/// Return the samples collected for function \p F, create empty
|
||||
/// FunctionSamples if it doesn't exist.
|
||||
FunctionSamples *getOrCreateSamplesFor(const Function &F) {
|
||||
std::string FGUID;
|
||||
StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
|
||||
CanonName = getRepInFormat(CanonName, useMD5(), FGUID);
|
||||
auto It = Profiles.find(CanonName);
|
||||
if (It != Profiles.end())
|
||||
return &It->second;
|
||||
if (!FGUID.empty()) {
|
||||
assert(useMD5() && "New name should only be generated for md5 profile");
|
||||
CanonName = *MD5NameBuffer.insert(FGUID).first;
|
||||
}
|
||||
return &Profiles[CanonName];
|
||||
}
|
||||
|
||||
/// Return the samples collected for function \p F.
|
||||
virtual FunctionSamples *getSamplesFor(StringRef Fname) {
|
||||
std::string FGUID;
|
||||
Fname = getRepInFormat(Fname, useMD5(), FGUID);
|
||||
auto It = Profiles.find(Fname);
|
||||
if (It != Profiles.end())
|
||||
return &It->second;
|
||||
|
||||
if (Remapper) {
|
||||
if (auto NameInProfile = Remapper->lookUpNameInProfile(Fname)) {
|
||||
auto It = Profiles.find(*NameInProfile);
|
||||
if (It != Profiles.end())
|
||||
return &It->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Return all the profiles.
|
||||
SampleProfileMap &getProfiles() { return Profiles; }
|
||||
|
||||
/// Report a parse error message.
|
||||
void reportError(int64_t LineNumber, const Twine &Msg) const {
|
||||
Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
|
||||
LineNumber, Msg));
|
||||
}
|
||||
|
||||
/// Create a sample profile reader appropriate to the file format.
|
||||
/// Create a remapper underlying if RemapFilename is not empty.
|
||||
/// Parameter P specifies the FSDiscriminatorPass.
|
||||
static ErrorOr<std::unique_ptr<SampleProfileReader>>
|
||||
create(const std::string Filename, LLVMContext &C,
|
||||
FSDiscriminatorPass P = FSDiscriminatorPass::Base,
|
||||
const std::string RemapFilename = "");
|
||||
|
||||
/// Create a sample profile reader from the supplied memory buffer.
|
||||
/// Create a remapper underlying if RemapFilename is not empty.
|
||||
/// Parameter P specifies the FSDiscriminatorPass.
|
||||
static ErrorOr<std::unique_ptr<SampleProfileReader>>
|
||||
create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
|
||||
FSDiscriminatorPass P = FSDiscriminatorPass::Base,
|
||||
const std::string RemapFilename = "");
|
||||
|
||||
/// Return the profile summary.
|
||||
ProfileSummary &getSummary() const { return *(Summary.get()); }
|
||||
|
||||
MemoryBuffer *getBuffer() const { return Buffer.get(); }
|
||||
|
||||
/// \brief Return the profile format.
|
||||
SampleProfileFormat getFormat() const { return Format; }
|
||||
|
||||
/// Whether input profile is based on pseudo probes.
|
||||
bool profileIsProbeBased() const { return ProfileIsProbeBased; }
|
||||
|
||||
/// Whether input profile is fully context-sensitive and flat.
|
||||
bool profileIsCSFlat() const { return ProfileIsCSFlat; }
|
||||
|
||||
/// Whether input profile is fully context-sensitive and nested.
|
||||
bool profileIsCSNested() const { return ProfileIsCSNested; }
|
||||
|
||||
virtual std::unique_ptr<ProfileSymbolList> getProfileSymbolList() {
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
/// It includes all the names that have samples either in outline instance
|
||||
/// or inline instance.
|
||||
virtual std::vector<StringRef> *getNameTable() { return nullptr; }
|
||||
virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) { return false; };
|
||||
|
||||
/// Return whether names in the profile are all MD5 numbers.
|
||||
virtual bool useMD5() { return false; }
|
||||
|
||||
/// Don't read profile without context if the flag is set. This is only meaningful
|
||||
/// for ExtBinary format.
|
||||
virtual void setSkipFlatProf(bool Skip) {}
|
||||
/// Return whether any name in the profile contains ".__uniq." suffix.
|
||||
virtual bool hasUniqSuffix() { return false; }
|
||||
|
||||
SampleProfileReaderItaniumRemapper *getRemapper() { return Remapper.get(); }
|
||||
|
||||
void setModule(const Module *Mod) { M = Mod; }
|
||||
|
||||
protected:
|
||||
/// Map every function to its associated profile.
|
||||
///
|
||||
/// The profile of every function executed at runtime is collected
|
||||
/// in the structure FunctionSamples. This maps function objects
|
||||
/// to their corresponding profiles.
|
||||
SampleProfileMap Profiles;
|
||||
|
||||
/// LLVM context used to emit diagnostics.
|
||||
LLVMContext &Ctx;
|
||||
|
||||
/// Memory buffer holding the profile file.
|
||||
std::unique_ptr<MemoryBuffer> Buffer;
|
||||
|
||||
/// Extra name buffer holding names created on demand.
|
||||
/// This should only be needed for md5 profiles.
|
||||
std::unordered_set<std::string> MD5NameBuffer;
|
||||
|
||||
/// Profile summary information.
|
||||
std::unique_ptr<ProfileSummary> Summary;
|
||||
|
||||
/// Take ownership of the summary of this reader.
|
||||
static std::unique_ptr<ProfileSummary>
|
||||
takeSummary(SampleProfileReader &Reader) {
|
||||
return std::move(Reader.Summary);
|
||||
}
|
||||
|
||||
/// Compute summary for this profile.
|
||||
void computeSummary();
|
||||
|
||||
std::unique_ptr<SampleProfileReaderItaniumRemapper> Remapper;
|
||||
|
||||
/// \brief Whether samples are collected based on pseudo probes.
|
||||
bool ProfileIsProbeBased = false;
|
||||
|
||||
/// Whether function profiles are context-sensitive flat profiles.
|
||||
bool ProfileIsCSFlat = false;
|
||||
|
||||
/// Whether function profiles are context-sensitive nested profiles.
|
||||
bool ProfileIsCSNested = false;
|
||||
|
||||
/// Number of context-sensitive profiles.
|
||||
uint32_t CSProfileCount = 0;
|
||||
|
||||
/// Whether the function profiles use FS discriminators.
|
||||
bool ProfileIsFS = false;
|
||||
|
||||
/// \brief The format of sample.
|
||||
SampleProfileFormat Format = SPF_None;
|
||||
|
||||
/// \brief The current module being compiled if SampleProfileReader
|
||||
/// is used by compiler. If SampleProfileReader is used by other
|
||||
/// tools which are not compiler, M is usually nullptr.
|
||||
const Module *M = nullptr;
|
||||
|
||||
/// Zero out the discriminator bits higher than bit MaskedBitFrom (0 based).
|
||||
/// The default is to keep all the bits.
|
||||
uint32_t MaskedBitFrom = 31;
|
||||
};
|
||||
|
||||
class SampleProfileReaderText : public SampleProfileReader {
|
||||
public:
|
||||
SampleProfileReaderText(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
|
||||
: SampleProfileReader(std::move(B), C, SPF_Text) {}
|
||||
|
||||
/// Read and validate the file header.
|
||||
std::error_code readHeader() override { return sampleprof_error::success; }
|
||||
|
||||
/// Read sample profiles from the associated file.
|
||||
std::error_code readImpl() override;
|
||||
|
||||
/// Return true if \p Buffer is in the format supported by this class.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
|
||||
private:
|
||||
/// CSNameTable is used to save full context vectors. This serves as an
|
||||
/// underlying immutable buffer for all clients.
|
||||
std::list<SampleContextFrameVector> CSNameTable;
|
||||
};
|
||||
|
||||
class SampleProfileReaderBinary : public SampleProfileReader {
|
||||
public:
|
||||
SampleProfileReaderBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
|
||||
SampleProfileFormat Format = SPF_None)
|
||||
: SampleProfileReader(std::move(B), C, Format) {}
|
||||
|
||||
/// Read and validate the file header.
|
||||
virtual std::error_code readHeader() override;
|
||||
|
||||
/// Read sample profiles from the associated file.
|
||||
std::error_code readImpl() override;
|
||||
|
||||
/// It includes all the names that have samples either in outline instance
|
||||
/// or inline instance.
|
||||
virtual std::vector<StringRef> *getNameTable() override { return &NameTable; }
|
||||
|
||||
protected:
|
||||
/// Read a numeric value of type T from the profile.
|
||||
///
|
||||
/// If an error occurs during decoding, a diagnostic message is emitted and
|
||||
/// EC is set.
|
||||
///
|
||||
/// \returns the read value.
|
||||
template <typename T> ErrorOr<T> readNumber();
|
||||
|
||||
/// Read a numeric value of type T from the profile. The value is saved
|
||||
/// without encoded.
|
||||
template <typename T> ErrorOr<T> readUnencodedNumber();
|
||||
|
||||
/// Read a string from the profile.
|
||||
///
|
||||
/// If an error occurs during decoding, a diagnostic message is emitted and
|
||||
/// EC is set.
|
||||
///
|
||||
/// \returns the read value.
|
||||
ErrorOr<StringRef> readString();
|
||||
|
||||
/// Read the string index and check whether it overflows the table.
|
||||
template <typename T> inline ErrorOr<uint32_t> readStringIndex(T &Table);
|
||||
|
||||
/// Return true if we've reached the end of file.
|
||||
bool at_eof() const { return Data >= End; }
|
||||
|
||||
/// Read the next function profile instance.
|
||||
std::error_code readFuncProfile(const uint8_t *Start);
|
||||
|
||||
/// Read the contents of the given profile instance.
|
||||
std::error_code readProfile(FunctionSamples &FProfile);
|
||||
|
||||
/// Read the contents of Magic number and Version number.
|
||||
std::error_code readMagicIdent();
|
||||
|
||||
/// Read profile summary.
|
||||
std::error_code readSummary();
|
||||
|
||||
/// Read the whole name table.
|
||||
virtual std::error_code readNameTable();
|
||||
|
||||
/// Points to the current location in the buffer.
|
||||
const uint8_t *Data = nullptr;
|
||||
|
||||
/// Points to the end of the buffer.
|
||||
const uint8_t *End = nullptr;
|
||||
|
||||
/// Function name table.
|
||||
std::vector<StringRef> NameTable;
|
||||
|
||||
/// Read a string indirectly via the name table.
|
||||
virtual ErrorOr<StringRef> readStringFromTable();
|
||||
virtual ErrorOr<SampleContext> readSampleContextFromTable();
|
||||
|
||||
private:
|
||||
std::error_code readSummaryEntry(std::vector<ProfileSummaryEntry> &Entries);
|
||||
virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
|
||||
};
|
||||
|
||||
class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
|
||||
private:
|
||||
virtual std::error_code verifySPMagic(uint64_t Magic) override;
|
||||
|
||||
public:
|
||||
SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
|
||||
SampleProfileFormat Format = SPF_Binary)
|
||||
: SampleProfileReaderBinary(std::move(B), C, Format) {}
|
||||
|
||||
/// \brief Return true if \p Buffer is in the format supported by this class.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
};
|
||||
|
||||
/// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase defines
|
||||
/// the basic structure of the extensible binary format.
|
||||
/// The format is organized in sections except the magic and version number
|
||||
/// at the beginning. There is a section table before all the sections, and
|
||||
/// each entry in the table describes the entry type, start, size and
|
||||
/// attributes. The format in each section is defined by the section itself.
|
||||
///
|
||||
/// It is easy to add a new section while maintaining the backward
|
||||
/// compatibility of the profile. Nothing extra needs to be done. If we want
|
||||
/// to extend an existing section, like add cache misses information in
|
||||
/// addition to the sample count in the profile body, we can add a new section
|
||||
/// with the extension and retire the existing section, and we could choose
|
||||
/// to keep the parser of the old section if we want the reader to be able
|
||||
/// to read both new and old format profile.
|
||||
///
|
||||
/// SampleProfileReaderExtBinary/SampleProfileWriterExtBinary define the
|
||||
/// commonly used sections of a profile in extensible binary format. It is
|
||||
/// possible to define other types of profile inherited from
|
||||
/// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase.
|
||||
class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary {
|
||||
private:
|
||||
std::error_code decompressSection(const uint8_t *SecStart,
|
||||
const uint64_t SecSize,
|
||||
const uint8_t *&DecompressBuf,
|
||||
uint64_t &DecompressBufSize);
|
||||
|
||||
BumpPtrAllocator Allocator;
|
||||
|
||||
protected:
|
||||
std::vector<SecHdrTableEntry> SecHdrTable;
|
||||
std::error_code readSecHdrTableEntry(uint32_t Idx);
|
||||
std::error_code readSecHdrTable();
|
||||
|
||||
std::error_code readFuncMetadata(bool ProfileHasAttribute);
|
||||
std::error_code readFuncMetadata(bool ProfileHasAttribute,
|
||||
FunctionSamples *FProfile);
|
||||
std::error_code readFuncOffsetTable();
|
||||
std::error_code readFuncProfiles();
|
||||
std::error_code readMD5NameTable();
|
||||
std::error_code readNameTableSec(bool IsMD5);
|
||||
std::error_code readCSNameTableSec();
|
||||
std::error_code readProfileSymbolList();
|
||||
|
||||
virtual std::error_code readHeader() override;
|
||||
virtual std::error_code verifySPMagic(uint64_t Magic) override = 0;
|
||||
virtual std::error_code readOneSection(const uint8_t *Start, uint64_t Size,
|
||||
const SecHdrTableEntry &Entry);
|
||||
// placeholder for subclasses to dispatch their own section readers.
|
||||
virtual std::error_code readCustomSection(const SecHdrTableEntry &Entry) = 0;
|
||||
virtual ErrorOr<StringRef> readStringFromTable() override;
|
||||
virtual ErrorOr<SampleContext> readSampleContextFromTable() override;
|
||||
ErrorOr<SampleContextFrames> readContextFromTable();
|
||||
|
||||
std::unique_ptr<ProfileSymbolList> ProfSymList;
|
||||
|
||||
/// The table mapping from function context to the offset of its
|
||||
/// FunctionSample towards file start.
|
||||
DenseMap<SampleContext, uint64_t> FuncOffsetTable;
|
||||
|
||||
/// Function offset mapping ordered by contexts.
|
||||
std::unique_ptr<std::vector<std::pair<SampleContext, uint64_t>>>
|
||||
OrderedFuncOffsets;
|
||||
|
||||
/// The set containing the functions to use when compiling a module.
|
||||
DenseSet<StringRef> FuncsToUse;
|
||||
|
||||
/// Use fixed length MD5 instead of ULEB128 encoding so NameTable doesn't
|
||||
/// need to be read in up front and can be directly accessed using index.
|
||||
bool FixedLengthMD5 = false;
|
||||
/// The starting address of NameTable containing fixed length MD5.
|
||||
const uint8_t *MD5NameMemStart = nullptr;
|
||||
|
||||
/// If MD5 is used in NameTable section, the section saves uint64_t data.
|
||||
/// The uint64_t data has to be converted to a string and then the string
|
||||
/// will be used to initialize StringRef in NameTable.
|
||||
/// Note NameTable contains StringRef so it needs another buffer to own
|
||||
/// the string data. MD5StringBuf serves as the string buffer that is
|
||||
/// referenced by NameTable (vector of StringRef). We make sure
|
||||
/// the lifetime of MD5StringBuf is not shorter than that of NameTable.
|
||||
std::unique_ptr<std::vector<std::string>> MD5StringBuf;
|
||||
|
||||
/// CSNameTable is used to save full context vectors. This serves as an
|
||||
/// underlying immutable buffer for all clients.
|
||||
std::unique_ptr<const std::vector<SampleContextFrameVector>> CSNameTable;
|
||||
|
||||
/// If SkipFlatProf is true, skip the sections with
|
||||
/// SecFlagFlat flag.
|
||||
bool SkipFlatProf = false;
|
||||
|
||||
bool FuncOffsetsOrdered = false;
|
||||
|
||||
public:
|
||||
SampleProfileReaderExtBinaryBase(std::unique_ptr<MemoryBuffer> B,
|
||||
LLVMContext &C, SampleProfileFormat Format)
|
||||
: SampleProfileReaderBinary(std::move(B), C, Format) {}
|
||||
|
||||
/// Read sample profiles in extensible format from the associated file.
|
||||
std::error_code readImpl() override;
|
||||
|
||||
/// Get the total size of all \p Type sections.
|
||||
uint64_t getSectionSize(SecType Type);
|
||||
/// Get the total size of header and all sections.
|
||||
uint64_t getFileSize();
|
||||
virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) override;
|
||||
|
||||
/// Collect functions with definitions in Module M. Return true if
|
||||
/// the reader has been given a module.
|
||||
bool collectFuncsFromModule() override;
|
||||
|
||||
/// Return whether names in the profile are all MD5 numbers.
|
||||
virtual bool useMD5() override { return MD5StringBuf.get(); }
|
||||
|
||||
virtual std::unique_ptr<ProfileSymbolList> getProfileSymbolList() override {
|
||||
return std::move(ProfSymList);
|
||||
};
|
||||
|
||||
virtual void setSkipFlatProf(bool Skip) override { SkipFlatProf = Skip; }
|
||||
};
|
||||
|
||||
class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
|
||||
private:
|
||||
virtual std::error_code verifySPMagic(uint64_t Magic) override;
|
||||
virtual std::error_code
|
||||
readCustomSection(const SecHdrTableEntry &Entry) override {
|
||||
// Update the data reader pointer to the end of the section.
|
||||
Data = End;
|
||||
return sampleprof_error::success;
|
||||
};
|
||||
|
||||
public:
|
||||
SampleProfileReaderExtBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
|
||||
SampleProfileFormat Format = SPF_Ext_Binary)
|
||||
: SampleProfileReaderExtBinaryBase(std::move(B), C, Format) {}
|
||||
|
||||
/// \brief Return true if \p Buffer is in the format supported by this class.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
};
|
||||
|
||||
class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary {
|
||||
private:
|
||||
/// Function name table.
|
||||
std::vector<std::string> NameTable;
|
||||
/// The table mapping from function name to the offset of its FunctionSample
|
||||
/// towards file start.
|
||||
DenseMap<StringRef, uint64_t> FuncOffsetTable;
|
||||
/// The set containing the functions to use when compiling a module.
|
||||
DenseSet<StringRef> FuncsToUse;
|
||||
virtual std::error_code verifySPMagic(uint64_t Magic) override;
|
||||
virtual std::error_code readNameTable() override;
|
||||
/// Read a string indirectly via the name table.
|
||||
virtual ErrorOr<StringRef> readStringFromTable() override;
|
||||
virtual std::error_code readHeader() override;
|
||||
std::error_code readFuncOffsetTable();
|
||||
|
||||
public:
|
||||
SampleProfileReaderCompactBinary(std::unique_ptr<MemoryBuffer> B,
|
||||
LLVMContext &C)
|
||||
: SampleProfileReaderBinary(std::move(B), C, SPF_Compact_Binary) {}
|
||||
|
||||
/// \brief Return true if \p Buffer is in the format supported by this class.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
|
||||
/// Read samples only for functions to use.
|
||||
std::error_code readImpl() override;
|
||||
|
||||
/// Collect functions with definitions in Module M. Return true if
|
||||
/// the reader has been given a module.
|
||||
bool collectFuncsFromModule() override;
|
||||
|
||||
/// Return whether names in the profile are all MD5 numbers.
|
||||
virtual bool useMD5() override { return true; }
|
||||
};
|
||||
|
||||
using InlineCallStack = SmallVector<FunctionSamples *, 10>;
|
||||
|
||||
// Supported histogram types in GCC. Currently, we only need support for
|
||||
// call target histograms.
|
||||
enum HistType {
|
||||
HIST_TYPE_INTERVAL,
|
||||
HIST_TYPE_POW2,
|
||||
HIST_TYPE_SINGLE_VALUE,
|
||||
HIST_TYPE_CONST_DELTA,
|
||||
HIST_TYPE_INDIR_CALL,
|
||||
HIST_TYPE_AVERAGE,
|
||||
HIST_TYPE_IOR,
|
||||
HIST_TYPE_INDIR_CALL_TOPN
|
||||
};
|
||||
|
||||
class SampleProfileReaderGCC : public SampleProfileReader {
|
||||
public:
|
||||
SampleProfileReaderGCC(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
|
||||
: SampleProfileReader(std::move(B), C, SPF_GCC),
|
||||
GcovBuffer(Buffer.get()) {}
|
||||
|
||||
/// Read and validate the file header.
|
||||
std::error_code readHeader() override;
|
||||
|
||||
/// Read sample profiles from the associated file.
|
||||
std::error_code readImpl() override;
|
||||
|
||||
/// Return true if \p Buffer is in the format supported by this class.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
|
||||
protected:
|
||||
std::error_code readNameTable();
|
||||
std::error_code readOneFunctionProfile(const InlineCallStack &InlineStack,
|
||||
bool Update, uint32_t Offset);
|
||||
std::error_code readFunctionProfiles();
|
||||
std::error_code skipNextWord();
|
||||
template <typename T> ErrorOr<T> readNumber();
|
||||
ErrorOr<StringRef> readString();
|
||||
|
||||
/// Read the section tag and check that it's the same as \p Expected.
|
||||
std::error_code readSectionTag(uint32_t Expected);
|
||||
|
||||
/// GCOV buffer containing the profile.
|
||||
GCOVBuffer GcovBuffer;
|
||||
|
||||
/// Function names in this profile.
|
||||
std::vector<std::string> Names;
|
||||
|
||||
/// GCOV tags used to separate sections in the profile file.
|
||||
static const uint32_t GCOVTagAFDOFileNames = 0xaa000000;
|
||||
static const uint32_t GCOVTagAFDOFunction = 0xac000000;
|
||||
};
|
||||
|
||||
} // end namespace sampleprof
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_SAMPLEPROFREADER_H
|
407
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/SampleProfWriter.h
vendored
Normal file
407
thirdparty/capstone/suite/synctools/tablegen/include/llvm/ProfileData/SampleProfWriter.h
vendored
Normal file
@@ -0,0 +1,407 @@
|
||||
//===- SampleProfWriter.h - Write LLVM sample profile data ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains definitions needed for writing sample profiles.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
|
||||
#define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/IR/ProfileSummary.h"
|
||||
#include "llvm/ProfileData/SampleProf.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <system_error>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace llvm {
|
||||
namespace sampleprof {
|
||||
|
||||
enum SectionLayout {
|
||||
DefaultLayout,
|
||||
// The layout splits profile with context information from profile without
|
||||
// context information. When Thinlto is enabled, ThinLTO postlink phase only
|
||||
// has to load profile with context information and can skip the other part.
|
||||
CtxSplitLayout,
|
||||
NumOfLayout,
|
||||
};
|
||||
|
||||
/// Sample-based profile writer. Base class.
|
||||
class SampleProfileWriter {
|
||||
public:
|
||||
virtual ~SampleProfileWriter() = default;
|
||||
|
||||
/// Write sample profiles in \p S.
|
||||
///
|
||||
/// \returns status code of the file update operation.
|
||||
virtual std::error_code writeSample(const FunctionSamples &S) = 0;
|
||||
|
||||
/// Write all the sample profiles in the given map of samples.
|
||||
///
|
||||
/// \returns status code of the file update operation.
|
||||
virtual std::error_code write(const SampleProfileMap &ProfileMap);
|
||||
|
||||
raw_ostream &getOutputStream() { return *OutputStream; }
|
||||
|
||||
/// Profile writer factory.
|
||||
///
|
||||
/// Create a new file writer based on the value of \p Format.
|
||||
static ErrorOr<std::unique_ptr<SampleProfileWriter>>
|
||||
create(StringRef Filename, SampleProfileFormat Format);
|
||||
|
||||
/// Create a new stream writer based on the value of \p Format.
|
||||
/// For testing.
|
||||
static ErrorOr<std::unique_ptr<SampleProfileWriter>>
|
||||
create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format);
|
||||
|
||||
virtual void setProfileSymbolList(ProfileSymbolList *PSL) {}
|
||||
virtual void setToCompressAllSections() {}
|
||||
virtual void setUseMD5() {}
|
||||
virtual void setPartialProfile() {}
|
||||
virtual void resetSecLayout(SectionLayout SL) {}
|
||||
|
||||
protected:
|
||||
SampleProfileWriter(std::unique_ptr<raw_ostream> &OS)
|
||||
: OutputStream(std::move(OS)) {}
|
||||
|
||||
/// Write a file header for the profile file.
|
||||
virtual std::error_code writeHeader(const SampleProfileMap &ProfileMap) = 0;
|
||||
|
||||
// Write function profiles to the profile file.
|
||||
virtual std::error_code writeFuncProfiles(const SampleProfileMap &ProfileMap);
|
||||
|
||||
/// Output stream where to emit the profile to.
|
||||
std::unique_ptr<raw_ostream> OutputStream;
|
||||
|
||||
/// Profile summary.
|
||||
std::unique_ptr<ProfileSummary> Summary;
|
||||
|
||||
/// Compute summary for this profile.
|
||||
void computeSummary(const SampleProfileMap &ProfileMap);
|
||||
|
||||
/// Profile format.
|
||||
SampleProfileFormat Format = SPF_None;
|
||||
};
|
||||
|
||||
/// Sample-based profile writer (text format).
|
||||
class SampleProfileWriterText : public SampleProfileWriter {
|
||||
public:
|
||||
std::error_code writeSample(const FunctionSamples &S) override;
|
||||
|
||||
protected:
|
||||
SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
|
||||
: SampleProfileWriter(OS), Indent(0) {}
|
||||
|
||||
std::error_code writeHeader(const SampleProfileMap &ProfileMap) override {
|
||||
return sampleprof_error::success;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Indent level to use when writing.
|
||||
///
|
||||
/// This is used when printing inlined callees.
|
||||
unsigned Indent;
|
||||
|
||||
friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
|
||||
SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
|
||||
SampleProfileFormat Format);
|
||||
};
|
||||
|
||||
/// Sample-based profile writer (binary format).
|
||||
class SampleProfileWriterBinary : public SampleProfileWriter {
|
||||
public:
|
||||
SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
|
||||
: SampleProfileWriter(OS) {}
|
||||
|
||||
virtual std::error_code writeSample(const FunctionSamples &S) override;
|
||||
|
||||
protected:
|
||||
virtual MapVector<StringRef, uint32_t> &getNameTable() { return NameTable; }
|
||||
virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
|
||||
virtual std::error_code writeNameTable();
|
||||
virtual std::error_code
|
||||
writeHeader(const SampleProfileMap &ProfileMap) override;
|
||||
std::error_code writeSummary();
|
||||
virtual std::error_code writeContextIdx(const SampleContext &Context);
|
||||
std::error_code writeNameIdx(StringRef FName);
|
||||
std::error_code writeBody(const FunctionSamples &S);
|
||||
inline void stablizeNameTable(MapVector<StringRef, uint32_t> &NameTable,
|
||||
std::set<StringRef> &V);
|
||||
|
||||
MapVector<StringRef, uint32_t> NameTable;
|
||||
|
||||
void addName(StringRef FName);
|
||||
virtual void addContext(const SampleContext &Context);
|
||||
void addNames(const FunctionSamples &S);
|
||||
|
||||
private:
|
||||
friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
|
||||
SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
|
||||
SampleProfileFormat Format);
|
||||
};
|
||||
|
||||
class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
|
||||
using SampleProfileWriterBinary::SampleProfileWriterBinary;
|
||||
};
|
||||
|
||||
const std::array<SmallVector<SecHdrTableEntry, 8>, NumOfLayout>
|
||||
ExtBinaryHdrLayoutTable = {
|
||||
// Note that SecFuncOffsetTable section is written after SecLBRProfile
|
||||
// in the profile, but is put before SecLBRProfile in SectionHdrLayout.
|
||||
// This is because sample reader follows the order in SectionHdrLayout
|
||||
// to read each section. To read function profiles on demand, sample
|
||||
// reader need to get the offset of each function profile first.
|
||||
//
|
||||
// DefaultLayout
|
||||
SmallVector<SecHdrTableEntry, 8>({{SecProfSummary, 0, 0, 0, 0},
|
||||
{SecNameTable, 0, 0, 0, 0},
|
||||
{SecCSNameTable, 0, 0, 0, 0},
|
||||
{SecFuncOffsetTable, 0, 0, 0, 0},
|
||||
{SecLBRProfile, 0, 0, 0, 0},
|
||||
{SecProfileSymbolList, 0, 0, 0, 0},
|
||||
{SecFuncMetadata, 0, 0, 0, 0}}),
|
||||
// CtxSplitLayout
|
||||
SmallVector<SecHdrTableEntry, 8>({{SecProfSummary, 0, 0, 0, 0},
|
||||
{SecNameTable, 0, 0, 0, 0},
|
||||
// profile with context
|
||||
// for next two sections
|
||||
{SecFuncOffsetTable, 0, 0, 0, 0},
|
||||
{SecLBRProfile, 0, 0, 0, 0},
|
||||
// profile without context
|
||||
// for next two sections
|
||||
{SecFuncOffsetTable, 0, 0, 0, 0},
|
||||
{SecLBRProfile, 0, 0, 0, 0},
|
||||
{SecProfileSymbolList, 0, 0, 0, 0},
|
||||
{SecFuncMetadata, 0, 0, 0, 0}}),
|
||||
};
|
||||
|
||||
class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
|
||||
using SampleProfileWriterBinary::SampleProfileWriterBinary;
|
||||
public:
|
||||
virtual std::error_code write(const SampleProfileMap &ProfileMap) override;
|
||||
|
||||
virtual void setToCompressAllSections() override;
|
||||
void setToCompressSection(SecType Type);
|
||||
virtual std::error_code writeSample(const FunctionSamples &S) override;
|
||||
|
||||
// Set to use MD5 to represent string in NameTable.
|
||||
virtual void setUseMD5() override {
|
||||
UseMD5 = true;
|
||||
addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagMD5Name);
|
||||
// MD5 will be stored as plain uint64_t instead of variable-length
|
||||
// quantity format in NameTable section.
|
||||
addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagFixedLengthMD5);
|
||||
}
|
||||
|
||||
// Set the profile to be partial. It means the profile is for
|
||||
// common/shared code. The common profile is usually merged from
|
||||
// profiles collected from running other targets.
|
||||
virtual void setPartialProfile() override {
|
||||
addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagPartial);
|
||||
}
|
||||
|
||||
virtual void setProfileSymbolList(ProfileSymbolList *PSL) override {
|
||||
ProfSymList = PSL;
|
||||
};
|
||||
|
||||
virtual void resetSecLayout(SectionLayout SL) override {
|
||||
verifySecLayout(SL);
|
||||
#ifndef NDEBUG
|
||||
// Make sure resetSecLayout is called before any flag setting.
|
||||
for (auto &Entry : SectionHdrLayout) {
|
||||
assert(Entry.Flags == 0 &&
|
||||
"resetSecLayout has to be called before any flag setting");
|
||||
}
|
||||
#endif
|
||||
SecLayout = SL;
|
||||
SectionHdrLayout = ExtBinaryHdrLayoutTable[SL];
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t markSectionStart(SecType Type, uint32_t LayoutIdx);
|
||||
std::error_code addNewSection(SecType Sec, uint32_t LayoutIdx,
|
||||
uint64_t SectionStart);
|
||||
template <class SecFlagType>
|
||||
void addSectionFlag(SecType Type, SecFlagType Flag) {
|
||||
for (auto &Entry : SectionHdrLayout) {
|
||||
if (Entry.Type == Type)
|
||||
addSecFlag(Entry, Flag);
|
||||
}
|
||||
}
|
||||
template <class SecFlagType>
|
||||
void addSectionFlag(uint32_t SectionIdx, SecFlagType Flag) {
|
||||
addSecFlag(SectionHdrLayout[SectionIdx], Flag);
|
||||
}
|
||||
|
||||
virtual void addContext(const SampleContext &Context) override;
|
||||
|
||||
// placeholder for subclasses to dispatch their own section writers.
|
||||
virtual std::error_code writeCustomSection(SecType Type) = 0;
|
||||
// Verify the SecLayout is supported by the format.
|
||||
virtual void verifySecLayout(SectionLayout SL) = 0;
|
||||
|
||||
// specify the order to write sections.
|
||||
virtual std::error_code writeSections(const SampleProfileMap &ProfileMap) = 0;
|
||||
|
||||
// Dispatch section writer for each section. \p LayoutIdx is the sequence
|
||||
// number indicating where the section is located in SectionHdrLayout.
|
||||
virtual std::error_code writeOneSection(SecType Type, uint32_t LayoutIdx,
|
||||
const SampleProfileMap &ProfileMap);
|
||||
|
||||
// Helper function to write name table.
|
||||
virtual std::error_code writeNameTable() override;
|
||||
virtual std::error_code
|
||||
writeContextIdx(const SampleContext &Context) override;
|
||||
std::error_code writeCSNameIdx(const SampleContext &Context);
|
||||
std::error_code writeCSNameTableSection();
|
||||
|
||||
std::error_code writeFuncMetadata(const SampleProfileMap &Profiles);
|
||||
std::error_code writeFuncMetadata(const FunctionSamples &Profile);
|
||||
|
||||
// Functions to write various kinds of sections.
|
||||
std::error_code writeNameTableSection(const SampleProfileMap &ProfileMap);
|
||||
std::error_code writeFuncOffsetTable();
|
||||
std::error_code writeProfileSymbolListSection();
|
||||
|
||||
SectionLayout SecLayout = DefaultLayout;
|
||||
// Specify the order of sections in section header table. Note
|
||||
// the order of sections in SecHdrTable may be different that the
|
||||
// order in SectionHdrLayout. sample Reader will follow the order
|
||||
// in SectionHdrLayout to read each section.
|
||||
SmallVector<SecHdrTableEntry, 8> SectionHdrLayout =
|
||||
ExtBinaryHdrLayoutTable[DefaultLayout];
|
||||
|
||||
// Save the start of SecLBRProfile so we can compute the offset to the
|
||||
// start of SecLBRProfile for each Function's Profile and will keep it
|
||||
// in FuncOffsetTable.
|
||||
uint64_t SecLBRProfileStart = 0;
|
||||
|
||||
private:
|
||||
void allocSecHdrTable();
|
||||
std::error_code writeSecHdrTable();
|
||||
virtual std::error_code
|
||||
writeHeader(const SampleProfileMap &ProfileMap) override;
|
||||
std::error_code compressAndOutput();
|
||||
|
||||
// We will swap the raw_ostream held by LocalBufStream and that
|
||||
// held by OutputStream if we try to add a section which needs
|
||||
// compression. After the swap, all the data written to output
|
||||
// will be temporarily buffered into the underlying raw_string_ostream
|
||||
// originally held by LocalBufStream. After the data writing for the
|
||||
// section is completed, compress the data in the local buffer,
|
||||
// swap the raw_ostream back and write the compressed data to the
|
||||
// real output.
|
||||
std::unique_ptr<raw_ostream> LocalBufStream;
|
||||
// The location where the output stream starts.
|
||||
uint64_t FileStart;
|
||||
// The location in the output stream where the SecHdrTable should be
|
||||
// written to.
|
||||
uint64_t SecHdrTableOffset;
|
||||
// The table contains SecHdrTableEntry entries in order of how they are
|
||||
// populated in the writer. It may be different from the order in
|
||||
// SectionHdrLayout which specifies the sequence in which sections will
|
||||
// be read.
|
||||
std::vector<SecHdrTableEntry> SecHdrTable;
|
||||
|
||||
// FuncOffsetTable maps function context to its profile offset in
|
||||
// SecLBRProfile section. It is used to load function profile on demand.
|
||||
MapVector<SampleContext, uint64_t> FuncOffsetTable;
|
||||
// Whether to use MD5 to represent string.
|
||||
bool UseMD5 = false;
|
||||
|
||||
/// CSNameTable maps function context to its offset in SecCSNameTable section.
|
||||
/// The offset will be used everywhere where the context is referenced.
|
||||
MapVector<SampleContext, uint32_t> CSNameTable;
|
||||
|
||||
ProfileSymbolList *ProfSymList = nullptr;
|
||||
};
|
||||
|
||||
class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase {
|
||||
public:
|
||||
SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS)
|
||||
: SampleProfileWriterExtBinaryBase(OS) {}
|
||||
|
||||
private:
|
||||
std::error_code writeDefaultLayout(const SampleProfileMap &ProfileMap);
|
||||
std::error_code writeCtxSplitLayout(const SampleProfileMap &ProfileMap);
|
||||
|
||||
virtual std::error_code
|
||||
writeSections(const SampleProfileMap &ProfileMap) override;
|
||||
|
||||
virtual std::error_code writeCustomSection(SecType Type) override {
|
||||
return sampleprof_error::success;
|
||||
};
|
||||
|
||||
virtual void verifySecLayout(SectionLayout SL) override {
|
||||
assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
|
||||
"Unsupported layout");
|
||||
}
|
||||
};
|
||||
|
||||
// CompactBinary is a compact format of binary profile which both reduces
|
||||
// the profile size and the load time needed when compiling. It has two
|
||||
// major difference with Binary format.
|
||||
// 1. It represents all the strings in name table using md5 hash.
|
||||
// 2. It saves a function offset table which maps function name index to
|
||||
// the offset of its function profile to the start of the binary profile,
|
||||
// so by using the function offset table, for those function profiles which
|
||||
// will not be needed when compiling a module, the profile reader does't
|
||||
// have to read them and it saves compile time if the profile size is huge.
|
||||
// The layout of the compact format is shown as follows:
|
||||
//
|
||||
// Part1: Profile header, the same as binary format, containing magic
|
||||
// number, version, summary, name table...
|
||||
// Part2: Function Offset Table Offset, which saves the position of
|
||||
// Part4.
|
||||
// Part3: Function profile collection
|
||||
// function1 profile start
|
||||
// ....
|
||||
// function2 profile start
|
||||
// ....
|
||||
// function3 profile start
|
||||
// ....
|
||||
// ......
|
||||
// Part4: Function Offset Table
|
||||
// function1 name index --> function1 profile start
|
||||
// function2 name index --> function2 profile start
|
||||
// function3 name index --> function3 profile start
|
||||
//
|
||||
// We need Part2 because profile reader can use it to find out and read
|
||||
// function offset table without reading Part3 first.
|
||||
class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary {
|
||||
using SampleProfileWriterBinary::SampleProfileWriterBinary;
|
||||
|
||||
public:
|
||||
virtual std::error_code writeSample(const FunctionSamples &S) override;
|
||||
virtual std::error_code write(const SampleProfileMap &ProfileMap) override;
|
||||
|
||||
protected:
|
||||
/// The table mapping from function name to the offset of its FunctionSample
|
||||
/// towards profile start.
|
||||
MapVector<StringRef, uint64_t> FuncOffsetTable;
|
||||
/// The offset of the slot to be filled with the offset of FuncOffsetTable
|
||||
/// towards profile start.
|
||||
uint64_t TableOffset;
|
||||
virtual std::error_code writeNameTable() override;
|
||||
virtual std::error_code
|
||||
writeHeader(const SampleProfileMap &ProfileMap) override;
|
||||
std::error_code writeFuncOffsetTable();
|
||||
};
|
||||
|
||||
} // end namespace sampleprof
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H
|
Reference in New Issue
Block a user