[llvm] r329169 - Re-land r329156 "Add llvm-exegesis tool."

Clement Courbet via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 5 04:19:28 PDT 2018


Hi Mikael, sorry I missed your e-mail. Can you confirm that my fix works ?
I'll add an option to disable libpfm completely for issues like this one.

On Thu, Apr 5, 2018 at 9:45 AM, Mikael Holmén <mikael.holmen at ericsson.com>
wrote:

> And now I suddenly saw you already made an attempt to fix this! :)
>
> I'll check again.
>
> Thanks,
> Mikael
>
> On 04/05/2018 09:43 AM, Mikael Holmén via llvm-commits wrote:
>
>> Hi Clement,
>>
>> Are there any requirements about the perfmon version?
>>
>> On several of my buildbots I get compilation failures now:
>>
>> ../tools/llvm-exegesis/lib/PerfHelper.cpp:14:10: fatal error:
>> 'perfmon/perf_event.h' file not found
>> #include "perfmon/perf_event.h"
>>
>> On those machines there does exist a perfmon/pfmlib.h file but not
>> perf_event.h nor pfmlib_perf_event.h. It looks like we have version 3.16
>> installed acording to pfmlib.h:
>>
>> #define PFMLIB_VERSION          (3 << 16 | 10)
>>
>> If you require a newer version than that, shouldn't that be checked by
>> the makefiles a well?
>>
>> I've also tried to find some CMAKE flag to turn off the pfm support
>> completely with something similar to LLVM_ENABLE_ZLIB but I can't find
>> anything like that.
>>
>> Regards,
>> Mikael
>>
>> On 04/04/2018 01:37 PM, Clement Courbet via llvm-commits wrote:
>>
>>> Author: courbet
>>> Date: Wed Apr  4 04:37:06 2018
>>> New Revision: 329169
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=329169&view=rev
>>> Log:
>>> Re-land r329156 "Add llvm-exegesis tool."
>>>
>>> Fixed to depend on and initialize the native target instead of X86.
>>>
>>> Added:
>>>      llvm/trunk/docs/CommandGuide/llvm-exegesis.rst
>>>      llvm/trunk/tools/llvm-exegesis/CMakeLists.txt
>>>      llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt
>>>        - copied, changed from r329157, llvm/trunk/tools/LLVMBuild.txt
>>>      llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt
>>>      llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt
>>>        - copied, changed from r329157, llvm/trunk/tools/LLVMBuild.txt
>>>      llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/Latency.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/Uops.h
>>>      llvm/trunk/tools/llvm-exegesis/lib/X86.cpp
>>>      llvm/trunk/tools/llvm-exegesis/lib/X86.h
>>>      llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp
>>>      llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp
>>>      llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt
>>>      llvm/trunk/unittests/tools/llvm-exegesis/InMemoryAssemblerTest.cpp
>>>      llvm/trunk/unittests/tools/llvm-exegesis/InstructionSnippetGeneratorTest.cpp
>>>
>>>      llvm/trunk/unittests/tools/llvm-exegesis/OperandGraphTest.cpp
>>>      llvm/trunk/unittests/tools/llvm-exegesis/PerfHelperTest.cpp
>>> Modified:
>>>      llvm/trunk/cmake/config-ix.cmake
>>>      llvm/trunk/docs/CommandGuide/index.rst
>>>      llvm/trunk/docs/ReleaseNotes.rst
>>>      llvm/trunk/include/llvm/Config/config.h.cmake
>>>      llvm/trunk/tools/LLVMBuild.txt
>>>      llvm/trunk/unittests/tools/CMakeLists.txt
>>>
>>> Modified: llvm/trunk/cmake/config-ix.cmake
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/config-
>>> ix.cmake?rev=329169&r1=329168&r2=329169&view=diff
>>> ==============================================================================
>>>
>>> --- llvm/trunk/cmake/config-ix.cmake (original)
>>> +++ llvm/trunk/cmake/config-ix.cmake Wed Apr  4 04:37:06 2018
>>> @@ -87,6 +87,7 @@ if( NOT PURE_WINDOWS )
>>>     endif()
>>>     check_library_exists(dl dlopen "" HAVE_LIBDL)
>>>     check_library_exists(rt clock_gettime "" HAVE_LIBRT)
>>> +  check_library_exists(pfm pfm_initialize "" HAVE_LIBPFM)
>>>   endif()
>>>   if(HAVE_LIBPTHREAD)
>>>
>>> Modified: llvm/trunk/docs/CommandGuide/index.rst
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandG
>>> uide/index.rst?rev=329169&r1=329168&r2=329169&view=diff
>>> ==============================================================================
>>>
>>> --- llvm/trunk/docs/CommandGuide/index.rst (original)
>>> +++ llvm/trunk/docs/CommandGuide/index.rst Wed Apr  4 04:37:06 2018
>>> @@ -53,5 +53,6 @@ Developer Tools
>>>      tblgen
>>>      lit
>>>      llvm-build
>>> +   llvm-exegesis
>>>      llvm-pdbutil
>>>      llvm-readobj
>>>
>>> Added: llvm/trunk/docs/CommandGuide/llvm-exegesis.rst
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandG
>>> uide/llvm-exegesis.rst?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/docs/CommandGuide/llvm-exegesis.rst (added)
>>> +++ llvm/trunk/docs/CommandGuide/llvm-exegesis.rst Wed Apr  4 04:37:06
>>> 2018
>>> @@ -0,0 +1,58 @@
>>> +llvm-exegesis - LLVM Machine Instruction Benchmark
>>> +==================================================
>>> +
>>> +SYNOPSIS
>>> +--------
>>> +
>>> +:program:`llvm-exegesis` [*options*]
>>> +
>>> +DESCRIPTION
>>> +-----------
>>> +
>>> +:program:`llvm-exegesis` is a benchmarking tool that uses information
>>> available
>>> +in LLVM to measure host machine instruction characteristics like
>>> latency or port
>>> +decomposition.
>>> +
>>> +Given an LLVM opcode name and a benchmarking mode,
>>> :program:`llvm-exegesis`
>>> +generates a code snippet that makes execution as serial (resp. as
>>> parallel) as
>>> +possible so that we can measure the latency (resp. uop decomposition)
>>> of the
>>> +instruction.
>>> +The code snippet is jitted and executed on the host subtarget. The time
>>> taken
>>> +(resp. resource usage) is measured using hardware performance counters.
>>> The
>>> +result is printed out as YAML to the standard output.
>>> +
>>> +The main goal of this tool is to automatically (in)validate the LLVM's
>>> TableDef
>>> +scheduling models.
>>> +
>>> +OPTIONS
>>> +-------
>>> +
>>> +.. option:: -help
>>> +
>>> + Print a summary of command line options.
>>> +
>>> +.. option:: -opcode-index=<LLVM opcode index>
>>> +
>>> + Specify the opcode to measure, by index.
>>> + Either `opcode-index` or `opcode-name` must be set.
>>> +
>>> +.. option:: -opcode-name=<LLVM opcode name>
>>> +
>>> + Specify the opcode to measure, by name.
>>> + Either `opcode-index` or `opcode-name` must be set.
>>> +
>>> +.. option:: -benchmark-mode=[Latency|Uops]
>>> +
>>> + Specify which characteristic of the opcode to measure.
>>> +
>>> +.. option:: -num-repetitions=<Number of repetition>
>>> +
>>> + Specify the number of repetitions of the asm snippet.
>>> + Higher values lead to more accurate measurements but lengthen the
>>> benchmark.
>>> +
>>> +
>>> +EXIT STATUS
>>> +-----------
>>> +
>>> +:program:`llvm-exegesis` returns 0 on success. Otherwise, an error
>>> message is
>>> +printed to standard error, and the tool returns a non 0 value.
>>>
>>> Modified: llvm/trunk/docs/ReleaseNotes.rst
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseN
>>> otes.rst?rev=329169&r1=329168&r2=329169&view=diff
>>> ==============================================================================
>>>
>>> --- llvm/trunk/docs/ReleaseNotes.rst (original)
>>> +++ llvm/trunk/docs/ReleaseNotes.rst Wed Apr  4 04:37:06 2018
>>> @@ -48,6 +48,11 @@ Non-comprehensive list of changes in thi
>>>   * Symbols starting with ``?`` are no longer mangled by LLVM when using
>>> the
>>>     Windows ``x`` or ``w`` IR mangling schemes.
>>> +* A new tool named :doc:`llvm-exegesis <CommandGuide/llvm-exegesis>`
>>> has been
>>> +  added. :program:`llvm-exegesis` automatically measures instruction
>>> scheduling
>>> +  properties (latency/uops) and provides a principled way to edit
>>> scheduling
>>> +  models.
>>> +
>>>   * A new tool named :doc:`llvm-mca <CommandGuide/llvm-mca>` has been
>>> added.
>>>     :program:`llvm-mca` is a  static performance analysis tool that uses
>>>     information available in LLVM to statically predict the performance
>>> of
>>>
>>> Modified: llvm/trunk/include/llvm/Config/config.h.cmake
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>>> Config/config.h.cmake?rev=329169&r1=329168&r2=329169&view=diff
>>> ==============================================================================
>>>
>>> --- llvm/trunk/include/llvm/Config/config.h.cmake (original)
>>> +++ llvm/trunk/include/llvm/Config/config.h.cmake Wed Apr  4 04:37:06
>>> 2018
>>> @@ -91,6 +91,12 @@
>>>   /* Define to 1 if you have the `edit' library (-ledit). */
>>>   #cmakedefine HAVE_LIBEDIT ${HAVE_LIBEDIT}
>>> +/* Define to 1 if you have the `pfm' library (-lpfm). */
>>> +#cmakedefine HAVE_LIBPFM ${HAVE_LIBPFM}
>>> +
>>> +/* Define to 1 if you have the `psapi' library (-lpsapi). */
>>> +#cmakedefine HAVE_LIBPSAPI ${HAVE_LIBPSAPI}
>>> +
>>>   /* Define to 1 if you have the `pthread' library (-lpthread). */
>>>   #cmakedefine HAVE_LIBPTHREAD ${HAVE_LIBPTHREAD}
>>>
>>> Modified: llvm/trunk/tools/LLVMBuild.txt
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBui
>>> ld.txt?rev=329169&r1=329168&r2=329169&view=diff
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/LLVMBuild.txt (original)
>>> +++ llvm/trunk/tools/LLVMBuild.txt Wed Apr  4 04:37:06 2018
>>> @@ -32,6 +32,7 @@ subdirectories =
>>>    llvm-dis
>>>    llvm-dwarfdump
>>>    llvm-dwp
>>> + llvm-exegesis
>>>    llvm-extract
>>>    llvm-jitlistener
>>>    llvm-link
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/CMakeLists.txt
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/CMakeLists.txt?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/CMakeLists.txt (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/CMakeLists.txt Wed Apr  4 04:37:06
>>> 2018
>>> @@ -0,0 +1,16 @@
>>> +set(LLVM_LINK_COMPONENTS
>>> +  Support
>>> +  native
>>> +  )
>>> +
>>> +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()
>>> +
>>>
>>> Copied: llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt (from r329157,
>>> llvm/trunk/tools/LLVMBuild.txt)
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-exegesis/
>>> LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=329157&
>>> r2=329169&rev=329169&view=diff
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/LLVMBuild.txt (original)
>>> +++ llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt Wed Apr  4 04:37:06
>>> 2018
>>> @@ -1,4 +1,4 @@
>>> -;===- ./tools/LLVMBuild.txt ------------------------------------*-
>>> Conf -*--===;
>>> +;===- ./tools/llvm-exegesis/LLVMBuild.txt ----------------------*-
>>> Conf -*--===;
>>>   ;
>>>   ;                     The LLVM Compiler Infrastructure
>>>   ;
>>> @@ -15,44 +15,8 @@
>>>   ;
>>>   ;===------------------------------------------------------------------------===;
>>>
>>> -[common]
>>> -subdirectories =
>>> - bugpoint
>>> - dsymutil
>>> - llc
>>> - lli
>>> - llvm-ar
>>> - llvm-as
>>> - llvm-bcanalyzer
>>> - llvm-cat
>>> - llvm-cfi-verify
>>> - llvm-cov
>>> - llvm-cvtres
>>> - llvm-diff
>>> - llvm-dis
>>> - llvm-dwarfdump
>>> - llvm-dwp
>>> - llvm-extract
>>> - llvm-jitlistener
>>> - llvm-link
>>> - llvm-lto
>>> - llvm-mc
>>> - llvm-mca
>>> - llvm-modextract
>>> - llvm-mt
>>> - llvm-nm
>>> - llvm-objcopy
>>> - llvm-objdump
>>> - llvm-pdbutil
>>> - llvm-profdata
>>> - llvm-rc
>>> - llvm-rtdyld
>>> - llvm-size
>>> - llvm-split
>>> - opt
>>> - verify-uselistorder
>>> -
>>>   [component_0]
>>> -type = Group
>>> -name = Tools
>>> -parent = $ROOT
>>> +type = Tool
>>> +name = llvm-exegesis
>>> +parent = Tools
>>> +required_libraries = CodeGen ExecutionEngine MC MCJIT Native
>>> NativeCodeGen Object Support
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/BenchmarkResult.cpp?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp Wed Apr  4
>>> 04:37:06 2018
>>> @@ -0,0 +1,85 @@
>>> +//===-- 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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/BenchmarkResult.h?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h Wed Apr  4
>>> 04:37:06 2018
>>> @@ -0,0 +1,53 @@
>>> +//===-- 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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/BenchmarkRunner.cpp?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp Wed Apr  4
>>> 04:37:06 2018
>>> @@ -0,0 +1,79 @@
>>> +//===-- 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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/BenchmarkRunner.h?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h Wed Apr  4
>>> 04:37:06 2018
>>> @@ -0,0 +1,64 @@
>>> +//===-- 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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/CMakeLists.txt?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt Wed Apr  4
>>> 04:37:06 2018
>>> @@ -0,0 +1,25 @@
>>> +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")
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/InMemoryAssembler.cpp?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp Wed Apr  4
>>> 04:37:06 2018
>>> @@ -0,0 +1,226 @@
>>> +//===-- 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->getT
>>> argetTriple()));
>>> +  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->getMemBuf
>>> ferRef()));
>>> +  // 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().getRegister
>>> Info()->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<TrackingSect
>>> ionMemoryManager>(&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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/InMemoryAssembler.h?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h Wed Apr  4
>>> 04:37:06 2018
>>> @@ -0,0 +1,78 @@
>>> +//===-- 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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerat
>>> or.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/InstructionSnippetGenerator.cpp?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
>>> (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
>>> Wed Apr  4 04:37:06 2018
>>> @@ -0,0 +1,355 @@
>>> +//===-- 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()[OpInd
>>> ex];
>>> +  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.As
>>> signedReg));
>>> +  }
>>> +  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)#B
>>> ipartite_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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/InstructionSnippetGenerator.h?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
>>> (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
>>> Wed Apr  4 04:37:06 2018
>>> @@ -0,0 +1,119 @@
>>> +//===-- 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
>>>
>>> Copied: llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt (from r329157,
>>> llvm/trunk/tools/LLVMBuild.txt)
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-exegesis/
>>> lib/LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=
>>> 329157&r2=329169&rev=329169&view=diff
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/LLVMBuild.txt (original)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt Wed Apr  4
>>> 04:37:06 2018
>>> @@ -1,4 +1,4 @@
>>> -;===- ./tools/LLVMBuild.txt ------------------------------------*-
>>> Conf -*--===;
>>> +;===- ./tools/llvm-exegesis/lib/LLVMBuild.txt ------------------*-
>>> Conf -*--===;
>>>   ;
>>>   ;                     The LLVM Compiler Infrastructure
>>>   ;
>>> @@ -15,44 +15,8 @@
>>>   ;
>>>   ;===------------------------------------------------------------------------===;
>>>
>>> -[common]
>>> -subdirectories =
>>> - bugpoint
>>> - dsymutil
>>> - llc
>>> - lli
>>> - llvm-ar
>>> - llvm-as
>>> - llvm-bcanalyzer
>>> - llvm-cat
>>> - llvm-cfi-verify
>>> - llvm-cov
>>> - llvm-cvtres
>>> - llvm-diff
>>> - llvm-dis
>>> - llvm-dwarfdump
>>> - llvm-dwp
>>> - llvm-extract
>>> - llvm-jitlistener
>>> - llvm-link
>>> - llvm-lto
>>> - llvm-mc
>>> - llvm-mca
>>> - llvm-modextract
>>> - llvm-mt
>>> - llvm-nm
>>> - llvm-objcopy
>>> - llvm-objdump
>>> - llvm-pdbutil
>>> - llvm-profdata
>>> - llvm-rc
>>> - llvm-rtdyld
>>> - llvm-size
>>> - llvm-split
>>> - opt
>>> - verify-uselistorder
>>> -
>>>   [component_0]
>>> -type = Group
>>> -name = Tools
>>> -parent = $ROOT
>>> +type = Library
>>> +name = Exegesis
>>> +parent = Libraries
>>> +required_libraries = CodeGen ExecutionEngine MC MCJIT Object Support
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/Latency.cpp?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp Wed Apr  4 04:37:06
>>> 2018
>>> @@ -0,0 +1,95 @@
>>> +//===-- 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
>>>
>>> Added: llvm/trunk/tools/llvm-exegesis/lib/Latency.h
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-ex
>>> egesis/lib/Latency.h?rev=329169&view=auto
>>> ==============================================================================
>>>
>>> --- llvm/trunk/tools/llvm-exegesis/lib/Latency.h (added)
>>> +++ llvm/trunk/tools/llvm-exegesis/lib/Latency.h Wed Apr  4 04:37:06
>>> 2018
>>> @@ -0,0 +1,41 @@
>>> +//===-- 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>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180405/375d412d/attachment.html>


More information about the llvm-commits mailing list