Index: test/tools/llvm-exegesis/X86/latency-by-opcode-name.s =================================================================== --- test/tools/llvm-exegesis/X86/latency-by-opcode-name.s +++ test/tools/llvm-exegesis/X86/latency-by-opcode-name.s @@ -1,8 +1,11 @@ # RUN: llvm-exegesis -mode=latency -opcode-name=ADD32rr | FileCheck %s CHECK: --- -CHECK-NEXT: mode: latency +CHECK-NEXT: mode: latency CHECK-NEXT: key: CHECK-NEXT: instructions: CHECK-NEXT: ADD32rr +CHECK-NEXT: config: '' +CHECK-NEXT: register_initial_values: +CHECK-DAG: - '[[REG1:[A-Z0-9]+]]=0x0' CHECK-LAST: ... Index: tools/llvm-exegesis/lib/BenchmarkResult.h =================================================================== --- tools/llvm-exegesis/lib/BenchmarkResult.h +++ tools/llvm-exegesis/lib/BenchmarkResult.h @@ -16,6 +16,7 @@ #ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H #define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H +#include "BenchmarkCode.h" #include "LlvmState.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -32,6 +33,8 @@ struct InstructionBenchmarkKey { // The LLVM opcode name. std::vector Instructions; + // The initial values of the registers. + std::vector RegisterInitialValues; // An opaque configuration, that can be used to separate several benchmarks of // the same instruction under different configurations. std::string Config; Index: tools/llvm-exegesis/lib/BenchmarkResult.cpp =================================================================== --- tools/llvm-exegesis/lib/BenchmarkResult.cpp +++ tools/llvm-exegesis/lib/BenchmarkResult.cpp @@ -54,6 +54,24 @@ std::string &getLastError() { return ErrorStream.str(); } + llvm::raw_string_ostream &getErrorStream() { return ErrorStream; } + + 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; + } + + 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; + } + private: void serializeMCOperand(const llvm::MCOperand &MCOperand, llvm::raw_ostream &OS) { @@ -83,13 +101,6 @@ 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()) @@ -97,15 +108,6 @@ 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) @@ -124,6 +126,10 @@ namespace llvm { namespace yaml { +static YamlContext &getTypedContext(void *Ctx) { + return *reinterpret_cast(Ctx); +} + // std::vector will be rendered as a list. template <> struct SequenceElementTraits { static const bool flow = false; @@ -133,15 +139,17 @@ static void output(const llvm::MCInst &Value, void *Ctx, llvm::raw_ostream &Out) { - reinterpret_cast(Ctx)->serializeMCInst(Value, Out); + getTypedContext(Ctx).serializeMCInst(Value, Out); } static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) { - YamlContext &Context = *reinterpret_cast(Ctx); + YamlContext &Context = getTypedContext(Ctx); Context.deserializeMCInst(Scalar, Value); return Context.getLastError(); } + // By default strings are quoted only when necessary. + // We force the use of single quotes for uniformity. static QuotingType mustQuote(StringRef) { return QuotingType::Single; } static const bool flow = true; @@ -173,6 +181,44 @@ } }; +// std::vector will be rendered as a list. +template <> struct SequenceElementTraits { + static const bool flow = false; +}; + +template <> struct ScalarTraits { + static constexpr const unsigned kRadix = 16; + static constexpr const bool kSigned = false; + + static void output(const exegesis::RegisterValue &RV, void *Ctx, + llvm::raw_ostream &Out) { + YamlContext &Context = getTypedContext(Ctx); + Out << Context.getRegName(RV.Register) << "=0x" + << RV.Value.toString(kRadix, kSigned); + } + + static StringRef input(StringRef String, void *Ctx, + exegesis::RegisterValue &RV) { + llvm::SmallVector Pieces; + String.split(Pieces, "=0x", /* MaxSplit */ -1, + /* KeepEmpty */ false); + YamlContext &Context = getTypedContext(Ctx); + if (Pieces.size() == 2) { + RV.Register = Context.getRegNo(Pieces[0]); + const unsigned BitsNeeded = llvm::APInt::getBitsNeeded(Pieces[1], kRadix); + RV.Value = llvm::APInt(BitsNeeded, Pieces[1], kRadix); + } else { + Context.getErrorStream() + << "Unknown initial register value: '" << String << "'"; + } + return Context.getLastError(); + } + + static QuotingType mustQuote(StringRef) { return QuotingType::Single; } + + static const bool flow = true; +}; + template <> struct MappingContextTraits { static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj, @@ -180,13 +226,13 @@ Io.setContext(&Context); Io.mapRequired("instructions", Obj.Instructions); Io.mapOptional("config", Obj.Config); + Io.mapRequired("register_initial_values", Obj.RegisterInitialValues); } }; template <> struct MappingContextTraits { - class NormalizedBinary { - public: + struct NormalizedBinary { NormalizedBinary(IO &io) {} NormalizedBinary(IO &, std::vector &Data) : Binary(Data) {} std::vector denormalize(IO &) { Index: tools/llvm-exegesis/lib/BenchmarkRunner.cpp =================================================================== --- tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -57,6 +57,7 @@ const std::vector &Instructions = BC.Instructions; InstrBenchmark.Key.Instructions = Instructions; + InstrBenchmark.Key.RegisterInitialValues = BC.RegisterInitialValues; // Assemble at least kMinInstructionsForSnippet instructions by repeating the // snippet for debug/analysis. This is so that the user clearly understands Index: unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp =================================================================== --- unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp +++ unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp @@ -68,6 +68,9 @@ .addImm(123) .addFPImm(0.5)); ToDisk.Key.Config = "config"; + ToDisk.Key.RegisterInitialValues = { + RegisterValue{llvm::X86::AL, llvm::APInt(8, "-1", 10)}, + RegisterValue{llvm::X86::AH, llvm::APInt(8, "123", 10)}}; ToDisk.Mode = InstructionBenchmark::Latency; ToDisk.CpuName = "cpu_name"; ToDisk.LLVMTriple = "llvm_triple";