From 6b7cfabf55525ef24ec212b307ad6dc8db585fa3 Mon Sep 17 00:00:00 2001 From: Clement Courbet Date: Tue, 26 Jun 2018 08:49:30 +0000 Subject: [PATCH] [llvm-exegesis] Get the BenchmarkRunner from the ExegesisTarget. Summary: This allows targets to override code generation for some instructions. As an example of override, this also moves ad-hoc instruction filtering for X86 into the X86 ExegesisTarget. Reviewers: gchatelet Subscribers: mgorny, tschuett, llvm-commits Differential Revision: https://reviews.llvm.org/D48587 llvm-svn: 335582 --- tools/llvm-exegesis/lib/Assembler.cpp | 17 +++---- tools/llvm-exegesis/lib/Assembler.h | 2 +- tools/llvm-exegesis/lib/BenchmarkRunner.cpp | 27 +++++----- tools/llvm-exegesis/lib/BenchmarkRunner.h | 36 +++++-------- tools/llvm-exegesis/lib/CMakeLists.txt | 1 - tools/llvm-exegesis/lib/Latency.cpp | 6 --- tools/llvm-exegesis/lib/Latency.h | 5 +- tools/llvm-exegesis/lib/LlvmState.cpp | 5 ++ tools/llvm-exegesis/lib/LlvmState.h | 5 +- tools/llvm-exegesis/lib/Target.cpp | 46 +++++++++++++++++ tools/llvm-exegesis/lib/Target.h | 18 +++++++ tools/llvm-exegesis/lib/Uops.cpp | 6 --- tools/llvm-exegesis/lib/Uops.h | 5 +- tools/llvm-exegesis/lib/X86.cpp | 38 -------------- tools/llvm-exegesis/lib/X86.h | 32 ------------ tools/llvm-exegesis/lib/X86/Target.cpp | 50 +++++++++++++++++++ tools/llvm-exegesis/llvm-exegesis.cpp | 40 ++++++--------- .../llvm-exegesis/Common/AssemblerUtils.h | 7 +-- .../X86/SnippetGeneratorTest.cpp | 7 +-- 19 files changed, 183 insertions(+), 170 deletions(-) delete mode 100644 tools/llvm-exegesis/lib/X86.cpp delete mode 100644 tools/llvm-exegesis/lib/X86.h diff --git a/tools/llvm-exegesis/lib/Assembler.cpp b/tools/llvm-exegesis/lib/Assembler.cpp index 9410c70c582..c7fc6bd9ee9 100644 --- a/tools/llvm-exegesis/lib/Assembler.cpp +++ b/tools/llvm-exegesis/lib/Assembler.cpp @@ -138,7 +138,7 @@ llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM) { return MF.getSubtarget().getRegisterInfo()->getReservedRegs(MF); } -void assembleToStream(const ExegesisTarget *ET, +void assembleToStream(const ExegesisTarget &ET, std::unique_ptr TM, llvm::ArrayRef RegsToDef, llvm::ArrayRef Instructions, @@ -157,11 +157,10 @@ void assembleToStream(const ExegesisTarget *ET, auto &Properties = MF.getProperties(); Properties.set(llvm::MachineFunctionProperties::Property::NoVRegs); Properties.reset(llvm::MachineFunctionProperties::Property::IsSSA); - std::vector SnippetWithSetup; - bool IsSnippetSetupComplete = RegsToDef.empty(); - if (ET) { - SnippetWithSetup = - generateSnippetSetupCode(RegsToDef, *ET, IsSnippetSetupComplete); + bool IsSnippetSetupComplete = false; + std::vector SnippetWithSetup = + generateSnippetSetupCode(RegsToDef, ET, IsSnippetSetupComplete); + if (!SnippetWithSetup.empty()) { SnippetWithSetup.insert(SnippetWithSetup.end(), Instructions.begin(), Instructions.end()); Instructions = SnippetWithSetup; @@ -190,10 +189,8 @@ void assembleToStream(const ExegesisTarget *ET, PM.add(MMI.release()); TPC->printAndVerify("MachineFunctionGenerator::assemble"); // Add target-specific passes. - if (ET) { - ET->addTargetSpecificPasses(PM); - TPC->printAndVerify("After ExegesisTarget::addTargetSpecificPasses"); - } + ET.addTargetSpecificPasses(PM); + TPC->printAndVerify("After ExegesisTarget::addTargetSpecificPasses"); // Adding the following passes: // - machineverifier: checks that the MachineFunction is well formed. // - prologepilog: saves and restore callee saved registers. diff --git a/tools/llvm-exegesis/lib/Assembler.h b/tools/llvm-exegesis/lib/Assembler.h index fb39053dbce..e9a65cbbe36 100644 --- a/tools/llvm-exegesis/lib/Assembler.h +++ b/tools/llvm-exegesis/lib/Assembler.h @@ -43,7 +43,7 @@ llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM); // Instructions. Runs a set of llvm Passes to provide correct prologue and // epilogue. Once the MachineFunction is ready, it is assembled for TM to // AsmStream, the temporary function is eventually discarded. -void assembleToStream(const ExegesisTarget *ET, +void assembleToStream(const ExegesisTarget &ET, std::unique_ptr TM, llvm::ArrayRef RegsToDef, llvm::ArrayRef Instructions, diff --git a/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/tools/llvm-exegesis/lib/BenchmarkRunner.cpp index 5223fbac335..c07775f880b 100644 --- a/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ b/tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -26,23 +26,26 @@ namespace exegesis { BenchmarkFailure::BenchmarkFailure(const llvm::Twine &S) : llvm::StringError(S, llvm::inconvertibleErrorCode()) {} -BenchmarkRunner::InstructionFilter::~InstructionFilter() = default; - -BenchmarkRunner::BenchmarkRunner(const LLVMState &State) - : State(State), - RATC(State.getRegInfo(), getFunctionReservedRegs(State.getTargetMachine())) {} +BenchmarkRunner::BenchmarkRunner(const LLVMState &State, + InstructionBenchmark::ModeE Mode) + : State(State), RATC(State.getRegInfo(), + getFunctionReservedRegs(State.getTargetMachine())), + Mode(Mode) {} BenchmarkRunner::~BenchmarkRunner() = default; llvm::Expected> -BenchmarkRunner::run(unsigned Opcode, const InstructionFilter &Filter, - unsigned NumRepetitions) { +BenchmarkRunner::run(unsigned Opcode, unsigned NumRepetitions) { + const llvm::MCInstrDesc &InstrDesc = State.getInstrInfo().get(Opcode); // Ignore instructions that we cannot run. - if (State.getInstrInfo().get(Opcode).isPseudo()) + if (InstrDesc.isPseudo()) return llvm::make_error("Unsupported opcode: isPseudo"); - - if (llvm::Error E = Filter.shouldRun(State, Opcode)) - return std::move(E); + if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch()) + return llvm::make_error( + "Unsupported opcode: isBranch/isIndirectBranch"); + if (InstrDesc.isCall() || InstrDesc.isReturn()) + return llvm::make_error( + "Unsupported opcode: isCall/isReturn"); llvm::Expected> ConfigurationOrError = generateConfigurations(Opcode); @@ -60,7 +63,7 @@ InstructionBenchmark BenchmarkRunner::runOne(const BenchmarkConfiguration &Configuration, unsigned Opcode, unsigned NumRepetitions) const { InstructionBenchmark InstrBenchmark; - InstrBenchmark.Mode = getMode(); + InstrBenchmark.Mode = Mode; InstrBenchmark.CpuName = State.getTargetMachine().getTargetCPU(); InstrBenchmark.LLVMTriple = State.getTargetMachine().getTargetTriple().normalize(); diff --git a/tools/llvm-exegesis/lib/BenchmarkRunner.h b/tools/llvm-exegesis/lib/BenchmarkRunner.h index 6d1da9e4ba7..d4cdad20ccc 100644 --- a/tools/llvm-exegesis/lib/BenchmarkRunner.h +++ b/tools/llvm-exegesis/lib/BenchmarkRunner.h @@ -54,25 +54,12 @@ struct BenchmarkConfiguration { // Common code for all benchmark modes. class BenchmarkRunner { public: - explicit BenchmarkRunner(const LLVMState &State); - - // Subtargets can disable running benchmarks for some instructions by - // returning an error here. - class InstructionFilter { - public: - virtual ~InstructionFilter(); - - virtual llvm::Error shouldRun(const LLVMState &State, - unsigned Opcode) const { - return llvm::ErrorSuccess(); - } - }; + explicit BenchmarkRunner(const LLVMState &State, InstructionBenchmark::ModeE Mode); virtual ~BenchmarkRunner(); llvm::Expected> - run(unsigned Opcode, const InstructionFilter &Filter, - unsigned NumRepetitions); + run(unsigned Opcode, unsigned NumRepetitions); // Given a snippet, computes which registers the setup code needs to define. std::vector @@ -83,6 +70,15 @@ protected: const RegisterAliasingTrackerCache RATC; private: + // API to be implemented by subclasses. + virtual llvm::Expected + generatePrototype(unsigned Opcode) const = 0; + + virtual std::vector + runMeasurements(const ExecutableFunction &EF, + const unsigned NumRepetitions) const = 0; + + // Internal helpers. InstructionBenchmark runOne(const BenchmarkConfiguration &Configuration, unsigned Opcode, unsigned NumRepetitions) const; @@ -91,18 +87,12 @@ private: llvm::Expected> generateConfigurations(unsigned Opcode) const; - virtual InstructionBenchmark::ModeE getMode() const = 0; - - virtual llvm::Expected - generatePrototype(unsigned Opcode) const = 0; - - virtual std::vector - runMeasurements(const ExecutableFunction &EF, - const unsigned NumRepetitions) const = 0; llvm::Expected writeObjectFile(const BenchmarkConfiguration::Setup &Setup, llvm::ArrayRef Code) const; + + const InstructionBenchmark::ModeE Mode; }; } // namespace exegesis diff --git a/tools/llvm-exegesis/lib/CMakeLists.txt b/tools/llvm-exegesis/lib/CMakeLists.txt index 96c6c91ece8..02eeb758fcf 100644 --- a/tools/llvm-exegesis/lib/CMakeLists.txt +++ b/tools/llvm-exegesis/lib/CMakeLists.txt @@ -16,7 +16,6 @@ add_library(LLVMExegesis RegisterAliasing.cpp Target.cpp Uops.cpp - X86.cpp ) llvm_update_compile_flags(LLVMExegesis) diff --git a/tools/llvm-exegesis/lib/Latency.cpp b/tools/llvm-exegesis/lib/Latency.cpp index 3cc0d85be8b..e73305ecdc7 100644 --- a/tools/llvm-exegesis/lib/Latency.cpp +++ b/tools/llvm-exegesis/lib/Latency.cpp @@ -31,14 +31,8 @@ static bool hasMemoryOperand(const llvm::MCOperandInfo &OpInfo) { LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default; -InstructionBenchmark::ModeE LatencyBenchmarkRunner::getMode() const { - return InstructionBenchmark::Latency; -} - llvm::Error LatencyBenchmarkRunner::isInfeasible( const llvm::MCInstrDesc &MCInstrDesc) const { - if (MCInstrDesc.isPseudo()) - return llvm::make_error("Infeasible : is pseudo"); if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand)) return llvm::make_error( "Infeasible : has unknown operands"); diff --git a/tools/llvm-exegesis/lib/Latency.h b/tools/llvm-exegesis/lib/Latency.h index 3a12bdd2004..3bb9f419b1b 100644 --- a/tools/llvm-exegesis/lib/Latency.h +++ b/tools/llvm-exegesis/lib/Latency.h @@ -22,7 +22,8 @@ namespace exegesis { class LatencyBenchmarkRunner : public BenchmarkRunner { public: - using BenchmarkRunner::BenchmarkRunner; + LatencyBenchmarkRunner(const LLVMState &State) + : BenchmarkRunner(State, InstructionBenchmark::Latency) {} ~LatencyBenchmarkRunner() override; llvm::Expected @@ -39,8 +40,6 @@ private: const Instruction &Instr, const AliasingConfigurations &SelfAliasing) const; - InstructionBenchmark::ModeE getMode() const override; - std::vector runMeasurements(const ExecutableFunction &EF, const unsigned NumRepetitions) const override; diff --git a/tools/llvm-exegesis/lib/LlvmState.cpp b/tools/llvm-exegesis/lib/LlvmState.cpp index 9b30d78b0c9..9ff42ca71fd 100644 --- a/tools/llvm-exegesis/lib/LlvmState.cpp +++ b/tools/llvm-exegesis/lib/LlvmState.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "LlvmState.h" +#include "Target.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" @@ -30,6 +31,10 @@ LLVMState::LLVMState(const std::string &Triple, const std::string &CpuName) { TheTarget->createTargetMachine(Triple, CpuName, /*Features*/ "", Options, llvm::Reloc::Model::Static))); TheExegesisTarget = ExegesisTarget::lookup(TargetMachine->getTargetTriple()); + if (!TheExegesisTarget) { + llvm::errs() << "no exegesis target for " << Triple << ", using default\n"; + TheExegesisTarget = &ExegesisTarget::getDefault(); + } } LLVMState::LLVMState() diff --git a/tools/llvm-exegesis/lib/LlvmState.h b/tools/llvm-exegesis/lib/LlvmState.h index 18c92b835ca..c84db300841 100644 --- a/tools/llvm-exegesis/lib/LlvmState.h +++ b/tools/llvm-exegesis/lib/LlvmState.h @@ -15,7 +15,6 @@ #ifndef LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H #define LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H -#include "Target.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" @@ -41,7 +40,7 @@ public: const llvm::TargetMachine &getTargetMachine() const { return *TargetMachine; } std::unique_ptr createTargetMachine() const; - const ExegesisTarget *getExegesisTarget() const { return TheExegesisTarget; } + const ExegesisTarget &getExegesisTarget() const { return *TheExegesisTarget; } bool canAssemble(const llvm::MCInst &mc_inst) const; @@ -57,7 +56,7 @@ public: } private: - const ExegesisTarget *TheExegesisTarget = nullptr; + const ExegesisTarget *TheExegesisTarget; std::unique_ptr TargetMachine; }; diff --git a/tools/llvm-exegesis/lib/Target.cpp b/tools/llvm-exegesis/lib/Target.cpp index 92e3e46f831..44156c815db 100644 --- a/tools/llvm-exegesis/lib/Target.cpp +++ b/tools/llvm-exegesis/lib/Target.cpp @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// #include "Target.h" +#include "Latency.h" +#include "Uops.h" + namespace exegesis { ExegesisTarget::~ExegesisTarget() {} // anchor. @@ -33,4 +36,47 @@ void ExegesisTarget::registerTarget(ExegesisTarget *Target) { Target->Next = FirstTarget; FirstTarget = Target; } + +std::unique_ptr +ExegesisTarget::createBenchmarkRunner(InstructionBenchmark::ModeE Mode, + const LLVMState &State) const { + switch (Mode) { + case InstructionBenchmark::Unknown: + return nullptr; + case InstructionBenchmark::Latency: + return createLatencyBenchmarkRunner(State); + case InstructionBenchmark::Uops: + return createUopsBenchmarkRunner(State); + } + return nullptr; +} + +std::unique_ptr +ExegesisTarget::createLatencyBenchmarkRunner(const LLVMState &State) const { + return llvm::make_unique(State); +} + +std::unique_ptr +ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const { + return llvm::make_unique(State); +} + +namespace { + +// Default implementation. +class ExegesisDefaultTarget : public ExegesisTarget { +private: + bool matchesArch(llvm::Triple::ArchType Arch) const override { + llvm_unreachable("never called"); + return false; + } +}; + +} // namespace + +const ExegesisTarget &ExegesisTarget::getDefault() { + static ExegesisDefaultTarget Target; + return Target; +} + } // namespace exegesis diff --git a/tools/llvm-exegesis/lib/Target.h b/tools/llvm-exegesis/lib/Target.h index 1d35824daed..cb87e3a6d4b 100644 --- a/tools/llvm-exegesis/lib/Target.h +++ b/tools/llvm-exegesis/lib/Target.h @@ -17,6 +17,9 @@ #ifndef LLVM_TOOLS_LLVM_EXEGESIS_TARGET_H #define LLVM_TOOLS_LLVM_EXEGESIS_TARGET_H +#include "BenchmarkResult.h" +#include "BenchmarkRunner.h" +#include "LlvmState.h" #include "llvm/ADT/Triple.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/LegacyPassManager.h" @@ -35,9 +38,16 @@ public: return {}; } + // Creates a benchmark runner for the given mode. + std::unique_ptr + createBenchmarkRunner(InstructionBenchmark::ModeE Mode, + const LLVMState &State) const; + // Returns the ExegesisTarget for the given triple or nullptr if the target // does not exist. static const ExegesisTarget *lookup(llvm::Triple TT); + // Returns the default (unspecialized) ExegesisTarget. + static const ExegesisTarget &getDefault(); // Registers a target. Not thread safe. static void registerTarget(ExegesisTarget *T); @@ -45,6 +55,14 @@ public: private: virtual bool matchesArch(llvm::Triple::ArchType Arch) const = 0; + + // Targets can implement their own Latency/Uops benchmarks runners by + // implementing these. + std::unique_ptr virtual createLatencyBenchmarkRunner( + const LLVMState &State) const; + std::unique_ptr virtual createUopsBenchmarkRunner( + const LLVMState &State) const; + const ExegesisTarget *Next = nullptr; }; diff --git a/tools/llvm-exegesis/lib/Uops.cpp b/tools/llvm-exegesis/lib/Uops.cpp index 677a9d3a104..0125b6cb099 100644 --- a/tools/llvm-exegesis/lib/Uops.cpp +++ b/tools/llvm-exegesis/lib/Uops.cpp @@ -91,8 +91,6 @@ static bool hasMemoryOperand(const llvm::MCOperandInfo &OpInfo) { llvm::Error UopsBenchmarkRunner::isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const { - if (MCInstrDesc.isPseudo()) - return llvm::make_error("Infeasible : is pseudo"); if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand)) return llvm::make_error( "Infeasible : has unknown operands"); @@ -133,10 +131,6 @@ static void remove(llvm::BitVector &a, const llvm::BitVector &b) { UopsBenchmarkRunner::~UopsBenchmarkRunner() = default; -InstructionBenchmark::ModeE UopsBenchmarkRunner::getMode() const { - return InstructionBenchmark::Uops; -} - llvm::Expected UopsBenchmarkRunner::generatePrototype(unsigned Opcode) const { const auto &InstrDesc = State.getInstrInfo().get(Opcode); diff --git a/tools/llvm-exegesis/lib/Uops.h b/tools/llvm-exegesis/lib/Uops.h index 284585b870f..c7b5709f7d9 100644 --- a/tools/llvm-exegesis/lib/Uops.h +++ b/tools/llvm-exegesis/lib/Uops.h @@ -21,7 +21,8 @@ namespace exegesis { class UopsBenchmarkRunner : public BenchmarkRunner { public: - using BenchmarkRunner::BenchmarkRunner; + UopsBenchmarkRunner(const LLVMState &State) + : BenchmarkRunner(State, InstructionBenchmark::Uops) {} ~UopsBenchmarkRunner() override; llvm::Expected @@ -30,8 +31,6 @@ public: private: llvm::Error isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const; - InstructionBenchmark::ModeE getMode() const override; - std::vector runMeasurements(const ExecutableFunction &EF, const unsigned NumRepetitions) const override; diff --git a/tools/llvm-exegesis/lib/X86.cpp b/tools/llvm-exegesis/lib/X86.cpp deleted file mode 100644 index c9afece4a9f..00000000000 --- a/tools/llvm-exegesis/lib/X86.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===-- X86.cpp --------------------------------------------------*- C++-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86.h" - -namespace exegesis { - -static llvm::Error makeError(llvm::Twine Msg) { - return llvm::make_error(Msg, - llvm::inconvertibleErrorCode()); -} - -X86Filter::~X86Filter() = default; - -// Test whether we can generate a snippet for this instruction. -llvm::Error X86Filter::shouldRun(const LLVMState &State, - const unsigned Opcode) const { - const auto &InstrInfo = State.getInstrInfo(); - const llvm::MCInstrDesc &InstrDesc = InstrInfo.get(Opcode); - if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch()) - return makeError("Unsupported opcode: isBranch/isIndirectBranch"); - if (InstrDesc.isCall() || InstrDesc.isReturn()) - return makeError("Unsupported opcode: isCall/isReturn"); - const auto OpcodeName = InstrInfo.getName(Opcode); - if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") || - OpcodeName.startswith("ADJCALLSTACK")) { - return makeError("Unsupported opcode: Push/Pop/AdjCallStack"); - } - return llvm::ErrorSuccess(); -} - -} // namespace exegesis diff --git a/tools/llvm-exegesis/lib/X86.h b/tools/llvm-exegesis/lib/X86.h deleted file mode 100644 index 52dd3391363..00000000000 --- a/tools/llvm-exegesis/lib/X86.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- X86.h ---------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// X86 target-specific setup. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_X86_H -#define LLVM_TOOLS_LLVM_EXEGESIS_X86_H - -#include "BenchmarkRunner.h" -#include "LlvmState.h" - -namespace exegesis { - -class X86Filter : public BenchmarkRunner::InstructionFilter { -public: - ~X86Filter() override; - - llvm::Error shouldRun(const LLVMState &State, unsigned Opcode) const override; -}; - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_X86_H diff --git a/tools/llvm-exegesis/lib/X86/Target.cpp b/tools/llvm-exegesis/lib/X86/Target.cpp index 591edd2afae..5951752e1d7 100644 --- a/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/tools/llvm-exegesis/lib/X86/Target.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "../Target.h" +#include "../Latency.h" +#include "../Uops.h" #include "MCTargetDesc/X86MCTargetDesc.h" #include "X86.h" #include "X86RegisterInfo.h" @@ -15,8 +17,46 @@ namespace exegesis { +// Test whether we can generate a snippet for this instruction. +static llvm::Error shouldRun(const LLVMState &State, const unsigned Opcode) { + const auto &InstrInfo = State.getInstrInfo(); + const auto OpcodeName = InstrInfo.getName(Opcode); + if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") || + OpcodeName.startswith("ADJCALLSTACK")) { + return llvm::make_error( + "Unsupported opcode: Push/Pop/AdjCallStack"); + } + return llvm::ErrorSuccess(); +} + namespace { +class X86LatencyBenchmarkRunner : public LatencyBenchmarkRunner { +private: + using LatencyBenchmarkRunner::LatencyBenchmarkRunner; + + llvm::Expected + generatePrototype(unsigned Opcode) const override { + if (llvm::Error E = shouldRun(State, Opcode)) { + return std::move(E); + } + return LatencyBenchmarkRunner::generatePrototype(Opcode); + } +}; + +class X86UopsBenchmarkRunner : public UopsBenchmarkRunner { +private: + using UopsBenchmarkRunner::UopsBenchmarkRunner; + + llvm::Expected + generatePrototype(unsigned Opcode) const override { + if (llvm::Error E = shouldRun(State, Opcode)) { + return std::move(E); + } + return UopsBenchmarkRunner::generatePrototype(Opcode); + } +}; + class ExegesisX86Target : public ExegesisTarget { void addTargetSpecificPasses(llvm::PassManagerBase &PM) const override { // Lowers FP pseudo-instructions, e.g. ABS_Fp32 -> ABS_F. @@ -55,6 +95,16 @@ class ExegesisX86Target : public ExegesisTarget { return {}; } + std::unique_ptr + createLatencyBenchmarkRunner(const LLVMState &State) const override { + return llvm::make_unique(State); + } + + std::unique_ptr + createUopsBenchmarkRunner(const LLVMState &State) const override { + return llvm::make_unique(State); + } + bool matchesArch(llvm::Triple::ArchType Arch) const override { return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86; } diff --git a/tools/llvm-exegesis/llvm-exegesis.cpp b/tools/llvm-exegesis/llvm-exegesis.cpp index 2ac92965a96..92d19c07015 100644 --- a/tools/llvm-exegesis/llvm-exegesis.cpp +++ b/tools/llvm-exegesis/llvm-exegesis.cpp @@ -16,11 +16,9 @@ #include "lib/BenchmarkResult.h" #include "lib/BenchmarkRunner.h" #include "lib/Clustering.h" -#include "lib/Latency.h" #include "lib/LlvmState.h" #include "lib/PerfHelper.h" -#include "lib/Uops.h" -#include "lib/X86.h" +#include "lib/Target.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCInstBuilder.h" @@ -47,13 +45,16 @@ static llvm::cl::opt static llvm::cl::opt BenchmarkFile("benchmarks-file", llvm::cl::desc(""), llvm::cl::init("")); -enum class BenchmarkModeE { Latency, Uops, Analysis }; -static llvm::cl::opt BenchmarkMode( +static llvm::cl::opt BenchmarkMode( "mode", llvm::cl::desc("the mode to run"), - llvm::cl::values( - clEnumValN(BenchmarkModeE::Latency, "latency", "Instruction Latency"), - clEnumValN(BenchmarkModeE::Uops, "uops", "Uop Decomposition"), - clEnumValN(BenchmarkModeE::Analysis, "analysis", "Analysis"))); + llvm::cl::values(clEnumValN(exegesis::InstructionBenchmark::Latency, + "latency", "Instruction Latency"), + clEnumValN(exegesis::InstructionBenchmark::Uops, "uops", + "Uop Decomposition"), + // When not asking for a specific benchmark mode, we'll + // analyse the results. + clEnumValN(exegesis::InstructionBenchmark::Unknown, + "analysis", "Analysis"))); static llvm::cl::opt NumRepetitions("num-repetitions", @@ -128,9 +129,6 @@ void benchmarkMain() { LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET(); #endif - // FIXME: Target-specific filter. - X86Filter Filter; - const LLVMState State; const auto Opcode = GetOpcodeOrDie(State.getInstrInfo()); @@ -146,16 +144,10 @@ void benchmarkMain() { if (!State.getSubtargetInfo().getSchedModel().hasExtraProcessorInfo()) llvm::report_fatal_error("sched model is missing extra processor info!"); - std::unique_ptr Runner; - switch (BenchmarkMode) { - case BenchmarkModeE::Latency: - Runner = llvm::make_unique(State); - break; - case BenchmarkModeE::Uops: - Runner = llvm::make_unique(State); - break; - case BenchmarkModeE::Analysis: - llvm_unreachable("not a benchmark"); + const std::unique_ptr Runner = + State.getExegesisTarget().createBenchmarkRunner(BenchmarkMode, State); + if (!Runner) { + llvm::report_fatal_error("cannot create benchmark runner"); } if (NumRepetitions == 0) @@ -167,7 +159,7 @@ void benchmarkMain() { const BenchmarkResultContext Context = getBenchmarkResultContext(State); std::vector Results = - ExitOnErr(Runner->run(Opcode, Filter, NumRepetitions)); + ExitOnErr(Runner->run(Opcode, NumRepetitions)); for (InstructionBenchmark &Result : Results) ExitOnErr(Result.writeYaml(Context, BenchmarkFile)); @@ -245,7 +237,7 @@ int main(int Argc, char **Argv) { return EXIT_FAILURE; }); - if (BenchmarkMode == BenchmarkModeE::Analysis) { + if (BenchmarkMode == exegesis::InstructionBenchmark::Unknown) { exegesis::analysisMain(); } else { exegesis::benchmarkMain(); diff --git a/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h b/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h index 52133b4aee8..a0cfb1d86c7 100644 --- a/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h +++ b/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "Assembler.h" +#include "Target.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/TargetInstrInfo.h" @@ -36,11 +37,11 @@ protected: } template inline void Check(llvm::MCInst MCInst, Bs... Bytes) { - CheckWithSetup(nullptr, {}, MCInst, Bytes...); + CheckWithSetup(ExegesisTarget::getDefault(), {}, MCInst, Bytes...); } template - inline void CheckWithSetup(const ExegesisTarget *ET, + inline void CheckWithSetup(const ExegesisTarget &ET, llvm::ArrayRef RegsToDef, llvm::MCInst MCInst, Bs... Bytes) { ExecutableFunction Function = @@ -67,7 +68,7 @@ private: } ExecutableFunction - assembleToFunction(const ExegesisTarget *ET, + assembleToFunction(const ExegesisTarget &ET, llvm::ArrayRef RegsToDef, llvm::ArrayRef Instructions) { llvm::SmallString<256> Buffer; diff --git a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp index 77de5e78926..edacd7fe629 100644 --- a/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp +++ b/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp @@ -217,17 +217,14 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedVariables) { class FakeBenchmarkRunner : public BenchmarkRunner { public: - using BenchmarkRunner::BenchmarkRunner; + FakeBenchmarkRunner(const LLVMState &State) + : BenchmarkRunner(State, InstructionBenchmark::Unknown) {} Instruction createInstruction(unsigned Opcode) { return Instruction(State.getInstrInfo().get(Opcode), RATC); } private: - InstructionBenchmark::ModeE getMode() const override { - return InstructionBenchmark::Unknown; - } - llvm::Expected generatePrototype(unsigned Opcode) const override { return llvm::make_error("not implemented",