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

Clement Courbet via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 4 04:37:06 PDT 2018


Author: courbet
Date: Wed Apr  4 04:37:06 2018
New Revision: 329169

URL: http://llvm.org/viewvc/llvm-project?rev=329169&view=rev
Log:
Re-land r329156 "Add llvm-exegesis tool."

Fixed to depend on and initialize the native target instead of X86.

Added:
    llvm/trunk/docs/CommandGuide/llvm-exegesis.rst
    llvm/trunk/tools/llvm-exegesis/CMakeLists.txt
    llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt
      - copied, changed from r329157, llvm/trunk/tools/LLVMBuild.txt
    llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp
    llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h
    llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
    llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
    llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt
    llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp
    llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
    llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
    llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
    llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt
      - copied, changed from r329157, llvm/trunk/tools/LLVMBuild.txt
    llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Latency.h
    llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp
    llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h
    llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.cpp
    llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.h
    llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.cpp
    llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.h
    llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Uops.h
    llvm/trunk/tools/llvm-exegesis/lib/X86.cpp
    llvm/trunk/tools/llvm-exegesis/lib/X86.h
    llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt
    llvm/trunk/unittests/tools/llvm-exegesis/InMemoryAssemblerTest.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/InstructionSnippetGeneratorTest.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/OperandGraphTest.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/PerfHelperTest.cpp
Modified:
    llvm/trunk/cmake/config-ix.cmake
    llvm/trunk/docs/CommandGuide/index.rst
    llvm/trunk/docs/ReleaseNotes.rst
    llvm/trunk/include/llvm/Config/config.h.cmake
    llvm/trunk/tools/LLVMBuild.txt
    llvm/trunk/unittests/tools/CMakeLists.txt

Modified: llvm/trunk/cmake/config-ix.cmake
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/config-ix.cmake?rev=329169&r1=329168&r2=329169&view=diff
==============================================================================
--- llvm/trunk/cmake/config-ix.cmake (original)
+++ llvm/trunk/cmake/config-ix.cmake Wed Apr  4 04:37:06 2018
@@ -87,6 +87,7 @@ if( NOT PURE_WINDOWS )
   endif()
   check_library_exists(dl dlopen "" HAVE_LIBDL)
   check_library_exists(rt clock_gettime "" HAVE_LIBRT)
+  check_library_exists(pfm pfm_initialize "" HAVE_LIBPFM)
 endif()
 
 if(HAVE_LIBPTHREAD)

Modified: llvm/trunk/docs/CommandGuide/index.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/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
==============================================================================
--- 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
==============================================================================
--- llvm/trunk/docs/ReleaseNotes.rst (original)
+++ llvm/trunk/docs/ReleaseNotes.rst Wed Apr  4 04:37:06 2018
@@ -48,6 +48,11 @@ Non-comprehensive list of changes in thi
 * Symbols starting with ``?`` are no longer mangled by LLVM when using the
   Windows ``x`` or ``w`` IR mangling schemes.
 
+* A new tool named :doc:`llvm-exegesis <CommandGuide/llvm-exegesis>` has been
+  added. :program:`llvm-exegesis` automatically measures instruction scheduling
+  properties (latency/uops) and provides a principled way to edit scheduling
+  models.
+
 * A new tool named :doc:`llvm-mca <CommandGuide/llvm-mca>` has been added.
   :program:`llvm-mca` is a  static performance analysis tool that uses
   information available in LLVM to statically predict the performance of

Modified: llvm/trunk/include/llvm/Config/config.h.cmake
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Config/config.h.cmake?rev=329169&r1=329168&r2=329169&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Config/config.h.cmake (original)
+++ llvm/trunk/include/llvm/Config/config.h.cmake Wed Apr  4 04:37:06 2018
@@ -91,6 +91,12 @@
 /* Define to 1 if you have the `edit' library (-ledit). */
 #cmakedefine HAVE_LIBEDIT ${HAVE_LIBEDIT}
 
+/* Define to 1 if you have the `pfm' library (-lpfm). */
+#cmakedefine HAVE_LIBPFM ${HAVE_LIBPFM}
+
+/* Define to 1 if you have the `psapi' library (-lpsapi). */
+#cmakedefine HAVE_LIBPSAPI ${HAVE_LIBPSAPI}
+
 /* Define to 1 if you have the `pthread' library (-lpthread). */
 #cmakedefine HAVE_LIBPTHREAD ${HAVE_LIBPTHREAD}
 

Modified: llvm/trunk/tools/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/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
==============================================================================
--- 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
==============================================================================
--- 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
==============================================================================
--- 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
==============================================================================
--- 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
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,79 @@
+//===-- BenchmarkRunner.cpp -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BenchmarkRunner.h"
+#include "InMemoryAssembler.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include <string>
+
+namespace exegesis {
+
+BenchmarkRunner::InstructionFilter::~InstructionFilter() = default;
+
+BenchmarkRunner::~BenchmarkRunner() = default;
+
+InstructionBenchmark
+BenchmarkRunner::run(const LLVMState &State, const unsigned Opcode,
+                     unsigned NumRepetitions,
+                     const InstructionFilter &Filter) const {
+  InstructionBenchmark InstrBenchmark;
+
+  InstrBenchmark.AsmTmpl.Name =
+      llvm::Twine(getDisplayName())
+          .concat(" ")
+          .concat(State.getInstrInfo().getName(Opcode))
+          .str();
+  InstrBenchmark.CpuName = State.getCpuName();
+  InstrBenchmark.LLVMTriple = State.getTriple();
+  InstrBenchmark.NumRepetitions = NumRepetitions;
+
+  // Ignore instructions that we cannot run.
+  if (State.getInstrInfo().get(Opcode).isPseudo()) {
+    InstrBenchmark.Error = "Unsupported opcode: isPseudo";
+    return InstrBenchmark;
+  }
+  if (llvm::Error E = Filter.shouldRun(State, Opcode)) {
+    InstrBenchmark.Error = llvm::toString(std::move(E));
+    return InstrBenchmark;
+  }
+
+  JitFunctionContext Context(State.createTargetMachine());
+  auto ExpectedInstructions =
+      createCode(State, Opcode, NumRepetitions, Context);
+  if (llvm::Error E = ExpectedInstructions.takeError()) {
+    InstrBenchmark.Error = llvm::toString(std::move(E));
+    return InstrBenchmark;
+  }
+
+  const std::vector<llvm::MCInst> Instructions = *ExpectedInstructions;
+  const JitFunction Function(std::move(Context), Instructions);
+  const llvm::StringRef CodeBytes = Function.getFunctionBytes();
+
+  std::string AsmExcerpt;
+  constexpr const int ExcerptSize = 100;
+  constexpr const int ExcerptTailSize = 10;
+  if (CodeBytes.size() <= ExcerptSize) {
+    AsmExcerpt = llvm::toHex(CodeBytes);
+  } else {
+    AsmExcerpt =
+        llvm::toHex(CodeBytes.take_front(ExcerptSize - ExcerptTailSize + 3));
+    AsmExcerpt += "...";
+    AsmExcerpt += llvm::toHex(CodeBytes.take_back(ExcerptTailSize));
+  }
+  llvm::outs() << "# Asm excerpt: " << AsmExcerpt << "\n";
+  llvm::outs().flush(); // In case we crash.
+
+  InstrBenchmark.Measurements =
+      runMeasurements(State, Function, NumRepetitions);
+  return InstrBenchmark;
+}
+
+} // namespace exegesis

Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-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
==============================================================================
--- 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
==============================================================================
--- 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
==============================================================================
--- 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
==============================================================================
--- 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
+// 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
==============================================================================
--- 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
==============================================================================
--- 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
==============================================================================
--- 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
==============================================================================
--- 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>
+  runMeasurements(const LLVMState &State, const JitFunction &Function,
+                  unsigned NumRepetitions) const override;
+};
+
+} // namespace exegesis
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H

Added: llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,56 @@
+//===-- LlvmState.cpp -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LlvmState.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+
+namespace exegesis {
+
+LLVMState::LLVMState()
+    : TheTriple(llvm::sys::getProcessTriple()),
+      CpuName(llvm::sys::getHostCPUName().str()) {
+  std::string Error;
+  TheTarget = llvm::TargetRegistry::lookupTarget(TheTriple, Error);
+  assert(TheTarget && "unknown target for host");
+  SubtargetInfo.reset(
+      TheTarget->createMCSubtargetInfo(TheTriple, CpuName, Features));
+  InstrInfo.reset(TheTarget->createMCInstrInfo());
+  RegInfo.reset(TheTarget->createMCRegInfo(TheTriple));
+  AsmInfo.reset(TheTarget->createMCAsmInfo(*RegInfo, TheTriple));
+}
+
+std::unique_ptr<llvm::LLVMTargetMachine>
+LLVMState::createTargetMachine() const {
+  const llvm::TargetOptions Options;
+  return std::unique_ptr<llvm::LLVMTargetMachine>(
+      static_cast<llvm::LLVMTargetMachine *>(TheTarget->createTargetMachine(
+          TheTriple, CpuName, Features, Options, llvm::Reloc::Model::Static)));
+}
+
+bool LLVMState::canAssemble(const llvm::MCInst &Inst) const {
+  llvm::MCObjectFileInfo ObjectFileInfo;
+  llvm::MCContext Context(AsmInfo.get(), RegInfo.get(), &ObjectFileInfo);
+  std::unique_ptr<const llvm::MCCodeEmitter> CodeEmitter(
+      TheTarget->createMCCodeEmitter(*InstrInfo, *RegInfo, Context));
+  llvm::SmallVector<char, 16> Tmp;
+  llvm::raw_svector_ostream OS(Tmp);
+  llvm::SmallVector<llvm::MCFixup, 4> Fixups;
+  CodeEmitter->encodeInstruction(Inst, OS, Fixups, *SubtargetInfo);
+  return Tmp.size() > 0;
+}
+
+} // namespace exegesis

Added: llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h Wed Apr  4 04:37:06 2018
@@ -0,0 +1,59 @@
+//===-- LlvmState.h ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H
+
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Target/TargetMachine.h"
+#include <memory>
+#include <string>
+
+namespace exegesis {
+
+// An object to initialize LLVM and prepare objects needed to run the
+// measurements.
+class LLVMState {
+public:
+  LLVMState();
+
+  llvm::StringRef getTriple() const { return TheTriple; }
+  llvm::StringRef getCpuName() const { return CpuName; }
+  llvm::StringRef getFeatures() const { return Features; }
+
+  const llvm::MCInstrInfo &getInstrInfo() const { return *InstrInfo; }
+
+  const llvm::MCRegisterInfo &getRegInfo() const { return *RegInfo; }
+
+  const llvm::MCSubtargetInfo &getSubtargetInfo() const {
+    return *SubtargetInfo;
+  }
+
+  std::unique_ptr<llvm::LLVMTargetMachine> createTargetMachine() const;
+
+  bool canAssemble(const llvm::MCInst &mc_inst) const;
+
+private:
+  std::string TheTriple;
+  std::string CpuName;
+  std::string Features;
+  const llvm::Target *TheTarget = nullptr;
+  std::unique_ptr<const llvm::MCSubtargetInfo> SubtargetInfo;
+  std::unique_ptr<const llvm::MCInstrInfo> InstrInfo;
+  std::unique_ptr<const llvm::MCRegisterInfo> RegInfo;
+  std::unique_ptr<const llvm::MCAsmInfo> AsmInfo;
+};
+
+} // namespace exegesis
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H

Added: llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,115 @@
+//===-- OperandGraph.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OperandGraph.h"
+#include "llvm/MC/MCRegisterInfo.h"
+
+namespace exegesis {
+namespace graph {
+
+void Node::dump(const llvm::MCRegisterInfo &RegInfo) const {
+  switch (type()) {
+  case NodeType::VARIABLE:
+    printf(" %d", varValue());
+    break;
+  case NodeType::REG:
+    printf(" %s", RegInfo.getName(regValue()));
+    break;
+  case NodeType::IN:
+    printf(" IN");
+    break;
+  case NodeType::OUT:
+    printf(" OUT");
+    break;
+  }
+}
+
+NodeType Node::type() const { return first; }
+
+int Node::regValue() const {
+  assert(first == NodeType::REG && "regValue() called on non-reg");
+  return second;
+}
+
+int Node::varValue() const {
+  assert(first == NodeType::VARIABLE && "varValue() called on non-var");
+  return second;
+}
+
+void Graph::connect(const Node From, const Node To) {
+  AdjacencyLists[From].insert(To);
+}
+
+void Graph::disconnect(const Node From, const Node To) {
+  AdjacencyLists[From].erase(To);
+}
+
+std::vector<Node> Graph::getPathFrom(const Node From, const Node To) const {
+  std::vector<Node> Path;
+  NodeSet Seen;
+  dfs(From, To, Path, Seen);
+  return Path;
+}
+
+// DFS is implemented recursively, this is fine as graph size is small (~250
+// nodes, ~200 edges, longuest path depth < 10).
+bool Graph::dfs(const Node Current, const Node Sentinel,
+                std::vector<Node> &Path, NodeSet &Seen) const {
+  Path.push_back(Current);
+  Seen.insert(Current);
+  if (Current == Sentinel)
+    return true;
+  if (AdjacencyLists.count(Current)) {
+    for (const Node Next : AdjacencyLists.find(Current)->second) {
+      if (Seen.count(Next))
+        continue;
+      if (dfs(Next, Sentinel, Path, Seen))
+        return true;
+    }
+  }
+  Path.pop_back();
+  return false;
+}
+
+// For each Register Units we walk up their parents.
+// Let's take the case of the A register family:
+//
+//  RAX
+//   ^
+//   EAX
+//    ^
+//    AX
+//   ^  ^
+//  AH  AL
+//
+// Register Units are AH and AL.
+// Walking them up gives the following lists:
+// AH->AX->EAX->RAX and AL->AX->EAX->RAX
+// When walking the lists we add connect current to parent both ways leading to
+// the following connections:
+//
+// AL<->AX, AH<->AX, AX<->EAX, EAX<->RAX
+// We repeat this process for all Unit Registers to cover all connections.
+void setupRegisterAliasing(const llvm::MCRegisterInfo &RegInfo,
+                           Graph &TheGraph) {
+  using SuperItr = llvm::MCSuperRegIterator;
+  for (size_t Reg = 0, E = RegInfo.getNumRegUnits(); Reg < E; ++Reg) {
+    size_t Current = Reg;
+    for (SuperItr Super(Reg, &RegInfo); Super.isValid(); ++Super) {
+      const Node A = Node::Reg(Current);
+      const Node B = Node::Reg(*Super);
+      TheGraph.connect(A, B);
+      TheGraph.connect(B, A);
+      Current = *Super;
+    }
+  }
+}
+
+} // namespace graph
+} // namespace exegesis

Added: llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.h?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.h (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.h Wed Apr  4 04:37:06 2018
@@ -0,0 +1,89 @@
+//===-- OperandGraph.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// A collection of tools to model register aliasing and instruction operand.
+/// This is used to find an aliasing between the input and output registers of
+/// an instruction. It allows us to repeat an instruction and make sure that
+/// successive instances are executed sequentially.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_OPERANDGRAPH_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_OPERANDGRAPH_H
+
+#include "llvm/MC/MCRegisterInfo.h"
+#include <map>
+#include <set>
+#include <tuple>
+#include <vector>
+
+namespace exegesis {
+namespace graph {
+
+enum class NodeType {
+  VARIABLE, // An set of "tied together operands" to resolve.
+  REG,      // A particular register.
+  IN,       // The input node.
+  OUT       // The output node.
+};
+
+// A Node in the graph, it has a type and an int value.
+struct Node : public std::pair<NodeType, int> {
+  using std::pair<NodeType, int>::pair;
+
+  static Node Reg(int Value) { return {NodeType::REG, Value}; }
+  static Node Var(int Value) { return {NodeType::VARIABLE, Value}; }
+  static Node In() { return {NodeType::IN, 0}; }
+  static Node Out() { return {NodeType::OUT, 0}; }
+
+  NodeType type() const;
+  int regValue() const; // checks that type==REG and returns value.
+  int varValue() const; // checks that type==VARIABLE and returns value.
+
+  void dump(const llvm::MCRegisterInfo &RegInfo) const;
+};
+
+// Graph represents the connectivity of registers for a particular instruction.
+// This object is used to select registers that would create a dependency chain
+// between instruction's input and output.
+struct Graph {
+public:
+  void connect(const Node From, const Node To);
+  void disconnect(const Node From, const Node To);
+
+  // Tries to find a path between 'From' and 'To' nodes.
+  // Returns empty if no path is found.
+  std::vector<Node> getPathFrom(const Node From, const Node To) const;
+
+private:
+  // We use std::set to keep the implementation simple, using an unordered_set
+  // requires the definition of a hasher.
+  using NodeSet = std::set<Node>;
+
+  // Performs a Depth First Search from 'current' node up until 'sentinel' node
+  // is found. 'path' is the recording of the traversed nodes, 'seen' is the
+  // collection of nodes seen so far.
+  bool dfs(const Node Current, const Node Sentinel, std::vector<Node> &Path,
+           NodeSet &Seen) const;
+
+  // We use std::map to keep the implementation simple, using an unordered_map
+  // requires the definition of a hasher.
+  std::map<Node, NodeSet> AdjacencyLists;
+};
+
+// Add register nodes to graph and connect them when they alias. Connection is
+// both ways.
+void setupRegisterAliasing(const llvm::MCRegisterInfo &RegInfo,
+                           Graph &TheGraph);
+
+} // namespace graph
+} // namespace exegesis
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_OPERANDGRAPH_H

Added: llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,129 @@
+//===-- PerfHelper.cpp ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PerfHelper.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/raw_ostream.h"
+#ifdef HAVE_LIBPFM
+#include "perfmon/perf_event.h"
+#include "perfmon/pfmlib.h"
+#include "perfmon/pfmlib_perf_event.h"
+#endif
+
+namespace exegesis {
+namespace pfm {
+
+#ifdef HAVE_LIBPFM
+static bool isPfmError(int Code) { return Code != PFM_SUCCESS; }
+#endif
+
+bool pfmInitialize() {
+#ifdef HAVE_LIBPFM
+  return isPfmError(pfm_initialize());
+#else
+  return true;
+#endif
+}
+
+void pfmTerminate() {
+#ifdef HAVE_LIBPFM
+  pfm_terminate();
+#endif
+}
+
+PerfEvent::~PerfEvent() {
+#ifdef HAVE_LIBPFM
+  delete Attr;
+  ;
+#endif
+}
+
+PerfEvent::PerfEvent(PerfEvent &&Other)
+    : EventString(std::move(Other.EventString)),
+      FullQualifiedEventString(std::move(Other.FullQualifiedEventString)),
+      Attr(Other.Attr) {
+  Other.Attr = nullptr;
+}
+
+PerfEvent::PerfEvent(llvm::StringRef PfmEventString)
+    : EventString(PfmEventString.str()), Attr(nullptr) {
+#ifdef HAVE_LIBPFM
+  char *Fstr = nullptr;
+  pfm_perf_encode_arg_t Arg = {};
+  Attr = new perf_event_attr();
+  Arg.attr = Attr;
+  Arg.fstr = &Fstr;
+  Arg.size = sizeof(pfm_perf_encode_arg_t);
+  const int Result = pfm_get_os_event_encoding(EventString.c_str(), PFM_PLM3,
+                                               PFM_OS_PERF_EVENT, &Arg);
+  if (isPfmError(Result)) {
+    // We don't know beforehand which counters are available (e.g. 6 uops ports
+    // on Sandybridge but 8 on Haswell) so we report the missing counter without
+    // crashing.
+    llvm::errs() << pfm_strerror(Result) << " - cannot create event "
+                 << EventString;
+  }
+  if (Fstr) {
+    FullQualifiedEventString = Fstr;
+    free(Fstr);
+  }
+#endif
+}
+
+llvm::StringRef PerfEvent::name() const { return EventString; }
+
+bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); }
+
+const perf_event_attr *PerfEvent::attribute() const { return Attr; }
+
+llvm::StringRef PerfEvent::getPfmEventString() const {
+  return FullQualifiedEventString;
+}
+
+#ifdef HAVE_LIBPFM
+Counter::Counter(const PerfEvent &Event) {
+  const pid_t Pid = 0;    // measure current process/thread.
+  const int Cpu = -1;     // measure any processor.
+  const int GroupFd = -1; // no grouping of counters.
+  const uint32_t Flags = 0;
+  perf_event_attr AttrCopy = *Event.attribute();
+  FileDescriptor = perf_event_open(&AttrCopy, Pid, Cpu, GroupFd, Flags);
+  assert(FileDescriptor != -1 &&
+         "Unable to open event, make sure your kernel allows user space perf "
+         "monitoring.");
+}
+
+Counter::~Counter() { close(FileDescriptor); }
+
+void Counter::start() { ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0); }
+
+void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); }
+
+int64_t Counter::read() const {
+  int64_t Count = 0;
+  ::read(FileDescriptor, &Count, sizeof(Count));
+  return Count;
+}
+
+#else
+
+Counter::Counter(const PerfEvent &Event) : FileDescriptor(-1) {}
+
+Counter::~Counter() = default;
+
+void Counter::start() {}
+
+void Counter::stop() {}
+
+int64_t Counter::read() const { return 42; }
+
+#endif
+
+} // namespace pfm
+} // namespace exegesis

Added: llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.h?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.h (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.h Wed Apr  4 04:37:06 2018
@@ -0,0 +1,103 @@
+//===-- PerfHelper.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Helpers for measuring perf events.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_PERFHELPER_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_PERFHELPER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <functional>
+#include <memory>
+
+struct perf_event_attr;
+
+namespace exegesis {
+namespace pfm {
+
+// Returns true on error.
+bool pfmInitialize();
+void pfmTerminate();
+
+// Retrieves the encoding for the event described by pfm_event_string.
+// NOTE: pfm_initialize() must be called before creating PerfEvent objects.
+class PerfEvent {
+public:
+  // http://perfmon2.sourceforge.net/manv4/libpfm.html
+  // Events are expressed as strings. e.g. "INSTRUCTION_RETIRED"
+  explicit PerfEvent(llvm::StringRef pfm_event_string);
+
+  PerfEvent(const PerfEvent &) = delete;
+  PerfEvent(PerfEvent &&other);
+  ~PerfEvent();
+
+  // The pfm_event_string passed at construction time.
+  llvm::StringRef name() const;
+
+  // Whether the event was successfully created.
+  bool valid() const;
+
+  // The encoded event to be passed to the Kernel.
+  const perf_event_attr *attribute() const;
+
+  // The fully qualified name for the event.
+  // e.g. "snb_ep::INSTRUCTION_RETIRED:e=0:i=0:c=0:t=0:u=1:k=0:mg=0:mh=1"
+  llvm::StringRef getPfmEventString() const;
+
+private:
+  const std::string EventString;
+  std::string FullQualifiedEventString;
+  perf_event_attr *Attr;
+};
+
+// Uses a valid PerfEvent to configure the Kernel so we can measure the
+// underlying event.
+struct Counter {
+  // event: the PerfEvent to measure.
+  explicit Counter(const PerfEvent &event);
+
+  Counter(const Counter &) = delete;
+  Counter(Counter &&other) = default;
+
+  ~Counter();
+
+  void start();         // Starts the measurement of the event.
+  void stop();          // Stops the measurement of the event.
+  int64_t read() const; // Return the current value of the counter.
+
+private:
+  int FileDescriptor = -1;
+};
+
+// Helper to measure a list of PerfEvent for a particular function.
+// callback is called for each successful measure (PerfEvent needs to be valid).
+template <typename Function>
+void Measure(
+    llvm::ArrayRef<PerfEvent> Events,
+    const std::function<void(const PerfEvent &Event, int64_t Value)> &Callback,
+    Function Fn) {
+  for (const auto &Event : Events) {
+    if (!Event.valid())
+      continue;
+    Counter Cnt(Event);
+    Cnt.start();
+    Fn();
+    Cnt.stop();
+    Callback(Event, Cnt.read());
+  }
+}
+
+} // namespace pfm
+} // namespace exegesis
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_PERFHELPER_H

Added: llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,248 @@
+//===-- Uops.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Uops.h"
+#include "BenchmarkResult.h"
+#include "InstructionSnippetGenerator.h"
+#include "PerfHelper.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCSchedule.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <random>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace exegesis {
+
+// FIXME: Handle memory (see PR36906)
+static bool isInvalidOperand(const llvm::MCOperandInfo &OpInfo) {
+  switch (OpInfo.OperandType) {
+  default:
+    return true;
+  case llvm::MCOI::OPERAND_IMMEDIATE:
+  case llvm::MCOI::OPERAND_REGISTER:
+    return false;
+  }
+}
+
+static llvm::Error makeError(llvm::Twine Msg) {
+  return llvm::make_error<llvm::StringError>(Msg,
+                                             llvm::inconvertibleErrorCode());
+}
+
+// FIXME: Read the counter names from the ProcResourceUnits when PR36984 is
+// fixed.
+static const std::string *getEventNameFromProcResName(const char *ProcResName) {
+  static const std::unordered_map<std::string, std::string> Entries = {
+      {"SBPort0", "UOPS_DISPATCHED_PORT:PORT_0"},
+      {"SBPort1", "UOPS_DISPATCHED_PORT:PORT_1"},
+      {"SBPort4", "UOPS_DISPATCHED_PORT:PORT_4"},
+      {"SBPort5", "UOPS_DISPATCHED_PORT:PORT_5"},
+      {"HWPort0", "UOPS_DISPATCHED_PORT:PORT_0"},
+      {"HWPort1", "UOPS_DISPATCHED_PORT:PORT_1"},
+      {"HWPort2", "UOPS_DISPATCHED_PORT:PORT_2"},
+      {"HWPort3", "UOPS_DISPATCHED_PORT:PORT_3"},
+      {"HWPort4", "UOPS_DISPATCHED_PORT:PORT_4"},
+      {"HWPort5", "UOPS_DISPATCHED_PORT:PORT_5"},
+      {"HWPort6", "UOPS_DISPATCHED_PORT:PORT_6"},
+      {"HWPort7", "UOPS_DISPATCHED_PORT:PORT_7"},
+      {"SKLPort0", "UOPS_DISPATCHED_PORT:PORT_0"},
+      {"SKLPort1", "UOPS_DISPATCHED_PORT:PORT_1"},
+      {"SKLPort2", "UOPS_DISPATCHED_PORT:PORT_2"},
+      {"SKLPort3", "UOPS_DISPATCHED_PORT:PORT_3"},
+      {"SKLPort4", "UOPS_DISPATCHED_PORT:PORT_4"},
+      {"SKLPort5", "UOPS_DISPATCHED_PORT:PORT_5"},
+      {"SKLPort6", "UOPS_DISPATCHED_PORT:PORT_6"},
+      {"SKXPort7", "UOPS_DISPATCHED_PORT:PORT_7"},
+      {"SKXPort0", "UOPS_DISPATCHED_PORT:PORT_0"},
+      {"SKXPort1", "UOPS_DISPATCHED_PORT:PORT_1"},
+      {"SKXPort2", "UOPS_DISPATCHED_PORT:PORT_2"},
+      {"SKXPort3", "UOPS_DISPATCHED_PORT:PORT_3"},
+      {"SKXPort4", "UOPS_DISPATCHED_PORT:PORT_4"},
+      {"SKXPort5", "UOPS_DISPATCHED_PORT:PORT_5"},
+      {"SKXPort6", "UOPS_DISPATCHED_PORT:PORT_6"},
+      {"SKXPort7", "UOPS_DISPATCHED_PORT:PORT_7"},
+  };
+  const auto It = Entries.find(ProcResName);
+  return It == Entries.end() ? nullptr : &It->second;
+}
+
+static std::vector<llvm::MCInst> generateIndependentAssignments(
+    const LLVMState &State, const llvm::MCInstrDesc &InstrDesc,
+    llvm::SmallVector<Variable, 8> Vars, int MaxAssignments) {
+  std::unordered_set<llvm::MCPhysReg> IsUsedByAnyVar;
+  for (const Variable &Var : Vars) {
+    if (Var.IsUse) {
+      IsUsedByAnyVar.insert(Var.PossibleRegisters.begin(),
+                            Var.PossibleRegisters.end());
+    }
+  }
+
+  std::vector<llvm::MCInst> Pattern;
+  for (int A = 0; A < MaxAssignments; ++A) {
+    // FIXME: This is a bit pessimistic. We should get away with an
+    // assignment that ensures that the set of assigned registers for uses and
+    // the set of assigned registers for defs do not intersect (registers
+    // for uses (resp defs) do not have to be all distinct).
+    const std::vector<llvm::MCPhysReg> Regs = getExclusiveAssignment(Vars);
+    if (Regs.empty())
+      break;
+    // Remove all assigned registers defs that are used by at least one other
+    // variable from the list of possible variable registers. This ensures that
+    // we never create a RAW hazard that would lead to serialization.
+    for (size_t I = 0, E = Vars.size(); I < E; ++I) {
+      llvm::MCPhysReg Reg = Regs[I];
+      if (Vars[I].IsDef && IsUsedByAnyVar.count(Reg)) {
+        Vars[I].PossibleRegisters.remove(Reg);
+      }
+    }
+    // Create an MCInst and check assembly.
+    llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs);
+    if (!State.canAssemble(Inst))
+      continue;
+    Pattern.push_back(std::move(Inst));
+  }
+  return Pattern;
+}
+
+UopsBenchmarkRunner::~UopsBenchmarkRunner() = default;
+
+const char *UopsBenchmarkRunner::getDisplayName() const { return "uops"; }
+
+llvm::Expected<std::vector<llvm::MCInst>> UopsBenchmarkRunner::createCode(
+    const LLVMState &State, const unsigned OpcodeIndex,
+    const unsigned NumRepetitions, const JitFunctionContext &Context) const {
+  const auto &InstrInfo = State.getInstrInfo();
+  const auto &RegInfo = State.getRegInfo();
+  const llvm::MCInstrDesc &InstrDesc = InstrInfo.get(OpcodeIndex);
+  for (const llvm::MCOperandInfo &OpInfo : InstrDesc.operands()) {
+    if (isInvalidOperand(OpInfo))
+      return makeError("Only registers and immediates are supported");
+  }
+
+  // FIXME: Load constants into registers (e.g. with fld1) to not break
+  // instructions like x87.
+
+  // Ideally we would like the only limitation on executing uops to be the issue
+  // ports. Maximizing port pressure increases the likelihood that the load is
+  // distributed evenly across possible ports.
+
+  // To achieve that, one approach is to generate instructions that do not have
+  // data dependencies between them.
+  //
+  // For some instructions, this is trivial:
+  //    mov rax, qword ptr [rsi]
+  //    mov rax, qword ptr [rsi]
+  //    mov rax, qword ptr [rsi]
+  //    mov rax, qword ptr [rsi]
+  // For the above snippet, haswell just renames rax four times and executes the
+  // four instructions two at a time on P23 and P0126.
+  //
+  // For some instructions, we just need to make sure that the source is
+  // different from the destination. For example, IDIV8r reads from GPR and
+  // writes to AX. We just need to ensure that the variable is assigned a
+  // register which is different from AX:
+  //    idiv bx
+  //    idiv bx
+  //    idiv bx
+  //    idiv bx
+  // The above snippet will be able to fully saturate the ports, while the same
+  // with ax would issue one uop every `latency(IDIV8r)` cycles.
+  //
+  // Some instructions make this harder because they both read and write from
+  // the same register:
+  //    inc rax
+  //    inc rax
+  //    inc rax
+  //    inc rax
+  // This has a data dependency from each instruction to the next, limit the
+  // number of instructions that can be issued in parallel.
+  // It turns out that this is not a big issue on recent Intel CPUs because they
+  // have heuristics to balance port pressure. In the snippet above, subsequent
+  // instructions will end up evenly distributed on {P0,P1,P5,P6}, but some CPUs
+  // might end up executing them all on P0 (just because they can), or try
+  // avoiding P5 because it's usually under high pressure from vector
+  // instructions.
+  // This issue is even more important for high-latency instructions because
+  // they increase the idle time of the CPU, e.g. :
+  //    imul rax, rbx
+  //    imul rax, rbx
+  //    imul rax, rbx
+  //    imul rax, rbx
+  //
+  // To avoid that, we do the renaming statically by generating as many
+  // independent exclusive assignments as possible (until all possible registers
+  // are exhausted) e.g.:
+  //    imul rax, rbx
+  //    imul rcx, rbx
+  //    imul rdx, rbx
+  //    imul r8,  rbx
+  //
+  // Some instruction even make the above static renaming impossible because
+  // they implicitly read and write from the same operand, e.g. ADC16rr reads
+  // and writes from EFLAGS.
+  // In that case we just use a greedy register assignment and hope for the
+  // best.
+
+  const auto Vars = getVariables(RegInfo, InstrDesc, Context.getReservedRegs());
+
+  // Generate as many independent exclusive assignments as possible.
+  constexpr const int MaxStaticRenames = 20;
+  std::vector<llvm::MCInst> Pattern =
+      generateIndependentAssignments(State, InstrDesc, Vars, MaxStaticRenames);
+  if (Pattern.empty()) {
+    // We don't even have a single exclusive assignment, fallback to a greedy
+    // assignment.
+    // FIXME: Tell the user about this decision to help debugging.
+    const std::vector<llvm::MCPhysReg> Regs = getGreedyAssignment(Vars);
+    if (!Vars.empty() && Regs.empty())
+      return makeError("No feasible greedy assignment");
+    llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs);
+    if (!State.canAssemble(Inst))
+      return makeError("Cannot assemble greedy assignment");
+    Pattern.push_back(std::move(Inst));
+  }
+
+  // Generate repetitions of the pattern until benchmark_iterations is reached.
+  std::vector<llvm::MCInst> Result;
+  Result.reserve(NumRepetitions);
+  for (unsigned I = 0; I < NumRepetitions; ++I)
+    Result.push_back(Pattern[I % Pattern.size()]);
+  return Result;
+}
+
+std::vector<BenchmarkMeasure>
+UopsBenchmarkRunner::runMeasurements(const LLVMState &State,
+                                     const JitFunction &Function,
+                                     const unsigned NumRepetitions) const {
+  const auto &SchedModel = State.getSubtargetInfo().getSchedModel();
+
+  std::vector<BenchmarkMeasure> Result;
+  for (unsigned ProcResIdx = 1;
+       ProcResIdx < SchedModel.getNumProcResourceKinds(); ++ProcResIdx) {
+    const llvm::MCProcResourceDesc &ProcRes =
+        *SchedModel.getProcResource(ProcResIdx);
+    const std::string *const EventName =
+        getEventNameFromProcResName(ProcRes.Name);
+    if (!EventName)
+      continue;
+    pfm::Counter Counter{pfm::PerfEvent(*EventName)};
+    Counter.start();
+    Function();
+    Counter.stop();
+    Result.push_back({llvm::itostr(ProcResIdx),
+                      static_cast<double>(Counter.read()) / NumRepetitions,
+                      ProcRes.Name});
+  }
+  return Result;
+}
+
+} // namespace exegesis

Added: llvm/trunk/tools/llvm-exegesis/lib/Uops.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.h?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.h (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.h Wed Apr  4 04:37:06 2018
@@ -0,0 +1,41 @@
+//===-- Uops.h --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// A BenchmarkRunner implementation to measure uop decomposition.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_UOPS_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_UOPS_H
+
+#include "BenchmarkRunner.h"
+
+namespace exegesis {
+
+class UopsBenchmarkRunner : public BenchmarkRunner {
+public:
+  ~UopsBenchmarkRunner() override;
+
+private:
+  const char *getDisplayName() const override;
+
+  llvm::Expected<std::vector<llvm::MCInst>>
+  createCode(const LLVMState &State, unsigned OpcodeIndex,
+             unsigned NumRepetitions,
+             const JitFunctionContext &Context) const override;
+
+  std::vector<BenchmarkMeasure>
+  runMeasurements(const LLVMState &State, const JitFunction &Function,
+                  unsigned NumRepetitions) const override;
+};
+
+} // namespace exegesis
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_UOPS_H

Added: llvm/trunk/tools/llvm-exegesis/lib/X86.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/X86.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/X86.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/X86.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,38 @@
+//===-- X86.cpp --------------------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+
+namespace exegesis {
+
+static llvm::Error makeError(llvm::Twine Msg) {
+  return llvm::make_error<llvm::StringError>(Msg,
+                                             llvm::inconvertibleErrorCode());
+}
+
+X86Filter::~X86Filter() = default;
+
+// Test whether we can generate a snippet for this instruction.
+llvm::Error X86Filter::shouldRun(const LLVMState &State,
+                                 const unsigned Opcode) const {
+  const auto &InstrInfo = State.getInstrInfo();
+  const llvm::MCInstrDesc &InstrDesc = InstrInfo.get(Opcode);
+  if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())
+    return makeError("Unsupported opcode: isBranch/isIndirectBranch");
+  if (InstrDesc.isCall() || InstrDesc.isReturn())
+    return makeError("Unsupported opcode: isCall/isReturn");
+  const auto OpcodeName = InstrInfo.getName(Opcode);
+  if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") ||
+      OpcodeName.startswith("ADJCALLSTACK")) {
+    return makeError("Unsupported opcode: Push/Pop/AdjCallStack");
+  }
+  return llvm::ErrorSuccess();
+}
+
+} // namespace exegesis

Added: llvm/trunk/tools/llvm-exegesis/lib/X86.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/X86.h?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/X86.h (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/X86.h Wed Apr  4 04:37:06 2018
@@ -0,0 +1,32 @@
+//===-- X86.h ---------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// X86 target-specific setup.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_X86_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_X86_H
+
+#include "BenchmarkRunner.h"
+#include "LlvmState.h"
+
+namespace exegesis {
+
+class X86Filter : public BenchmarkRunner::InstructionFilter {
+public:
+  ~X86Filter() override;
+
+  llvm::Error shouldRun(const LLVMState &State, unsigned Opcode) const override;
+};
+
+} // namespace exegesis
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_X86_H

Added: llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,114 @@
+//===-- llvm-exegesis.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Measures execution properties (latencies/uops) of an instruction.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lib/BenchmarkResult.h"
+#include "lib/BenchmarkRunner.h"
+#include "lib/Latency.h"
+#include "lib/LlvmState.h"
+#include "lib/PerfHelper.h"
+#include "lib/Uops.h"
+#include "lib/X86.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetSelect.h"
+#include <algorithm>
+#include <random>
+#include <string>
+#include <unordered_map>
+
+static llvm::cl::opt<unsigned>
+    OpcodeIndex("opcode-index", llvm::cl::desc("opcode to measure, by index"),
+                llvm::cl::init(0));
+
+static llvm::cl::opt<std::string>
+    OpcodeName("opcode-name", llvm::cl::desc("opcode to measure, by name"),
+               llvm::cl::init(""));
+
+enum class BenchmarkModeE { Latency, Uops };
+static llvm::cl::opt<BenchmarkModeE>
+    BenchmarkMode("benchmark-mode", llvm::cl::desc("the benchmark mode to run"),
+                  llvm::cl::values(clEnumValN(BenchmarkModeE::Latency,
+                                              "latency", "Instruction Latency"),
+                                   clEnumValN(BenchmarkModeE::Uops, "uops",
+                                              "Uop Decomposition")));
+
+static llvm::cl::opt<unsigned>
+    NumRepetitions("num-repetitions",
+                   llvm::cl::desc("number of time to repeat the asm snippet"),
+                   llvm::cl::init(10000));
+
+namespace exegesis {
+
+void main() {
+  if (OpcodeName.empty() == (OpcodeIndex == 0)) {
+    llvm::report_fatal_error(
+        "please provide one and only one of 'opcode-index' or 'opcode-name' ");
+  }
+
+  llvm::InitializeNativeTarget();
+  llvm::InitializeNativeTargetAsmPrinter();
+
+  // FIXME: Target-specific filter.
+  X86Filter Filter;
+
+  const LLVMState State;
+
+  unsigned Opcode = OpcodeIndex;
+  if (Opcode == 0) {
+    // Resolve opcode name -> opcode.
+    for (unsigned I = 0, E = State.getInstrInfo().getNumOpcodes(); I < E; ++I) {
+      if (State.getInstrInfo().getName(I) == OpcodeName) {
+        Opcode = I;
+        break;
+      }
+    }
+    if (Opcode == 0) {
+      llvm::report_fatal_error(
+          llvm::Twine("unknown opcode ").concat(OpcodeName));
+    }
+  }
+
+  std::unique_ptr<BenchmarkRunner> Runner;
+  switch (BenchmarkMode) {
+  case BenchmarkModeE::Latency:
+    Runner = llvm::make_unique<LatencyBenchmarkRunner>();
+    break;
+  case BenchmarkModeE::Uops:
+    Runner = llvm::make_unique<UopsBenchmarkRunner>();
+    break;
+  }
+
+  Runner->run(State, Opcode, NumRepetitions > 0 ? NumRepetitions : 1, Filter)
+      .writeYamlOrDie("-");
+}
+
+} // namespace exegesis
+
+int main(int Argc, char **Argv) {
+  llvm::cl::ParseCommandLineOptions(Argc, Argv, "");
+
+  if (exegesis::pfm::pfmInitialize()) {
+    llvm::errs() << "cannot initialize libpfm\n";
+    return EXIT_FAILURE;
+  }
+
+  exegesis::main();
+
+  exegesis::pfm::pfmTerminate();
+  return EXIT_SUCCESS;
+}

Modified: llvm/trunk/unittests/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/CMakeLists.txt?rev=329169&r1=329168&r2=329169&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/CMakeLists.txt (original)
+++ llvm/trunk/unittests/tools/CMakeLists.txt Wed Apr  4 04:37:06 2018
@@ -1,4 +1,9 @@
 if(LLVM_TARGETS_TO_BUILD MATCHES "X86")
-  add_subdirectory(llvm-cfi-verify)
+  add_subdirectory(
+    llvm-cfi-verify
+  )
+  add_subdirectory(
+    llvm-exegesis
+  )
 endif()
 

Added: llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp (added)
+++ llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,54 @@
+//===-- BenchmarkResultTest.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/SmallString.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace exegesis {
+
+bool operator==(const BenchmarkMeasure &A, const BenchmarkMeasure &B) {
+  return std::tie(A.Key, A.Value) == std::tie(B.Key, B.Value);
+}
+
+namespace {
+
+TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
+  InstructionBenchmark ToDisk;
+
+  ToDisk.AsmTmpl.Name = "name";
+  ToDisk.CpuName = "cpu_name";
+  ToDisk.LLVMTriple = "llvm_triple";
+  ToDisk.NumRepetitions = 1;
+  ToDisk.Measurements.push_back(BenchmarkMeasure{"a", 1, "debug a"});
+  ToDisk.Measurements.push_back(BenchmarkMeasure{"b", 2});
+  ToDisk.Error = "error";
+
+  const llvm::StringRef Filename("data.yaml");
+
+  ToDisk.writeYamlOrDie(Filename);
+
+  {
+    const auto FromDisk = InstructionBenchmark::readYamlOrDie(Filename);
+
+    EXPECT_EQ(FromDisk.AsmTmpl.Name, ToDisk.AsmTmpl.Name);
+    EXPECT_EQ(FromDisk.CpuName, ToDisk.CpuName);
+    EXPECT_EQ(FromDisk.LLVMTriple, ToDisk.LLVMTriple);
+    EXPECT_EQ(FromDisk.NumRepetitions, ToDisk.NumRepetitions);
+    EXPECT_THAT(FromDisk.Measurements, ToDisk.Measurements);
+    EXPECT_THAT(FromDisk.Error, ToDisk.Error);
+  }
+}
+
+} // namespace
+} // namespace exegesis

Added: llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt?rev=329169&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt (added)
+++ llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt Wed Apr  4 04:37:06 2018
@@ -0,0 +1,28 @@
+include_directories(
+  ${CMAKE_SOURCE_DIR}/lib/Target/X86
+  ${CMAKE_BINARY_DIR}/lib/Target/X86
+  ${CMAKE_SOURCE_DIR}/tools/llvm-exegesis/lib
+  )
+
+set(LLVM_LINK_COMPONENTS
+  MC
+  MCParser
+  Object
+  Support
+  Symbolize
+  native
+  )
+
+add_llvm_unittest(LLVMExegesisTests
+  BenchmarkResultTest.cpp
+  InMemoryAssemblerTest.cpp
+  InstructionSnippetGeneratorTest.cpp
+  OperandGraphTest.cpp
+  PerfHelperTest.cpp
+  )
+target_link_libraries(LLVMExegesisTests PRIVATE LLVMExegesis)
+
+if(HAVE_LIBPFM)
+  target_link_libraries(LLVMExegesisTests PRIVATE pfm)
+endif()
+

Added: llvm/trunk/unittests/tools/llvm-exegesis/InMemoryAssemblerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/InMemoryAssemblerTest.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/InMemoryAssemblerTest.cpp (added)
+++ llvm/trunk/unittests/tools/llvm-exegesis/InMemoryAssemblerTest.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,97 @@
+//===-- InMemoryAssemblerTest.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 "X86InstrInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+namespace exegesis {
+namespace {
+
+using llvm::MCInstBuilder;
+using llvm::X86::EAX;
+using llvm::X86::MOV32ri;
+using llvm::X86::MOV64ri32;
+using llvm::X86::RAX;
+using llvm::X86::XOR32rr;
+using testing::ElementsAre;
+
+class MachineFunctionGeneratorTest : public ::testing::Test {
+protected:
+  MachineFunctionGeneratorTest()
+      : TT(llvm::sys::getProcessTriple()),
+        CpuName(llvm::sys::getHostCPUName().str()) {}
+
+  static void SetUpTestCase() {
+    llvm::InitializeNativeTarget();
+    llvm::InitializeNativeTargetAsmPrinter();
+  }
+
+  std::unique_ptr<llvm::LLVMTargetMachine> createTargetMachine() {
+    std::string Error;
+    const llvm::Target *TheTarget =
+        llvm::TargetRegistry::lookupTarget(TT, Error);
+    assert(TheTarget);
+    const llvm::TargetOptions Options;
+    return std::unique_ptr<llvm::LLVMTargetMachine>(
+        static_cast<llvm::LLVMTargetMachine *>(TheTarget->createTargetMachine(
+            TT, CpuName, "", Options, llvm::Reloc::Model::Static)));
+  }
+
+private:
+  const std::string TT;
+  const std::string CpuName;
+};
+
+TEST_F(MachineFunctionGeneratorTest, JitFunction) {
+  JitFunctionContext Context(createTargetMachine());
+  JitFunction Function(std::move(Context), {});
+  ASSERT_THAT(Function.getFunctionBytes().str(), ElementsAre(0xc3));
+  Function();
+}
+
+TEST_F(MachineFunctionGeneratorTest, JitFunctionXOR32rr) {
+  JitFunctionContext Context(createTargetMachine());
+  JitFunction Function(
+      std::move(Context),
+      {MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX)});
+  ASSERT_THAT(Function.getFunctionBytes().str(), ElementsAre(0x31, 0xc0, 0xc3));
+  Function();
+}
+
+TEST_F(MachineFunctionGeneratorTest, JitFunctionMOV64ri) {
+  JitFunctionContext Context(createTargetMachine());
+  JitFunction Function(std::move(Context),
+                       {MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42)});
+  ASSERT_THAT(Function.getFunctionBytes().str(),
+              ElementsAre(0x48, 0xc7, 0xc0, 0x2a, 0x00, 0x00, 0x00, 0xc3));
+  Function();
+}
+
+TEST_F(MachineFunctionGeneratorTest, JitFunctionMOV32ri) {
+  JitFunctionContext Context(createTargetMachine());
+  JitFunction Function(std::move(Context),
+                       {MCInstBuilder(MOV32ri).addReg(EAX).addImm(42)});
+  ASSERT_THAT(Function.getFunctionBytes().str(),
+              ElementsAre(0xb8, 0x2a, 0x00, 0x00, 0x00, 0xc3));
+  Function();
+}
+
+} // namespace
+} // namespace exegesis

Added: llvm/trunk/unittests/tools/llvm-exegesis/InstructionSnippetGeneratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/InstructionSnippetGeneratorTest.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/InstructionSnippetGeneratorTest.cpp (added)
+++ llvm/trunk/unittests/tools/llvm-exegesis/InstructionSnippetGeneratorTest.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,307 @@
+//===-- InstructionSnippetGeneratorTest.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 "X86InstrInfo.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <set>
+
+namespace llvm {
+
+bool operator==(const MCOperand &A, const MCOperand &B) {
+  if ((A.isValid() == false) && (B.isValid() == false))
+    return true;
+  if (A.isReg() && B.isReg())
+    return A.getReg() == B.getReg();
+  if (A.isImm() && B.isImm())
+    return A.getImm() == B.getImm();
+  return false;
+}
+
+} // namespace llvm
+
+namespace exegesis {
+namespace {
+
+using testing::_;
+using testing::AllOf;
+using testing::AnyOf;
+using testing::Contains;
+using testing::ElementsAre;
+using testing::Eq;
+using testing::Field;
+using testing::Not;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
+using testing::Value;
+
+using llvm::X86::AL;
+using llvm::X86::AX;
+using llvm::X86::EFLAGS;
+using llvm::X86::RAX;
+
+class MCInstrDescViewTest : public ::testing::Test {
+protected:
+  MCInstrDescViewTest()
+      : TheTriple(llvm::sys::getProcessTriple()),
+        CpuName(llvm::sys::getHostCPUName().str()) {}
+
+  void SetUp() override {
+    llvm::InitializeNativeTarget();
+
+    std::string Error;
+    const auto *Target = llvm::TargetRegistry::lookupTarget(TheTriple, Error);
+    InstrInfo.reset(Target->createMCInstrInfo());
+    RegInfo.reset(Target->createMCRegInfo(TheTriple));
+  }
+
+  const std::string TheTriple;
+  const std::string CpuName;
+  std::unique_ptr<const llvm::MCInstrInfo> InstrInfo;
+  std::unique_ptr<const llvm::MCRegisterInfo> RegInfo;
+};
+
+MATCHER(IsDef, "") { return arg.IsDef; }
+MATCHER(IsUse, "") { return arg.IsUse; }
+MATCHER_P2(EqVarAssignement, VariableIndexMatcher, AssignedRegisterMatcher,
+           "") {
+  return Value(
+      arg,
+      AllOf(Field(&VariableAssignment::VarIdx, VariableIndexMatcher),
+            Field(&VariableAssignment::AssignedReg, AssignedRegisterMatcher)));
+}
+
+size_t returnIndexZero(const size_t UpperBound) { return 0; }
+
+TEST_F(MCInstrDescViewTest, XOR64rr) {
+  const llvm::MCInstrDesc &InstrDesc = InstrInfo->get(llvm::X86::XOR64rr);
+  const auto Vars =
+      getVariables(*RegInfo, InstrDesc, llvm::BitVector(RegInfo->getNumRegs()));
+
+  // XOR64rr has the following operands:
+  //  0. out register
+  //  1. in register (tied to out)
+  //  2. in register
+  //  3. out EFLAGS (implicit)
+  //
+  // This translates to 3 variables, one for 0 and 1, one for 2, one for 3.
+  ASSERT_THAT(Vars, SizeIs(3));
+
+  EXPECT_THAT(Vars[0].ExplicitOperands, ElementsAre(0, 1));
+  EXPECT_THAT(Vars[1].ExplicitOperands, ElementsAre(2));
+  EXPECT_THAT(Vars[2].ExplicitOperands, ElementsAre()); // implicit
+
+  EXPECT_THAT(Vars[0], AllOf(IsUse(), IsDef()));
+  EXPECT_THAT(Vars[1], AllOf(IsUse(), Not(IsDef())));
+  EXPECT_THAT(Vars[2], AllOf(Not(IsUse()), IsDef()));
+
+  EXPECT_THAT(Vars[0].PossibleRegisters, Contains(RAX));
+  EXPECT_THAT(Vars[1].PossibleRegisters, Contains(RAX));
+  EXPECT_THAT(Vars[2].PossibleRegisters, ElementsAre(EFLAGS));
+
+  // Computing chains.
+  const auto Chains = computeSequentialAssignmentChains(*RegInfo, Vars);
+
+  // Because operands 0 and 1 are tied together any possible value for variable
+  // 0 would do.
+  for (const auto &Reg : Vars[0].PossibleRegisters) {
+    EXPECT_THAT(Chains, Contains(ElementsAre(EqVarAssignement(0, Reg))));
+  }
+
+  // We also have chains going through operand 0 to 2 (i.e. Vars 0 and 1).
+  EXPECT_THAT(Vars[0].PossibleRegisters, Eq(Vars[1].PossibleRegisters))
+      << "Variables 0 and 1 are of the same class";
+  for (const auto &Reg : Vars[0].PossibleRegisters) {
+    EXPECT_THAT(Chains,
+                Contains(UnorderedElementsAre(EqVarAssignement(0, Reg),
+                                              EqVarAssignement(1, Reg))));
+  }
+
+  // EFLAGS does not appear as an input therefore no chain can contain EFLAGS.
+  EXPECT_THAT(Chains, Not(Contains(Contains(EqVarAssignement(_, EFLAGS)))));
+
+  // Computing assignment.
+  const auto Regs = getRandomAssignment(Vars, Chains, &returnIndexZero);
+  EXPECT_THAT(Regs, ElementsAre(RAX, RAX, EFLAGS));
+
+  // Generating assembler representation.
+  const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs);
+  EXPECT_THAT(Inst.getOpcode(), llvm::X86::XOR64rr);
+  EXPECT_THAT(Inst.getNumOperands(), 3);
+  EXPECT_THAT(Inst.getOperand(0), llvm::MCOperand::createReg(RAX));
+  EXPECT_THAT(Inst.getOperand(1), llvm::MCOperand::createReg(RAX));
+  EXPECT_THAT(Inst.getOperand(2), llvm::MCOperand::createReg(RAX));
+}
+
+TEST_F(MCInstrDescViewTest, AAA) {
+  const llvm::MCInstrDesc &InstrDesc = InstrInfo->get(llvm::X86::AAA);
+  const auto Vars =
+      getVariables(*RegInfo, InstrDesc, llvm::BitVector(RegInfo->getNumRegs()));
+
+  // AAA has the following operands:
+  //  0. out AX      (implicit)
+  //  1. out EFLAGS  (implicit)
+  //  2. in AL       (implicit)
+  //  3. in EFLAGS   (implicit)
+  //
+  // This translates to 4 Vars (non are tied together).
+  ASSERT_THAT(Vars, SizeIs(4));
+
+  EXPECT_THAT(Vars[0].ExplicitOperands, ElementsAre()); // implicit
+  EXPECT_THAT(Vars[1].ExplicitOperands, ElementsAre()); // implicit
+  EXPECT_THAT(Vars[2].ExplicitOperands, ElementsAre()); // implicit
+  EXPECT_THAT(Vars[3].ExplicitOperands, ElementsAre()); // implicit
+
+  EXPECT_THAT(Vars[0], AllOf(Not(IsUse()), IsDef()));
+  EXPECT_THAT(Vars[1], AllOf(Not(IsUse()), IsDef()));
+  EXPECT_THAT(Vars[2], AllOf(IsUse(), Not(IsDef())));
+  EXPECT_THAT(Vars[3], AllOf(IsUse(), Not(IsDef())));
+
+  EXPECT_THAT(Vars[0].PossibleRegisters, ElementsAre(AX));
+  EXPECT_THAT(Vars[1].PossibleRegisters, ElementsAre(EFLAGS));
+  EXPECT_THAT(Vars[2].PossibleRegisters, ElementsAre(AL));
+  EXPECT_THAT(Vars[3].PossibleRegisters, ElementsAre(EFLAGS));
+
+  const auto Chains = computeSequentialAssignmentChains(*RegInfo, Vars);
+  EXPECT_THAT(Chains,
+              ElementsAre(UnorderedElementsAre(EqVarAssignement(0, AX),
+                                               EqVarAssignement(2, AL)),
+                          UnorderedElementsAre(EqVarAssignement(1, EFLAGS),
+                                               EqVarAssignement(3, EFLAGS))));
+
+  // Computing assignment.
+  const auto Regs = getRandomAssignment(Vars, Chains, &returnIndexZero);
+  EXPECT_THAT(Regs, ElementsAre(AX, EFLAGS, AL, EFLAGS));
+
+  // Generating assembler representation.
+  const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs);
+  EXPECT_THAT(Inst.getOpcode(), llvm::X86::AAA);
+  EXPECT_THAT(Inst.getNumOperands(), 0) << "All operands are implicit";
+}
+
+TEST_F(MCInstrDescViewTest, ReservedRegisters) {
+  llvm::BitVector ReservedRegisters(RegInfo->getNumRegs());
+
+  const llvm::MCInstrDesc &InstrDesc = InstrInfo->get(llvm::X86::XOR64rr);
+  {
+    const auto Vars = getVariables(*RegInfo, InstrDesc, ReservedRegisters);
+    ASSERT_THAT(Vars, SizeIs(3));
+    EXPECT_THAT(Vars[0].PossibleRegisters, Contains(RAX));
+    EXPECT_THAT(Vars[1].PossibleRegisters, Contains(RAX));
+  }
+
+  // Disable RAX.
+  ReservedRegisters.set(RAX);
+  {
+    const auto Vars = getVariables(*RegInfo, InstrDesc, ReservedRegisters);
+    ASSERT_THAT(Vars, SizeIs(3));
+    EXPECT_THAT(Vars[0].PossibleRegisters, Not(Contains(RAX)));
+    EXPECT_THAT(Vars[1].PossibleRegisters, Not(Contains(RAX)));
+  }
+}
+
+Variable makeVariableWithRegisters(bool IsReg,
+                                   std::initializer_list<int> Regs) {
+  assert((IsReg || (Regs.size() == 0)) && "IsReg => !(Regs.size() == 0)");
+  Variable Var;
+  Var.IsReg = IsReg;
+  Var.PossibleRegisters.insert(Regs.begin(), Regs.end());
+  return Var;
+}
+
+TEST(getExclusiveAssignment, TriviallyFeasible) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(true, {3}),
+      makeVariableWithRegisters(false, {}),
+      makeVariableWithRegisters(true, {4}),
+      makeVariableWithRegisters(true, {5}),
+  };
+  const auto Regs = getExclusiveAssignment(Vars);
+  EXPECT_THAT(Regs, ElementsAre(3, 0, 4, 5));
+}
+
+TEST(getExclusiveAssignment, TriviallyInfeasible1) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(true, {3}),
+      makeVariableWithRegisters(true, {}),
+      makeVariableWithRegisters(true, {4}),
+      makeVariableWithRegisters(true, {5}),
+  };
+  const auto Regs = getExclusiveAssignment(Vars);
+  EXPECT_THAT(Regs, ElementsAre());
+}
+
+TEST(getExclusiveAssignment, TriviallyInfeasible) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(true, {4}),
+      makeVariableWithRegisters(true, {4}),
+  };
+  const auto Regs = getExclusiveAssignment(Vars);
+  EXPECT_THAT(Regs, ElementsAre());
+}
+
+TEST(getExclusiveAssignment, Feasible1) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(true, {4, 3}),
+      makeVariableWithRegisters(true, {6, 3}),
+      makeVariableWithRegisters(true, {6, 4}),
+  };
+  const auto Regs = getExclusiveAssignment(Vars);
+  ASSERT_THAT(Regs, AnyOf(ElementsAre(3, 6, 4), ElementsAre(4, 3, 6)));
+}
+
+TEST(getExclusiveAssignment, Feasible2) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(true, {1, 2}),
+      makeVariableWithRegisters(true, {3, 4}),
+  };
+  const auto Regs = getExclusiveAssignment(Vars);
+  ASSERT_THAT(Regs, AnyOf(ElementsAre(1, 3), ElementsAre(1, 4),
+                          ElementsAre(2, 3), ElementsAre(2, 4)));
+}
+
+TEST(getGreedyAssignment, Infeasible) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(true, {}),
+      makeVariableWithRegisters(true, {1, 2}),
+  };
+  const auto Regs = getGreedyAssignment(Vars);
+  ASSERT_THAT(Regs, ElementsAre());
+}
+
+TEST(getGreedyAssignment, FeasibleNoFallback) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(true, {1, 2}),
+      makeVariableWithRegisters(false, {}),
+      makeVariableWithRegisters(true, {2, 3}),
+  };
+  const auto Regs = getGreedyAssignment(Vars);
+  ASSERT_THAT(Regs, ElementsAre(1, 0, 2));
+}
+
+TEST(getGreedyAssignment, Feasible) {
+  const std::vector<Variable> Vars = {
+      makeVariableWithRegisters(false, {}),
+      makeVariableWithRegisters(true, {1, 2}),
+      makeVariableWithRegisters(true, {2, 3}),
+      makeVariableWithRegisters(true, {2, 3}),
+      makeVariableWithRegisters(true, {2, 3}),
+  };
+  const auto Regs = getGreedyAssignment(Vars);
+  ASSERT_THAT(Regs, ElementsAre(0, 1, 2, 3, 2));
+}
+
+} // namespace
+} // namespace exegesis

Added: llvm/trunk/unittests/tools/llvm-exegesis/OperandGraphTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/OperandGraphTest.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/OperandGraphTest.cpp (added)
+++ llvm/trunk/unittests/tools/llvm-exegesis/OperandGraphTest.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,48 @@
+//===-- OperandGraphTest.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OperandGraph.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::Not;
+
+namespace exegesis {
+namespace graph {
+namespace {
+
+static const auto In = Node::In();
+static const auto Out = Node::Out();
+
+TEST(OperandGraphTest, NoPath) {
+  Graph TheGraph;
+  EXPECT_THAT(TheGraph.getPathFrom(In, Out), IsEmpty());
+}
+
+TEST(OperandGraphTest, Connecting) {
+  Graph TheGraph;
+  TheGraph.connect(In, Out);
+  EXPECT_THAT(TheGraph.getPathFrom(In, Out), Not(IsEmpty()));
+  EXPECT_THAT(TheGraph.getPathFrom(In, Out), ElementsAre(In, Out));
+}
+
+TEST(OperandGraphTest, ConnectingThroughVariable) {
+  const Node Var = Node::Var(1);
+  Graph TheGraph;
+  TheGraph.connect(In, Var);
+  TheGraph.connect(Var, Out);
+  EXPECT_THAT(TheGraph.getPathFrom(In, Out), Not(IsEmpty()));
+  EXPECT_THAT(TheGraph.getPathFrom(In, Out), ElementsAre(In, Var, Out));
+}
+
+} // namespace
+} // namespace graph
+} // namespace exegesis

Added: llvm/trunk/unittests/tools/llvm-exegesis/PerfHelperTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/PerfHelperTest.cpp?rev=329169&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/PerfHelperTest.cpp (added)
+++ llvm/trunk/unittests/tools/llvm-exegesis/PerfHelperTest.cpp Wed Apr  4 04:37:06 2018
@@ -0,0 +1,47 @@
+//===-- PerfHelperTest.cpp --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PerfHelper.h"
+#include "llvm/Config/config.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace exegesis {
+namespace pfm {
+namespace {
+
+using ::testing::IsEmpty;
+using ::testing::Not;
+
+TEST(PerfHelperTest, FunctionalTest) {
+#ifdef HAVE_LIBPFM
+  ASSERT_FALSE(pfmInitialize());
+  const PerfEvent SingleEvent("CYCLES:u");
+  const auto &EmptyFn = []() {};
+  std::string CallbackEventName;
+  std::string CallbackEventNameFullyQualifed;
+  int64_t CallbackEventCycles;
+  Measure(llvm::makeArrayRef(SingleEvent),
+          [&](const PerfEvent &Event, int64_t Value) {
+            CallbackEventName = Event.name();
+            CallbackEventNameFullyQualifed = Event.getPfmEventString();
+            CallbackEventCycles = Value;
+          },
+          EmptyFn);
+  EXPECT_EQ(CallbackEventName, "CYCLES:u");
+  EXPECT_THAT(CallbackEventNameFullyQualifed, Not(IsEmpty()));
+  pfmTerminate();
+#else
+  ASSERT_TRUE(PfmInitialize());
+#endif
+}
+
+} // namespace
+} // namespace pfm
+} // namespace exegesis




More information about the llvm-commits mailing list