mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[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
This commit is contained in:
parent
35344b129a
commit
6b7cfabf55
@ -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<llvm::LLVMTargetMachine> TM,
|
||||
llvm::ArrayRef<unsigned> RegsToDef,
|
||||
llvm::ArrayRef<llvm::MCInst> 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<llvm::MCInst> SnippetWithSetup;
|
||||
bool IsSnippetSetupComplete = RegsToDef.empty();
|
||||
if (ET) {
|
||||
SnippetWithSetup =
|
||||
generateSnippetSetupCode(RegsToDef, *ET, IsSnippetSetupComplete);
|
||||
bool IsSnippetSetupComplete = false;
|
||||
std::vector<llvm::MCInst> 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.
|
||||
|
@ -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<llvm::LLVMTargetMachine> TM,
|
||||
llvm::ArrayRef<unsigned> RegsToDef,
|
||||
llvm::ArrayRef<llvm::MCInst> Instructions,
|
||||
|
@ -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<std::vector<InstructionBenchmark>>
|
||||
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<BenchmarkFailure>("Unsupported opcode: isPseudo");
|
||||
|
||||
if (llvm::Error E = Filter.shouldRun(State, Opcode))
|
||||
return std::move(E);
|
||||
if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())
|
||||
return llvm::make_error<BenchmarkFailure>(
|
||||
"Unsupported opcode: isBranch/isIndirectBranch");
|
||||
if (InstrDesc.isCall() || InstrDesc.isReturn())
|
||||
return llvm::make_error<BenchmarkFailure>(
|
||||
"Unsupported opcode: isCall/isReturn");
|
||||
|
||||
llvm::Expected<std::vector<BenchmarkConfiguration>> 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();
|
||||
|
@ -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<std::vector<InstructionBenchmark>>
|
||||
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<unsigned>
|
||||
@ -83,6 +70,15 @@ protected:
|
||||
const RegisterAliasingTrackerCache RATC;
|
||||
|
||||
private:
|
||||
// API to be implemented by subclasses.
|
||||
virtual llvm::Expected<SnippetPrototype>
|
||||
generatePrototype(unsigned Opcode) const = 0;
|
||||
|
||||
virtual std::vector<BenchmarkMeasure>
|
||||
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<std::vector<BenchmarkConfiguration>>
|
||||
generateConfigurations(unsigned Opcode) const;
|
||||
|
||||
virtual InstructionBenchmark::ModeE getMode() const = 0;
|
||||
|
||||
virtual llvm::Expected<SnippetPrototype>
|
||||
generatePrototype(unsigned Opcode) const = 0;
|
||||
|
||||
virtual std::vector<BenchmarkMeasure>
|
||||
runMeasurements(const ExecutableFunction &EF,
|
||||
const unsigned NumRepetitions) const = 0;
|
||||
|
||||
llvm::Expected<std::string>
|
||||
writeObjectFile(const BenchmarkConfiguration::Setup &Setup,
|
||||
llvm::ArrayRef<llvm::MCInst> Code) const;
|
||||
|
||||
const InstructionBenchmark::ModeE Mode;
|
||||
};
|
||||
|
||||
} // namespace exegesis
|
||||
|
@ -16,7 +16,6 @@ add_library(LLVMExegesis
|
||||
RegisterAliasing.cpp
|
||||
Target.cpp
|
||||
Uops.cpp
|
||||
X86.cpp
|
||||
)
|
||||
|
||||
llvm_update_compile_flags(LLVMExegesis)
|
||||
|
@ -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<BenchmarkFailure>("Infeasible : is pseudo");
|
||||
if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand))
|
||||
return llvm::make_error<BenchmarkFailure>(
|
||||
"Infeasible : has unknown operands");
|
||||
|
@ -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<SnippetPrototype>
|
||||
@ -39,8 +40,6 @@ private:
|
||||
const Instruction &Instr,
|
||||
const AliasingConfigurations &SelfAliasing) const;
|
||||
|
||||
InstructionBenchmark::ModeE getMode() const override;
|
||||
|
||||
std::vector<BenchmarkMeasure>
|
||||
runMeasurements(const ExecutableFunction &EF,
|
||||
const unsigned NumRepetitions) const override;
|
||||
|
@ -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()
|
||||
|
@ -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<llvm::LLVMTargetMachine> 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<const llvm::TargetMachine> TargetMachine;
|
||||
};
|
||||
|
||||
|
@ -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<BenchmarkRunner>
|
||||
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<BenchmarkRunner>
|
||||
ExegesisTarget::createLatencyBenchmarkRunner(const LLVMState &State) const {
|
||||
return llvm::make_unique<LatencyBenchmarkRunner>(State);
|
||||
}
|
||||
|
||||
std::unique_ptr<BenchmarkRunner>
|
||||
ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const {
|
||||
return llvm::make_unique<UopsBenchmarkRunner>(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
|
||||
|
@ -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<BenchmarkRunner>
|
||||
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<BenchmarkRunner> virtual createLatencyBenchmarkRunner(
|
||||
const LLVMState &State) const;
|
||||
std::unique_ptr<BenchmarkRunner> virtual createUopsBenchmarkRunner(
|
||||
const LLVMState &State) const;
|
||||
|
||||
const ExegesisTarget *Next = nullptr;
|
||||
};
|
||||
|
||||
|
@ -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<BenchmarkFailure>("Infeasible : is pseudo");
|
||||
if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand))
|
||||
return llvm::make_error<BenchmarkFailure>(
|
||||
"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<SnippetPrototype>
|
||||
UopsBenchmarkRunner::generatePrototype(unsigned Opcode) const {
|
||||
const auto &InstrDesc = State.getInstrInfo().get(Opcode);
|
||||
|
@ -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<SnippetPrototype>
|
||||
@ -30,8 +31,6 @@ public:
|
||||
private:
|
||||
llvm::Error isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const;
|
||||
|
||||
InstructionBenchmark::ModeE getMode() const override;
|
||||
|
||||
std::vector<BenchmarkMeasure>
|
||||
runMeasurements(const ExecutableFunction &EF,
|
||||
const unsigned NumRepetitions) const override;
|
||||
|
@ -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<llvm::StringError>(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
|
@ -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
|
@ -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<BenchmarkFailure>(
|
||||
"Unsupported opcode: Push/Pop/AdjCallStack");
|
||||
}
|
||||
return llvm::ErrorSuccess();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class X86LatencyBenchmarkRunner : public LatencyBenchmarkRunner {
|
||||
private:
|
||||
using LatencyBenchmarkRunner::LatencyBenchmarkRunner;
|
||||
|
||||
llvm::Expected<SnippetPrototype>
|
||||
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<SnippetPrototype>
|
||||
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<BenchmarkRunner>
|
||||
createLatencyBenchmarkRunner(const LLVMState &State) const override {
|
||||
return llvm::make_unique<X86LatencyBenchmarkRunner>(State);
|
||||
}
|
||||
|
||||
std::unique_ptr<BenchmarkRunner>
|
||||
createUopsBenchmarkRunner(const LLVMState &State) const override {
|
||||
return llvm::make_unique<X86UopsBenchmarkRunner>(State);
|
||||
}
|
||||
|
||||
bool matchesArch(llvm::Triple::ArchType Arch) const override {
|
||||
return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86;
|
||||
}
|
||||
|
@ -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<std::string>
|
||||
static llvm::cl::opt<std::string>
|
||||
BenchmarkFile("benchmarks-file", llvm::cl::desc(""), llvm::cl::init(""));
|
||||
|
||||
enum class BenchmarkModeE { Latency, Uops, Analysis };
|
||||
static llvm::cl::opt<BenchmarkModeE> BenchmarkMode(
|
||||
static llvm::cl::opt<exegesis::InstructionBenchmark::ModeE> 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<unsigned>
|
||||
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<BenchmarkRunner> Runner;
|
||||
switch (BenchmarkMode) {
|
||||
case BenchmarkModeE::Latency:
|
||||
Runner = llvm::make_unique<LatencyBenchmarkRunner>(State);
|
||||
break;
|
||||
case BenchmarkModeE::Uops:
|
||||
Runner = llvm::make_unique<UopsBenchmarkRunner>(State);
|
||||
break;
|
||||
case BenchmarkModeE::Analysis:
|
||||
llvm_unreachable("not a benchmark");
|
||||
const std::unique_ptr<BenchmarkRunner> 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<InstructionBenchmark> 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();
|
||||
|
@ -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 <class... Bs> inline void Check(llvm::MCInst MCInst, Bs... Bytes) {
|
||||
CheckWithSetup(nullptr, {}, MCInst, Bytes...);
|
||||
CheckWithSetup(ExegesisTarget::getDefault(), {}, MCInst, Bytes...);
|
||||
}
|
||||
|
||||
template <class... Bs>
|
||||
inline void CheckWithSetup(const ExegesisTarget *ET,
|
||||
inline void CheckWithSetup(const ExegesisTarget &ET,
|
||||
llvm::ArrayRef<unsigned> RegsToDef,
|
||||
llvm::MCInst MCInst, Bs... Bytes) {
|
||||
ExecutableFunction Function =
|
||||
@ -67,7 +68,7 @@ private:
|
||||
}
|
||||
|
||||
ExecutableFunction
|
||||
assembleToFunction(const ExegesisTarget *ET,
|
||||
assembleToFunction(const ExegesisTarget &ET,
|
||||
llvm::ArrayRef<unsigned> RegsToDef,
|
||||
llvm::ArrayRef<llvm::MCInst> Instructions) {
|
||||
llvm::SmallString<256> Buffer;
|
||||
|
@ -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<SnippetPrototype>
|
||||
generatePrototype(unsigned Opcode) const override {
|
||||
return llvm::make_error<llvm::StringError>("not implemented",
|
||||
|
Loading…
x
Reference in New Issue
Block a user