diff options
| author | Clement Courbet <courbet@google.com> | 2018-04-04 08:22:54 +0000 |
|---|---|---|
| committer | Clement Courbet <courbet@google.com> | 2018-04-04 08:22:54 +0000 |
| commit | 7949b3b1dcbdbd815dd28122871761f742b08278 (patch) | |
| tree | 1adcd98e14a5ef1947a83f250bff3b6eac0af7c0 /llvm/tools | |
| parent | 7287b2c1ec669791df8b1c704e2457338f6bee47 (diff) | |
| download | bcm5719-llvm-7949b3b1dcbdbd815dd28122871761f742b08278.tar.gz bcm5719-llvm-7949b3b1dcbdbd815dd28122871761f742b08278.zip | |
Revert r329156 "Add llvm-exegesis tool."
Breaks a bunch of bots.
llvm-svn: 329157
Diffstat (limited to 'llvm/tools')
26 files changed, 0 insertions, 2308 deletions
diff --git a/llvm/tools/LLVMBuild.txt b/llvm/tools/LLVMBuild.txt index 5dea5b44048..8fe289c933b 100644 --- a/llvm/tools/LLVMBuild.txt +++ b/llvm/tools/LLVMBuild.txt @@ -32,7 +32,6 @@ subdirectories = llvm-dis llvm-dwarfdump llvm-dwp - llvm-exegesis llvm-extract llvm-jitlistener llvm-link diff --git a/llvm/tools/llvm-exegesis/CMakeLists.txt b/llvm/tools/llvm-exegesis/CMakeLists.txt deleted file mode 100644 index 996c784a2c7..00000000000 --- a/llvm/tools/llvm-exegesis/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(LLVM_LINK_COMPONENTS - AllTargetsAsmPrinters - AllTargetsDescs - AllTargetsInfos - X86 - ) - -add_llvm_tool(llvm-exegesis - llvm-exegesis.cpp - ) - -add_subdirectory(lib) -target_link_libraries(llvm-exegesis PRIVATE LLVMExegesis) - -if(HAVE_LIBPFM) - target_link_libraries(llvm-exegesis PRIVATE pfm) -endif() - diff --git a/llvm/tools/llvm-exegesis/LLVMBuild.txt b/llvm/tools/llvm-exegesis/LLVMBuild.txt deleted file mode 100644 index e5edc3bbb21..00000000000 --- a/llvm/tools/llvm-exegesis/LLVMBuild.txt +++ /dev/null @@ -1,22 +0,0 @@ -;===- ./tools/llvm-exegesis/LLVMBuild.txt ----------------------*- Conf -*--===; -; -; The LLVM Compiler Infrastructure -; -; This file is distributed under the University of Illinois Open Source -; License. See LICENSE.TXT for details. -; -;===------------------------------------------------------------------------===; -; -; This is an LLVMBuild description file for the components in this subdirectory. -; -; For more information on the LLVMBuild system, please see: -; -; http://llvm.org/docs/LLVMBuild.html -; -;===------------------------------------------------------------------------===; - -[component_0] -type = Tool -name = llvm-exegesis -parent = Tools -required_libraries = CodeGen ExecutionEngine MC MCJIT Object Support all-targets diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp deleted file mode 100644 index e9b8d29aaec..00000000000 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===-- BenchmarkResult.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "BenchmarkResult.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -// Defining YAML traits for IO. -namespace llvm { -namespace yaml { - -// std::vector<exegesis::Measure> will be rendered as a list. -template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> { - static const bool flow = false; -}; - -// exegesis::Measure is rendererd as a flow instead of a list. -// e.g. { "key": "the key", "value": 0123 } -template <> struct MappingTraits<exegesis::BenchmarkMeasure> { - static void mapping(IO &Io, exegesis::BenchmarkMeasure &Obj) { - Io.mapRequired("key", Obj.Key); - Io.mapRequired("value", Obj.Value); - Io.mapOptional("debug_string", Obj.DebugString); - } - static const bool flow = true; -}; - -template <> struct MappingTraits<exegesis::AsmTemplate> { - static void mapping(IO &Io, exegesis::AsmTemplate &Obj) { - Io.mapRequired("name", Obj.Name); - } -}; - -template <> struct MappingTraits<exegesis::InstructionBenchmark> { - static void mapping(IO &Io, exegesis::InstructionBenchmark &Obj) { - Io.mapRequired("asm_template", Obj.AsmTmpl); - Io.mapRequired("cpu_name", Obj.CpuName); - Io.mapRequired("llvm_triple", Obj.LLVMTriple); - Io.mapRequired("num_repetitions", Obj.NumRepetitions); - Io.mapRequired("measurements", Obj.Measurements); - Io.mapRequired("error", Obj.Error); - } -}; - -} // namespace yaml -} // namespace llvm - -namespace exegesis { - -InstructionBenchmark -InstructionBenchmark::readYamlOrDie(llvm::StringRef Filename) { - std::unique_ptr<llvm::MemoryBuffer> MemBuffer = llvm::cantFail( - llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))); - llvm::yaml::Input Yin(*MemBuffer); - InstructionBenchmark Benchmark; - Yin >> Benchmark; - return Benchmark; -} - -void InstructionBenchmark::writeYamlOrDie(const llvm::StringRef Filename) { - if (Filename == "-") { - llvm::yaml::Output Yout(llvm::outs()); - Yout << *this; - } else { - llvm::SmallString<1024> Buffer; - llvm::raw_svector_ostream Ostr(Buffer); - llvm::yaml::Output Yout(Ostr); - Yout << *this; - std::unique_ptr<llvm::FileOutputBuffer> File = - llvm::cantFail(llvm::FileOutputBuffer::create(Filename, Buffer.size())); - memcpy(File->getBufferStart(), Buffer.data(), Buffer.size()); - llvm::cantFail(File->commit()); - } -} - -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h deleted file mode 100644 index 6c238fd1484..00000000000 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h +++ /dev/null @@ -1,53 +0,0 @@ -//===-- BenchmarkResult.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines classes to represent measurements and serialize/deserialize them to -// Yaml. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H -#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/YAMLTraits.h" -#include <string> -#include <vector> - -namespace exegesis { - -struct AsmTemplate { - std::string Name; -}; - -struct BenchmarkMeasure { - std::string Key; - double Value; - std::string DebugString; -}; - -// The result of an instruction benchmark. -struct InstructionBenchmark { - AsmTemplate AsmTmpl; - std::string CpuName; - std::string LLVMTriple; - size_t NumRepetitions = 0; - std::vector<BenchmarkMeasure> Measurements; - std::string Error; - - static InstructionBenchmark readYamlOrDie(llvm::StringRef Filename); - - // Unfortunately this function is non const because of YAML traits. - void writeYamlOrDie(const llvm::StringRef Filename); -}; - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp deleted file mode 100644 index bdce72c1c11..00000000000 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//===-- BenchmarkRunner.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "BenchmarkRunner.h" -#include "InMemoryAssembler.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include <string> - -namespace exegesis { - -BenchmarkRunner::InstructionFilter::~InstructionFilter() = default; - -BenchmarkRunner::~BenchmarkRunner() = default; - -InstructionBenchmark -BenchmarkRunner::run(const LLVMState &State, const unsigned Opcode, - unsigned NumRepetitions, - const InstructionFilter &Filter) const { - InstructionBenchmark InstrBenchmark; - - InstrBenchmark.AsmTmpl.Name = - llvm::Twine(getDisplayName()) - .concat(" ") - .concat(State.getInstrInfo().getName(Opcode)) - .str(); - InstrBenchmark.CpuName = State.getCpuName(); - InstrBenchmark.LLVMTriple = State.getTriple(); - InstrBenchmark.NumRepetitions = NumRepetitions; - - // Ignore instructions that we cannot run. - if (State.getInstrInfo().get(Opcode).isPseudo()) { - InstrBenchmark.Error = "Unsupported opcode: isPseudo"; - return InstrBenchmark; - } - if (llvm::Error E = Filter.shouldRun(State, Opcode)) { - InstrBenchmark.Error = llvm::toString(std::move(E)); - return InstrBenchmark; - } - - JitFunctionContext Context(State.createTargetMachine()); - auto ExpectedInstructions = - createCode(State, Opcode, NumRepetitions, Context); - if (llvm::Error E = ExpectedInstructions.takeError()) { - InstrBenchmark.Error = llvm::toString(std::move(E)); - return InstrBenchmark; - } - - const std::vector<llvm::MCInst> Instructions = *ExpectedInstructions; - const JitFunction Function(std::move(Context), Instructions); - const llvm::StringRef CodeBytes = Function.getFunctionBytes(); - - std::string AsmExcerpt; - constexpr const int ExcerptSize = 100; - constexpr const int ExcerptTailSize = 10; - if (CodeBytes.size() <= ExcerptSize) { - AsmExcerpt = llvm::toHex(CodeBytes); - } else { - AsmExcerpt = - llvm::toHex(CodeBytes.take_front(ExcerptSize - ExcerptTailSize + 3)); - AsmExcerpt += "..."; - AsmExcerpt += llvm::toHex(CodeBytes.take_back(ExcerptTailSize)); - } - llvm::outs() << "# Asm excerpt: " << AsmExcerpt << "\n"; - llvm::outs().flush(); // In case we crash. - - InstrBenchmark.Measurements = - runMeasurements(State, Function, NumRepetitions); - return InstrBenchmark; -} - -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h deleted file mode 100644 index 715ad5884c1..00000000000 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h +++ /dev/null @@ -1,64 +0,0 @@ -//===-- BenchmarkRunner.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the abstract BenchmarkRunner class for measuring a certain execution -/// property of instructions (e.g. latency). -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H -#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H - -#include "BenchmarkResult.h" -#include "InMemoryAssembler.h" -#include "LlvmState.h" -#include "llvm/MC/MCInst.h" -#include "llvm/Support/Error.h" -#include <vector> - -namespace exegesis { - -// Common code for all benchmark modes. -class BenchmarkRunner { -public: - // 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(); - } - }; - - virtual ~BenchmarkRunner(); - - InstructionBenchmark run(const LLVMState &State, unsigned Opcode, - unsigned NumRepetitions, - const InstructionFilter &Filter) const; - -private: - virtual const char *getDisplayName() const = 0; - - virtual llvm::Expected<std::vector<llvm::MCInst>> - createCode(const LLVMState &State, unsigned OpcodeIndex, - unsigned NumRepetitions, - const JitFunctionContext &Context) const = 0; - - virtual std::vector<BenchmarkMeasure> - runMeasurements(const LLVMState &State, const JitFunction &Function, - unsigned NumRepetitions) const = 0; -}; - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H diff --git a/llvm/tools/llvm-exegesis/lib/CMakeLists.txt b/llvm/tools/llvm-exegesis/lib/CMakeLists.txt deleted file mode 100644 index 17627fbe972..00000000000 --- a/llvm/tools/llvm-exegesis/lib/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -add_library(LLVMExegesis - STATIC - BenchmarkResult.cpp - BenchmarkRunner.cpp - InMemoryAssembler.cpp - InstructionSnippetGenerator.cpp - Latency.cpp - LlvmState.cpp - OperandGraph.cpp - PerfHelper.cpp - Uops.cpp - X86.cpp - ) - -llvm_update_compile_flags(LLVMExegesis) -llvm_map_components_to_libnames(libs - CodeGen - ExecutionEngine - MC - MCJIT - Support - ) - -target_link_libraries(LLVMExegesis ${libs}) -set_target_properties(LLVMExegesis PROPERTIES FOLDER "Libraries") diff --git a/llvm/tools/llvm-exegesis/lib/InMemoryAssembler.cpp b/llvm/tools/llvm-exegesis/lib/InMemoryAssembler.cpp deleted file mode 100644 index 3a60d03ccff..00000000000 --- a/llvm/tools/llvm-exegesis/lib/InMemoryAssembler.cpp +++ /dev/null @@ -1,226 +0,0 @@ -//===-- InMemoryAssembler.cpp -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InMemoryAssembler.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/TargetInstrInfo.h" -#include "llvm/CodeGen/TargetPassConfig.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/MC/MCFixup.h" -#include "llvm/MC/MCInstrDesc.h" -#include "llvm/Object/Binary.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/PassInfo.h" -#include "llvm/PassRegistry.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" - -namespace exegesis { - -static constexpr const char ModuleID[] = "ExegesisInfoTest"; -static constexpr const char FunctionID[] = "foo"; - -// Small utility function to add named passes. -static bool addPass(llvm::PassManagerBase &PM, llvm::StringRef PassName, - llvm::TargetPassConfig &TPC) { - const llvm::PassRegistry *PR = llvm::PassRegistry::getPassRegistry(); - const llvm::PassInfo *PI = PR->getPassInfo(PassName); - if (!PI) { - llvm::errs() << " run-pass " << PassName << " is not registered.\n"; - return true; - } - - if (!PI->getNormalCtor()) { - llvm::errs() << " cannot create pass: " << PI->getPassName() << "\n"; - return true; - } - llvm::Pass *P = PI->getNormalCtor()(); - std::string Banner = std::string("After ") + std::string(P->getPassName()); - PM.add(P); - TPC.printAndVerify(Banner); - - return false; -} - -// Creates a void MachineFunction with no argument. -static llvm::MachineFunction & -createVoidVoidMachineFunction(llvm::StringRef FunctionID, llvm::Module *Module, - llvm::MachineModuleInfo *MMI) { - llvm::Type *const ReturnType = llvm::Type::getInt32Ty(Module->getContext()); - llvm::FunctionType *FunctionType = llvm::FunctionType::get(ReturnType, false); - llvm::Function *const F = llvm::Function::Create( - FunctionType, llvm::GlobalValue::InternalLinkage, FunctionID, Module); - // Making sure we can create a MachineFunction out of this Function even if it - // contains no IR. - F->setIsMaterializable(true); - return MMI->getOrCreateMachineFunction(*F); -} - -static llvm::object::OwningBinary<llvm::object::ObjectFile> -assemble(llvm::Module *Module, std::unique_ptr<llvm::MachineModuleInfo> MMI, - llvm::LLVMTargetMachine *LLVMTM) { - llvm::legacy::PassManager PM; - llvm::MCContext &Context = MMI->getContext(); - - llvm::TargetLibraryInfoImpl TLII(llvm::Triple(Module->getTargetTriple())); - PM.add(new llvm::TargetLibraryInfoWrapperPass(TLII)); - - llvm::TargetPassConfig *TPC = LLVMTM->createPassConfig(PM); - PM.add(TPC); - PM.add(MMI.release()); - TPC->printAndVerify("MachineFunctionGenerator::assemble"); - // Adding the following passes: - // - machineverifier: checks that the MachineFunction is well formed. - // - prologepilog: saves and restore callee saved registers. - for (const char *PassName : {"machineverifier", "prologepilog"}) - if (addPass(PM, PassName, *TPC)) - llvm::report_fatal_error("Unable to add a mandatory pass"); - TPC->setInitialized(); - - llvm::SmallVector<char, 4096> AsmBuffer; - llvm::raw_svector_ostream AsmStream(AsmBuffer); - // AsmPrinter is responsible for generating the assembly into AsmBuffer. - if (LLVMTM->addAsmPrinter(PM, AsmStream, llvm::TargetMachine::CGFT_ObjectFile, - Context)) - llvm::report_fatal_error("Cannot add AsmPrinter passes"); - - PM.run(*Module); // Run all the passes - - // Storing the generated assembly into a MemoryBuffer that owns the memory. - std::unique_ptr<llvm::MemoryBuffer> Buffer = - llvm::MemoryBuffer::getMemBufferCopy(AsmStream.str()); - // Create the ObjectFile from the MemoryBuffer. - std::unique_ptr<llvm::object::ObjectFile> Obj = llvm::cantFail( - llvm::object::ObjectFile::createObjectFile(Buffer->getMemBufferRef())); - // Returning both the MemoryBuffer and the ObjectFile. - return llvm::object::OwningBinary<llvm::object::ObjectFile>( - std::move(Obj), std::move(Buffer)); -} - -static void fillMachineFunction(llvm::MachineFunction &MF, - llvm::ArrayRef<llvm::MCInst> Instructions) { - llvm::MachineBasicBlock *MBB = MF.CreateMachineBasicBlock(); - MF.push_back(MBB); - const llvm::MCInstrInfo *MCII = MF.getTarget().getMCInstrInfo(); - const llvm::DebugLoc DL; - for (const llvm::MCInst &Inst : Instructions) { - const unsigned Opcode = Inst.getOpcode(); - const llvm::MCInstrDesc &MCID = MCII->get(Opcode); - llvm::MachineInstrBuilder Builder = llvm::BuildMI(MBB, DL, MCID); - for (unsigned OpIndex = 0, E = Inst.getNumOperands(); OpIndex < E; - ++OpIndex) { - const llvm::MCOperand &Op = Inst.getOperand(OpIndex); - if (Op.isReg()) { - const bool IsDef = OpIndex < MCID.getNumDefs(); - unsigned Flags = 0; - const llvm::MCOperandInfo &OpInfo = MCID.operands().begin()[OpIndex]; - if (IsDef && !OpInfo.isOptionalDef()) - Flags |= llvm::RegState::Define; - Builder.addReg(Op.getReg(), Flags); - } else if (Op.isImm()) { - Builder.addImm(Op.getImm()); - } else { - llvm_unreachable("Not yet implemented"); - } - } - } - // Adding the Return Opcode. - const llvm::TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); - llvm::BuildMI(MBB, DL, TII->get(TII->getReturnOpcode())); -} - -namespace { - -// Implementation of this class relies on the fact that a single object with a -// single function will be loaded into memory. -class TrackingSectionMemoryManager : public llvm::SectionMemoryManager { -public: - explicit TrackingSectionMemoryManager(uintptr_t *CodeSize) - : CodeSize(CodeSize) {} - - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, - llvm::StringRef SectionName) override { - *CodeSize = Size; - return llvm::SectionMemoryManager::allocateCodeSection( - Size, Alignment, SectionID, SectionName); - } - -private: - uintptr_t *const CodeSize = nullptr; -}; - -} // namespace - -JitFunctionContext::JitFunctionContext( - std::unique_ptr<llvm::LLVMTargetMachine> TheTM) - : Context(llvm::make_unique<llvm::LLVMContext>()), TM(std::move(TheTM)), - MMI(llvm::make_unique<llvm::MachineModuleInfo>(TM.get())), - Module(llvm::make_unique<llvm::Module>(ModuleID, *Context)) { - Module->setDataLayout(TM->createDataLayout()); - MF = &createVoidVoidMachineFunction(FunctionID, Module.get(), MMI.get()); - // We need to instruct the passes that we're done with SSA and virtual - // registers. - auto &Properties = MF->getProperties(); - Properties.set(llvm::MachineFunctionProperties::Property::NoVRegs); - Properties.reset(llvm::MachineFunctionProperties::Property::IsSSA); - Properties.reset(llvm::MachineFunctionProperties::Property::TracksLiveness); - // prologue/epilogue pass needs the reserved registers to be frozen, this is - // usually done by the SelectionDAGISel pass. - MF->getRegInfo().freezeReservedRegs(*MF); - // Saving reserved registers for client. - ReservedRegs = MF->getSubtarget().getRegisterInfo()->getReservedRegs(*MF); -} - -JitFunction::JitFunction(JitFunctionContext &&Context, - llvm::ArrayRef<llvm::MCInst> Instructions) - : FunctionContext(std::move(Context)) { - fillMachineFunction(*FunctionContext.MF, Instructions); - // We create the pass manager, run the passes and returns the produced - // ObjectFile. - llvm::object::OwningBinary<llvm::object::ObjectFile> ObjHolder = - assemble(FunctionContext.Module.get(), std::move(FunctionContext.MMI), - FunctionContext.TM.get()); - assert(ObjHolder.getBinary() && "cannot create object file"); - // Initializing the execution engine. - // We need to use the JIT EngineKind to be able to add an object file. - LLVMLinkInMCJIT(); - uintptr_t CodeSize = 0; - std::string Error; - ExecEngine.reset( - llvm::EngineBuilder(std::move(FunctionContext.Module)) - .setErrorStr(&Error) - .setMCPU(FunctionContext.TM->getTargetCPU()) - .setEngineKind(llvm::EngineKind::JIT) - .setMCJITMemoryManager( - llvm::make_unique<TrackingSectionMemoryManager>(&CodeSize)) - .create(FunctionContext.TM.release())); - if (!ExecEngine) - llvm::report_fatal_error(Error); - // Adding the generated object file containing the assembled function. - // The ExecutionEngine makes sure the object file is copied into an - // executable page. - ExecEngine->addObjectFile(ObjHolder.takeBinary().first); - // Setting function - FunctionBytes = - llvm::StringRef(reinterpret_cast<const char *>( - ExecEngine->getFunctionAddress(FunctionID)), - CodeSize); -} - -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/InMemoryAssembler.h b/llvm/tools/llvm-exegesis/lib/InMemoryAssembler.h deleted file mode 100644 index 751ea60ff26..00000000000 --- a/llvm/tools/llvm-exegesis/lib/InMemoryAssembler.h +++ /dev/null @@ -1,78 +0,0 @@ -//===-- InMemoryAssembler.h -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines classes to assemble functions composed of a single basic block of -/// MCInsts. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_INMEMORYASSEMBLER_H -#define LLVM_TOOLS_LLVM_EXEGESIS_INMEMORYASSEMBLER_H - -#include "llvm/ADT/BitVector.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/TargetRegisterInfo.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/MC/MCInst.h" -#include <memory> -#include <vector> - -namespace exegesis { - -// Consumable context for JitFunction below. -// This temporary object allows for retrieving MachineFunction properties before -// assembling it. -class JitFunctionContext { -public: - explicit JitFunctionContext(std::unique_ptr<llvm::LLVMTargetMachine> TM); - // Movable - JitFunctionContext(JitFunctionContext &&) = default; - JitFunctionContext &operator=(JitFunctionContext &&) = default; - // Non copyable - JitFunctionContext(const JitFunctionContext &) = delete; - JitFunctionContext &operator=(const JitFunctionContext &) = delete; - - const llvm::BitVector &getReservedRegs() const { return ReservedRegs; } - -private: - friend class JitFunction; - - std::unique_ptr<llvm::LLVMContext> Context; - std::unique_ptr<llvm::LLVMTargetMachine> TM; - std::unique_ptr<llvm::MachineModuleInfo> MMI; - std::unique_ptr<llvm::Module> Module; - llvm::MachineFunction *MF = nullptr; - llvm::BitVector ReservedRegs; -}; - -// Creates a void() function from a sequence of llvm::MCInst. -class JitFunction { -public: - // Assembles Instructions into an executable function. - JitFunction(JitFunctionContext &&Context, - llvm::ArrayRef<llvm::MCInst> Instructions); - - // Retrieves the function as an array of bytes. - llvm::StringRef getFunctionBytes() const { return FunctionBytes; } - - // Retrieves the callable function. - void operator()() const { ((void (*)())FunctionBytes.data())(); } - -private: - JitFunctionContext FunctionContext; - std::unique_ptr<llvm::ExecutionEngine> ExecEngine; - llvm::StringRef FunctionBytes; -}; - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_INMEMORYASSEMBLER_H diff --git a/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp deleted file mode 100644 index 2ab3379faed..00000000000 --- a/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp +++ /dev/null @@ -1,355 +0,0 @@ -//===-- InstructionSnippetGenerator.cpp -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InstructionSnippetGenerator.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/MC/MCInstBuilder.h" -#include <algorithm> -#include <unordered_map> -#include <unordered_set> - -namespace exegesis { - -void Variable::print(llvm::raw_ostream &OS, - const llvm::MCRegisterInfo *RegInfo) const { - OS << "IsUse=" << IsUse << " IsDef=" << IsDef << " possible regs: {"; - for (const size_t Reg : PossibleRegisters) { - if (RegInfo) - OS << RegInfo->getName(Reg); - else - OS << Reg; - OS << ","; - } - OS << "} "; - if (ExplicitOperands.empty()) { - OS << "implicit"; - } else { - OS << "explicit ops: {"; - for (const size_t Op : ExplicitOperands) - OS << Op << ","; - OS << "}"; - } - OS << "\n"; -} - -// Update the state of a Variable with an explicit operand. -static void updateExplicitOperandVariable(const llvm::MCRegisterInfo &RegInfo, - const llvm::MCInstrDesc &InstrInfo, - const size_t OpIndex, - const llvm::BitVector &ReservedRegs, - Variable &Var) { - const bool IsDef = OpIndex < InstrInfo.getNumDefs(); - if (IsDef) - Var.IsDef = true; - if (!IsDef) - Var.IsUse = true; - Var.ExplicitOperands.push_back(OpIndex); - const llvm::MCOperandInfo &OpInfo = InstrInfo.opInfo_begin()[OpIndex]; - if (OpInfo.RegClass >= 0) { - Var.IsReg = true; - for (const llvm::MCPhysReg &Reg : RegInfo.getRegClass(OpInfo.RegClass)) { - if (!ReservedRegs[Reg]) - Var.PossibleRegisters.insert(Reg); - } - } -} - -static Variable &findVariableWithOperand(llvm::SmallVector<Variable, 8> &Vars, - size_t OpIndex) { - // Vars.size() is small (<10) so a linear scan is good enough. - for (Variable &Var : Vars) { - if (llvm::is_contained(Var.ExplicitOperands, OpIndex)) - return Var; - } - assert(false && "Illegal state"); - static Variable *const EmptyVariable = new Variable(); - return *EmptyVariable; -} - -llvm::SmallVector<Variable, 8> -getVariables(const llvm::MCRegisterInfo &RegInfo, - const llvm::MCInstrDesc &InstrInfo, - const llvm::BitVector &ReservedRegs) { - llvm::SmallVector<Variable, 8> Vars; - // For each operand, its "tied to" operand or -1. - llvm::SmallVector<int, 10> TiedToMap; - for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) { - TiedToMap.push_back(InstrInfo.getOperandConstraint(I, llvm::MCOI::TIED_TO)); - } - // Adding non tied operands. - for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) { - if (TiedToMap[I] >= 0) - continue; // dropping tied ones. - Vars.emplace_back(); - updateExplicitOperandVariable(RegInfo, InstrInfo, I, ReservedRegs, - Vars.back()); - } - // Adding tied operands to existing variables. - for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) { - if (TiedToMap[I] < 0) - continue; // dropping non-tied ones. - updateExplicitOperandVariable(RegInfo, InstrInfo, I, ReservedRegs, - findVariableWithOperand(Vars, TiedToMap[I])); - } - // Adding implicit defs. - for (size_t I = 0, E = InstrInfo.getNumImplicitDefs(); I < E; ++I) { - Vars.emplace_back(); - Variable &Var = Vars.back(); - const llvm::MCPhysReg Reg = InstrInfo.getImplicitDefs()[I]; - assert(!ReservedRegs[Reg] && "implicit def of reserved register"); - Var.PossibleRegisters.insert(Reg); - Var.IsDef = true; - Var.IsReg = true; - } - // Adding implicit uses. - for (size_t I = 0, E = InstrInfo.getNumImplicitUses(); I < E; ++I) { - Vars.emplace_back(); - Variable &Var = Vars.back(); - const llvm::MCPhysReg Reg = InstrInfo.getImplicitUses()[I]; - assert(!ReservedRegs[Reg] && "implicit use of reserved register"); - Var.PossibleRegisters.insert(Reg); - Var.IsUse = true; - Var.IsReg = true; - } - - return Vars; -} - -VariableAssignment::VariableAssignment(size_t VarIdx, - llvm::MCPhysReg AssignedReg) - : VarIdx(VarIdx), AssignedReg(AssignedReg) {} - -bool VariableAssignment::operator==(const VariableAssignment &Other) const { - return std::tie(VarIdx, AssignedReg) == - std::tie(Other.VarIdx, Other.AssignedReg); -} - -bool VariableAssignment::operator<(const VariableAssignment &Other) const { - return std::tie(VarIdx, AssignedReg) < - std::tie(Other.VarIdx, Other.AssignedReg); -} - -void dumpAssignmentChain(const llvm::MCRegisterInfo &RegInfo, - const AssignmentChain &Chain) { - for (const VariableAssignment &Assignment : Chain) { - llvm::outs() << llvm::format("(%d %s) ", Assignment.VarIdx, - RegInfo.getName(Assignment.AssignedReg)); - } - llvm::outs() << "\n"; -} - -std::vector<AssignmentChain> -computeSequentialAssignmentChains(const llvm::MCRegisterInfo &RegInfo, - llvm::ArrayRef<Variable> Vars) { - using graph::Node; - graph::Graph Graph; - - // Add register aliasing to the graph. - setupRegisterAliasing(RegInfo, Graph); - - // Adding variables to the graph. - for (size_t I = 0, E = Vars.size(); I < E; ++I) { - const Variable &Var = Vars[I]; - const Node N = Node::Var(I); - if (Var.IsDef) { - Graph.connect(Node::In(), N); - for (const size_t Reg : Var.PossibleRegisters) - Graph.connect(N, Node::Reg(Reg)); - } - if (Var.IsUse) { - Graph.connect(N, Node::Out()); - for (const size_t Reg : Var.PossibleRegisters) - Graph.connect(Node::Reg(Reg), N); - } - } - - // Find all possible dependency chains (aka all possible paths from In to Out - // node). - std::vector<AssignmentChain> AllChains; - for (;;) { - const auto Path = Graph.getPathFrom(Node::In(), Node::Out()); - if (Path.empty()) - break; - switch (Path.size()) { - case 0: - case 1: - case 2: - case 4: - assert(false && "Illegal state"); - break; - case 3: { // IN -> variable -> OUT - const size_t VarIdx = Path[1].varValue(); - for (size_t Reg : Vars[VarIdx].PossibleRegisters) { - AllChains.emplace_back(); - AllChains.back().emplace(VarIdx, Reg); - } - Graph.disconnect(Path[0], Path[1]); // IN -> variable - Graph.disconnect(Path[1], Path[2]); // variable -> OUT - break; - } - default: { // IN -> var1 -> Reg[...] -> var2 -> OUT - const size_t Last = Path.size() - 1; - const size_t Var1 = Path[1].varValue(); - const llvm::MCPhysReg Reg1 = Path[2].regValue(); - const llvm::MCPhysReg Reg2 = Path[Last - 2].regValue(); - const size_t Var2 = Path[Last - 1].varValue(); - AllChains.emplace_back(); - AllChains.back().emplace(Var1, Reg1); - AllChains.back().emplace(Var2, Reg2); - Graph.disconnect(Path[1], Path[2]); // Var1 -> Reg[0] - break; - } - } - } - - return AllChains; -} - -std::vector<llvm::MCPhysReg> -getRandomAssignment(llvm::ArrayRef<Variable> Vars, - llvm::ArrayRef<AssignmentChain> Chains, - const std::function<size_t(size_t)> &RandomIndexForSize) { - // Registers are initialized with 0 (aka NoRegister). - std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0); - if (Chains.empty()) - return Registers; - // Pick one of the chains and set Registers that are fully constrained (have - // no degrees of freedom). - const size_t ChainIndex = RandomIndexForSize(Chains.size()); - for (const VariableAssignment Assignment : Chains[ChainIndex]) - Registers[Assignment.VarIdx] = Assignment.AssignedReg; - // Registers with remaining degrees of freedom are assigned randomly. - for (size_t I = 0, E = Vars.size(); I < E; ++I) { - llvm::MCPhysReg &Reg = Registers[I]; - const Variable &Var = Vars[I]; - const auto &PossibleRegisters = Var.PossibleRegisters; - if (Reg > 0 || PossibleRegisters.empty()) - continue; - Reg = PossibleRegisters[RandomIndexForSize(PossibleRegisters.size())]; - } - return Registers; -} - -// Finds a matching register `reg` for variable `VarIdx` and sets -// `RegAssignments[r]` to `VarIdx`. Returns false if no matching can be found. -// `seen.count(r)` is 1 if register `reg` has been processed. -static bool findMatchingRegister( - llvm::ArrayRef<Variable> Vars, const size_t VarIdx, - std::unordered_set<llvm::MCPhysReg> &Seen, - std::unordered_map<llvm::MCPhysReg, size_t> &RegAssignments) { - for (const llvm::MCPhysReg Reg : Vars[VarIdx].PossibleRegisters) { - if (!Seen.count(Reg)) { - Seen.insert(Reg); // Mark `Reg` as seen. - // If `Reg` is not assigned to a variable, or if `Reg` was assigned to a - // variable which has an alternate possible register, assign `Reg` to - // variable `VarIdx`. Since `Reg` is marked as assigned in the above line, - // `RegAssignments[r]` in the following recursive call will not get - // assigned `Reg` again. - const auto AssignedVarIt = RegAssignments.find(Reg); - if (AssignedVarIt == RegAssignments.end() || - findMatchingRegister(Vars, AssignedVarIt->second, Seen, - RegAssignments)) { - RegAssignments[Reg] = VarIdx; - return true; - } - } - } - return false; -} - -// This is actually a maximum bipartite matching problem: -// https://en.wikipedia.org/wiki/Matching_(graph_theory)#Bipartite_matching -// The graph has variables on the left and registers on the right, with an edge -// between variable `I` and register `Reg` iff -// `Vars[I].PossibleRegisters.count(A)`. -// Note that a greedy approach won't work for cases like: -// Vars[0] PossibleRegisters={C,B} -// Vars[1] PossibleRegisters={A,B} -// Vars[2] PossibleRegisters={A,C} -// There is a feasible solution {0->B, 1->A, 2->C}, but the greedy solution is -// {0->C, 1->A, oops}. -std::vector<llvm::MCPhysReg> -getExclusiveAssignment(llvm::ArrayRef<Variable> Vars) { - // `RegAssignments[r]` is the variable id that was assigned register `Reg`. - std::unordered_map<llvm::MCPhysReg, size_t> RegAssignments; - - for (size_t VarIdx = 0, E = Vars.size(); VarIdx < E; ++VarIdx) { - if (!Vars[VarIdx].IsReg) - continue; - std::unordered_set<llvm::MCPhysReg> Seen; - if (!findMatchingRegister(Vars, VarIdx, Seen, RegAssignments)) - return {}; // Infeasible. - } - - std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0); - for (const auto &RegVarIdx : RegAssignments) - Registers[RegVarIdx.second] = RegVarIdx.first; - return Registers; -} - -std::vector<llvm::MCPhysReg> -getGreedyAssignment(llvm::ArrayRef<Variable> Vars) { - std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0); - llvm::SmallSet<llvm::MCPhysReg, 8> Assigned; - for (size_t VarIdx = 0, E = Vars.size(); VarIdx < E; ++VarIdx) { - const auto &Var = Vars[VarIdx]; - if (!Var.IsReg) - continue; - if (Var.PossibleRegisters.empty()) - return {}; - // Try possible registers until an unassigned one is found. - for (const auto Reg : Var.PossibleRegisters) { - if (Assigned.insert(Reg).second) { - Registers[VarIdx] = Reg; - break; - } - } - // Fallback to first possible register. - if (Registers[VarIdx] == 0) - Registers[VarIdx] = Var.PossibleRegisters[0]; - } - return Registers; -} - -llvm::MCInst generateMCInst(const llvm::MCInstrDesc &InstrInfo, - llvm::ArrayRef<Variable> Vars, - llvm::ArrayRef<llvm::MCPhysReg> VarRegs) { - const size_t NumOperands = InstrInfo.getNumOperands(); - llvm::SmallVector<llvm::MCPhysReg, 16> OperandToRegister(NumOperands, 0); - - // We browse the variable and for each explicit operands we set the selected - // register in the OperandToRegister array. - for (size_t I = 0, E = Vars.size(); I < E; ++I) { - for (const size_t OpIndex : Vars[I].ExplicitOperands) { - OperandToRegister[OpIndex] = VarRegs[I]; - } - } - - // Building the instruction. - llvm::MCInstBuilder Builder(InstrInfo.getOpcode()); - for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) { - const llvm::MCOperandInfo &OpInfo = InstrInfo.opInfo_begin()[I]; - switch (OpInfo.OperandType) { - case llvm::MCOI::OperandType::OPERAND_REGISTER: - Builder.addReg(OperandToRegister[I]); - break; - case llvm::MCOI::OperandType::OPERAND_IMMEDIATE: - Builder.addImm(1); - break; - default: - Builder.addOperand(llvm::MCOperand()); - } - } - - return Builder; -} - -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h b/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h deleted file mode 100644 index be21f8725ad..00000000000 --- a/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h +++ /dev/null @@ -1,119 +0,0 @@ -//===-- InstructionSnippetGenerator.h ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines helper classes to generate code snippets, in particular register -/// assignment. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_INSTRUCTIONSNIPPETGENERATOR_H -#define LLVM_TOOLS_LLVM_EXEGESIS_INSTRUCTIONSNIPPETGENERATOR_H - -#include "OperandGraph.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstrDesc.h" -#include "llvm/MC/MCRegisterInfo.h" -#include <vector> - -namespace exegesis { - -// A Variable represents a set of possible values that we need to choose from. -// It may represent one or more explicit operands that are tied together, or one -// implicit operand. -class Variable final { -public: - bool IsUse = false; - bool IsDef = false; - bool IsReg = false; - - // Lists all the explicit operand indices that are tied to this variable. - // Empty if Variable represents an implicit operand. - llvm::SmallVector<size_t, 8> ExplicitOperands; - - // - In case of explicit operands, PossibleRegisters is the expansion of the - // operands's RegClass registers. Please note that tied together explicit - // operands share the same RegClass. - // - In case of implicit operands, PossibleRegisters is a singleton MCPhysReg. - llvm::SmallSetVector<llvm::MCPhysReg, 16> PossibleRegisters; - - // If RegInfo is null, register names won't get resolved. - void print(llvm::raw_ostream &OS, const llvm::MCRegisterInfo *RegInfo) const; -}; - -// Builds a model of implicit and explicit operands for InstrDesc into -// Variables. -llvm::SmallVector<Variable, 8> -getVariables(const llvm::MCRegisterInfo &RegInfo, - const llvm::MCInstrDesc &InstrDesc, - const llvm::BitVector &ReservedRegs); - -// A simple object to represent a Variable assignement. -struct VariableAssignment { - VariableAssignment(size_t VarIdx, llvm::MCPhysReg AssignedReg); - - size_t VarIdx; - llvm::MCPhysReg AssignedReg; - - bool operator==(const VariableAssignment &) const; - bool operator<(const VariableAssignment &) const; -}; - -// An AssignmentChain is a set of assignement realizing a dependency chain. -// We inherit from std::set to leverage uniqueness of elements. -using AssignmentChain = std::set<VariableAssignment>; - -// Debug function to print an assignment chain. -void dumpAssignmentChain(const llvm::MCRegisterInfo &RegInfo, - const AssignmentChain &Chain); - -// Inserts Variables into a graph representing register aliasing and finds all -// the possible dependency chains for this instruction, i.e. all the possible -// assignement of operands that would make execution of the instruction -// sequential. -std::vector<AssignmentChain> -computeSequentialAssignmentChains(const llvm::MCRegisterInfo &RegInfo, - llvm::ArrayRef<Variable> Vars); - -// Selects a random configuration leading to a dependency chain. -// The result is a vector of the same size as `Vars`. -// `random_index_for_size` is a functor giving a random value in [0, arg[. -std::vector<llvm::MCPhysReg> -getRandomAssignment(llvm::ArrayRef<Variable> Vars, - llvm::ArrayRef<AssignmentChain> Chains, - const std::function<size_t(size_t)> &RandomIndexForSize); - -// Finds an assignment of registers to variables such that no two variables are -// assigned the same register. -// The result is a vector of the same size as `Vars`, or `{}` if the -// assignment is not feasible. -std::vector<llvm::MCPhysReg> -getExclusiveAssignment(llvm::ArrayRef<Variable> Vars); - -// Finds a greedy assignment of registers to variables. Each variable gets -// assigned the first possible register that is not already assigned to a -// previous variable. If there is no such register, the variable gets assigned -// the first possible register. -// The result is a vector of the same size as `Vars`, or `{}` if the -// assignment is not feasible. -std::vector<llvm::MCPhysReg> -getGreedyAssignment(llvm::ArrayRef<Variable> Vars); - -// Generates an LLVM MCInst with the previously computed variables. -// Immediate values are set to 1. -llvm::MCInst generateMCInst(const llvm::MCInstrDesc &InstrDesc, - llvm::ArrayRef<Variable> Vars, - llvm::ArrayRef<llvm::MCPhysReg> VarRegs); - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_INSTRUCTIONSNIPPETGENERATOR_H diff --git a/llvm/tools/llvm-exegesis/lib/LLVMBuild.txt b/llvm/tools/llvm-exegesis/lib/LLVMBuild.txt deleted file mode 100644 index 0e4c6d12db2..00000000000 --- a/llvm/tools/llvm-exegesis/lib/LLVMBuild.txt +++ /dev/null @@ -1,22 +0,0 @@ -;===- ./tools/llvm-exegesis/lib/LLVMBuild.txt ------------------*- Conf -*--===; -; -; The LLVM Compiler Infrastructure -; -; This file is distributed under the University of Illinois Open Source -; License. See LICENSE.TXT for details. -; -;===------------------------------------------------------------------------===; -; -; This is an LLVMBuild description file for the components in this subdirectory. -; -; For more information on the LLVMBuild system, please see: -; -; http://llvm.org/docs/LLVMBuild.html -; -;===------------------------------------------------------------------------===; - -[component_0] -type = Library -name = Exegesis -parent = Libraries -required_libraries = CodeGen ExecutionEngine MC MCJIT Object Support diff --git a/llvm/tools/llvm-exegesis/lib/Latency.cpp b/llvm/tools/llvm-exegesis/lib/Latency.cpp deleted file mode 100644 index b28b81cc940..00000000000 --- a/llvm/tools/llvm-exegesis/lib/Latency.cpp +++ /dev/null @@ -1,95 +0,0 @@ -//===-- Latency.cpp ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Latency.h" -#include "BenchmarkResult.h" -#include "InstructionSnippetGenerator.h" -#include "PerfHelper.h" -#include "llvm/MC/MCInstrDesc.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <random> - -namespace exegesis { - -// FIXME: Handle memory, see PR36905. -static bool isInvalidOperand(const llvm::MCOperandInfo &OpInfo) { - switch (OpInfo.OperandType) { - default: - return true; - case llvm::MCOI::OPERAND_IMMEDIATE: - case llvm::MCOI::OPERAND_REGISTER: - return false; - } -} - -static llvm::Error makeError(llvm::Twine Msg) { - return llvm::make_error<llvm::StringError>(Msg, - llvm::inconvertibleErrorCode()); -} - -LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default; - -const char *LatencyBenchmarkRunner::getDisplayName() const { return "latency"; } - -llvm::Expected<std::vector<llvm::MCInst>> LatencyBenchmarkRunner::createCode( - const LLVMState &State, const unsigned OpcodeIndex, - const unsigned NumRepetitions, const JitFunctionContext &Context) const { - std::default_random_engine RandomEngine; - const auto GetRandomIndex = [&RandomEngine](size_t Size) { - assert(Size > 0 && "trying to get select a random element of an empty set"); - return std::uniform_int_distribution<>(0, Size - 1)(RandomEngine); - }; - - const auto &InstrInfo = State.getInstrInfo(); - const auto &RegInfo = State.getRegInfo(); - const llvm::MCInstrDesc &InstrDesc = InstrInfo.get(OpcodeIndex); - for (const llvm::MCOperandInfo &OpInfo : InstrDesc.operands()) { - if (isInvalidOperand(OpInfo)) - return makeError("Only registers and immediates are supported"); - } - - const auto Vars = getVariables(RegInfo, InstrDesc, Context.getReservedRegs()); - const std::vector<AssignmentChain> AssignmentChains = - computeSequentialAssignmentChains(RegInfo, Vars); - if (AssignmentChains.empty()) - return makeError("Unable to find a dependency chain."); - const std::vector<llvm::MCPhysReg> Regs = - getRandomAssignment(Vars, AssignmentChains, GetRandomIndex); - const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs); - if (!State.canAssemble(Inst)) - return makeError("MCInst does not assemble."); - return std::vector<llvm::MCInst>(NumRepetitions, Inst); -} - -std::vector<BenchmarkMeasure> -LatencyBenchmarkRunner::runMeasurements(const LLVMState &State, - const JitFunction &Function, - const unsigned NumRepetitions) const { - // Cycle measurements include some overhead from the kernel. Repeat the - // measure several times and take the minimum value. - constexpr const int NumMeasurements = 30; - int64_t MinLatency = std::numeric_limits<int64_t>::max(); - // FIXME: Read the perf event from the MCSchedModel (see PR36984). - const pfm::PerfEvent CyclesPerfEvent("UNHALTED_CORE_CYCLES"); - if (!CyclesPerfEvent.valid()) - llvm::report_fatal_error("invalid perf event 'UNHALTED_CORE_CYCLES'"); - for (size_t I = 0; I < NumMeasurements; ++I) { - pfm::Counter Counter(CyclesPerfEvent); - Counter.start(); - Function(); - Counter.stop(); - const int64_t Value = Counter.read(); - if (Value < MinLatency) - MinLatency = Value; - } - return {{"latency", static_cast<double>(MinLatency) / NumRepetitions}}; -} - -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/Latency.h b/llvm/tools/llvm-exegesis/lib/Latency.h deleted file mode 100644 index 65a1b33af50..00000000000 --- a/llvm/tools/llvm-exegesis/lib/Latency.h +++ /dev/null @@ -1,41 +0,0 @@ -//===-- Latency.h -----------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// A BenchmarkRunner implementation to measure instruction latencies. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H -#define LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H - -#include "BenchmarkRunner.h" - -namespace exegesis { - -class LatencyBenchmarkRunner : public BenchmarkRunner { -public: - ~LatencyBenchmarkRunner() override; - -private: - const char *getDisplayName() const override; - - llvm::Expected<std::vector<llvm::MCInst>> - createCode(const LLVMState &State, unsigned OpcodeIndex, - unsigned NumRepetitions, - const JitFunctionContext &Context) const override; - - std::vector<BenchmarkMeasure> - runMeasurements(const LLVMState &State, const JitFunction &Function, - unsigned NumRepetitions) const override; -}; - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H diff --git a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp deleted file mode 100644 index cb534f50998..00000000000 --- a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===-- LlvmState.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "LlvmState.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/MC/MCCodeEmitter.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCFixup.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" - -namespace exegesis { - -LLVMState::LLVMState() - : TheTriple(llvm::sys::getProcessTriple()), - CpuName(llvm::sys::getHostCPUName().str()) { - std::string Error; - TheTarget = llvm::TargetRegistry::lookupTarget(TheTriple, Error); - assert(TheTarget && "unknown target for host"); - SubtargetInfo.reset( - TheTarget->createMCSubtargetInfo(TheTriple, CpuName, Features)); - InstrInfo.reset(TheTarget->createMCInstrInfo()); - RegInfo.reset(TheTarget->createMCRegInfo(TheTriple)); - AsmInfo.reset(TheTarget->createMCAsmInfo(*RegInfo, TheTriple)); -} - -std::unique_ptr<llvm::LLVMTargetMachine> -LLVMState::createTargetMachine() const { - const llvm::TargetOptions Options; - return std::unique_ptr<llvm::LLVMTargetMachine>( - static_cast<llvm::LLVMTargetMachine *>(TheTarget->createTargetMachine( - TheTriple, CpuName, Features, Options, llvm::Reloc::Model::Static))); -} - -bool LLVMState::canAssemble(const llvm::MCInst &Inst) const { - llvm::MCObjectFileInfo ObjectFileInfo; - llvm::MCContext Context(AsmInfo.get(), RegInfo.get(), &ObjectFileInfo); - std::unique_ptr<const llvm::MCCodeEmitter> CodeEmitter( - TheTarget->createMCCodeEmitter(*InstrInfo, *RegInfo, Context)); - llvm::SmallVector<char, 16> Tmp; - llvm::raw_svector_ostream OS(Tmp); - llvm::SmallVector<llvm::MCFixup, 4> Fixups; - CodeEmitter->encodeInstruction(Inst, OS, Fixups, *SubtargetInfo); - return Tmp.size() > 0; -} - -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/LlvmState.h b/llvm/tools/llvm-exegesis/lib/LlvmState.h deleted file mode 100644 index c0a9bb29d8c..00000000000 --- a/llvm/tools/llvm-exegesis/lib/LlvmState.h +++ /dev/null @@ -1,59 +0,0 @@ -//===-- LlvmState.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H -#define LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H - -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Target/TargetMachine.h" -#include <memory> -#include <string> - -namespace exegesis { - -// An object to initialize LLVM and prepare objects needed to run the -// measurements. -class LLVMState { -public: - LLVMState(); - - llvm::StringRef getTriple() const { return TheTriple; } - llvm::StringRef getCpuName() const { return CpuName; } - llvm::StringRef getFeatures() const { return Features; } - - const llvm::MCInstrInfo &getInstrInfo() const { return *InstrInfo; } - - const llvm::MCRegisterInfo &getRegInfo() const { return *RegInfo; } - - const llvm::MCSubtargetInfo &getSubtargetInfo() const { - return *SubtargetInfo; - } - - std::unique_ptr<llvm::LLVMTargetMachine> createTargetMachine() const; - - bool canAssemble(const llvm::MCInst &mc_inst) const; - -private: - std::string TheTriple; - std::string CpuName; - std::string Features; - const llvm::Target *TheTarget = nullptr; - std::unique_ptr<const llvm::MCSubtargetInfo> SubtargetInfo; - std::unique_ptr<const llvm::MCInstrInfo> InstrInfo; - std::unique_ptr<const llvm::MCRegisterInfo> RegInfo; - std::unique_ptr<const llvm::MCAsmInfo> AsmInfo; -}; - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H diff --git a/llvm/tools/llvm-exegesis/lib/OperandGraph.cpp b/llvm/tools/llvm-exegesis/lib/OperandGraph.cpp deleted file mode 100644 index f6bdc9d73ee..00000000000 --- a/llvm/tools/llvm-exegesis/lib/OperandGraph.cpp +++ /dev/null @@ -1,115 +0,0 @@ -//===-- OperandGraph.cpp ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "OperandGraph.h" -#include "llvm/MC/MCRegisterInfo.h" - -namespace exegesis { -namespace graph { - -void Node::dump(const llvm::MCRegisterInfo &RegInfo) const { - switch (type()) { - case NodeType::VARIABLE: - printf(" %d", varValue()); - break; - case NodeType::REG: - printf(" %s", RegInfo.getName(regValue())); - break; - case NodeType::IN: - printf(" IN"); - break; - case NodeType::OUT: - printf(" OUT"); - break; - } -} - -NodeType Node::type() const { return first; } - -int Node::regValue() const { - assert(first == NodeType::REG && "regValue() called on non-reg"); - return second; -} - -int Node::varValue() const { - assert(first == NodeType::VARIABLE && "varValue() called on non-var"); - return second; -} - -void Graph::connect(const Node From, const Node To) { - AdjacencyLists[From].insert(To); -} - -void Graph::disconnect(const Node From, const Node To) { - AdjacencyLists[From].erase(To); -} - -std::vector<Node> Graph::getPathFrom(const Node From, const Node To) const { - std::vector<Node> Path; - NodeSet Seen; - dfs(From, To, Path, Seen); - return Path; -} - -// DFS is implemented recursively, this is fine as graph size is small (~250 -// nodes, ~200 edges, longuest path depth < 10). -bool Graph::dfs(const Node Current, const Node Sentinel, - std::vector<Node> &Path, NodeSet &Seen) const { - Path.push_back(Current); - Seen.insert(Current); - if (Current == Sentinel) - return true; - if (AdjacencyLists.count(Current)) { - for (const Node Next : AdjacencyLists.find(Current)->second) { - if (Seen.count(Next)) - continue; - if (dfs(Next, Sentinel, Path, Seen)) - return true; - } - } - Path.pop_back(); - return false; -} - -// For each Register Units we walk up their parents. -// Let's take the case of the A register family: -// -// RAX -// ^ -// EAX -// ^ -// AX -// ^ ^ -// AH AL -// -// Register Units are AH and AL. -// Walking them up gives the following lists: -// AH->AX->EAX->RAX and AL->AX->EAX->RAX -// When walking the lists we add connect current to parent both ways leading to -// the following connections: -// -// AL<->AX, AH<->AX, AX<->EAX, EAX<->RAX -// We repeat this process for all Unit Registers to cover all connections. -void setupRegisterAliasing(const llvm::MCRegisterInfo &RegInfo, - Graph &TheGraph) { - using SuperItr = llvm::MCSuperRegIterator; - for (size_t Reg = 0, E = RegInfo.getNumRegUnits(); Reg < E; ++Reg) { - size_t Current = Reg; - for (SuperItr Super(Reg, &RegInfo); Super.isValid(); ++Super) { - const Node A = Node::Reg(Current); - const Node B = Node::Reg(*Super); - TheGraph.connect(A, B); - TheGraph.connect(B, A); - Current = *Super; - } - } -} - -} // namespace graph -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/OperandGraph.h b/llvm/tools/llvm-exegesis/lib/OperandGraph.h deleted file mode 100644 index 3db1a2a578b..00000000000 --- a/llvm/tools/llvm-exegesis/lib/OperandGraph.h +++ /dev/null @@ -1,89 +0,0 @@ -//===-- OperandGraph.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// A collection of tools to model register aliasing and instruction operand. -/// This is used to find an aliasing between the input and output registers of -/// an instruction. It allows us to repeat an instruction and make sure that -/// successive instances are executed sequentially. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_OPERANDGRAPH_H -#define LLVM_TOOLS_LLVM_EXEGESIS_OPERANDGRAPH_H - -#include "llvm/MC/MCRegisterInfo.h" -#include <map> -#include <set> -#include <tuple> -#include <vector> - -namespace exegesis { -namespace graph { - -enum class NodeType { - VARIABLE, // An set of "tied together operands" to resolve. - REG, // A particular register. - IN, // The input node. - OUT // The output node. -}; - -// A Node in the graph, it has a type and an int value. -struct Node : public std::pair<NodeType, int> { - using std::pair<NodeType, int>::pair; - - static Node Reg(int Value) { return {NodeType::REG, Value}; } - static Node Var(int Value) { return {NodeType::VARIABLE, Value}; } - static Node In() { return {NodeType::IN, 0}; } - static Node Out() { return {NodeType::OUT, 0}; } - - NodeType type() const; - int regValue() const; // checks that type==REG and returns value. - int varValue() const; // checks that type==VARIABLE and returns value. - - void dump(const llvm::MCRegisterInfo &RegInfo) const; -}; - -// Graph represents the connectivity of registers for a particular instruction. -// This object is used to select registers that would create a dependency chain -// between instruction's input and output. -struct Graph { -public: - void connect(const Node From, const Node To); - void disconnect(const Node From, const Node To); - - // Tries to find a path between 'From' and 'To' nodes. - // Returns empty if no path is found. - std::vector<Node> getPathFrom(const Node From, const Node To) const; - -private: - // We use std::set to keep the implementation simple, using an unordered_set - // requires the definition of a hasher. - using NodeSet = std::set<Node>; - - // Performs a Depth First Search from 'current' node up until 'sentinel' node - // is found. 'path' is the recording of the traversed nodes, 'seen' is the - // collection of nodes seen so far. - bool dfs(const Node Current, const Node Sentinel, std::vector<Node> &Path, - NodeSet &Seen) const; - - // We use std::map to keep the implementation simple, using an unordered_map - // requires the definition of a hasher. - std::map<Node, NodeSet> AdjacencyLists; -}; - -// Add register nodes to graph and connect them when they alias. Connection is -// both ways. -void setupRegisterAliasing(const llvm::MCRegisterInfo &RegInfo, - Graph &TheGraph); - -} // namespace graph -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_OPERANDGRAPH_H diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp b/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp deleted file mode 100644 index bba0433ad5d..00000000000 --- a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp +++ /dev/null @@ -1,129 +0,0 @@ -//===-- PerfHelper.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PerfHelper.h" -#include "llvm/Config/config.h" -#include "llvm/Support/raw_ostream.h" -#ifdef HAVE_LIBPFM -#include "perfmon/perf_event.h" -#include "perfmon/pfmlib.h" -#include "perfmon/pfmlib_perf_event.h" -#endif - -namespace exegesis { -namespace pfm { - -#ifdef HAVE_LIBPFM -static bool isPfmError(int Code) { return Code != PFM_SUCCESS; } -#endif - -bool pfmInitialize() { -#ifdef HAVE_LIBPFM - return isPfmError(pfm_initialize()); -#else - return true; -#endif -} - -void pfmTerminate() { -#ifdef HAVE_LIBPFM - pfm_terminate(); -#endif -} - -PerfEvent::~PerfEvent() { -#ifdef HAVE_LIBPFM - delete Attr; - ; -#endif -} - -PerfEvent::PerfEvent(PerfEvent &&Other) - : EventString(std::move(Other.EventString)), - FullQualifiedEventString(std::move(Other.FullQualifiedEventString)), - Attr(Other.Attr) { - Other.Attr = nullptr; -} - -PerfEvent::PerfEvent(llvm::StringRef PfmEventString) - : EventString(PfmEventString.str()), Attr(nullptr) { -#ifdef HAVE_LIBPFM - char *Fstr = nullptr; - pfm_perf_encode_arg_t Arg = {}; - Attr = new perf_event_attr(); - Arg.attr = Attr; - Arg.fstr = &Fstr; - Arg.size = sizeof(pfm_perf_encode_arg_t); - const int Result = pfm_get_os_event_encoding(EventString.c_str(), PFM_PLM3, - PFM_OS_PERF_EVENT, &Arg); - if (isPfmError(Result)) { - // We don't know beforehand which counters are available (e.g. 6 uops ports - // on Sandybridge but 8 on Haswell) so we report the missing counter without - // crashing. - llvm::errs() << pfm_strerror(Result) << " - cannot create event " - << EventString; - } - if (Fstr) { - FullQualifiedEventString = Fstr; - free(Fstr); - } -#endif -} - -llvm::StringRef PerfEvent::name() const { return EventString; } - -bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); } - -const perf_event_attr *PerfEvent::attribute() const { return Attr; } - -llvm::StringRef PerfEvent::getPfmEventString() const { - return FullQualifiedEventString; -} - -#ifdef HAVE_LIBPFM -Counter::Counter(const PerfEvent &Event) { - const pid_t Pid = 0; // measure current process/thread. - const int Cpu = -1; // measure any processor. - const int GroupFd = -1; // no grouping of counters. - const uint32_t Flags = 0; - perf_event_attr AttrCopy = *Event.attribute(); - FileDescriptor = perf_event_open(&AttrCopy, Pid, Cpu, GroupFd, Flags); - assert(FileDescriptor != -1 && - "Unable to open event, make sure your kernel allows user space perf " - "monitoring."); -} - -Counter::~Counter() { close(FileDescriptor); } - -void Counter::start() { ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0); } - -void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); } - -int64_t Counter::read() const { - int64_t Count = 0; - ::read(FileDescriptor, &Count, sizeof(Count)); - return Count; -} - -#else - -Counter::Counter(const PerfEvent &Event) : FileDescriptor(-1) {} - -Counter::~Counter() = default; - -void Counter::start() {} - -void Counter::stop() {} - -int64_t Counter::read() const { return 42; } - -#endif - -} // namespace pfm -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.h b/llvm/tools/llvm-exegesis/lib/PerfHelper.h deleted file mode 100644 index 22da2061c52..00000000000 --- a/llvm/tools/llvm-exegesis/lib/PerfHelper.h +++ /dev/null @@ -1,103 +0,0 @@ -//===-- PerfHelper.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Helpers for measuring perf events. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_PERFHELPER_H -#define LLVM_TOOLS_LLVM_EXEGESIS_PERFHELPER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include <functional> -#include <memory> - -struct perf_event_attr; - -namespace exegesis { -namespace pfm { - -// Returns true on error. -bool pfmInitialize(); -void pfmTerminate(); - -// Retrieves the encoding for the event described by pfm_event_string. -// NOTE: pfm_initialize() must be called before creating PerfEvent objects. -class PerfEvent { -public: - // http://perfmon2.sourceforge.net/manv4/libpfm.html - // Events are expressed as strings. e.g. "INSTRUCTION_RETIRED" - explicit PerfEvent(llvm::StringRef pfm_event_string); - - PerfEvent(const PerfEvent &) = delete; - PerfEvent(PerfEvent &&other); - ~PerfEvent(); - - // The pfm_event_string passed at construction time. - llvm::StringRef name() const; - - // Whether the event was successfully created. - bool valid() const; - - // The encoded event to be passed to the Kernel. - const perf_event_attr *attribute() const; - - // The fully qualified name for the event. - // e.g. "snb_ep::INSTRUCTION_RETIRED:e=0:i=0:c=0:t=0:u=1:k=0:mg=0:mh=1" - llvm::StringRef getPfmEventString() const; - -private: - const std::string EventString; - std::string FullQualifiedEventString; - perf_event_attr *Attr; -}; - -// Uses a valid PerfEvent to configure the Kernel so we can measure the -// underlying event. -struct Counter { - // event: the PerfEvent to measure. - explicit Counter(const PerfEvent &event); - - Counter(const Counter &) = delete; - Counter(Counter &&other) = default; - - ~Counter(); - - void start(); // Starts the measurement of the event. - void stop(); // Stops the measurement of the event. - int64_t read() const; // Return the current value of the counter. - -private: - int FileDescriptor = -1; -}; - -// Helper to measure a list of PerfEvent for a particular function. -// callback is called for each successful measure (PerfEvent needs to be valid). -template <typename Function> -void Measure( - llvm::ArrayRef<PerfEvent> Events, - const std::function<void(const PerfEvent &Event, int64_t Value)> &Callback, - Function Fn) { - for (const auto &Event : Events) { - if (!Event.valid()) - continue; - Counter Cnt(Event); - Cnt.start(); - Fn(); - Cnt.stop(); - Callback(Event, Cnt.read()); - } -} - -} // namespace pfm -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_PERFHELPER_H diff --git a/llvm/tools/llvm-exegesis/lib/Uops.cpp b/llvm/tools/llvm-exegesis/lib/Uops.cpp deleted file mode 100644 index bcfc5572a1f..00000000000 --- a/llvm/tools/llvm-exegesis/lib/Uops.cpp +++ /dev/null @@ -1,248 +0,0 @@ -//===-- Uops.cpp ------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Uops.h" -#include "BenchmarkResult.h" -#include "InstructionSnippetGenerator.h" -#include "PerfHelper.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/MC/MCInstrDesc.h" -#include "llvm/MC/MCSchedule.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <random> -#include <unordered_map> -#include <unordered_set> - -namespace exegesis { - -// FIXME: Handle memory (see PR36906) -static bool isInvalidOperand(const llvm::MCOperandInfo &OpInfo) { - switch (OpInfo.OperandType) { - default: - return true; - case llvm::MCOI::OPERAND_IMMEDIATE: - case llvm::MCOI::OPERAND_REGISTER: - return false; - } -} - -static llvm::Error makeError(llvm::Twine Msg) { - return llvm::make_error<llvm::StringError>(Msg, - llvm::inconvertibleErrorCode()); -} - -// FIXME: Read the counter names from the ProcResourceUnits when PR36984 is -// fixed. -static const std::string *getEventNameFromProcResName(const char *ProcResName) { - static const std::unordered_map<std::string, std::string> Entries = { - {"SBPort0", "UOPS_DISPATCHED_PORT:PORT_0"}, - {"SBPort1", "UOPS_DISPATCHED_PORT:PORT_1"}, - {"SBPort4", "UOPS_DISPATCHED_PORT:PORT_4"}, - {"SBPort5", "UOPS_DISPATCHED_PORT:PORT_5"}, - {"HWPort0", "UOPS_DISPATCHED_PORT:PORT_0"}, - {"HWPort1", "UOPS_DISPATCHED_PORT:PORT_1"}, - {"HWPort2", "UOPS_DISPATCHED_PORT:PORT_2"}, - {"HWPort3", "UOPS_DISPATCHED_PORT:PORT_3"}, - {"HWPort4", "UOPS_DISPATCHED_PORT:PORT_4"}, - {"HWPort5", "UOPS_DISPATCHED_PORT:PORT_5"}, - {"HWPort6", "UOPS_DISPATCHED_PORT:PORT_6"}, - {"HWPort7", "UOPS_DISPATCHED_PORT:PORT_7"}, - {"SKLPort0", "UOPS_DISPATCHED_PORT:PORT_0"}, - {"SKLPort1", "UOPS_DISPATCHED_PORT:PORT_1"}, - {"SKLPort2", "UOPS_DISPATCHED_PORT:PORT_2"}, - {"SKLPort3", "UOPS_DISPATCHED_PORT:PORT_3"}, - {"SKLPort4", "UOPS_DISPATCHED_PORT:PORT_4"}, - {"SKLPort5", "UOPS_DISPATCHED_PORT:PORT_5"}, - {"SKLPort6", "UOPS_DISPATCHED_PORT:PORT_6"}, - {"SKXPort7", "UOPS_DISPATCHED_PORT:PORT_7"}, - {"SKXPort0", "UOPS_DISPATCHED_PORT:PORT_0"}, - {"SKXPort1", "UOPS_DISPATCHED_PORT:PORT_1"}, - {"SKXPort2", "UOPS_DISPATCHED_PORT:PORT_2"}, - {"SKXPort3", "UOPS_DISPATCHED_PORT:PORT_3"}, - {"SKXPort4", "UOPS_DISPATCHED_PORT:PORT_4"}, - {"SKXPort5", "UOPS_DISPATCHED_PORT:PORT_5"}, - {"SKXPort6", "UOPS_DISPATCHED_PORT:PORT_6"}, - {"SKXPort7", "UOPS_DISPATCHED_PORT:PORT_7"}, - }; - const auto It = Entries.find(ProcResName); - return It == Entries.end() ? nullptr : &It->second; -} - -static std::vector<llvm::MCInst> generateIndependentAssignments( - const LLVMState &State, const llvm::MCInstrDesc &InstrDesc, - llvm::SmallVector<Variable, 8> Vars, int MaxAssignments) { - std::unordered_set<llvm::MCPhysReg> IsUsedByAnyVar; - for (const Variable &Var : Vars) { - if (Var.IsUse) { - IsUsedByAnyVar.insert(Var.PossibleRegisters.begin(), - Var.PossibleRegisters.end()); - } - } - - std::vector<llvm::MCInst> Pattern; - for (int A = 0; A < MaxAssignments; ++A) { - // FIXME: This is a bit pessimistic. We should get away with an - // assignment that ensures that the set of assigned registers for uses and - // the set of assigned registers for defs do not intersect (registers - // for uses (resp defs) do not have to be all distinct). - const std::vector<llvm::MCPhysReg> Regs = getExclusiveAssignment(Vars); - if (Regs.empty()) - break; - // Remove all assigned registers defs that are used by at least one other - // variable from the list of possible variable registers. This ensures that - // we never create a RAW hazard that would lead to serialization. - for (size_t I = 0, E = Vars.size(); I < E; ++I) { - llvm::MCPhysReg Reg = Regs[I]; - if (Vars[I].IsDef && IsUsedByAnyVar.count(Reg)) { - Vars[I].PossibleRegisters.remove(Reg); - } - } - // Create an MCInst and check assembly. - llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs); - if (!State.canAssemble(Inst)) - continue; - Pattern.push_back(std::move(Inst)); - } - return Pattern; -} - -UopsBenchmarkRunner::~UopsBenchmarkRunner() = default; - -const char *UopsBenchmarkRunner::getDisplayName() const { return "uops"; } - -llvm::Expected<std::vector<llvm::MCInst>> UopsBenchmarkRunner::createCode( - const LLVMState &State, const unsigned OpcodeIndex, - const unsigned NumRepetitions, const JitFunctionContext &Context) const { - const auto &InstrInfo = State.getInstrInfo(); - const auto &RegInfo = State.getRegInfo(); - const llvm::MCInstrDesc &InstrDesc = InstrInfo.get(OpcodeIndex); - for (const llvm::MCOperandInfo &OpInfo : InstrDesc.operands()) { - if (isInvalidOperand(OpInfo)) - return makeError("Only registers and immediates are supported"); - } - - // FIXME: Load constants into registers (e.g. with fld1) to not break - // instructions like x87. - - // Ideally we would like the only limitation on executing uops to be the issue - // ports. Maximizing port pressure increases the likelihood that the load is - // distributed evenly across possible ports. - - // To achieve that, one approach is to generate instructions that do not have - // data dependencies between them. - // - // For some instructions, this is trivial: - // mov rax, qword ptr [rsi] - // mov rax, qword ptr [rsi] - // mov rax, qword ptr [rsi] - // mov rax, qword ptr [rsi] - // For the above snippet, haswell just renames rax four times and executes the - // four instructions two at a time on P23 and P0126. - // - // For some instructions, we just need to make sure that the source is - // different from the destination. For example, IDIV8r reads from GPR and - // writes to AX. We just need to ensure that the variable is assigned a - // register which is different from AX: - // idiv bx - // idiv bx - // idiv bx - // idiv bx - // The above snippet will be able to fully saturate the ports, while the same - // with ax would issue one uop every `latency(IDIV8r)` cycles. - // - // Some instructions make this harder because they both read and write from - // the same register: - // inc rax - // inc rax - // inc rax - // inc rax - // This has a data dependency from each instruction to the next, limit the - // number of instructions that can be issued in parallel. - // It turns out that this is not a big issue on recent Intel CPUs because they - // have heuristics to balance port pressure. In the snippet above, subsequent - // instructions will end up evenly distributed on {P0,P1,P5,P6}, but some CPUs - // might end up executing them all on P0 (just because they can), or try - // avoiding P5 because it's usually under high pressure from vector - // instructions. - // This issue is even more important for high-latency instructions because - // they increase the idle time of the CPU, e.g. : - // imul rax, rbx - // imul rax, rbx - // imul rax, rbx - // imul rax, rbx - // - // To avoid that, we do the renaming statically by generating as many - // independent exclusive assignments as possible (until all possible registers - // are exhausted) e.g.: - // imul rax, rbx - // imul rcx, rbx - // imul rdx, rbx - // imul r8, rbx - // - // Some instruction even make the above static renaming impossible because - // they implicitly read and write from the same operand, e.g. ADC16rr reads - // and writes from EFLAGS. - // In that case we just use a greedy register assignment and hope for the - // best. - - const auto Vars = getVariables(RegInfo, InstrDesc, Context.getReservedRegs()); - - // Generate as many independent exclusive assignments as possible. - constexpr const int MaxStaticRenames = 20; - std::vector<llvm::MCInst> Pattern = - generateIndependentAssignments(State, InstrDesc, Vars, MaxStaticRenames); - if (Pattern.empty()) { - // We don't even have a single exclusive assignment, fallback to a greedy - // assignment. - // FIXME: Tell the user about this decision to help debugging. - const std::vector<llvm::MCPhysReg> Regs = getGreedyAssignment(Vars); - if (!Vars.empty() && Regs.empty()) - return makeError("No feasible greedy assignment"); - llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs); - if (!State.canAssemble(Inst)) - return makeError("Cannot assemble greedy assignment"); - Pattern.push_back(std::move(Inst)); - } - - // Generate repetitions of the pattern until benchmark_iterations is reached. - std::vector<llvm::MCInst> Result; - Result.reserve(NumRepetitions); - for (unsigned I = 0; I < NumRepetitions; ++I) - Result.push_back(Pattern[I % Pattern.size()]); - return Result; -} - -std::vector<BenchmarkMeasure> -UopsBenchmarkRunner::runMeasurements(const LLVMState &State, - const JitFunction &Function, - const unsigned NumRepetitions) const { - const auto &SchedModel = State.getSubtargetInfo().getSchedModel(); - - std::vector<BenchmarkMeasure> Result; - for (unsigned ProcResIdx = 1; - ProcResIdx < SchedModel.getNumProcResourceKinds(); ++ProcResIdx) { - const llvm::MCProcResourceDesc &ProcRes = - *SchedModel.getProcResource(ProcResIdx); - const std::string *const EventName = - getEventNameFromProcResName(ProcRes.Name); - if (!EventName) - continue; - pfm::Counter Counter{pfm::PerfEvent(*EventName)}; - Counter.start(); - Function(); - Counter.stop(); - Result.push_back({llvm::itostr(ProcResIdx), - static_cast<double>(Counter.read()) / NumRepetitions, - ProcRes.Name}); - } - return Result; -} - -} // namespace exegesis diff --git a/llvm/tools/llvm-exegesis/lib/Uops.h b/llvm/tools/llvm-exegesis/lib/Uops.h deleted file mode 100644 index e9dc181061d..00000000000 --- a/llvm/tools/llvm-exegesis/lib/Uops.h +++ /dev/null @@ -1,41 +0,0 @@ -//===-- Uops.h --------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// A BenchmarkRunner implementation to measure uop decomposition. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_EXEGESIS_UOPS_H -#define LLVM_TOOLS_LLVM_EXEGESIS_UOPS_H - -#include "BenchmarkRunner.h" - -namespace exegesis { - -class UopsBenchmarkRunner : public BenchmarkRunner { -public: - ~UopsBenchmarkRunner() override; - -private: - const char *getDisplayName() const override; - - llvm::Expected<std::vector<llvm::MCInst>> - createCode(const LLVMState &State, unsigned OpcodeIndex, - unsigned NumRepetitions, - const JitFunctionContext &Context) const override; - - std::vector<BenchmarkMeasure> - runMeasurements(const LLVMState &State, const JitFunction &Function, - unsigned NumRepetitions) const override; -}; - -} // namespace exegesis - -#endif // LLVM_TOOLS_LLVM_EXEGESIS_UOPS_H diff --git a/llvm/tools/llvm-exegesis/lib/X86.cpp b/llvm/tools/llvm-exegesis/lib/X86.cpp deleted file mode 100644 index c9afece4a9f..00000000000 --- a/llvm/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<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 diff --git a/llvm/tools/llvm-exegesis/lib/X86.h b/llvm/tools/llvm-exegesis/lib/X86.h deleted file mode 100644 index 52dd3391363..00000000000 --- a/llvm/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/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp deleted file mode 100644 index f71f99469d1..00000000000 --- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp +++ /dev/null @@ -1,115 +0,0 @@ -//===-- llvm-exegesis.cpp ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Measures execution properties (latencies/uops) of an instruction. -/// -//===----------------------------------------------------------------------===// - -#include "lib/BenchmarkResult.h" -#include "lib/BenchmarkRunner.h" -#include "lib/Latency.h" -#include "lib/LlvmState.h" -#include "lib/PerfHelper.h" -#include "lib/Uops.h" -#include "lib/X86.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Twine.h" -#include "llvm/MC/MCInstBuilder.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Path.h" -#include <algorithm> -#include <random> -#include <string> -#include <unordered_map> - -static llvm::cl::opt<unsigned> - OpcodeIndex("opcode-index", llvm::cl::desc("opcode to measure, by index"), - llvm::cl::init(0)); - -static llvm::cl::opt<std::string> - OpcodeName("opcode-name", llvm::cl::desc("opcode to measure, by name"), - llvm::cl::init("")); - -enum class BenchmarkModeE { Latency, Uops }; -static llvm::cl::opt<BenchmarkModeE> - BenchmarkMode("benchmark-mode", llvm::cl::desc("the benchmark mode to run"), - llvm::cl::values(clEnumValN(BenchmarkModeE::Latency, - "latency", "Instruction Latency"), - clEnumValN(BenchmarkModeE::Uops, "uops", - "Uop Decomposition"))); - -static llvm::cl::opt<unsigned> - NumRepetitions("num-repetitions", - llvm::cl::desc("number of time to repeat the asm snippet"), - llvm::cl::init(10000)); - -namespace exegesis { - -void main() { - if (OpcodeName.empty() == (OpcodeIndex == 0)) { - llvm::report_fatal_error( - "please provide one and only one of 'opcode-index' or 'opcode-name' "); - } - - LLVMInitializeX86Target(); - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86AsmPrinter(); - - // FIXME: Target-specific filter. - X86Filter Filter; - - const LLVMState State; - - unsigned Opcode = OpcodeIndex; - if (Opcode == 0) { - // Resolve opcode name -> opcode. - for (unsigned I = 0, E = State.getInstrInfo().getNumOpcodes(); I < E; ++I) { - if (State.getInstrInfo().getName(I) == OpcodeName) { - Opcode = I; - break; - } - } - if (Opcode == 0) { - llvm::report_fatal_error( - llvm::Twine("unknown opcode ").concat(OpcodeName)); - } - } - - std::unique_ptr<BenchmarkRunner> Runner; - switch (BenchmarkMode) { - case BenchmarkModeE::Latency: - Runner = llvm::make_unique<LatencyBenchmarkRunner>(); - break; - case BenchmarkModeE::Uops: - Runner = llvm::make_unique<UopsBenchmarkRunner>(); - break; - } - - Runner->run(State, Opcode, NumRepetitions > 0 ? NumRepetitions : 1, Filter) - .writeYamlOrDie("-"); -} - -} // namespace exegesis - -int main(int Argc, char **Argv) { - llvm::cl::ParseCommandLineOptions(Argc, Argv, ""); - - if (exegesis::pfm::pfmInitialize()) { - llvm::errs() << "cannot initialize libpfm\n"; - return EXIT_FAILURE; - } - - exegesis::main(); - - exegesis::pfm::pfmTerminate(); - return EXIT_SUCCESS; -} |

