forked from OSchip/llvm-project
[llvm-exegesis][NFC] Rewrite of the YAML serialization.
Summary: This is a NFC in preparation of exporting the initial registers as part of the YAML dump Reviewers: courbet Reviewed By: courbet Subscribers: mgorny, tschuett, llvm-commits Differential Revision: https://reviews.llvm.org/D52427 llvm-svn: 342967
This commit is contained in:
parent
99d98ed2b2
commit
55ad087a4c
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BenchmarkResult.h"
|
||||
#include "BenchmarkRunner.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ObjectYAML/YAML.h"
|
||||
|
@ -18,75 +19,106 @@
|
|||
|
||||
static constexpr const char kIntegerFormat[] = "i_0x%" PRId64 "x";
|
||||
static constexpr const char kDoubleFormat[] = "f_%la";
|
||||
static constexpr const char kInvalidOperand[] = "INVALID";
|
||||
|
||||
static void serialize(const exegesis::BenchmarkResultContext &Context,
|
||||
const llvm::MCOperand &MCOperand, llvm::raw_ostream &OS) {
|
||||
if (MCOperand.isReg()) {
|
||||
OS << Context.getRegName(MCOperand.getReg());
|
||||
} else if (MCOperand.isImm()) {
|
||||
OS << llvm::format(kIntegerFormat, MCOperand.getImm());
|
||||
} else if (MCOperand.isFPImm()) {
|
||||
OS << llvm::format(kDoubleFormat, MCOperand.getFPImm());
|
||||
} else {
|
||||
OS << "INVALID";
|
||||
}
|
||||
}
|
||||
// A mutable struct holding an LLVMState that can be passed through the
|
||||
// serialization process to encode/decode registers and instructions.
|
||||
struct YamlContext {
|
||||
YamlContext(const exegesis::LLVMState &State)
|
||||
: State(&State), ErrorStream(LastError) {}
|
||||
|
||||
static void serialize(const exegesis::BenchmarkResultContext &Context,
|
||||
const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
|
||||
OS << Context.getInstrName(MCInst.getOpcode());
|
||||
for (const auto &Op : MCInst) {
|
||||
OS << ' ';
|
||||
serialize(Context, Op, OS);
|
||||
}
|
||||
}
|
||||
|
||||
static llvm::MCOperand
|
||||
deserialize(const exegesis::BenchmarkResultContext &Context,
|
||||
llvm::StringRef String) {
|
||||
assert(!String.empty());
|
||||
int64_t IntValue = 0;
|
||||
double DoubleValue = 0;
|
||||
if (sscanf(String.data(), kIntegerFormat, &IntValue) == 1)
|
||||
return llvm::MCOperand::createImm(IntValue);
|
||||
if (sscanf(String.data(), kDoubleFormat, &DoubleValue) == 1)
|
||||
return llvm::MCOperand::createFPImm(DoubleValue);
|
||||
if (unsigned RegNo = Context.getRegNo(String)) // Returns 0 if invalid.
|
||||
return llvm::MCOperand::createReg(RegNo);
|
||||
return {};
|
||||
}
|
||||
|
||||
static llvm::StringRef
|
||||
deserialize(const exegesis::BenchmarkResultContext &Context,
|
||||
llvm::StringRef String, llvm::MCInst &Value) {
|
||||
llvm::SmallVector<llvm::StringRef, 8> Pieces;
|
||||
String.split(Pieces, " ", /* MaxSplit */ -1, /* KeepEmpty */ false);
|
||||
if (Pieces.empty())
|
||||
return "Invalid Instruction";
|
||||
bool ProcessOpcode = true;
|
||||
for (llvm::StringRef Piece : Pieces) {
|
||||
if (ProcessOpcode) {
|
||||
ProcessOpcode = false;
|
||||
Value.setOpcode(Context.getInstrOpcode(Piece));
|
||||
if (Value.getOpcode() == 0)
|
||||
return "Unknown Opcode Name";
|
||||
} else {
|
||||
Value.addOperand(deserialize(Context, Piece));
|
||||
void serializeMCInst(const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
|
||||
OS << getInstrName(MCInst.getOpcode());
|
||||
for (const auto &Op : MCInst) {
|
||||
OS << ' ';
|
||||
serializeMCOperand(Op, OS);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// YAML IO requires a mutable pointer to Context but we guarantee to not
|
||||
// modify it.
|
||||
static void *getUntypedContext(const exegesis::BenchmarkResultContext &Ctx) {
|
||||
return const_cast<exegesis::BenchmarkResultContext *>(&Ctx);
|
||||
}
|
||||
void deserializeMCInst(llvm::StringRef String, llvm::MCInst &Value) {
|
||||
llvm::SmallVector<llvm::StringRef, 8> Pieces;
|
||||
String.split(Pieces, " ", /* MaxSplit */ -1, /* KeepEmpty */ false);
|
||||
if (Pieces.empty()) {
|
||||
ErrorStream << "Unknown Instruction: '" << String << "'";
|
||||
return;
|
||||
}
|
||||
bool ProcessOpcode = true;
|
||||
for (llvm::StringRef Piece : Pieces) {
|
||||
if (ProcessOpcode)
|
||||
Value.setOpcode(getInstrOpcode(Piece));
|
||||
else
|
||||
Value.addOperand(deserializeMCOperand(Piece));
|
||||
ProcessOpcode = false;
|
||||
}
|
||||
}
|
||||
|
||||
static const exegesis::BenchmarkResultContext &getTypedContext(void *Ctx) {
|
||||
assert(Ctx);
|
||||
return *static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
|
||||
}
|
||||
std::string &getLastError() { return ErrorStream.str(); }
|
||||
|
||||
private:
|
||||
void serializeMCOperand(const llvm::MCOperand &MCOperand,
|
||||
llvm::raw_ostream &OS) {
|
||||
if (MCOperand.isReg()) {
|
||||
OS << getRegName(MCOperand.getReg());
|
||||
} else if (MCOperand.isImm()) {
|
||||
OS << llvm::format(kIntegerFormat, MCOperand.getImm());
|
||||
} else if (MCOperand.isFPImm()) {
|
||||
OS << llvm::format(kDoubleFormat, MCOperand.getFPImm());
|
||||
} else {
|
||||
OS << kInvalidOperand;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::MCOperand deserializeMCOperand(llvm::StringRef String) {
|
||||
assert(!String.empty());
|
||||
int64_t IntValue = 0;
|
||||
double DoubleValue = 0;
|
||||
if (sscanf(String.data(), kIntegerFormat, &IntValue) == 1)
|
||||
return llvm::MCOperand::createImm(IntValue);
|
||||
if (sscanf(String.data(), kDoubleFormat, &DoubleValue) == 1)
|
||||
return llvm::MCOperand::createFPImm(DoubleValue);
|
||||
if (unsigned RegNo = getRegNo(String))
|
||||
return llvm::MCOperand::createReg(RegNo);
|
||||
if (String != kInvalidOperand)
|
||||
ErrorStream << "Unknown Operand: '" << String << "'";
|
||||
return {};
|
||||
}
|
||||
|
||||
llvm::StringRef getRegName(unsigned RegNo) {
|
||||
const llvm::StringRef RegName = State->getRegInfo().getName(RegNo);
|
||||
if (RegName.empty())
|
||||
ErrorStream << "No register with enum value" << RegNo;
|
||||
return RegName;
|
||||
}
|
||||
|
||||
llvm::StringRef getInstrName(unsigned InstrNo) {
|
||||
const llvm::StringRef InstrName = State->getInstrInfo().getName(InstrNo);
|
||||
if (InstrName.empty())
|
||||
ErrorStream << "No opcode with enum value" << InstrNo;
|
||||
return InstrName;
|
||||
}
|
||||
|
||||
unsigned getRegNo(llvm::StringRef RegName) {
|
||||
const llvm::MCRegisterInfo &RegInfo = State->getRegInfo();
|
||||
for (unsigned E = RegInfo.getNumRegs(), I = 0; I < E; ++I)
|
||||
if (RegInfo.getName(I) == RegName)
|
||||
return I;
|
||||
ErrorStream << "No register with name " << RegName;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned getInstrOpcode(llvm::StringRef InstrName) {
|
||||
const llvm::MCInstrInfo &InstrInfo = State->getInstrInfo();
|
||||
for (unsigned E = InstrInfo.getNumOpcodes(), I = 0; I < E; ++I)
|
||||
if (InstrInfo.getName(I) == InstrName)
|
||||
return I;
|
||||
ErrorStream << "No opcode with name " << InstrName;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const exegesis::LLVMState *State;
|
||||
std::string LastError;
|
||||
llvm::raw_string_ostream ErrorStream;
|
||||
};
|
||||
|
||||
// Defining YAML traits for IO.
|
||||
namespace llvm {
|
||||
|
@ -101,11 +133,13 @@ template <> struct ScalarTraits<llvm::MCInst> {
|
|||
|
||||
static void output(const llvm::MCInst &Value, void *Ctx,
|
||||
llvm::raw_ostream &Out) {
|
||||
serialize(getTypedContext(Ctx), Value, Out);
|
||||
reinterpret_cast<YamlContext *>(Ctx)->serializeMCInst(Value, Out);
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
|
||||
return deserialize(getTypedContext(Ctx), Scalar, Value);
|
||||
YamlContext &Context = *reinterpret_cast<YamlContext *>(Ctx);
|
||||
Context.deserializeMCInst(Scalar, Value);
|
||||
return Context.getLastError();
|
||||
}
|
||||
|
||||
static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
|
||||
|
@ -139,14 +173,18 @@ struct ScalarEnumerationTraits<exegesis::InstructionBenchmark::ModeE> {
|
|||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<exegesis::InstructionBenchmarkKey> {
|
||||
static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj) {
|
||||
template <>
|
||||
struct MappingContextTraits<exegesis::InstructionBenchmarkKey, YamlContext> {
|
||||
static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj,
|
||||
YamlContext &Context) {
|
||||
Io.setContext(&Context);
|
||||
Io.mapRequired("instructions", Obj.Instructions);
|
||||
Io.mapOptional("config", Obj.Config);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<exegesis::InstructionBenchmark> {
|
||||
template <>
|
||||
struct MappingContextTraits<exegesis::InstructionBenchmark, YamlContext> {
|
||||
class NormalizedBinary {
|
||||
public:
|
||||
NormalizedBinary(IO &io) {}
|
||||
|
@ -164,9 +202,10 @@ template <> struct MappingTraits<exegesis::InstructionBenchmark> {
|
|||
BinaryRef Binary;
|
||||
};
|
||||
|
||||
static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj) {
|
||||
static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj,
|
||||
YamlContext &Context) {
|
||||
Io.mapRequired("mode", Obj.Mode);
|
||||
Io.mapRequired("key", Obj.Key);
|
||||
Io.mapRequired("key", Obj.Key, Context);
|
||||
Io.mapRequired("cpu_name", Obj.CpuName);
|
||||
Io.mapRequired("llvm_triple", Obj.LLVMTriple);
|
||||
Io.mapRequired("num_repetitions", Obj.NumRepetitions);
|
||||
|
@ -183,99 +222,68 @@ template <> struct MappingTraits<exegesis::InstructionBenchmark> {
|
|||
} // namespace yaml
|
||||
} // namespace llvm
|
||||
|
||||
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(exegesis::InstructionBenchmark)
|
||||
|
||||
namespace exegesis {
|
||||
|
||||
void BenchmarkResultContext::addRegEntry(unsigned RegNo, llvm::StringRef Name) {
|
||||
assert(RegNoToName.find(RegNo) == RegNoToName.end());
|
||||
assert(RegNameToNo.find(Name) == RegNameToNo.end());
|
||||
RegNoToName[RegNo] = Name;
|
||||
RegNameToNo[Name] = RegNo;
|
||||
}
|
||||
|
||||
llvm::StringRef BenchmarkResultContext::getRegName(unsigned RegNo) const {
|
||||
const auto Itr = RegNoToName.find(RegNo);
|
||||
if (Itr != RegNoToName.end())
|
||||
return Itr->second;
|
||||
return {};
|
||||
}
|
||||
|
||||
unsigned BenchmarkResultContext::getRegNo(llvm::StringRef Name) const {
|
||||
const auto Itr = RegNameToNo.find(Name);
|
||||
if (Itr != RegNameToNo.end())
|
||||
return Itr->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BenchmarkResultContext::addInstrEntry(unsigned Opcode,
|
||||
llvm::StringRef Name) {
|
||||
assert(InstrOpcodeToName.find(Opcode) == InstrOpcodeToName.end());
|
||||
assert(InstrNameToOpcode.find(Name) == InstrNameToOpcode.end());
|
||||
InstrOpcodeToName[Opcode] = Name;
|
||||
InstrNameToOpcode[Name] = Opcode;
|
||||
}
|
||||
|
||||
llvm::StringRef BenchmarkResultContext::getInstrName(unsigned Opcode) const {
|
||||
const auto Itr = InstrOpcodeToName.find(Opcode);
|
||||
if (Itr != InstrOpcodeToName.end())
|
||||
return Itr->second;
|
||||
return {};
|
||||
}
|
||||
|
||||
unsigned BenchmarkResultContext::getInstrOpcode(llvm::StringRef Name) const {
|
||||
const auto Itr = InstrNameToOpcode.find(Name);
|
||||
if (Itr != InstrNameToOpcode.end())
|
||||
return Itr->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ObjectOrList>
|
||||
static llvm::Expected<ObjectOrList>
|
||||
readYamlCommon(const BenchmarkResultContext &Context,
|
||||
llvm::StringRef Filename) {
|
||||
llvm::Expected<InstructionBenchmark>
|
||||
InstructionBenchmark::readYaml(const LLVMState &State,
|
||||
llvm::StringRef Filename) {
|
||||
if (auto ExpectedMemoryBuffer =
|
||||
llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
|
||||
std::unique_ptr<llvm::MemoryBuffer> MemoryBuffer =
|
||||
std::move(ExpectedMemoryBuffer.get());
|
||||
llvm::yaml::Input Yin(*MemoryBuffer, getUntypedContext(Context));
|
||||
ObjectOrList Benchmark;
|
||||
Yin >> Benchmark;
|
||||
llvm::yaml::Input Yin(*ExpectedMemoryBuffer.get());
|
||||
YamlContext Context(State);
|
||||
InstructionBenchmark Benchmark;
|
||||
if (Yin.setCurrentDocument())
|
||||
llvm::yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
|
||||
if (!Context.getLastError().empty())
|
||||
return llvm::make_error<BenchmarkFailure>(Context.getLastError());
|
||||
return Benchmark;
|
||||
} else {
|
||||
return ExpectedMemoryBuffer.takeError();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Expected<InstructionBenchmark>
|
||||
InstructionBenchmark::readYaml(const BenchmarkResultContext &Context,
|
||||
llvm::StringRef Filename) {
|
||||
return readYamlCommon<InstructionBenchmark>(Context, Filename);
|
||||
}
|
||||
|
||||
llvm::Expected<std::vector<InstructionBenchmark>>
|
||||
InstructionBenchmark::readYamls(const BenchmarkResultContext &Context,
|
||||
InstructionBenchmark::readYamls(const LLVMState &State,
|
||||
llvm::StringRef Filename) {
|
||||
return readYamlCommon<std::vector<InstructionBenchmark>>(Context, Filename);
|
||||
if (auto ExpectedMemoryBuffer =
|
||||
llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
|
||||
llvm::yaml::Input Yin(*ExpectedMemoryBuffer.get());
|
||||
YamlContext Context(State);
|
||||
std::vector<InstructionBenchmark> Benchmarks;
|
||||
while (Yin.setCurrentDocument()) {
|
||||
Benchmarks.emplace_back();
|
||||
yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context);
|
||||
if (Yin.error())
|
||||
return llvm::errorCodeToError(Yin.error());
|
||||
if (!Context.getLastError().empty())
|
||||
return llvm::make_error<BenchmarkFailure>(Context.getLastError());
|
||||
Yin.nextDocument();
|
||||
}
|
||||
return Benchmarks;
|
||||
} else {
|
||||
return ExpectedMemoryBuffer.takeError();
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
|
||||
void InstructionBenchmark::writeYamlTo(const LLVMState &State,
|
||||
llvm::raw_ostream &OS) {
|
||||
llvm::yaml::Output Yout(OS, getUntypedContext(Context));
|
||||
Yout << *this;
|
||||
llvm::yaml::Output Yout(OS);
|
||||
YamlContext Context(State);
|
||||
llvm::yaml::yamlize(Yout, *this, /*unused*/ true, Context);
|
||||
}
|
||||
|
||||
void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
|
||||
void InstructionBenchmark::readYamlFrom(const LLVMState &State,
|
||||
llvm::StringRef InputContent) {
|
||||
llvm::yaml::Input Yin(InputContent, getUntypedContext(Context));
|
||||
Yin >> *this;
|
||||
llvm::yaml::Input Yin(InputContent);
|
||||
YamlContext Context(State);
|
||||
if (Yin.setCurrentDocument())
|
||||
llvm::yaml::yamlize(Yin, *this, /*unused*/ true, Context);
|
||||
}
|
||||
|
||||
llvm::Error
|
||||
InstructionBenchmark::writeYaml(const BenchmarkResultContext &Context,
|
||||
const llvm::StringRef Filename) {
|
||||
llvm::Error InstructionBenchmark::writeYaml(const LLVMState &State,
|
||||
const llvm::StringRef Filename) {
|
||||
if (Filename == "-") {
|
||||
writeYamlTo(Context, llvm::outs());
|
||||
writeYamlTo(State, llvm::outs());
|
||||
} else {
|
||||
int ResultFD = 0;
|
||||
if (auto E = llvm::errorCodeToError(
|
||||
|
@ -284,7 +292,7 @@ InstructionBenchmark::writeYaml(const BenchmarkResultContext &Context,
|
|||
return E;
|
||||
}
|
||||
llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
|
||||
writeYamlTo(Context, Ostr);
|
||||
writeYamlTo(State, Ostr);
|
||||
}
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
|
||||
#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
|
||||
|
||||
#include "LlvmState.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
|
@ -28,8 +29,6 @@
|
|||
|
||||
namespace exegesis {
|
||||
|
||||
struct BenchmarkResultContext; // Forward declaration.
|
||||
|
||||
struct InstructionBenchmarkKey {
|
||||
// The LLVM opcode name.
|
||||
std::vector<llvm::MCInst> Instructions;
|
||||
|
@ -62,19 +61,17 @@ struct InstructionBenchmark {
|
|||
|
||||
// Read functions.
|
||||
static llvm::Expected<InstructionBenchmark>
|
||||
readYaml(const BenchmarkResultContext &Context, llvm::StringRef Filename);
|
||||
readYaml(const LLVMState &State, llvm::StringRef Filename);
|
||||
|
||||
static llvm::Expected<std::vector<InstructionBenchmark>>
|
||||
readYamls(const BenchmarkResultContext &Context, llvm::StringRef Filename);
|
||||
readYamls(const LLVMState &State, llvm::StringRef Filename);
|
||||
|
||||
void readYamlFrom(const BenchmarkResultContext &Context,
|
||||
llvm::StringRef InputContent);
|
||||
void readYamlFrom(const LLVMState &State, llvm::StringRef InputContent);
|
||||
|
||||
// Write functions, non-const because of YAML traits.
|
||||
void writeYamlTo(const BenchmarkResultContext &Context, llvm::raw_ostream &S);
|
||||
void writeYamlTo(const LLVMState &State, llvm::raw_ostream &S);
|
||||
|
||||
llvm::Error writeYaml(const BenchmarkResultContext &Context,
|
||||
const llvm::StringRef Filename);
|
||||
llvm::Error writeYaml(const LLVMState &State, const llvm::StringRef Filename);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -102,38 +99,6 @@ private:
|
|||
double MinValue = std::numeric_limits<double>::max();
|
||||
};
|
||||
|
||||
// This context is used when de/serializing InstructionBenchmark to guarantee
|
||||
// that Registers and Instructions are human readable and preserved accross
|
||||
// different versions of LLVM.
|
||||
struct BenchmarkResultContext {
|
||||
BenchmarkResultContext() = default;
|
||||
BenchmarkResultContext(BenchmarkResultContext &&) = default;
|
||||
BenchmarkResultContext &operator=(BenchmarkResultContext &&) = default;
|
||||
BenchmarkResultContext(const BenchmarkResultContext &) = delete;
|
||||
BenchmarkResultContext &operator=(const BenchmarkResultContext &) = delete;
|
||||
|
||||
// Populate Registers and Instruction mapping.
|
||||
void addRegEntry(unsigned RegNo, llvm::StringRef Name);
|
||||
void addInstrEntry(unsigned Opcode, llvm::StringRef Name);
|
||||
|
||||
// Register accessors.
|
||||
llvm::StringRef getRegName(unsigned RegNo) const;
|
||||
unsigned getRegNo(llvm::StringRef Name) const; // 0 is not found.
|
||||
|
||||
// Instruction accessors.
|
||||
llvm::StringRef getInstrName(unsigned Opcode) const;
|
||||
unsigned getInstrOpcode(llvm::StringRef Name) const; // 0 is not found.
|
||||
|
||||
private:
|
||||
// Ideally we would like to use MCRegisterInfo and MCInstrInfo but doing so
|
||||
// would make testing harder, instead we create a mapping that we can easily
|
||||
// populate.
|
||||
std::unordered_map<unsigned, llvm::StringRef> InstrOpcodeToName;
|
||||
std::unordered_map<unsigned, llvm::StringRef> RegNoToName;
|
||||
llvm::StringMap<unsigned> InstrNameToOpcode;
|
||||
llvm::StringMap<unsigned> RegNameToNo;
|
||||
};
|
||||
|
||||
} // namespace exegesis
|
||||
|
||||
#endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
|
||||
|
|
|
@ -123,21 +123,6 @@ static unsigned getOpcodeOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
|
|||
llvm::report_fatal_error(llvm::Twine("unknown opcode ").concat(OpcodeName));
|
||||
}
|
||||
|
||||
static BenchmarkResultContext
|
||||
getBenchmarkResultContext(const LLVMState &State) {
|
||||
BenchmarkResultContext Ctx;
|
||||
|
||||
const llvm::MCInstrInfo &InstrInfo = State.getInstrInfo();
|
||||
for (unsigned E = InstrInfo.getNumOpcodes(), I = 0; I < E; ++I)
|
||||
Ctx.addInstrEntry(I, InstrInfo.getName(I).data());
|
||||
|
||||
const llvm::MCRegisterInfo &RegInfo = State.getRegInfo();
|
||||
for (unsigned E = RegInfo.getNumRegs(), I = 0; I < E; ++I)
|
||||
Ctx.addRegEntry(I, RegInfo.getName(I));
|
||||
|
||||
return Ctx;
|
||||
}
|
||||
|
||||
// Generates code snippets for opcode `Opcode`.
|
||||
static llvm::Expected<std::vector<BenchmarkCode>>
|
||||
generateSnippets(const LLVMState &State, unsigned Opcode) {
|
||||
|
@ -345,12 +330,10 @@ void benchmarkMain() {
|
|||
if (BenchmarkFile.empty())
|
||||
BenchmarkFile = "-";
|
||||
|
||||
const BenchmarkResultContext Context = getBenchmarkResultContext(State);
|
||||
|
||||
for (const BenchmarkCode &Conf : Configurations) {
|
||||
InstructionBenchmark Result =
|
||||
Runner->runConfiguration(Conf, NumRepetitions);
|
||||
ExitOnErr(Result.writeYaml(Context, BenchmarkFile));
|
||||
ExitOnErr(Result.writeYaml(State, BenchmarkFile));
|
||||
}
|
||||
exegesis::pfm::pfmTerminate();
|
||||
}
|
||||
|
@ -386,8 +369,7 @@ static void analysisMain() {
|
|||
// Read benchmarks.
|
||||
const LLVMState State;
|
||||
const std::vector<InstructionBenchmark> Points =
|
||||
ExitOnErr(InstructionBenchmark::readYamls(
|
||||
getBenchmarkResultContext(State), BenchmarkFile));
|
||||
ExitOnErr(InstructionBenchmark::readYamls(State, BenchmarkFile));
|
||||
llvm::outs() << "Parsed " << Points.size() << " benchmark points\n";
|
||||
if (Points.empty()) {
|
||||
llvm::errs() << "no benchmarks to analyze\n";
|
||||
|
|
|
@ -11,7 +11,6 @@ set(LLVM_LINK_COMPONENTS
|
|||
)
|
||||
|
||||
add_llvm_unittest(LLVMExegesisTests
|
||||
BenchmarkResultTest.cpp
|
||||
BenchmarkRunnerTest.cpp
|
||||
ClusteringTest.cpp
|
||||
PerfHelperTest.cpp
|
||||
|
|
|
@ -8,9 +8,12 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BenchmarkResult.h"
|
||||
#include "X86InstrInfo.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
@ -47,25 +50,21 @@ MATCHER(EqMCInst, "") {
|
|||
|
||||
namespace {
|
||||
|
||||
static constexpr const unsigned kInstrId = 5;
|
||||
static constexpr const char kInstrName[] = "Instruction5";
|
||||
static constexpr const unsigned kReg1Id = 1;
|
||||
static constexpr const char kReg1Name[] = "Reg1";
|
||||
static constexpr const unsigned kReg2Id = 2;
|
||||
static constexpr const char kReg2Name[] = "Reg2";
|
||||
|
||||
TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
|
||||
LLVMInitializeX86TargetInfo();
|
||||
LLVMInitializeX86Target();
|
||||
LLVMInitializeX86TargetMC();
|
||||
|
||||
// Read benchmarks.
|
||||
const LLVMState State;
|
||||
|
||||
llvm::ExitOnError ExitOnErr;
|
||||
BenchmarkResultContext Ctx;
|
||||
Ctx.addInstrEntry(kInstrId, kInstrName);
|
||||
Ctx.addRegEntry(kReg1Id, kReg1Name);
|
||||
Ctx.addRegEntry(kReg2Id, kReg2Name);
|
||||
|
||||
InstructionBenchmark ToDisk;
|
||||
|
||||
ToDisk.Key.Instructions.push_back(llvm::MCInstBuilder(kInstrId)
|
||||
.addReg(kReg1Id)
|
||||
.addReg(kReg2Id)
|
||||
ToDisk.Key.Instructions.push_back(llvm::MCInstBuilder(llvm::X86::XOR32rr)
|
||||
.addReg(llvm::X86::AL)
|
||||
.addReg(llvm::X86::AH)
|
||||
.addImm(123)
|
||||
.addFPImm(0.5));
|
||||
ToDisk.Key.Config = "config";
|
||||
|
@ -83,12 +82,13 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
|
|||
EC = llvm::sys::fs::createUniqueDirectory("BenchmarkResultTestDir", Filename);
|
||||
ASSERT_FALSE(EC);
|
||||
llvm::sys::path::append(Filename, "data.yaml");
|
||||
ExitOnErr(ToDisk.writeYaml(Ctx, Filename));
|
||||
llvm::errs() << Filename << "-------\n";
|
||||
ExitOnErr(ToDisk.writeYaml(State, Filename));
|
||||
|
||||
{
|
||||
// One-element version.
|
||||
const auto FromDisk =
|
||||
ExitOnErr(InstructionBenchmark::readYaml(Ctx, Filename));
|
||||
ExitOnErr(InstructionBenchmark::readYaml(State, Filename));
|
||||
|
||||
EXPECT_THAT(FromDisk.Key.Instructions,
|
||||
Pointwise(EqMCInst(), ToDisk.Key.Instructions));
|
||||
|
@ -104,7 +104,7 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
|
|||
{
|
||||
// Vector version.
|
||||
const auto FromDiskVector =
|
||||
ExitOnErr(InstructionBenchmark::readYamls(Ctx, Filename));
|
||||
ExitOnErr(InstructionBenchmark::readYamls(State, Filename));
|
||||
ASSERT_EQ(FromDiskVector.size(), size_t{1});
|
||||
const auto FromDisk = FromDiskVector[0];
|
||||
EXPECT_THAT(FromDisk.Key.Instructions,
|
|
@ -16,6 +16,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
add_llvm_unittest(LLVMExegesisX86Tests
|
||||
AssemblerTest.cpp
|
||||
AnalysisTest.cpp
|
||||
BenchmarkResultTest.cpp
|
||||
SnippetGeneratorTest.cpp
|
||||
RegisterAliasingTest.cpp
|
||||
TargetTest.cpp
|
||||
|
|
Loading…
Reference in New Issue