[llvm] r329169 - Re-land r329156 "Add llvm-exegesis tool."
Mikael Holmén via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 5 04:22:07 PDT 2018
On 04/05/2018 01:19 PM, Clement Courbet wrote:
> Hi Mikael, sorry I missed your e-mail. Can you confirm that my fix works ?
Yes the fix you pushed works for me so no problems that I'm aware of now.
> I'll add an option to disable libpfm completely for issues like this one.
>
Thanks,
Mikael
> On Thu, Apr 5, 2018 at 9:45 AM, Mikael Holmén
> <mikael.holmen at ericsson.com <mailto:mikael.holmen at ericsson.com>> wrote:
>
> And now I suddenly saw you already made an attempt to fix this! :)
>
> I'll check again.
>
> Thanks,
> Mikael
>
> On 04/05/2018 09:43 AM, Mikael Holmén via llvm-commits wrote:
>
> Hi Clement,
>
> Are there any requirements about the perfmon version?
>
> On several of my buildbots I get compilation failures now:
>
> ../tools/llvm-exegesis/lib/PerfHelper.cpp:14:10: fatal error:
> 'perfmon/perf_event.h' file not found
> #include "perfmon/perf_event.h"
>
> On those machines there does exist a perfmon/pfmlib.h file but
> not perf_event.h nor pfmlib_perf_event.h. It looks like we have
> version 3.16 installed acording to pfmlib.h:
>
> #define PFMLIB_VERSION (3 << 16 | 10)
>
> If you require a newer version than that, shouldn't that be
> checked by the makefiles a well?
>
> I've also tried to find some CMAKE flag to turn off the pfm
> support completely with something similar to LLVM_ENABLE_ZLIB
> but I can't find anything like that.
>
> Regards,
> Mikael
>
> On 04/04/2018 01:37 PM, Clement Courbet via llvm-commits wrote:
>
> Author: courbet
> Date: Wed Apr 4 04:37:06 2018
> New Revision: 329169
>
> URL: http://llvm.org/viewvc/llvm-project?rev=329169&view=rev
> <http://llvm.org/viewvc/llvm-project?rev=329169&view=rev>
> Log:
> Re-land r329156 "Add llvm-exegesis tool."
>
> Fixed to depend on and initialize the native target instead
> of X86.
>
> Added:
> llvm/trunk/docs/CommandGuide/llvm-exegesis.rst
> llvm/trunk/tools/llvm-exegesis/CMakeLists.txt
> llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt
> - copied, changed from r329157,
> llvm/trunk/tools/LLVMBuild.txt
> llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp
> llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h
> llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
> llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
> llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt
> llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp
> llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
>
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
>
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
> llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt
> - copied, changed from r329157,
> llvm/trunk/tools/LLVMBuild.txt
> llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
> llvm/trunk/tools/llvm-exegesis/lib/Latency.h
> llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp
> llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h
> llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.cpp
> llvm/trunk/tools/llvm-exegesis/lib/OperandGraph.h
> llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.cpp
> llvm/trunk/tools/llvm-exegesis/lib/PerfHelper.h
> llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
> llvm/trunk/tools/llvm-exegesis/lib/Uops.h
> llvm/trunk/tools/llvm-exegesis/lib/X86.cpp
> llvm/trunk/tools/llvm-exegesis/lib/X86.h
> llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp
>
> llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp
> llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt
>
> llvm/trunk/unittests/tools/llvm-exegesis/InMemoryAssemblerTest.cpp
>
> llvm/trunk/unittests/tools/llvm-exegesis/InstructionSnippetGeneratorTest.cpp
>
> llvm/trunk/unittests/tools/llvm-exegesis/OperandGraphTest.cpp
>
> llvm/trunk/unittests/tools/llvm-exegesis/PerfHelperTest.cpp
> Modified:
> llvm/trunk/cmake/config-ix.cmake
> llvm/trunk/docs/CommandGuide/index.rst
> llvm/trunk/docs/ReleaseNotes.rst
> llvm/trunk/include/llvm/Config/config.h.cmake
> llvm/trunk/tools/LLVMBuild.txt
> llvm/trunk/unittests/tools/CMakeLists.txt
>
> Modified: llvm/trunk/cmake/config-ix.cmake
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/config-ix.cmake?rev=329169&r1=329168&r2=329169&view=diff
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/config-ix.cmake?rev=329169&r1=329168&r2=329169&view=diff>
>
> ==============================================================================
>
> --- llvm/trunk/cmake/config-ix.cmake (original)
> +++ llvm/trunk/cmake/config-ix.cmake Wed Apr 4 04:37:06 2018
> @@ -87,6 +87,7 @@ if( NOT PURE_WINDOWS )
> endif()
> check_library_exists(dl dlopen "" HAVE_LIBDL)
> check_library_exists(rt clock_gettime "" HAVE_LIBRT)
> + check_library_exists(pfm pfm_initialize "" HAVE_LIBPFM)
> endif()
> if(HAVE_LIBPTHREAD)
>
> Modified: llvm/trunk/docs/CommandGuide/index.rst
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/index.rst?rev=329169&r1=329168&r2=329169&view=diff
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/index.rst?rev=329169&r1=329168&r2=329169&view=diff>
>
> ==============================================================================
>
> --- llvm/trunk/docs/CommandGuide/index.rst (original)
> +++ llvm/trunk/docs/CommandGuide/index.rst Wed Apr 4
> 04:37:06 2018
> @@ -53,5 +53,6 @@ Developer Tools
> tblgen
> lit
> llvm-build
> + llvm-exegesis
> llvm-pdbutil
> llvm-readobj
>
> Added: llvm/trunk/docs/CommandGuide/llvm-exegesis.rst
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-exegesis.rst?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-exegesis.rst?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/docs/CommandGuide/llvm-exegesis.rst (added)
> +++ llvm/trunk/docs/CommandGuide/llvm-exegesis.rst Wed Apr
> 4 04:37:06 2018
> @@ -0,0 +1,58 @@
> +llvm-exegesis - LLVM Machine Instruction Benchmark
> +==================================================
> +
> +SYNOPSIS
> +--------
> +
> +:program:`llvm-exegesis` [*options*]
> +
> +DESCRIPTION
> +-----------
> +
> +:program:`llvm-exegesis` is a benchmarking tool that uses
> information available
> +in LLVM to measure host machine instruction characteristics
> like latency or port
> +decomposition.
> +
> +Given an LLVM opcode name and a benchmarking mode,
> :program:`llvm-exegesis`
> +generates a code snippet that makes execution as serial
> (resp. as parallel) as
> +possible so that we can measure the latency (resp. uop
> decomposition) of the
> +instruction.
> +The code snippet is jitted and executed on the host
> subtarget. The time taken
> +(resp. resource usage) is measured using hardware
> performance counters. The
> +result is printed out as YAML to the standard output.
> +
> +The main goal of this tool is to automatically (in)validate
> the LLVM's TableDef
> +scheduling models.
> +
> +OPTIONS
> +-------
> +
> +.. option:: -help
> +
> + Print a summary of command line options.
> +
> +.. option:: -opcode-index=<LLVM opcode index>
> +
> + Specify the opcode to measure, by index.
> + Either `opcode-index` or `opcode-name` must be set.
> +
> +.. option:: -opcode-name=<LLVM opcode name>
> +
> + Specify the opcode to measure, by name.
> + Either `opcode-index` or `opcode-name` must be set.
> +
> +.. option:: -benchmark-mode=[Latency|Uops]
> +
> + Specify which characteristic of the opcode to measure.
> +
> +.. option:: -num-repetitions=<Number of repetition>
> +
> + Specify the number of repetitions of the asm snippet.
> + Higher values lead to more accurate measurements but
> lengthen the benchmark.
> +
> +
> +EXIT STATUS
> +-----------
> +
> +:program:`llvm-exegesis` returns 0 on success. Otherwise,
> an error message is
> +printed to standard error, and the tool returns a non 0 value.
>
> Modified: llvm/trunk/docs/ReleaseNotes.rst
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.rst?rev=329169&r1=329168&r2=329169&view=diff
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.rst?rev=329169&r1=329168&r2=329169&view=diff>
>
> ==============================================================================
>
> --- llvm/trunk/docs/ReleaseNotes.rst (original)
> +++ llvm/trunk/docs/ReleaseNotes.rst Wed Apr 4 04:37:06 2018
> @@ -48,6 +48,11 @@ Non-comprehensive list of changes in thi
> * Symbols starting with ``?`` are no longer mangled by
> LLVM when using the
> Windows ``x`` or ``w`` IR mangling schemes.
> +* A new tool named :doc:`llvm-exegesis
> <CommandGuide/llvm-exegesis>` has been
> + added. :program:`llvm-exegesis` automatically measures
> instruction scheduling
> + properties (latency/uops) and provides a principled way
> to edit scheduling
> + models.
> +
> * A new tool named :doc:`llvm-mca
> <CommandGuide/llvm-mca>` has been added.
> :program:`llvm-mca` is a static performance analysis
> tool that uses
> information available in LLVM to statically predict the
> performance of
>
> Modified: llvm/trunk/include/llvm/Config/config.h.cmake
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Config/config.h.cmake?rev=329169&r1=329168&r2=329169&view=diff
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Config/config.h.cmake?rev=329169&r1=329168&r2=329169&view=diff>
>
> ==============================================================================
>
> --- llvm/trunk/include/llvm/Config/config.h.cmake (original)
> +++ llvm/trunk/include/llvm/Config/config.h.cmake Wed Apr 4
> 04:37:06 2018
> @@ -91,6 +91,12 @@
> /* Define to 1 if you have the `edit' library (-ledit). */
> #cmakedefine HAVE_LIBEDIT ${HAVE_LIBEDIT}
> +/* Define to 1 if you have the `pfm' library (-lpfm). */
> +#cmakedefine HAVE_LIBPFM ${HAVE_LIBPFM}
> +
> +/* Define to 1 if you have the `psapi' library (-lpsapi). */
> +#cmakedefine HAVE_LIBPSAPI ${HAVE_LIBPSAPI}
> +
> /* Define to 1 if you have the `pthread' library
> (-lpthread). */
> #cmakedefine HAVE_LIBPTHREAD ${HAVE_LIBPTHREAD}
>
> Modified: llvm/trunk/tools/LLVMBuild.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.txt?rev=329169&r1=329168&r2=329169&view=diff
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.txt?rev=329169&r1=329168&r2=329169&view=diff>
>
> ==============================================================================
>
> --- llvm/trunk/tools/LLVMBuild.txt (original)
> +++ llvm/trunk/tools/LLVMBuild.txt Wed Apr 4 04:37:06 2018
> @@ -32,6 +32,7 @@ subdirectories =
> llvm-dis
> llvm-dwarfdump
> llvm-dwp
> + llvm-exegesis
> llvm-extract
> llvm-jitlistener
> llvm-link
>
> Added: llvm/trunk/tools/llvm-exegesis/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/CMakeLists.txt?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/CMakeLists.txt?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/CMakeLists.txt (added)
> +++ llvm/trunk/tools/llvm-exegesis/CMakeLists.txt Wed Apr 4
> 04:37:06 2018
> @@ -0,0 +1,16 @@
> +set(LLVM_LINK_COMPONENTS
> + Support
> + native
> + )
> +
> +add_llvm_tool(llvm-exegesis
> + llvm-exegesis.cpp
> + )
> +
> +add_subdirectory(lib)
> +target_link_libraries(llvm-exegesis PRIVATE LLVMExegesis)
> +
> +if(HAVE_LIBPFM)
> + target_link_libraries(llvm-exegesis PRIVATE pfm)
> +endif()
> +
>
> Copied: llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt (from
> r329157, llvm/trunk/tools/LLVMBuild.txt)
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=329157&r2=329169&rev=329169&view=diff
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=329157&r2=329169&rev=329169&view=diff>
>
> ==============================================================================
>
> --- llvm/trunk/tools/LLVMBuild.txt (original)
> +++ llvm/trunk/tools/llvm-exegesis/LLVMBuild.txt Wed Apr 4
> 04:37:06 2018
> @@ -1,4 +1,4 @@
> -;===- ./tools/LLVMBuild.txt
> ------------------------------------*- Conf -*--===;
> +;===- ./tools/llvm-exegesis/LLVMBuild.txt
> ----------------------*- Conf -*--===;
> ;
> ; The LLVM Compiler Infrastructure
> ;
> @@ -15,44 +15,8 @@
> ;
>
> ;===------------------------------------------------------------------------===;
>
> -[common]
> -subdirectories =
> - bugpoint
> - dsymutil
> - llc
> - lli
> - llvm-ar
> - llvm-as
> - llvm-bcanalyzer
> - llvm-cat
> - llvm-cfi-verify
> - llvm-cov
> - llvm-cvtres
> - llvm-diff
> - llvm-dis
> - llvm-dwarfdump
> - llvm-dwp
> - llvm-extract
> - llvm-jitlistener
> - llvm-link
> - llvm-lto
> - llvm-mc
> - llvm-mca
> - llvm-modextract
> - llvm-mt
> - llvm-nm
> - llvm-objcopy
> - llvm-objdump
> - llvm-pdbutil
> - llvm-profdata
> - llvm-rc
> - llvm-rtdyld
> - llvm-size
> - llvm-split
> - opt
> - verify-uselistorder
> -
> [component_0]
> -type = Group
> -name = Tools
> -parent = $ROOT
> +type = Tool
> +name = llvm-exegesis
> +parent = Tools
> +required_libraries = CodeGen ExecutionEngine MC MCJIT
> Native NativeCodeGen Object Support
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp
> (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.cpp
> Wed Apr 4 04:37:06 2018
> @@ -0,0 +1,85 @@
> +//===-- BenchmarkResult.cpp
> -------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +
> +#include "BenchmarkResult.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/FileOutputBuffer.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +// Defining YAML traits for IO.
> +namespace llvm {
> +namespace yaml {
> +
> +// std::vector<exegesis::Measure> will be rendered as a list.
> +template <> struct
> SequenceElementTraits<exegesis::BenchmarkMeasure> {
> + static const bool flow = false;
> +};
> +
> +// exegesis::Measure is rendererd as a flow instead of a list.
> +// e.g. { "key": "the key", "value": 0123 }
> +template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
> + static void mapping(IO &Io, exegesis::BenchmarkMeasure
> &Obj) {
> + Io.mapRequired("key", Obj.Key);
> + Io.mapRequired("value", Obj.Value);
> + Io.mapOptional("debug_string", Obj.DebugString);
> + }
> + static const bool flow = true;
> +};
> +
> +template <> struct MappingTraits<exegesis::AsmTemplate> {
> + static void mapping(IO &Io, exegesis::AsmTemplate &Obj) {
> + Io.mapRequired("name", Obj.Name);
> + }
> +};
> +
> +template <> struct
> MappingTraits<exegesis::InstructionBenchmark> {
> + static void mapping(IO &Io,
> exegesis::InstructionBenchmark &Obj) {
> + Io.mapRequired("asm_template", Obj.AsmTmpl);
> + Io.mapRequired("cpu_name", Obj.CpuName);
> + Io.mapRequired("llvm_triple", Obj.LLVMTriple);
> + Io.mapRequired("num_repetitions", Obj.NumRepetitions);
> + Io.mapRequired("measurements", Obj.Measurements);
> + Io.mapRequired("error", Obj.Error);
> + }
> +};
> +
> +} // namespace yaml
> +} // namespace llvm
> +
> +namespace exegesis {
> +
> +InstructionBenchmark
> +InstructionBenchmark::readYamlOrDie(llvm::StringRef Filename) {
> + std::unique_ptr<llvm::MemoryBuffer> MemBuffer =
> llvm::cantFail(
> +
> llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename)));
> + llvm::yaml::Input Yin(*MemBuffer);
> + InstructionBenchmark Benchmark;
> + Yin >> Benchmark;
> + return Benchmark;
> +}
> +
> +void InstructionBenchmark::writeYamlOrDie(const
> llvm::StringRef Filename) {
> + if (Filename == "-") {
> + llvm::yaml::Output Yout(llvm::outs());
> + Yout << *this;
> + } else {
> + llvm::SmallString<1024> Buffer;
> + llvm::raw_svector_ostream Ostr(Buffer);
> + llvm::yaml::Output Yout(Ostr);
> + Yout << *this;
> + std::unique_ptr<llvm::FileOutputBuffer> File =
> +
> llvm::cantFail(llvm::FileOutputBuffer::create(Filename,
> Buffer.size()));
> + memcpy(File->getBufferStart(), Buffer.data(),
> Buffer.size());
> + llvm::cantFail(File->commit());
> + }
> +}
> +
> +} // namespace exegesis
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkResult.h Wed
> Apr 4 04:37:06 2018
> @@ -0,0 +1,53 @@
> +//===-- BenchmarkResult.h
> ---------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +///
> +/// \file
> +/// Defines classes to represent measurements and
> serialize/deserialize them to
> +// Yaml.
> +///
> +//===----------------------------------------------------------------------===//
>
> +
> +#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
> +#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
> +
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/YAMLTraits.h"
> +#include <string>
> +#include <vector>
> +
> +namespace exegesis {
> +
> +struct AsmTemplate {
> + std::string Name;
> +};
> +
> +struct BenchmarkMeasure {
> + std::string Key;
> + double Value;
> + std::string DebugString;
> +};
> +
> +// The result of an instruction benchmark.
> +struct InstructionBenchmark {
> + AsmTemplate AsmTmpl;
> + std::string CpuName;
> + std::string LLVMTriple;
> + size_t NumRepetitions = 0;
> + std::vector<BenchmarkMeasure> Measurements;
> + std::string Error;
> +
> + static InstructionBenchmark readYamlOrDie(llvm::StringRef
> Filename);
> +
> + // Unfortunately this function is non const because of
> YAML traits.
> + void writeYamlOrDie(const llvm::StringRef Filename);
> +};
> +
> +} // namespace exegesis
> +
> +#endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRESULT_H
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
> (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
> Wed Apr 4 04:37:06 2018
> @@ -0,0 +1,79 @@
> +//===-- BenchmarkRunner.cpp
> -------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +
> +#include "BenchmarkRunner.h"
> +#include "InMemoryAssembler.h"
> +#include "llvm/ADT/StringExtras.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/Twine.h"
> +#include <string>
> +
> +namespace exegesis {
> +
> +BenchmarkRunner::InstructionFilter::~InstructionFilter() =
> default;
> +
> +BenchmarkRunner::~BenchmarkRunner() = default;
> +
> +InstructionBenchmark
> +BenchmarkRunner::run(const LLVMState &State, const unsigned
> Opcode,
> + unsigned NumRepetitions,
> + const InstructionFilter &Filter) const {
> + InstructionBenchmark InstrBenchmark;
> +
> + InstrBenchmark.AsmTmpl.Name
> <http://InstrBenchmark.AsmTmpl.Name> =
> + llvm::Twine(getDisplayName())
> + .concat(" ")
> + .concat(State.getInstrInfo().getName(Opcode))
> + .str();
> + InstrBenchmark.CpuName = State.getCpuName();
> + InstrBenchmark.LLVMTriple = State.getTriple();
> + InstrBenchmark.NumRepetitions = NumRepetitions;
> +
> + // Ignore instructions that we cannot run.
> + if (State.getInstrInfo().get(Opcode).isPseudo()) {
> + InstrBenchmark.Error = "Unsupported opcode: isPseudo";
> + return InstrBenchmark;
> + }
> + if (llvm::Error E = Filter.shouldRun(State, Opcode)) {
> + InstrBenchmark.Error = llvm::toString(std::move(E));
> + return InstrBenchmark;
> + }
> +
> + JitFunctionContext Context(State.createTargetMachine());
> + auto ExpectedInstructions =
> + createCode(State, Opcode, NumRepetitions, Context);
> + if (llvm::Error E = ExpectedInstructions.takeError()) {
> + InstrBenchmark.Error = llvm::toString(std::move(E));
> + return InstrBenchmark;
> + }
> +
> + const std::vector<llvm::MCInst> Instructions =
> *ExpectedInstructions;
> + const JitFunction Function(std::move(Context), Instructions);
> + const llvm::StringRef CodeBytes =
> Function.getFunctionBytes();
> +
> + std::string AsmExcerpt;
> + constexpr const int ExcerptSize = 100;
> + constexpr const int ExcerptTailSize = 10;
> + if (CodeBytes.size() <= ExcerptSize) {
> + AsmExcerpt = llvm::toHex(CodeBytes);
> + } else {
> + AsmExcerpt =
> + llvm::toHex(CodeBytes.take_front(ExcerptSize -
> ExcerptTailSize + 3));
> + AsmExcerpt += "...";
> + AsmExcerpt +=
> llvm::toHex(CodeBytes.take_back(ExcerptTailSize));
> + }
> + llvm::outs() << "# Asm excerpt: " << AsmExcerpt << "\n";
> + llvm::outs().flush(); // In case we crash.
> +
> + InstrBenchmark.Measurements =
> + runMeasurements(State, Function, NumRepetitions);
> + return InstrBenchmark;
> +}
> +
> +} // namespace exegesis
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h Wed
> Apr 4 04:37:06 2018
> @@ -0,0 +1,64 @@
> +//===-- BenchmarkRunner.h
> ---------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +///
> +/// \file
> +/// Defines the abstract BenchmarkRunner class for
> measuring a certain execution
> +/// property of instructions (e.g. latency).
> +///
> +//===----------------------------------------------------------------------===//
>
> +
> +#ifndef LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H
> +#define LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H
> +
> +#include "BenchmarkResult.h"
> +#include "InMemoryAssembler.h"
> +#include "LlvmState.h"
> +#include "llvm/MC/MCInst.h"
> +#include "llvm/Support/Error.h"
> +#include <vector>
> +
> +namespace exegesis {
> +
> +// Common code for all benchmark modes.
> +class BenchmarkRunner {
> +public:
> + // Subtargets can disable running benchmarks for some
> instructions by
> + // returning an error here.
> + class InstructionFilter {
> + public:
> + virtual ~InstructionFilter();
> +
> + virtual llvm::Error shouldRun(const LLVMState &State,
> + unsigned Opcode) const {
> + return llvm::ErrorSuccess();
> + }
> + };
> +
> + virtual ~BenchmarkRunner();
> +
> + InstructionBenchmark run(const LLVMState &State, unsigned
> Opcode,
> + unsigned NumRepetitions,
> + const InstructionFilter &Filter)
> const;
> +
> +private:
> + virtual const char *getDisplayName() const = 0;
> +
> + virtual llvm::Expected<std::vector<llvm::MCInst>>
> + createCode(const LLVMState &State, unsigned OpcodeIndex,
> + unsigned NumRepetitions,
> + const JitFunctionContext &Context) const = 0;
> +
> + virtual std::vector<BenchmarkMeasure>
> + runMeasurements(const LLVMState &State, const JitFunction
> &Function,
> + unsigned NumRepetitions) const = 0;
> +};
> +
> +} // namespace exegesis
> +
> +#endif // LLVM_TOOLS_LLVM_EXEGESIS_BENCHMARKRUNNER_H
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt Wed
> Apr 4 04:37:06 2018
> @@ -0,0 +1,25 @@
> +add_library(LLVMExegesis
> + STATIC
> + BenchmarkResult.cpp
> + BenchmarkRunner.cpp
> + InMemoryAssembler.cpp
> + InstructionSnippetGenerator.cpp
> + Latency.cpp
> + LlvmState.cpp
> + OperandGraph.cpp
> + PerfHelper.cpp
> + Uops.cpp
> + X86.cpp
> + )
> +
> +llvm_update_compile_flags(LLVMExegesis)
> +llvm_map_components_to_libnames(libs
> + CodeGen
> + ExecutionEngine
> + MC
> + MCJIT
> + Support
> + )
> +
> +target_link_libraries(LLVMExegesis ${libs})
> +set_target_properties(LLVMExegesis PROPERTIES FOLDER
> "Libraries")
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp
> (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.cpp
> Wed Apr 4 04:37:06 2018
> @@ -0,0 +1,226 @@
> +//===-- InMemoryAssembler.cpp
> -----------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +
> +#include "InMemoryAssembler.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/CodeGen/MachineInstrBuilder.h"
> +#include "llvm/CodeGen/MachineModuleInfo.h"
> +#include "llvm/CodeGen/MachineRegisterInfo.h"
> +#include "llvm/CodeGen/TargetInstrInfo.h"
> +#include "llvm/CodeGen/TargetPassConfig.h"
> +#include "llvm/ExecutionEngine/ExecutionEngine.h"
> +#include "llvm/ExecutionEngine/MCJIT.h"
> +#include "llvm/ExecutionEngine/SectionMemoryManager.h"
> +#include "llvm/IR/LLVMContext.h"
> +#include "llvm/IR/LegacyPassManager.h"
> +#include "llvm/MC/MCFixup.h"
> +#include "llvm/MC/MCInstrDesc.h"
> +#include "llvm/Object/Binary.h"
> +#include "llvm/Object/ObjectFile.h"
> +#include "llvm/PassInfo.h"
> +#include "llvm/PassRegistry.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/Target/TargetMachine.h"
> +#include "llvm/Target/TargetOptions.h"
> +
> +namespace exegesis {
> +
> +static constexpr const char ModuleID[] = "ExegesisInfoTest";
> +static constexpr const char FunctionID[] = "foo";
> +
> +// Small utility function to add named passes.
> +static bool addPass(llvm::PassManagerBase &PM,
> llvm::StringRef PassName,
> + llvm::TargetPassConfig &TPC) {
> + const llvm::PassRegistry *PR =
> llvm::PassRegistry::getPassRegistry();
> + const llvm::PassInfo *PI = PR->getPassInfo(PassName);
> + if (!PI) {
> + llvm::errs() << " run-pass " << PassName << " is not
> registered.\n";
> + return true;
> + }
> +
> + if (!PI->getNormalCtor()) {
> + llvm::errs() << " cannot create pass: " <<
> PI->getPassName() << "\n";
> + return true;
> + }
> + llvm::Pass *P = PI->getNormalCtor()();
> + std::string Banner = std::string("After ") +
> std::string(P->getPassName());
> + PM.add(P);
> + TPC.printAndVerify(Banner);
> +
> + return false;
> +}
> +
> +// Creates a void MachineFunction with no argument.
> +static llvm::MachineFunction &
> +createVoidVoidMachineFunction(llvm::StringRef FunctionID,
> llvm::Module *Module,
> + llvm::MachineModuleInfo *MMI) {
> + llvm::Type *const ReturnType =
> llvm::Type::getInt32Ty(Module->getContext());
> + llvm::FunctionType *FunctionType =
> llvm::FunctionType::get(ReturnType, false);
> + llvm::Function *const F = llvm::Function::Create(
> + FunctionType, llvm::GlobalValue::InternalLinkage,
> FunctionID, Module);
> + // Making sure we can create a MachineFunction out of
> this Function even if it
> + // contains no IR.
> + F->setIsMaterializable(true);
> + return MMI->getOrCreateMachineFunction(*F);
> +}
> +
> +static llvm::object::OwningBinary<llvm::object::ObjectFile>
> +assemble(llvm::Module *Module,
> std::unique_ptr<llvm::MachineModuleInfo> MMI,
> + llvm::LLVMTargetMachine *LLVMTM) {
> + llvm::legacy::PassManager PM;
> + llvm::MCContext &Context = MMI->getContext();
> +
> + llvm::TargetLibraryInfoImpl
> TLII(llvm::Triple(Module->getTargetTriple()));
> + PM.add(new llvm::TargetLibraryInfoWrapperPass(TLII));
> +
> + llvm::TargetPassConfig *TPC = LLVMTM->createPassConfig(PM);
> + PM.add(TPC);
> + PM.add(MMI.release());
> + TPC->printAndVerify("MachineFunctionGenerator::assemble");
> + // Adding the following passes:
> + // - machineverifier: checks that the MachineFunction is
> well formed.
> + // - prologepilog: saves and restore callee saved registers.
> + for (const char *PassName : {"machineverifier",
> "prologepilog"})
> + if (addPass(PM, PassName, *TPC))
> + llvm::report_fatal_error("Unable to add a mandatory
> pass");
> + TPC->setInitialized();
> +
> + llvm::SmallVector<char, 4096> AsmBuffer;
> + llvm::raw_svector_ostream AsmStream(AsmBuffer);
> + // AsmPrinter is responsible for generating the assembly
> into AsmBuffer.
> + if (LLVMTM->addAsmPrinter(PM, AsmStream,
> llvm::TargetMachine::CGFT_ObjectFile,
> + Context))
> + llvm::report_fatal_error("Cannot add AsmPrinter passes");
> +
> + PM.run(*Module); // Run all the passes
> +
> + // Storing the generated assembly into a MemoryBuffer
> that owns the memory.
> + std::unique_ptr<llvm::MemoryBuffer> Buffer =
> + llvm::MemoryBuffer::getMemBufferCopy(AsmStream.str());
> + // Create the ObjectFile from the MemoryBuffer.
> + std::unique_ptr<llvm::object::ObjectFile> Obj =
> llvm::cantFail(
> +
> llvm::object::ObjectFile::createObjectFile(Buffer->getMemBufferRef()));
> + // Returning both the MemoryBuffer and the ObjectFile.
> + return llvm::object::OwningBinary<llvm::object::ObjectFile>(
> + std::move(Obj), std::move(Buffer));
> +}
> +
> +static void fillMachineFunction(llvm::MachineFunction &MF,
> + llvm::ArrayRef<llvm::MCInst> Instructions) {
> + llvm::MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
> + MF.push_back(MBB);
> + const llvm::MCInstrInfo *MCII =
> MF.getTarget().getMCInstrInfo();
> + const llvm::DebugLoc DL;
> + for (const llvm::MCInst &Inst : Instructions) {
> + const unsigned Opcode = Inst.getOpcode();
> + const llvm::MCInstrDesc &MCID = MCII->get(Opcode);
> + llvm::MachineInstrBuilder Builder = llvm::BuildMI(MBB,
> DL, MCID);
> + for (unsigned OpIndex = 0, E = Inst.getNumOperands();
> OpIndex < E;
> + ++OpIndex) {
> + const llvm::MCOperand &Op = Inst.getOperand(OpIndex);
> + if (Op.isReg()) {
> + const bool IsDef = OpIndex < MCID.getNumDefs();
> + unsigned Flags = 0;
> + const llvm::MCOperandInfo &OpInfo =
> MCID.operands().begin()[OpIndex];
> + if (IsDef && !OpInfo.isOptionalDef())
> + Flags |= llvm::RegState::Define;
> + Builder.addReg(Op.getReg(), Flags);
> + } else if (Op.isImm()) {
> + Builder.addImm(Op.getImm());
> + } else {
> + llvm_unreachable("Not yet implemented");
> + }
> + }
> + }
> + // Adding the Return Opcode.
> + const llvm::TargetInstrInfo *TII =
> MF.getSubtarget().getInstrInfo();
> + llvm::BuildMI(MBB, DL, TII->get(TII->getReturnOpcode()));
> +}
> +
> +namespace {
> +
> +// Implementation of this class relies on the fact that a
> single object with a
> +// single function will be loaded into memory.
> +class TrackingSectionMemoryManager : public
> llvm::SectionMemoryManager {
> +public:
> + explicit TrackingSectionMemoryManager(uintptr_t *CodeSize)
> + : CodeSize(CodeSize) {}
> +
> + uint8_t *allocateCodeSection(uintptr_t Size, unsigned
> Alignment,
> + unsigned SectionID,
> + llvm::StringRef SectionName) override {
> + *CodeSize = Size;
> + return llvm::SectionMemoryManager::allocateCodeSection(
> + Size, Alignment, SectionID, SectionName);
> + }
> +
> +private:
> + uintptr_t *const CodeSize = nullptr;
> +};
> +
> +} // namespace
> +
> +JitFunctionContext::JitFunctionContext(
> + std::unique_ptr<llvm::LLVMTargetMachine> TheTM)
> + : Context(llvm::make_unique<llvm::LLVMContext>()),
> TM(std::move(TheTM)),
> +
> MMI(llvm::make_unique<llvm::MachineModuleInfo>(TM.get())),
> + Module(llvm::make_unique<llvm::Module>(ModuleID,
> *Context)) {
> + Module->setDataLayout(TM->createDataLayout());
> + MF = &createVoidVoidMachineFunction(FunctionID,
> Module.get(), MMI.get());
> + // We need to instruct the passes that we're done with
> SSA and virtual
> + // registers.
> + auto &Properties = MF->getProperties();
> +
> Properties.set(llvm::MachineFunctionProperties::Property::NoVRegs);
> +
> Properties.reset(llvm::MachineFunctionProperties::Property::IsSSA);
> +
> Properties.reset(llvm::MachineFunctionProperties::Property::TracksLiveness);
>
> + // prologue/epilogue pass needs the reserved registers to
> be frozen, this is
> + // usually done by the SelectionDAGISel pass.
> + MF->getRegInfo().freezeReservedRegs(*MF);
> + // Saving reserved registers for client.
> + ReservedRegs =
> MF->getSubtarget().getRegisterInfo()->getReservedRegs(*MF);
> +}
> +
> +JitFunction::JitFunction(JitFunctionContext &&Context,
> + llvm::ArrayRef<llvm::MCInst>
> Instructions)
> + : FunctionContext(std::move(Context)) {
> + fillMachineFunction(*FunctionContext.MF, Instructions);
> + // We create the pass manager, run the passes and returns
> the produced
> + // ObjectFile.
> + llvm::object::OwningBinary<llvm::object::ObjectFile>
> ObjHolder =
> + assemble(FunctionContext.Module.get(),
> std::move(FunctionContext.MMI),
> + FunctionContext.TM.get());
> + assert(ObjHolder.getBinary() && "cannot create object file");
> + // Initializing the execution engine.
> + // We need to use the JIT EngineKind to be able to add an
> object file.
> + LLVMLinkInMCJIT();
> + uintptr_t CodeSize = 0;
> + std::string Error;
> + ExecEngine.reset(
> + llvm::EngineBuilder(std::move(FunctionContext.Module))
> + .setErrorStr(&Error)
> + .setMCPU(FunctionContext.TM->getTargetCPU())
> + .setEngineKind(llvm::EngineKind::JIT)
> + .setMCJITMemoryManager(
> +
> llvm::make_unique<TrackingSectionMemoryManager>(&CodeSize))
> + .create(FunctionContext.TM.release()));
> + if (!ExecEngine)
> + llvm::report_fatal_error(Error);
> + // Adding the generated object file containing the
> assembled function.
> + // The ExecutionEngine makes sure the object file is
> copied into an
> + // executable page.
> + ExecEngine->addObjectFile(ObjHolder.takeBinary().first);
> + // Setting function
> + FunctionBytes =
> + llvm::StringRef(reinterpret_cast<const char *>(
> +
> ExecEngine->getFunctionAddress(FunctionID)),
> + CodeSize);
> +}
> +
> +} // namespace exegesis
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
> (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/InMemoryAssembler.h
> Wed Apr 4 04:37:06 2018
> @@ -0,0 +1,78 @@
> +//===-- InMemoryAssembler.h
> -------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +///
> +/// \file
> +/// Defines classes to assemble functions composed of a
> single basic block of
> +/// MCInsts.
> +///
> +//===----------------------------------------------------------------------===//
>
> +
> +#ifndef LLVM_TOOLS_LLVM_EXEGESIS_INMEMORYASSEMBLER_H
> +#define LLVM_TOOLS_LLVM_EXEGESIS_INMEMORYASSEMBLER_H
> +
> +#include "llvm/ADT/BitVector.h"
> +#include "llvm/CodeGen/MachineFunction.h"
> +#include "llvm/CodeGen/MachineModuleInfo.h"
> +#include "llvm/CodeGen/TargetRegisterInfo.h"
> +#include "llvm/ExecutionEngine/ExecutionEngine.h"
> +#include "llvm/IR/LLVMContext.h"
> +#include "llvm/MC/MCInst.h"
> +#include <memory>
> +#include <vector>
> +
> +namespace exegesis {
> +
> +// Consumable context for JitFunction below.
> +// This temporary object allows for retrieving
> MachineFunction properties before
> +// assembling it.
> +class JitFunctionContext {
> +public:
> + explicit
> JitFunctionContext(std::unique_ptr<llvm::LLVMTargetMachine> TM);
> + // Movable
> + JitFunctionContext(JitFunctionContext &&) = default;
> + JitFunctionContext &operator=(JitFunctionContext &&) =
> default;
> + // Non copyable
> + JitFunctionContext(const JitFunctionContext &) = delete;
> + JitFunctionContext &operator=(const JitFunctionContext &)
> = delete;
> +
> + const llvm::BitVector &getReservedRegs() const { return
> ReservedRegs; }
> +
> +private:
> + friend class JitFunction;
> +
> + std::unique_ptr<llvm::LLVMContext> Context;
> + std::unique_ptr<llvm::LLVMTargetMachine> TM;
> + std::unique_ptr<llvm::MachineModuleInfo> MMI;
> + std::unique_ptr<llvm::Module> Module;
> + llvm::MachineFunction *MF = nullptr;
> + llvm::BitVector ReservedRegs;
> +};
> +
> +// Creates a void() function from a sequence of llvm::MCInst.
> +class JitFunction {
> +public:
> + // Assembles Instructions into an executable function.
> + JitFunction(JitFunctionContext &&Context,
> + llvm::ArrayRef<llvm::MCInst> Instructions);
> +
> + // Retrieves the function as an array of bytes.
> + llvm::StringRef getFunctionBytes() const { return
> FunctionBytes; }
> +
> + // Retrieves the callable function.
> + void operator()() const { ((void
> (*)())FunctionBytes.data())(); }
> +
> +private:
> + JitFunctionContext FunctionContext;
> + std::unique_ptr<llvm::ExecutionEngine> ExecEngine;
> + llvm::StringRef FunctionBytes;
> +};
> +
> +} // namespace exegesis
> +
> +#endif // LLVM_TOOLS_LLVM_EXEGESIS_INMEMORYASSEMBLER_H
>
> Added:
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp?rev=329169&view=auto>
>
> ==============================================================================
>
> ---
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
> (added)
> +++
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
> Wed Apr 4 04:37:06 2018
> @@ -0,0 +1,355 @@
> +//===-- InstructionSnippetGenerator.cpp
> -------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +
> +#include "InstructionSnippetGenerator.h"
> +#include "llvm/ADT/MapVector.h"
> +#include "llvm/ADT/STLExtras.h"
> +#include "llvm/ADT/SmallSet.h"
> +#include "llvm/MC/MCInstBuilder.h"
> +#include <algorithm>
> +#include <unordered_map>
> +#include <unordered_set>
> +
> +namespace exegesis {
> +
> +void Variable::print(llvm::raw_ostream &OS,
> + const llvm::MCRegisterInfo *RegInfo)
> const {
> + OS << "IsUse=" << IsUse << " IsDef=" << IsDef << "
> possible regs: {";
> + for (const size_t Reg : PossibleRegisters) {
> + if (RegInfo)
> + OS << RegInfo->getName(Reg);
> + else
> + OS << Reg;
> + OS << ",";
> + }
> + OS << "} ";
> + if (ExplicitOperands.empty()) {
> + OS << "implicit";
> + } else {
> + OS << "explicit ops: {";
> + for (const size_t Op : ExplicitOperands)
> + OS << Op << ",";
> + OS << "}";
> + }
> + OS << "\n";
> +}
> +
> +// Update the state of a Variable with an explicit operand.
> +static void updateExplicitOperandVariable(const
> llvm::MCRegisterInfo &RegInfo,
> + const llvm::MCInstrDesc &InstrInfo,
> + const size_t OpIndex,
> + const llvm::BitVector &ReservedRegs,
> + Variable &Var) {
> + const bool IsDef = OpIndex < InstrInfo.getNumDefs();
> + if (IsDef)
> + Var.IsDef = true;
> + if (!IsDef)
> + Var.IsUse = true;
> + Var.ExplicitOperands.push_back(OpIndex);
> + const llvm::MCOperandInfo &OpInfo =
> InstrInfo.opInfo_begin()[OpIndex];
> + if (OpInfo.RegClass >= 0) {
> + Var.IsReg = true;
> + for (const llvm::MCPhysReg &Reg :
> RegInfo.getRegClass(OpInfo.RegClass)) {
> + if (!ReservedRegs[Reg])
> + Var.PossibleRegisters.insert(Reg);
> + }
> + }
> +}
> +
> +static Variable
> &findVariableWithOperand(llvm::SmallVector<Variable, 8> &Vars,
> + size_t OpIndex) {
> + // Vars.size() is small (<10) so a linear scan is good
> enough.
> + for (Variable &Var : Vars) {
> + if (llvm::is_contained(Var.ExplicitOperands, OpIndex))
> + return Var;
> + }
> + assert(false && "Illegal state");
> + static Variable *const EmptyVariable = new Variable();
> + return *EmptyVariable;
> +}
> +
> +llvm::SmallVector<Variable, 8>
> +getVariables(const llvm::MCRegisterInfo &RegInfo,
> + const llvm::MCInstrDesc &InstrInfo,
> + const llvm::BitVector &ReservedRegs) {
> + llvm::SmallVector<Variable, 8> Vars;
> + // For each operand, its "tied to" operand or -1.
> + llvm::SmallVector<int, 10> TiedToMap;
> + for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E;
> ++I) {
> + TiedToMap.push_back(InstrInfo.getOperandConstraint(I,
> llvm::MCOI::TIED_TO));
> + }
> + // Adding non tied operands.
> + for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E;
> ++I) {
> + if (TiedToMap[I] >= 0)
> + continue; // dropping tied ones.
> + Vars.emplace_back();
> + updateExplicitOperandVariable(RegInfo, InstrInfo, I,
> ReservedRegs,
> + Vars.back());
> + }
> + // Adding tied operands to existing variables.
> + for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E;
> ++I) {
> + if (TiedToMap[I] < 0)
> + continue; // dropping non-tied ones.
> + updateExplicitOperandVariable(RegInfo, InstrInfo, I,
> ReservedRegs,
> + findVariableWithOperand(Vars, TiedToMap[I]));
> + }
> + // Adding implicit defs.
> + for (size_t I = 0, E = InstrInfo.getNumImplicitDefs(); I
> < E; ++I) {
> + Vars.emplace_back();
> + Variable &Var = Vars.back();
> + const llvm::MCPhysReg Reg = InstrInfo.getImplicitDefs()[I];
> + assert(!ReservedRegs[Reg] && "implicit def of reserved
> register");
> + Var.PossibleRegisters.insert(Reg);
> + Var.IsDef = true;
> + Var.IsReg = true;
> + }
> + // Adding implicit uses.
> + for (size_t I = 0, E = InstrInfo.getNumImplicitUses(); I
> < E; ++I) {
> + Vars.emplace_back();
> + Variable &Var = Vars.back();
> + const llvm::MCPhysReg Reg = InstrInfo.getImplicitUses()[I];
> + assert(!ReservedRegs[Reg] && "implicit use of reserved
> register");
> + Var.PossibleRegisters.insert(Reg);
> + Var.IsUse = true;
> + Var.IsReg = true;
> + }
> +
> + return Vars;
> +}
> +
> +VariableAssignment::VariableAssignment(size_t VarIdx,
> + llvm::MCPhysReg AssignedReg)
> + : VarIdx(VarIdx), AssignedReg(AssignedReg) {}
> +
> +bool VariableAssignment::operator==(const
> VariableAssignment &Other) const {
> + return std::tie(VarIdx, AssignedReg) ==
> + std::tie(Other.VarIdx, Other.AssignedReg);
> +}
> +
> +bool VariableAssignment::operator<(const VariableAssignment
> &Other) const {
> + return std::tie(VarIdx, AssignedReg) <
> + std::tie(Other.VarIdx, Other.AssignedReg);
> +}
> +
> +void dumpAssignmentChain(const llvm::MCRegisterInfo &RegInfo,
> + const AssignmentChain &Chain) {
> + for (const VariableAssignment &Assignment : Chain) {
> + llvm::outs() << llvm::format("(%d %s) ", Assignment.VarIdx,
> +
> RegInfo.getName(Assignment.AssignedReg));
> + }
> + llvm::outs() << "\n";
> +}
> +
> +std::vector<AssignmentChain>
> +computeSequentialAssignmentChains(const
> llvm::MCRegisterInfo &RegInfo,
> + llvm::ArrayRef<Variable> Vars) {
> + using graph::Node;
> + graph::Graph Graph;
> +
> + // Add register aliasing to the graph.
> + setupRegisterAliasing(RegInfo, Graph);
> +
> + // Adding variables to the graph.
> + for (size_t I = 0, E = Vars.size(); I < E; ++I) {
> + const Variable &Var = Vars[I];
> + const Node N = Node::Var(I);
> + if (Var.IsDef) {
> + Graph.connect(Node::In(), N);
> + for (const size_t Reg : Var.PossibleRegisters)
> + Graph.connect(N, Node::Reg(Reg));
> + }
> + if (Var.IsUse) {
> + Graph.connect(N, Node::Out());
> + for (const size_t Reg : Var.PossibleRegisters)
> + Graph.connect(Node::Reg(Reg), N);
> + }
> + }
> +
> + // Find all possible dependency chains (aka all possible
> paths from In to Out
> + // node).
> + std::vector<AssignmentChain> AllChains;
> + for (;;) {
> + const auto Path = Graph.getPathFrom(Node::In(),
> Node::Out());
> + if (Path.empty())
> + break;
> + switch (Path.size()) {
> + case 0:
> + case 1:
> + case 2:
> + case 4:
> + assert(false && "Illegal state");
> + break;
> + case 3: { // IN -> variable -> OUT
> + const size_t VarIdx = Path[1].varValue();
> + for (size_t Reg : Vars[VarIdx].PossibleRegisters) {
> + AllChains.emplace_back();
> + AllChains.back().emplace(VarIdx, Reg);
> + }
> + Graph.disconnect(Path[0], Path[1]); // IN -> variable
> + Graph.disconnect(Path[1], Path[2]); // variable -> OUT
> + break;
> + }
> + default: { // IN -> var1 -> Reg[...] -> var2 -> OUT
> + const size_t Last = Path.size() - 1;
> + const size_t Var1 = Path[1].varValue();
> + const llvm::MCPhysReg Reg1 = Path[2].regValue();
> + const llvm::MCPhysReg Reg2 = Path[Last - 2].regValue();
> + const size_t Var2 = Path[Last - 1].varValue();
> + AllChains.emplace_back();
> + AllChains.back().emplace(Var1, Reg1);
> + AllChains.back().emplace(Var2, Reg2);
> + Graph.disconnect(Path[1], Path[2]); // Var1 -> Reg[0]
> + break;
> + }
> + }
> + }
> +
> + return AllChains;
> +}
> +
> +std::vector<llvm::MCPhysReg>
> +getRandomAssignment(llvm::ArrayRef<Variable> Vars,
> + llvm::ArrayRef<AssignmentChain> Chains,
> + const std::function<size_t(size_t)>
> &RandomIndexForSize) {
> + // Registers are initialized with 0 (aka NoRegister).
> + std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0);
> + if (Chains.empty())
> + return Registers;
> + // Pick one of the chains and set Registers that are
> fully constrained (have
> + // no degrees of freedom).
> + const size_t ChainIndex = RandomIndexForSize(Chains.size());
> + for (const VariableAssignment Assignment :
> Chains[ChainIndex])
> + Registers[Assignment.VarIdx] = Assignment.AssignedReg;
> + // Registers with remaining degrees of freedom are
> assigned randomly.
> + for (size_t I = 0, E = Vars.size(); I < E; ++I) {
> + llvm::MCPhysReg &Reg = Registers[I];
> + const Variable &Var = Vars[I];
> + const auto &PossibleRegisters = Var.PossibleRegisters;
> + if (Reg > 0 || PossibleRegisters.empty())
> + continue;
> + Reg =
> PossibleRegisters[RandomIndexForSize(PossibleRegisters.size())];
> + }
> + return Registers;
> +}
> +
> +// Finds a matching register `reg` for variable `VarIdx`
> and sets
> +// `RegAssignments[r]` to `VarIdx`. Returns false if no
> matching can be found.
> +// `seen.count(r)` is 1 if register `reg` has been processed.
> +static bool findMatchingRegister(
> + llvm::ArrayRef<Variable> Vars, const size_t VarIdx,
> + std::unordered_set<llvm::MCPhysReg> &Seen,
> + std::unordered_map<llvm::MCPhysReg, size_t>
> &RegAssignments) {
> + for (const llvm::MCPhysReg Reg :
> Vars[VarIdx].PossibleRegisters) {
> + if (!Seen.count(Reg)) {
> + Seen.insert(Reg); // Mark `Reg` as seen.
> + // If `Reg` is not assigned to a variable, or if
> `Reg` was assigned to a
> + // variable which has an alternate possible register,
> assign `Reg` to
> + // variable `VarIdx`. Since `Reg` is marked as
> assigned in the above line,
> + // `RegAssignments[r]` in the following recursive
> call will not get
> + // assigned `Reg` again.
> + const auto AssignedVarIt = RegAssignments.find(Reg);
> + if (AssignedVarIt == RegAssignments.end() ||
> + findMatchingRegister(Vars, AssignedVarIt->second,
> Seen,
> + RegAssignments)) {
> + RegAssignments[Reg] = VarIdx;
> + return true;
> + }
> + }
> + }
> + return false;
> +}
> +
> +// This is actually a maximum bipartite matching problem:
> +//
> https://en.wikipedia.org/wiki/Matching_(graph_theory)#Bipartite_matching
> <https://en.wikipedia.org/wiki/Matching_(graph_theory)#Bipartite_matching>
> +// The graph has variables on the left and registers on the
> right, with an edge
> +// between variable `I` and register `Reg` iff
> +// `Vars[I].PossibleRegisters.count(A)`.
> +// Note that a greedy approach won't work for cases like:
> +// Vars[0] PossibleRegisters={C,B}
> +// Vars[1] PossibleRegisters={A,B}
> +// Vars[2] PossibleRegisters={A,C}
> +// There is a feasible solution {0->B, 1->A, 2->C}, but the
> greedy solution is
> +// {0->C, 1->A, oops}.
> +std::vector<llvm::MCPhysReg>
> +getExclusiveAssignment(llvm::ArrayRef<Variable> Vars) {
> + // `RegAssignments[r]` is the variable id that was
> assigned register `Reg`.
> + std::unordered_map<llvm::MCPhysReg, size_t> RegAssignments;
> +
> + for (size_t VarIdx = 0, E = Vars.size(); VarIdx < E;
> ++VarIdx) {
> + if (!Vars[VarIdx].IsReg)
> + continue;
> + std::unordered_set<llvm::MCPhysReg> Seen;
> + if (!findMatchingRegister(Vars, VarIdx, Seen,
> RegAssignments))
> + return {}; // Infeasible.
> + }
> +
> + std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0);
> + for (const auto &RegVarIdx : RegAssignments)
> + Registers[RegVarIdx.second] = RegVarIdx.first;
> + return Registers;
> +}
> +
> +std::vector<llvm::MCPhysReg>
> +getGreedyAssignment(llvm::ArrayRef<Variable> Vars) {
> + std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0);
> + llvm::SmallSet<llvm::MCPhysReg, 8> Assigned;
> + for (size_t VarIdx = 0, E = Vars.size(); VarIdx < E;
> ++VarIdx) {
> + const auto &Var = Vars[VarIdx];
> + if (!Var.IsReg)
> + continue;
> + if (Var.PossibleRegisters.empty())
> + return {};
> + // Try possible registers until an unassigned one is found.
> + for (const auto Reg : Var.PossibleRegisters) {
> + if (Assigned.insert(Reg).second) {
> + Registers[VarIdx] = Reg;
> + break;
> + }
> + }
> + // Fallback to first possible register.
> + if (Registers[VarIdx] == 0)
> + Registers[VarIdx] = Var.PossibleRegisters[0];
> + }
> + return Registers;
> +}
> +
> +llvm::MCInst generateMCInst(const llvm::MCInstrDesc &InstrInfo,
> + llvm::ArrayRef<Variable> Vars,
> + llvm::ArrayRef<llvm::MCPhysReg>
> VarRegs) {
> + const size_t NumOperands = InstrInfo.getNumOperands();
> + llvm::SmallVector<llvm::MCPhysReg, 16>
> OperandToRegister(NumOperands, 0);
> +
> + // We browse the variable and for each explicit operands
> we set the selected
> + // register in the OperandToRegister array.
> + for (size_t I = 0, E = Vars.size(); I < E; ++I) {
> + for (const size_t OpIndex : Vars[I].ExplicitOperands) {
> + OperandToRegister[OpIndex] = VarRegs[I];
> + }
> + }
> +
> + // Building the instruction.
> + llvm::MCInstBuilder Builder(InstrInfo.getOpcode());
> + for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E;
> ++I) {
> + const llvm::MCOperandInfo &OpInfo =
> InstrInfo.opInfo_begin()[I];
> + switch (OpInfo.OperandType) {
> + case llvm::MCOI::OperandType::OPERAND_REGISTER:
> + Builder.addReg(OperandToRegister[I]);
> + break;
> + case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
> + Builder.addImm(1);
> + break;
> + default:
> + Builder.addOperand(llvm::MCOperand());
> + }
> + }
> +
> + return Builder;
> +}
> +
> +} // namespace exegesis
>
> Added:
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h?rev=329169&view=auto>
>
> ==============================================================================
>
> ---
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
> (added)
> +++
> llvm/trunk/tools/llvm-exegesis/lib/InstructionSnippetGenerator.h
> Wed Apr 4 04:37:06 2018
> @@ -0,0 +1,119 @@
> +//===-- InstructionSnippetGenerator.h
> ---------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +///
> +/// \file
> +/// Defines helper classes to generate code snippets, in
> particular register
> +/// assignment.
> +///
> +//===----------------------------------------------------------------------===//
>
> +
> +#ifndef LLVM_TOOLS_LLVM_EXEGESIS_INSTRUCTIONSNIPPETGENERATOR_H
> +#define LLVM_TOOLS_LLVM_EXEGESIS_INSTRUCTIONSNIPPETGENERATOR_H
> +
> +#include "OperandGraph.h"
> +#include "llvm/ADT/BitVector.h"
> +#include "llvm/ADT/SetVector.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/MC/MCInst.h"
> +#include "llvm/MC/MCInstrDesc.h"
> +#include "llvm/MC/MCRegisterInfo.h"
> +#include <vector>
> +
> +namespace exegesis {
> +
> +// A Variable represents a set of possible values that we
> need to choose from.
> +// It may represent one or more explicit operands that are
> tied together, or one
> +// implicit operand.
> +class Variable final {
> +public:
> + bool IsUse = false;
> + bool IsDef = false;
> + bool IsReg = false;
> +
> + // Lists all the explicit operand indices that are tied
> to this variable.
> + // Empty if Variable represents an implicit operand.
> + llvm::SmallVector<size_t, 8> ExplicitOperands;
> +
> + // - In case of explicit operands, PossibleRegisters is
> the expansion of the
> + // operands's RegClass registers. Please note that tied
> together explicit
> + // operands share the same RegClass.
> + // - In case of implicit operands, PossibleRegisters is a
> singleton MCPhysReg.
> + llvm::SmallSetVector<llvm::MCPhysReg, 16> PossibleRegisters;
> +
> + // If RegInfo is null, register names won't get resolved.
> + void print(llvm::raw_ostream &OS, const
> llvm::MCRegisterInfo *RegInfo) const;
> +};
> +
> +// Builds a model of implicit and explicit operands for
> InstrDesc into
> +// Variables.
> +llvm::SmallVector<Variable, 8>
> +getVariables(const llvm::MCRegisterInfo &RegInfo,
> + const llvm::MCInstrDesc &InstrDesc,
> + const llvm::BitVector &ReservedRegs);
> +
> +// A simple object to represent a Variable assignement.
> +struct VariableAssignment {
> + VariableAssignment(size_t VarIdx, llvm::MCPhysReg
> AssignedReg);
> +
> + size_t VarIdx;
> + llvm::MCPhysReg AssignedReg;
> +
> + bool operator==(const VariableAssignment &) const;
> + bool operator<(const VariableAssignment &) const;
> +};
> +
> +// An AssignmentChain is a set of assignement realizing a
> dependency chain.
> +// We inherit from std::set to leverage uniqueness of elements.
> +using AssignmentChain = std::set<VariableAssignment>;
> +
> +// Debug function to print an assignment chain.
> +void dumpAssignmentChain(const llvm::MCRegisterInfo &RegInfo,
> + const AssignmentChain &Chain);
> +
> +// Inserts Variables into a graph representing register
> aliasing and finds all
> +// the possible dependency chains for this instruction,
> i.e. all the possible
> +// assignement of operands that would make execution of the
> instruction
> +// sequential.
> +std::vector<AssignmentChain>
> +computeSequentialAssignmentChains(const
> llvm::MCRegisterInfo &RegInfo,
> + llvm::ArrayRef<Variable> Vars);
> +
> +// Selects a random configuration leading to a dependency
> chain.
> +// The result is a vector of the same size as `Vars`.
> +// `random_index_for_size` is a functor giving a random
> value in [0, arg[.
> +std::vector<llvm::MCPhysReg>
> +getRandomAssignment(llvm::ArrayRef<Variable> Vars,
> + llvm::ArrayRef<AssignmentChain> Chains,
> + const std::function<size_t(size_t)>
> &RandomIndexForSize);
> +
> +// Finds an assignment of registers to variables such that
> no two variables are
> +// assigned the same register.
> +// The result is a vector of the same size as `Vars`, or
> `{}` if the
> +// assignment is not feasible.
> +std::vector<llvm::MCPhysReg>
> +getExclusiveAssignment(llvm::ArrayRef<Variable> Vars);
> +
> +// Finds a greedy assignment of registers to variables.
> Each variable gets
> +// assigned the first possible register that is not already
> assigned to a
> +// previous variable. If there is no such register, the
> variable gets assigned
> +// the first possible register.
> +// The result is a vector of the same size as `Vars`, or
> `{}` if the
> +// assignment is not feasible.
> +std::vector<llvm::MCPhysReg>
> +getGreedyAssignment(llvm::ArrayRef<Variable> Vars);
> +
> +// Generates an LLVM MCInst with the previously computed
> variables.
> +// Immediate values are set to 1.
> +llvm::MCInst generateMCInst(const llvm::MCInstrDesc &InstrDesc,
> + llvm::ArrayRef<Variable> Vars,
> + llvm::ArrayRef<llvm::MCPhysReg>
> VarRegs);
> +
> +} // namespace exegesis
> +
> +#endif //
> LLVM_TOOLS_LLVM_EXEGESIS_INSTRUCTIONSNIPPETGENERATOR_H
>
> Copied: llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt
> (from r329157, llvm/trunk/tools/LLVMBuild.txt)
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=329157&r2=329169&rev=329169&view=diff
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=329157&r2=329169&rev=329169&view=diff>
>
> ==============================================================================
>
> --- llvm/trunk/tools/LLVMBuild.txt (original)
> +++ llvm/trunk/tools/llvm-exegesis/lib/LLVMBuild.txt Wed
> Apr 4 04:37:06 2018
> @@ -1,4 +1,4 @@
> -;===- ./tools/LLVMBuild.txt
> ------------------------------------*- Conf -*--===;
> +;===- ./tools/llvm-exegesis/lib/LLVMBuild.txt
> ------------------*- Conf -*--===;
> ;
> ; The LLVM Compiler Infrastructure
> ;
> @@ -15,44 +15,8 @@
> ;
>
> ;===------------------------------------------------------------------------===;
>
> -[common]
> -subdirectories =
> - bugpoint
> - dsymutil
> - llc
> - lli
> - llvm-ar
> - llvm-as
> - llvm-bcanalyzer
> - llvm-cat
> - llvm-cfi-verify
> - llvm-cov
> - llvm-cvtres
> - llvm-diff
> - llvm-dis
> - llvm-dwarfdump
> - llvm-dwp
> - llvm-extract
> - llvm-jitlistener
> - llvm-link
> - llvm-lto
> - llvm-mc
> - llvm-mca
> - llvm-modextract
> - llvm-mt
> - llvm-nm
> - llvm-objcopy
> - llvm-objdump
> - llvm-pdbutil
> - llvm-profdata
> - llvm-rc
> - llvm-rtdyld
> - llvm-size
> - llvm-split
> - opt
> - verify-uselistorder
> -
> [component_0]
> -type = Group
> -name = Tools
> -parent = $ROOT
> +type = Library
> +name = Exegesis
> +parent = Libraries
> +required_libraries = CodeGen ExecutionEngine MC MCJIT
> Object Support
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp Wed Apr
> 4 04:37:06 2018
> @@ -0,0 +1,95 @@
> +//===-- Latency.cpp
> ---------------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +
> +#include "Latency.h"
> +#include "BenchmarkResult.h"
> +#include "InstructionSnippetGenerator.h"
> +#include "PerfHelper.h"
> +#include "llvm/MC/MCInstrDesc.h"
> +#include "llvm/Support/Error.h"
> +#include <algorithm>
> +#include <random>
> +
> +namespace exegesis {
> +
> +// FIXME: Handle memory, see PR36905.
> +static bool isInvalidOperand(const llvm::MCOperandInfo
> &OpInfo) {
> + switch (OpInfo.OperandType) {
> + default:
> + return true;
> + case llvm::MCOI::OPERAND_IMMEDIATE:
> + case llvm::MCOI::OPERAND_REGISTER:
> + return false;
> + }
> +}
> +
> +static llvm::Error makeError(llvm::Twine Msg) {
> + return llvm::make_error<llvm::StringError>(Msg,
> +
> llvm::inconvertibleErrorCode());
> +}
> +
> +LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
> +
> +const char *LatencyBenchmarkRunner::getDisplayName() const
> { return "latency"; }
> +
> +llvm::Expected<std::vector<llvm::MCInst>>
> LatencyBenchmarkRunner::createCode(
> + const LLVMState &State, const unsigned OpcodeIndex,
> + const unsigned NumRepetitions, const JitFunctionContext
> &Context) const {
> + std::default_random_engine RandomEngine;
> + const auto GetRandomIndex = [&RandomEngine](size_t Size) {
> + assert(Size > 0 && "trying to get select a random
> element of an empty set");
> + return std::uniform_int_distribution<>(0, Size -
> 1)(RandomEngine);
> + };
> +
> + const auto &InstrInfo = State.getInstrInfo();
> + const auto &RegInfo = State.getRegInfo();
> + const llvm::MCInstrDesc &InstrDesc =
> InstrInfo.get(OpcodeIndex);
> + for (const llvm::MCOperandInfo &OpInfo :
> InstrDesc.operands()) {
> + if (isInvalidOperand(OpInfo))
> + return makeError("Only registers and immediates are
> supported");
> + }
> +
> + const auto Vars = getVariables(RegInfo, InstrDesc,
> Context.getReservedRegs());
> + const std::vector<AssignmentChain> AssignmentChains =
> + computeSequentialAssignmentChains(RegInfo, Vars);
> + if (AssignmentChains.empty())
> + return makeError("Unable to find a dependency chain.");
> + const std::vector<llvm::MCPhysReg> Regs =
> + getRandomAssignment(Vars, AssignmentChains,
> GetRandomIndex);
> + const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars,
> Regs);
> + if (!State.canAssemble(Inst))
> + return makeError("MCInst does not assemble.");
> + return std::vector<llvm::MCInst>(NumRepetitions, Inst);
> +}
> +
> +std::vector<BenchmarkMeasure>
> +LatencyBenchmarkRunner::runMeasurements(const LLVMState &State,
> + const JitFunction &Function,
> + const unsigned NumRepetitions) const {
> + // Cycle measurements include some overhead from the
> kernel. Repeat the
> + // measure several times and take the minimum value.
> + constexpr const int NumMeasurements = 30;
> + int64_t MinLatency = std::numeric_limits<int64_t>::max();
> + // FIXME: Read the perf event from the MCSchedModel (see
> PR36984).
> + const pfm::PerfEvent CyclesPerfEvent("UNHALTED_CORE_CYCLES");
> + if (!CyclesPerfEvent.valid())
> + llvm::report_fatal_error("invalid perf event
> 'UNHALTED_CORE_CYCLES'");
> + for (size_t I = 0; I < NumMeasurements; ++I) {
> + pfm::Counter Counter(CyclesPerfEvent);
> + Counter.start();
> + Function();
> + Counter.stop();
> + const int64_t Value = Counter.read();
> + if (Value < MinLatency)
> + MinLatency = Value;
> + }
> + return {{"latency", static_cast<double>(MinLatency) /
> NumRepetitions}};
> +}
> +
> +} // namespace exegesis
>
> Added: llvm/trunk/tools/llvm-exegesis/lib/Latency.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.h?rev=329169&view=auto
> <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.h?rev=329169&view=auto>
>
> ==============================================================================
>
> --- llvm/trunk/tools/llvm-exegesis/lib/Latency.h (added)
> +++ llvm/trunk/tools/llvm-exegesis/lib/Latency.h Wed Apr 4
> 04:37:06 2018
> @@ -0,0 +1,41 @@
> +//===-- Latency.h
> -----------------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of
> Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
>
> +///
> +/// \file
> +/// A BenchmarkRunner implementation to measure instruction
> latencies.
> +///
> +//===----------------------------------------------------------------------===//
>
> +
> +#ifndef LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H
> +#define LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H
> +
> +#include "BenchmarkRunner.h"
> +
> +namespace exegesis {
> +
> +class LatencyBenchmarkRunner : public BenchmarkRunner {
> +public:
> + ~LatencyBenchmarkRunner() override;
> +
> +private:
> + const char *getDisplayName() const override;
> +
> + llvm::Expected<std::vector<llvm::MCInst>>
> + createCode(const LLVMState &State, unsigned OpcodeIndex,
> + unsigned NumRepetitions,
> + const JitFunctionContext &Context) const override;
> +
> + std::vector<BenchmarkMeasure>
>
>
More information about the llvm-commits
mailing list