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

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 5 04:22:07 PDT 2018



On 04/05/2018 01:19 PM, Clement Courbet wrote:
> Hi Mikael, sorry I missed your e-mail. Can you confirm that my fix works ?

Yes the fix you pushed works for me so no problems that I'm aware of now.

> I'll add an option to disable libpfm completely for issues like this one.
> 

Thanks,
Mikael

> On Thu, Apr 5, 2018 at 9:45 AM, Mikael Holmén 
> <mikael.holmen at ericsson.com <mailto: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
>             <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
>             <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/CommandGuide/index.rst?rev=329169&r1=329168&r2=329169&view=diff
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/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/CommandGuide/llvm-exegesis.rst?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/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/ReleaseNotes.rst?rev=329169&r1=329168&r2=329169&view=diff
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.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
>             <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/LLVMBuild.txt?rev=329169&r1=329168&r2=329169&view=diff
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.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-exegesis/CMakeLists.txt?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=329157&r2=329169&rev=329169&view=diff
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/lib/BenchmarkResult.cpp?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/lib/BenchmarkResult.h?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/lib/BenchmarkRunner.cpp?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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
>             <http://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-exegesis/lib/BenchmarkRunner.h?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/lib/CMakeLists.txt?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/lib/InMemoryAssembler.cpp?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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->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
> 
>             Added: llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
>             URL:
>             http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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/InstructionSnippetGenerator.cpp
>             URL:
>             http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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()[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
>             <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
> 
>             Added:
>             llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
>             URL:
>             http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/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
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/lib/Latency.cpp?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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-exegesis/lib/Latency.h?rev=329169&view=auto
>             <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/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>
> 
> 



More information about the llvm-commits mailing list