[llvm] r338567 - [llvm-exegesis] Provide a way to handle memory instructions.

Guillaume Chatelet via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 1 07:41:45 PDT 2018


Author: gchatelet
Date: Wed Aug  1 07:41:45 2018
New Revision: 338567

URL: http://llvm.org/viewvc/llvm-project?rev=338567&view=rev
Log:
[llvm-exegesis] Provide a way to handle memory instructions.

Summary:
And implement memory instructions on X86.

This fixes PR36906.

Reviewers: gchatelet

Reviewed By: gchatelet

Subscribers: lebedev.ri, filcab, mgorny, tschuett, RKSimon, llvm-commits

Differential Revision: https://reviews.llvm.org/D48935

Added:
    llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkRunnerTest.cpp
Modified:
    llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Assembler.h
    llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
    llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
    llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Latency.h
    llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp
    llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h
    llvm/trunk/tools/llvm-exegesis/lib/RegisterAliasing.h
    llvm/trunk/tools/llvm-exegesis/lib/Target.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Target.h
    llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Uops.h
    llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt
    llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h
    llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp

Modified: llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp Wed Aug  1 07:41:45 2018
@@ -66,12 +66,16 @@ static bool addPass(llvm::PassManagerBas
   return false;
 }
 
-// Creates a void MachineFunction with no argument.
+// Creates a void(int8*) MachineFunction.
 static llvm::MachineFunction &
-createVoidVoidMachineFunction(llvm::StringRef FunctionID, llvm::Module *Module,
-                              llvm::MachineModuleInfo *MMI) {
+createVoidVoidPtrMachineFunction(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::Type *const MemParamType = llvm::PointerType::get(
+      llvm::Type::getInt8Ty(Module->getContext()), 0 /*default address space*/);
+  llvm::FunctionType *FunctionType =
+      llvm::FunctionType::get(ReturnType, {MemParamType}, 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
@@ -81,9 +85,12 @@ createVoidVoidMachineFunction(llvm::Stri
 }
 
 static void fillMachineFunction(llvm::MachineFunction &MF,
+                                llvm::ArrayRef<unsigned> LiveIns,
                                 llvm::ArrayRef<llvm::MCInst> Instructions) {
   llvm::MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
   MF.push_back(MBB);
+  for (const unsigned Reg : LiveIns)
+    MBB->addLiveIn(Reg);
   const llvm::MCInstrInfo *MCII = MF.getTarget().getMCInstrInfo();
   llvm::DebugLoc DL;
   for (const llvm::MCInst &Inst : Instructions) {
@@ -134,13 +141,14 @@ llvm::BitVector getFunctionReservedRegs(
   std::unique_ptr<llvm::MachineModuleInfo> MMI =
       llvm::make_unique<llvm::MachineModuleInfo>(&TM);
   llvm::MachineFunction &MF =
-      createVoidVoidMachineFunction(FunctionID, Module.get(), MMI.get());
+      createVoidVoidPtrMachineFunction(FunctionID, Module.get(), MMI.get());
   // Saving reserved registers for client.
   return MF.getSubtarget().getRegisterInfo()->getReservedRegs(MF);
 }
 
 void assembleToStream(const ExegesisTarget &ET,
                       std::unique_ptr<llvm::LLVMTargetMachine> TM,
+                      llvm::ArrayRef<unsigned> LiveIns,
                       llvm::ArrayRef<unsigned> RegsToDef,
                       llvm::ArrayRef<llvm::MCInst> Instructions,
                       llvm::raw_pwrite_stream &AsmStream) {
@@ -151,13 +159,17 @@ void assembleToStream(const ExegesisTarg
   std::unique_ptr<llvm::MachineModuleInfo> MMI =
       llvm::make_unique<llvm::MachineModuleInfo>(TM.get());
   llvm::MachineFunction &MF =
-      createVoidVoidMachineFunction(FunctionID, Module.get(), MMI.get());
+      createVoidVoidPtrMachineFunction(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);
+
+  for (const unsigned Reg : LiveIns)
+    MF.getRegInfo().addLiveIn(Reg);
+
   bool IsSnippetSetupComplete = false;
   std::vector<llvm::MCInst> SnippetWithSetup =
       generateSnippetSetupCode(RegsToDef, ET, *TM, IsSnippetSetupComplete);
@@ -176,7 +188,7 @@ void assembleToStream(const ExegesisTarg
   MF.getRegInfo().freezeReservedRegs(MF);
 
   // Fill the MachineFunction from the instructions.
-  fillMachineFunction(MF, Instructions);
+  fillMachineFunction(MF, LiveIns, Instructions);
 
   // We create the pass manager, run the passes to populate AsmBuffer.
   llvm::MCContext &MCContext = MMI->getContext();

Modified: llvm/trunk/tools/llvm-exegesis/lib/Assembler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Assembler.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Assembler.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Assembler.h Wed Aug  1 07:41:45 2018
@@ -39,12 +39,13 @@ class ExegesisTarget;
 // convention and target machine).
 llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM);
 
-// Creates a temporary `void foo()` function containing the provided
+// Creates a temporary `void foo(char*)` function containing the provided
 // Instructions. Runs a set of llvm Passes to provide correct prologue and
 // epilogue. Once the MachineFunction is ready, it is assembled for TM to
 // AsmStream, the temporary function is eventually discarded.
 void assembleToStream(const ExegesisTarget &ET,
                       std::unique_ptr<llvm::LLVMTargetMachine> TM,
+                      llvm::ArrayRef<unsigned> LiveIns,
                       llvm::ArrayRef<unsigned> RegsToDef,
                       llvm::ArrayRef<llvm::MCInst> Instructions,
                       llvm::raw_pwrite_stream &AsmStream);
@@ -59,7 +60,7 @@ getObjectFromBuffer(llvm::StringRef Buff
 llvm::object::OwningBinary<llvm::object::ObjectFile>
 getObjectFromFile(llvm::StringRef Filename);
 
-// Consumes an ObjectFile containing a `void foo()` function and make it
+// Consumes an ObjectFile containing a `void foo(char*)` function and make it
 // executable.
 struct ExecutableFunction {
   explicit ExecutableFunction(
@@ -70,7 +71,9 @@ struct ExecutableFunction {
   llvm::StringRef getFunctionBytes() const { return FunctionBytes; }
 
   // Executes the function.
-  void operator()() const { ((void (*)())(intptr_t)FunctionBytes.data())(); }
+  void operator()(char *Memory) const {
+    ((void (*)(char *))(intptr_t)FunctionBytes.data())(Memory);
+  }
 
   std::unique_ptr<llvm::LLVMContext> Context;
   std::unique_ptr<llvm::ExecutionEngine> ExecEngine;

Modified: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp Wed Aug  1 07:41:45 2018
@@ -30,7 +30,7 @@ BenchmarkRunner::BenchmarkRunner(const L
                                  InstructionBenchmark::ModeE Mode)
     : State(State), RATC(State.getRegInfo(),
                          getFunctionReservedRegs(State.getTargetMachine())),
-      Mode(Mode) {}
+      Mode(Mode), Scratch(llvm::make_unique<ScratchSpace>()) {}
 
 BenchmarkRunner::~BenchmarkRunner() = default;
 
@@ -119,7 +119,7 @@ BenchmarkRunner::runOne(const BenchmarkC
                << *ObjectFilePath << "\n";
   const ExecutableFunction EF(State.createTargetMachine(),
                               getObjectFromFile(*ObjectFilePath));
-  InstrBenchmark.Measurements = runMeasurements(EF, NumRepetitions);
+  InstrBenchmark.Measurements = runMeasurements(EF, *Scratch, NumRepetitions);
 
   return InstrBenchmark;
 }
@@ -132,9 +132,14 @@ BenchmarkRunner::generateConfigurations(
     BenchmarkConfiguration Configuration;
     Configuration.Info = Prototype.Explanation;
     for (InstructionInstance &II : Prototype.Snippet) {
-      II.randomizeUnsetVariables();
+      II.randomizeUnsetVariables(
+          Prototype.ScratchSpaceReg
+              ? RATC.getRegister(Prototype.ScratchSpaceReg).aliasedBits()
+              : RATC.emptyRegisters());
       Configuration.Snippet.push_back(II.build());
     }
+    if (Prototype.ScratchSpaceReg)
+      Configuration.SnippetSetup.LiveIns.push_back(Prototype.ScratchSpaceReg);
     Configuration.SnippetSetup.RegsToDef = computeRegsToDef(Prototype.Snippet);
     return std::vector<BenchmarkConfiguration>{Configuration};
   } else
@@ -144,6 +149,7 @@ BenchmarkRunner::generateConfigurations(
 std::vector<unsigned> BenchmarkRunner::computeRegsToDef(
     const std::vector<InstructionInstance> &Snippet) const {
   // Collect all register uses and create an assignment for each of them.
+  // Ignore memory operands which are handled separately.
   // Loop invariant: DefinedRegs[i] is true iif it has been set at least once
   // before the current instruction.
   llvm::BitVector DefinedRegs = RATC.emptyRegisters();
@@ -152,11 +158,12 @@ std::vector<unsigned> BenchmarkRunner::c
     // Returns the register that this Operand sets or uses, or 0 if this is not
     // a register.
     const auto GetOpReg = [&II](const Operand &Op) -> unsigned {
-      if (Op.ImplicitReg) {
+      if (Op.IsMem)
+        return 0;
+      if (Op.ImplicitReg)
         return *Op.ImplicitReg;
-      } else if (Op.IsExplicit && II.getValueFor(Op).isReg()) {
+      if (Op.IsExplicit && II.getValueFor(Op).isReg())
         return II.getValueFor(Op).getReg();
-      }
       return 0;
     };
     // Collect used registers that have never been def'ed.
@@ -173,9 +180,8 @@ std::vector<unsigned> BenchmarkRunner::c
     for (const Operand &Op : II.Instr.Operands) {
       if (Op.IsDef) {
         const unsigned Reg = GetOpReg(Op);
-        if (Reg > 0) {
+        if (Reg > 0)
           DefinedRegs.set(Reg);
-        }
       }
     }
   }
@@ -192,7 +198,7 @@ BenchmarkRunner::writeObjectFile(const B
     return std::move(E);
   llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
   assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
-                   Setup.RegsToDef, Code, OFS);
+                   Setup.LiveIns, Setup.RegsToDef, Code, OFS);
   return ResultPath.str();
 }
 

Modified: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h Wed Aug  1 07:41:45 2018
@@ -23,6 +23,8 @@
 #include "RegisterAliasing.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/Support/Error.h"
+#include <cstdlib>
+#include <memory>
 #include <vector>
 
 namespace exegesis {
@@ -40,6 +42,7 @@ struct BenchmarkConfiguration {
   // measurement it should be as short as possible. It is usually used to setup
   // the content of the Registers.
   struct Setup {
+    std::vector<unsigned> LiveIns; // The registers that are live on entry.
     std::vector<unsigned> RegsToDef;
   };
   Setup SnippetSetup;
@@ -66,6 +69,23 @@ public:
   std::vector<unsigned>
   computeRegsToDef(const std::vector<InstructionInstance> &Snippet) const;
 
+  // Scratch space to run instructions that touch memory.
+  struct ScratchSpace {
+    static constexpr const size_t kAlignment = 1024;
+    static constexpr const size_t kSize = 1 << 20; // 1MB.
+    ScratchSpace()
+        : UnalignedPtr(llvm::make_unique<char[]>(kSize + kAlignment)),
+          AlignedPtr(
+              UnalignedPtr.get() + kAlignment -
+              (reinterpret_cast<intptr_t>(UnalignedPtr.get()) % kAlignment)) {}
+    char *ptr() const { return AlignedPtr; }
+    void clear() { std::memset(ptr(), 0, kSize); }
+
+  private:
+    const std::unique_ptr<char[]> UnalignedPtr;
+    char *const AlignedPtr;
+  };
+
 protected:
   const LLVMState &State;
   const RegisterAliasingTrackerCache RATC;
@@ -84,7 +104,7 @@ private:
   generatePrototype(unsigned Opcode) const = 0;
 
   virtual std::vector<BenchmarkMeasure>
-  runMeasurements(const ExecutableFunction &EF,
+  runMeasurements(const ExecutableFunction &EF, ScratchSpace &Scratch,
                   const unsigned NumRepetitions) const = 0;
 
   // Internal helpers.
@@ -101,6 +121,8 @@ private:
                   llvm::ArrayRef<llvm::MCInst> Code) const;
 
   const InstructionBenchmark::ModeE Mode;
+
+  const std::unique_ptr<ScratchSpace> Scratch;
 };
 
 } // namespace exegesis

Modified: llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp Wed Aug  1 07:41:45 2018
@@ -108,6 +108,7 @@ const char *LatencyBenchmarkRunner::getC
 
 std::vector<BenchmarkMeasure>
 LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
+                                        ScratchSpace &Scratch,
                                         const unsigned NumRepetitions) const {
   // Cycle measurements include some overhead from the kernel. Repeat the
   // measure several times and take the minimum value.
@@ -121,8 +122,9 @@ LatencyBenchmarkRunner::runMeasurements(
     llvm::report_fatal_error("invalid perf event");
   for (size_t I = 0; I < NumMeasurements; ++I) {
     pfm::Counter Counter(CyclesPerfEvent);
+    Scratch.clear();
     Counter.start();
-    Function();
+    Function(Scratch.ptr());
     Counter.stop();
     const int64_t Value = Counter.read();
     if (Value < MinLatency)

Modified: llvm/trunk/tools/llvm-exegesis/lib/Latency.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.h Wed Aug  1 07:41:45 2018
@@ -36,7 +36,7 @@ private:
       const Instruction &Instr) const;
 
   std::vector<BenchmarkMeasure>
-  runMeasurements(const ExecutableFunction &EF,
+  runMeasurements(const ExecutableFunction &EF, ScratchSpace &Scratch,
                   const unsigned NumRepetitions) const override;
 
   virtual const char *getCounterName() const;

Modified: llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp Wed Aug  1 07:41:45 2018
@@ -26,6 +26,7 @@ Instruction::Instruction(const llvm::MCI
     Operand Operand;
     Operand.Index = OpIndex;
     Operand.IsDef = (OpIndex < MCInstrDesc.getNumDefs());
+    Operand.IsMem = OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY;
     Operand.IsExplicit = true;
     // TODO(gchatelet): Handle isLookupPtrRegClass.
     if (OpInfo.RegClass >= 0)
@@ -83,6 +84,11 @@ Instruction::Instruction(const llvm::MCI
   }
 }
 
+bool Instruction::hasMemoryOperands() const {
+  return std::any_of(Operands.begin(), Operands.end(),
+                     [](const Operand &Op) { return Op.IsMem; });
+}
+
 InstructionInstance::InstructionInstance(const Instruction &Instr)
     : Instr(Instr), VariableValues(Instr.Variables.size()) {}
 
@@ -91,6 +97,11 @@ InstructionInstance::InstructionInstance
 InstructionInstance &InstructionInstance::
 operator=(InstructionInstance &&) = default;
 
+InstructionInstance::InstructionInstance(const InstructionInstance &) = default;
+
+InstructionInstance &InstructionInstance::
+operator=(const InstructionInstance &) = default;
+
 unsigned InstructionInstance::getOpcode() const {
   return Instr.Description->getOpcode();
 }
@@ -117,7 +128,8 @@ InstructionInstance::getValueFor(const O
 
 // forward declaration.
 static void randomize(const Instruction &Instr, const Variable &Var,
-                      llvm::MCOperand &AssignedValue);
+                      llvm::MCOperand &AssignedValue,
+                      const llvm::BitVector &ForbiddenRegs);
 
 bool InstructionInstance::hasImmediateVariables() const {
   return llvm::any_of(Instr.Variables, [this](const Variable &Var) {
@@ -129,11 +141,12 @@ bool InstructionInstance::hasImmediateVa
   });
 }
 
-void InstructionInstance::randomizeUnsetVariables() {
+void InstructionInstance::randomizeUnsetVariables(
+    const llvm::BitVector &ForbiddenRegs) {
   for (const Variable &Var : Instr.Variables) {
     llvm::MCOperand &AssignedValue = getValueFor(Var);
     if (!AssignedValue.isValid())
-      randomize(Instr, Var, AssignedValue);
+      randomize(Instr, Var, AssignedValue, ForbiddenRegs);
   }
 }
 
@@ -222,7 +235,8 @@ static auto randomElement(const C &Conta
 }
 
 static void randomize(const Instruction &Instr, const Variable &Var,
-                      llvm::MCOperand &AssignedValue) {
+                      llvm::MCOperand &AssignedValue,
+                      const llvm::BitVector &ForbiddenRegs) {
   assert(!Var.TiedOperands.empty());
   const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
   assert(Op.Info != nullptr);
@@ -234,8 +248,11 @@ static void randomize(const Instruction
     break;
   case llvm::MCOI::OperandType::OPERAND_REGISTER: {
     assert(Op.Tracker);
-    const auto &Registers = Op.Tracker->sourceBits();
-    AssignedValue = llvm::MCOperand::createReg(randomBit(Registers));
+    auto AllowedRegs = Op.Tracker->sourceBits();
+    assert(AllowedRegs.size() == ForbiddenRegs.size());
+    for (auto I : ForbiddenRegs.set_bits())
+      AllowedRegs.reset(I);
+    AssignedValue = llvm::MCOperand::createReg(randomBit(AllowedRegs));
     break;
   }
   default:

Modified: llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h Wed Aug  1 07:41:45 2018
@@ -58,6 +58,7 @@ struct Variable {
 struct Operand {
   unsigned Index = 0;
   bool IsDef = false;
+  bool IsMem = false;
   bool IsExplicit = false;
   const RegisterAliasingTracker *Tracker = nullptr; // Set for Register Op.
   const llvm::MCOperandInfo *Info = nullptr;        // Set for Explicit Op.
@@ -72,6 +73,8 @@ struct Instruction {
   Instruction(const llvm::MCInstrDesc &MCInstrDesc,
               const RegisterAliasingTrackerCache &ATC);
 
+  bool hasMemoryOperands() const;
+
   const llvm::MCInstrDesc *Description; // Never nullptr.
   llvm::SmallVector<Operand, 8> Operands;
   llvm::SmallVector<Variable, 4> Variables;
@@ -83,11 +86,8 @@ struct Instruction {
 struct InstructionInstance {
   InstructionInstance(const Instruction &Instr);
 
-  // No copy.
-  InstructionInstance(const InstructionInstance &) = delete;
-  InstructionInstance &operator=(const InstructionInstance &) = delete;
-
-  // Moving is OK.
+  InstructionInstance(const InstructionInstance &);
+  InstructionInstance &operator=(const InstructionInstance &);
   InstructionInstance(InstructionInstance &&);
   InstructionInstance &operator=(InstructionInstance &&);
 
@@ -99,7 +99,8 @@ struct InstructionInstance {
   bool hasImmediateVariables() const;
 
   // Assigns a Random Value to all Variables that are still Invalid.
-  void randomizeUnsetVariables();
+  // Do not use any of the registers in `ForbiddenRegs`.
+  void randomizeUnsetVariables(const llvm::BitVector &ForbiddenRegs);
 
   // Returns the instance as an llvm::MCInst. The InstructionInstance must be
   // fully allocated (no invalid variables).
@@ -125,6 +126,9 @@ struct SnippetPrototype {
   SnippetPrototype &operator=(SnippetPrototype &&);
 
   std::string Explanation;
+  // If the prototype uses the provided scratch memory, the register in which
+  // the pointer to this memory is passed in to the function.
+  unsigned ScratchSpaceReg = 0;
   std::vector<InstructionInstance> Snippet;
 };
 

Modified: llvm/trunk/tools/llvm-exegesis/lib/RegisterAliasing.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/RegisterAliasing.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/RegisterAliasing.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/RegisterAliasing.h Wed Aug  1 07:41:45 2018
@@ -62,6 +62,7 @@ struct RegisterAliasingTracker {
 
 private:
   RegisterAliasingTracker(const llvm::MCRegisterInfo &RegInfo);
+  RegisterAliasingTracker(const RegisterAliasingTracker &) = delete;
 
   void FillOriginAndAliasedBits(const llvm::MCRegisterInfo &RegInfo,
                                 const llvm::BitVector &OriginalBits);

Modified: llvm/trunk/tools/llvm-exegesis/lib/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Target.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Target.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Target.cpp Wed Aug  1 07:41:45 2018
@@ -30,9 +30,8 @@ void ExegesisTarget::registerTarget(Exeg
     FirstTarget = Target;
     return;
   }
-  assert(Target->Next == nullptr && "target has already been registered");
   if (Target->Next != nullptr)
-    return;
+    return; // Already registered.
   Target->Next = FirstTarget;
   FirstTarget = Target;
 }

Modified: llvm/trunk/tools/llvm-exegesis/lib/Target.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Target.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Target.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Target.h Wed Aug  1 07:41:45 2018
@@ -22,6 +22,7 @@
 #include "LlvmState.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/CallingConv.h"
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -39,6 +40,27 @@ public:
     return {};
   }
 
+  // Returns the register pointing to scratch memory, or 0 if this target does
+  // not support memory operands. The benchmark function uses the default
+  // calling convention.
+  virtual unsigned getScratchMemoryRegister(const llvm::Triple &) const {
+    return 0;
+  }
+
+  // Fills memory operands with references to the address at [Reg] + Offset.
+  virtual void fillMemoryOperands(InstructionInstance &II, unsigned Reg,
+                                  unsigned Offset) const {
+    llvm_unreachable(
+        "fillMemoryOperands() requires getScratchMemoryRegister() > 0");
+  }
+
+  // Returns the maximum number of bytes a load/store instruction can access at
+  // once. This is typically the size of the largest register available on the
+  // processor. Note that this only used as a hint to generate independant
+  // load/stores to/from memory, so the exact returned value does not really
+  // matter as long as it's large enough.
+  virtual unsigned getMaxMemoryAccessSize() const { return 0; }
+
   // Creates a benchmark runner for the given mode.
   std::unique_ptr<BenchmarkRunner>
   createBenchmarkRunner(InstructionBenchmark::ModeE Mode,

Modified: llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp Wed Aug  1 07:41:45 2018
@@ -13,6 +13,7 @@
 #include "BenchmarkRunner.h"
 #include "MCInstrDescView.h"
 #include "PerfHelper.h"
+#include "Target.h"
 
 // FIXME: Load constants into registers (e.g. with fld1) to not break
 // instructions like x87.
@@ -84,19 +85,11 @@ static bool hasUnknownOperand(const llvm
   return OpInfo.OperandType == llvm::MCOI::OPERAND_UNKNOWN;
 }
 
-// FIXME: Handle memory, see PR36905.
-static bool hasMemoryOperand(const llvm::MCOperandInfo &OpInfo) {
-  return OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY;
-}
-
 llvm::Error
 UopsBenchmarkRunner::isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const {
   if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand))
     return llvm::make_error<BenchmarkFailure>(
         "Infeasible : has unknown operands");
-  if (llvm::any_of(MCInstrDesc.operands(), hasMemoryOperand))
-    return llvm::make_error<BenchmarkFailure>(
-        "Infeasible : has memory operands");
   return llvm::Error::success();
 }
 
@@ -131,18 +124,70 @@ static void remove(llvm::BitVector &a, c
 
 UopsBenchmarkRunner::~UopsBenchmarkRunner() = default;
 
+void UopsBenchmarkRunner::instantiateMemoryOperands(
+    const unsigned ScratchSpaceReg,
+    std::vector<InstructionInstance> &Snippet) const {
+  if (ScratchSpaceReg == 0)
+    return;  // no memory operands.
+  const auto &ET = State.getExegesisTarget();
+  const unsigned MemStep = ET.getMaxMemoryAccessSize();
+  const size_t OriginalSnippetSize = Snippet.size();
+  size_t I = 0;
+  for (InstructionInstance &II : Snippet) {
+    ET.fillMemoryOperands(II, ScratchSpaceReg, I * MemStep);
+    ++I;
+  }
+
+  while (Snippet.size() < kMinNumDifferentAddresses) {
+    InstructionInstance II = Snippet[I % OriginalSnippetSize];
+    ET.fillMemoryOperands(II, ScratchSpaceReg, I * MemStep);
+    ++I;
+    Snippet.push_back(std::move(II));
+  }
+  assert(I * MemStep < ScratchSpace::kSize && "not enough scratch space");
+}
+
 llvm::Expected<SnippetPrototype>
 UopsBenchmarkRunner::generatePrototype(unsigned Opcode) const {
   const auto &InstrDesc = State.getInstrInfo().get(Opcode);
   if (auto E = isInfeasible(InstrDesc))
     return std::move(E);
   const Instruction Instr(InstrDesc, RATC);
+  const auto &ET = State.getExegesisTarget();
+  SnippetPrototype Prototype;
+
+  const llvm::BitVector *ScratchSpaceAliasedRegs = nullptr;
+  if (Instr.hasMemoryOperands()) {
+    Prototype.ScratchSpaceReg =
+        ET.getScratchMemoryRegister(State.getTargetMachine().getTargetTriple());
+    if (Prototype.ScratchSpaceReg == 0)
+      return llvm::make_error<BenchmarkFailure>(
+          "Infeasible : target does not support memory instructions");
+    ScratchSpaceAliasedRegs =
+        &RATC.getRegister(Prototype.ScratchSpaceReg).aliasedBits();
+    // If the instruction implicitly writes to ScratchSpaceReg , abort.
+    // FIXME: We could make a copy of the scratch register.
+    for (const auto &Op : Instr.Operands) {
+      if (Op.IsDef && Op.ImplicitReg &&
+          ScratchSpaceAliasedRegs->test(*Op.ImplicitReg))
+        return llvm::make_error<BenchmarkFailure>(
+            "Infeasible : memory instruction uses scratch memory register");
+    }
+  }
+
   const AliasingConfigurations SelfAliasing(Instr, Instr);
+  InstructionInstance II(Instr);
   if (SelfAliasing.empty()) {
-    return generateUnconstrainedPrototype(Instr, "instruction is parallel");
+    Prototype.Explanation = "instruction is parallel, repeating a random one.";
+    Prototype.Snippet.push_back(std::move(II));
+    instantiateMemoryOperands(Prototype.ScratchSpaceReg, Prototype.Snippet);
+    return std::move(Prototype);
   }
   if (SelfAliasing.hasImplicitAliasing()) {
-    return generateUnconstrainedPrototype(Instr, "instruction is serial");
+    Prototype.Explanation = "instruction is serial, repeating a random one.";
+    Prototype.Snippet.push_back(std::move(II));
+    instantiateMemoryOperands(Prototype.ScratchSpaceReg, Prototype.Snippet);
+    return std::move(Prototype);
   }
   const auto TiedVariables = getTiedVariables(Instr);
   if (!TiedVariables.empty()) {
@@ -155,23 +200,27 @@ UopsBenchmarkRunner::generatePrototype(u
     assert(!Var->TiedOperands.empty());
     const Operand &Op = Instr.Operands[Var->TiedOperands.front()];
     assert(Op.Tracker);
-    SnippetPrototype Prototype;
     Prototype.Explanation =
         "instruction has tied variables using static renaming.";
     for (const llvm::MCPhysReg Reg : Op.Tracker->sourceBits().set_bits()) {
-      Prototype.Snippet.emplace_back(Instr);
-      Prototype.Snippet.back().getValueFor(*Var) =
-          llvm::MCOperand::createReg(Reg);
+      if (ScratchSpaceAliasedRegs && ScratchSpaceAliasedRegs->test(Reg))
+        continue; // Do not use the scratch memory address register.
+      InstructionInstance TmpII = II;
+      TmpII.getValueFor(*Var) = llvm::MCOperand::createReg(Reg);
+      Prototype.Snippet.push_back(std::move(TmpII));
     }
+    instantiateMemoryOperands(Prototype.ScratchSpaceReg, Prototype.Snippet);
     return std::move(Prototype);
   }
-  InstructionInstance II(Instr);
   // No tied variables, we pick random values for defs.
   llvm::BitVector Defs(State.getRegInfo().getNumRegs());
   for (const auto &Op : Instr.Operands) {
-    if (Op.Tracker && Op.IsExplicit && Op.IsDef) {
+    if (Op.Tracker && Op.IsExplicit && Op.IsDef && !Op.IsMem) {
       auto PossibleRegisters = Op.Tracker->sourceBits();
       remove(PossibleRegisters, RATC.reservedRegisters());
+      // Do not use the scratch memory address register.
+      if (ScratchSpaceAliasedRegs)
+        remove(PossibleRegisters, *ScratchSpaceAliasedRegs);
       assert(PossibleRegisters.any() && "No register left to choose from");
       const auto RandomReg = randomBit(PossibleRegisters);
       Defs.set(RandomReg);
@@ -181,24 +230,28 @@ UopsBenchmarkRunner::generatePrototype(u
   // And pick random use values that are not reserved and don't alias with defs.
   const auto DefAliases = getAliasedBits(State.getRegInfo(), Defs);
   for (const auto &Op : Instr.Operands) {
-    if (Op.Tracker && Op.IsExplicit && !Op.IsDef) {
+    if (Op.Tracker && Op.IsExplicit && !Op.IsDef && !Op.IsMem) {
       auto PossibleRegisters = Op.Tracker->sourceBits();
       remove(PossibleRegisters, RATC.reservedRegisters());
+      // Do not use the scratch memory address register.
+      if (ScratchSpaceAliasedRegs)
+        remove(PossibleRegisters, *ScratchSpaceAliasedRegs);
       remove(PossibleRegisters, DefAliases);
       assert(PossibleRegisters.any() && "No register left to choose from");
       const auto RandomReg = randomBit(PossibleRegisters);
       II.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
     }
   }
-  SnippetPrototype Prototype;
   Prototype.Explanation =
       "instruction has no tied variables picking Uses different from defs";
   Prototype.Snippet.push_back(std::move(II));
+  instantiateMemoryOperands(Prototype.ScratchSpaceReg, Prototype.Snippet);
   return std::move(Prototype);
 }
 
 std::vector<BenchmarkMeasure>
 UopsBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
+                                     ScratchSpace &Scratch,
                                      const unsigned NumRepetitions) const {
   const auto &SchedModel = State.getSubtargetInfo().getSchedModel();
 
@@ -220,8 +273,9 @@ UopsBenchmarkRunner::runMeasurements(con
         llvm::report_fatal_error(
             llvm::Twine("invalid perf event ").concat(PfmCounters));
       pfm::Counter Counter(UopPerfEvent);
+      Scratch.clear();
       Counter.start();
-      Function();
+      Function(Scratch.ptr());
       Counter.stop();
       CounterValue += Counter.read();
     }
@@ -232,4 +286,6 @@ UopsBenchmarkRunner::runMeasurements(con
   return Result;
 }
 
+constexpr const size_t UopsBenchmarkRunner::kMinNumDifferentAddresses;
+
 } // namespace exegesis

Modified: llvm/trunk/tools/llvm-exegesis/lib/Uops.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.h Wed Aug  1 07:41:45 2018
@@ -28,12 +28,41 @@ public:
   llvm::Expected<SnippetPrototype>
   generatePrototype(unsigned Opcode) const override;
 
+  static constexpr const size_t kMinNumDifferentAddresses = 6;
+
 private:
   llvm::Error isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const;
 
   std::vector<BenchmarkMeasure>
-  runMeasurements(const ExecutableFunction &EF,
+  runMeasurements(const ExecutableFunction &EF, ScratchSpace &Scratch,
                   const unsigned NumRepetitions) const override;
+
+  // Instantiates memory operands within a snippet.
+  // To make computations as parallel as possible, we generate independant
+  // memory locations for instructions that load and store. If there are less
+  // than kMinNumDifferentAddresses in the original snippet, we duplicate
+  // instructions until there are this number of instructions.
+  // For example, assuming kMinNumDifferentAddresses=5 and
+  // getMaxMemoryAccessSize()=64, if the original snippet is:
+  //   mov eax, [memory]
+  // we might generate:
+  //   mov eax, [rdi]
+  //   mov eax, [rdi + 64]
+  //   mov eax, [rdi + 128]
+  //   mov eax, [rdi + 192]
+  //   mov eax, [rdi + 256]
+  // If the original snippet is:
+  //   mov eax, [memory]
+  //   add eax, [memory]
+  // we might generate:
+  //   mov eax, [rdi]
+  //   add eax, [rdi + 64]
+  //   mov eax, [rdi + 128]
+  //   add eax, [rdi + 192]
+  //   mov eax, [rdi + 256]
+  void
+  instantiateMemoryOperands(unsigned ScratchSpaceReg,
+                            std::vector<InstructionInstance> &Snippet) const;
 };
 
 } // namespace exegesis

Modified: llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp Wed Aug  1 07:41:45 2018
@@ -109,6 +109,48 @@ class ExegesisX86Target : public Exegesi
     PM.add(llvm::createX86FloatingPointStackifierPass());
   }
 
+  unsigned getScratchMemoryRegister(const llvm::Triple &TT) const override {
+    if (!TT.isArch64Bit()) {
+      // FIXME: This would require popping from the stack, so we would have to
+      // add some additional setup code.
+      return 0;
+    }
+    return TT.isOSWindows() ? llvm::X86::RCX : llvm::X86::RDI;
+  }
+
+  unsigned getMaxMemoryAccessSize() const override { return 64; }
+
+  void fillMemoryOperands(InstructionInstance &II, unsigned Reg,
+                          unsigned Offset) const override {
+    // FIXME: For instructions that read AND write to memory, we use the same
+    // value for input and output.
+    for (size_t I = 0, E = II.Instr.Operands.size(); I < E; ++I) {
+      const Operand *Op = &II.Instr.Operands[I];
+      if (Op->IsExplicit && Op->IsMem) {
+        // Case 1: 5-op memory.
+        assert((I + 5 <= E) && "x86 memory references are always 5 ops");
+        II.getValueFor(*Op) = llvm::MCOperand::createReg(Reg); // BaseReg
+        Op = &II.Instr.Operands[++I];
+        assert(Op->IsMem);
+        assert(Op->IsExplicit);
+        II.getValueFor(*Op) = llvm::MCOperand::createImm(1); // ScaleAmt
+        Op = &II.Instr.Operands[++I];
+        assert(Op->IsMem);
+        assert(Op->IsExplicit);
+        II.getValueFor(*Op) = llvm::MCOperand::createReg(0); // IndexReg
+        Op = &II.Instr.Operands[++I];
+        assert(Op->IsMem);
+        assert(Op->IsExplicit);
+        II.getValueFor(*Op) = llvm::MCOperand::createImm(Offset); // Disp
+        Op = &II.Instr.Operands[++I];
+        assert(Op->IsMem);
+        assert(Op->IsExplicit);
+        II.getValueFor(*Op) = llvm::MCOperand::createReg(0); // Segment
+        // Case2: segment:index addressing. We assume that ES is 0.
+      }
+    }
+  }
+
   std::vector<llvm::MCInst> setRegToConstant(const llvm::MCSubtargetInfo &STI,
                                              unsigned Reg) const override {
     // GPR.

Modified: llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp Wed Aug  1 07:41:45 2018
@@ -30,11 +30,13 @@ protected:
 };
 
 TEST_F(ARMMachineFunctionGeneratorTest, DISABLED_JitFunction) {
-  Check(llvm::MCInst(), 0x1e, 0xff, 0x2f, 0xe1);
+  Check(ExegesisTarget::getDefault(), {}, llvm::MCInst(), 0x1e, 0xff, 0x2f,
+        0xe1);
 }
 
 TEST_F(ARMMachineFunctionGeneratorTest, DISABLED_JitFunctionADDrr) {
-  Check(MCInstBuilder(llvm::ARM::ADDrr)
+  Check(ExegesisTarget::getDefault(), {llvm::ARM::R0},
+        MCInstBuilder(llvm::ARM::ADDrr)
             .addReg(llvm::ARM::R0)
             .addReg(llvm::ARM::R0)
             .addReg(llvm::ARM::R0)

Added: llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkRunnerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkRunnerTest.cpp?rev=338567&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkRunnerTest.cpp (added)
+++ llvm/trunk/unittests/tools/llvm-exegesis/BenchmarkRunnerTest.cpp Wed Aug  1 07:41:45 2018
@@ -0,0 +1,31 @@
+//===-- BenchmarkRunnerTest.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 "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace exegesis {
+
+namespace {
+
+TEST(ScratchSpaceTest, Works) {
+  BenchmarkRunner::ScratchSpace Space;
+  EXPECT_EQ(reinterpret_cast<intptr_t>(Space.ptr()) %
+                BenchmarkRunner::ScratchSpace::kAlignment,
+            0u);
+  Space.ptr()[0] = 42;
+  Space.ptr()[BenchmarkRunner::ScratchSpace::kSize - 1] = 43;
+  Space.clear();
+  EXPECT_EQ(Space.ptr()[0], 0);
+  EXPECT_EQ(Space.ptr()[BenchmarkRunner::ScratchSpace::kSize - 1], 0);
+}
+
+} // namespace
+} // namespace exegesis

Modified: llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/CMakeLists.txt Wed Aug  1 07:41:45 2018
@@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(LLVMExegesisTests
   BenchmarkResultTest.cpp
+  BenchmarkRunnerTest.cpp
   ClusteringTest.cpp
   PerfHelperTest.cpp
   )

Modified: llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h Wed Aug  1 07:41:45 2018
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Assembler.h"
+#include "BenchmarkRunner.h"
 #include "Target.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -36,21 +37,19 @@ protected:
     }
   }
 
-  template <class... Bs> inline void Check(llvm::MCInst MCInst, Bs... Bytes) {
-    CheckWithSetup(ExegesisTarget::getDefault(), {}, MCInst, Bytes...);
-  }
-
   template <class... Bs>
-  inline void CheckWithSetup(const ExegesisTarget &ET,
-                             llvm::ArrayRef<unsigned> RegsToDef,
-                             llvm::MCInst MCInst, Bs... Bytes) {
+  inline void Check(const ExegesisTarget &ET,
+                    llvm::ArrayRef<unsigned> RegsToDef, llvm::MCInst MCInst,
+                    Bs... Bytes) {
     ExecutableFunction Function =
         (MCInst.getOpcode() == 0) ? assembleToFunction(ET, RegsToDef, {})
                                   : assembleToFunction(ET, RegsToDef, {MCInst});
     ASSERT_THAT(Function.getFunctionBytes().str(),
                 testing::ElementsAre(Bytes...));
-    if (CanExecute)
-      Function();
+    if (CanExecute) {
+      BenchmarkRunner::ScratchSpace Scratch;
+      Function(Scratch.ptr());
+    }
   }
 
 private:
@@ -73,7 +72,8 @@ private:
                      llvm::ArrayRef<llvm::MCInst> Instructions) {
     llvm::SmallString<256> Buffer;
     llvm::raw_svector_ostream AsmStream(Buffer);
-    assembleToStream(ET, createTargetMachine(), RegsToDef, Instructions,
+    assembleToStream(ET, createTargetMachine(), /*LiveIns=*/{},
+                     RegsToDef, Instructions,
                      AsmStream);
     return ExecutableFunction(createTargetMachine(),
                               getObjectFromBuffer(AsmStream.str()));

Modified: llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp Wed Aug  1 07:41:45 2018
@@ -11,6 +11,9 @@
 #include "X86InstrInfo.h"
 
 namespace exegesis {
+
+void InitializeX86ExegesisTarget();
+
 namespace {
 
 using llvm::MCInstBuilder;
@@ -31,25 +34,39 @@ protected:
     LLVMInitializeX86TargetMC();
     LLVMInitializeX86Target();
     LLVMInitializeX86AsmPrinter();
+    InitializeX86ExegesisTarget();
   }
 };
 
 TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunction) {
-  Check(llvm::MCInst(), 0xc3);
+  Check(ExegesisTarget::getDefault(), {}, llvm::MCInst(), 0xc3);
 }
 
-TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionXOR32rr) {
-  Check(MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX), 0x31, 0xc0,
+TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionXOR32rr_Default) {
+  Check(ExegesisTarget::getDefault(), {EAX},
+        MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX), 0x31, 0xc0,
         0xc3);
 }
 
+TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionXOR32rr_X86) {
+  const auto *ET = ExegesisTarget::lookup(llvm::Triple("x86_64-unknown-linux"));
+  ASSERT_NE(ET, nullptr);
+  Check(*ET, {EAX}, MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX),
+        // mov eax, 1
+        0xb8, 0x01, 0x00, 0x00, 0x00,
+        // xor eax, eax
+        0x31, 0xc0, 0xc3);
+}
+
 TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV64ri) {
-  Check(MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42), 0x48, 0xc7, 0xc0, 0x2a,
+  Check(ExegesisTarget::getDefault(), {},
+        MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42), 0x48, 0xc7, 0xc0, 0x2a,
         0x00, 0x00, 0x00, 0xc3);
 }
 
 TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV32ri) {
-  Check(MCInstBuilder(MOV32ri).addReg(EAX).addImm(42), 0xb8, 0x2a, 0x00, 0x00,
+  Check(ExegesisTarget::getDefault(), {},
+        MCInstBuilder(MOV32ri).addReg(EAX).addImm(42), 0xb8, 0x2a, 0x00, 0x00,
         0x00, 0xc3);
 }
 

Modified: llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp?rev=338567&r1=338566&r2=338567&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp Wed Aug  1 07:41:45 2018
@@ -18,6 +18,9 @@
 #include <unordered_set>
 
 namespace exegesis {
+
+void InitializeX86ExegesisTarget();
+
 namespace {
 
 using testing::AnyOf;
@@ -41,6 +44,7 @@ protected:
     LLVMInitializeX86TargetMC();
     LLVMInitializeX86Target();
     LLVMInitializeX86AsmPrinter();
+    InitializeX86ExegesisTarget();
   }
 
   const LLVMState State;
@@ -215,6 +219,30 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedV
   EXPECT_THAT(II.VariableValues[3], IsInvalid());
 }
 
+TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
+  // Mov32rm reads from memory.
+  const unsigned Opcode = llvm::X86::MOV32rm;
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("no tied variables"));
+  ASSERT_THAT(Proto.Snippet,
+              SizeIs(UopsBenchmarkRunner::kMinNumDifferentAddresses));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(6));
+  EXPECT_EQ(II.VariableValues[2].getImm(), 1);
+  EXPECT_EQ(II.VariableValues[3].getReg(), 0u);
+  EXPECT_EQ(II.VariableValues[4].getImm(), 0);
+  EXPECT_EQ(II.VariableValues[5].getReg(), 0u);
+}
+
+TEST_F(UopsSnippetGeneratorTest, MemoryUse_Movsb) {
+  // MOVSB writes to scratch memory register.
+  const unsigned Opcode = llvm::X86::MOVSB;
+  auto Error = Runner.generatePrototype(Opcode).takeError();
+  EXPECT_TRUE((bool)Error);
+  llvm::consumeError(std::move(Error));
+}
+
 class FakeBenchmarkRunner : public BenchmarkRunner {
 public:
   FakeBenchmarkRunner(const LLVMState &State)
@@ -232,7 +260,7 @@ private:
   }
 
   std::vector<BenchmarkMeasure>
-  runMeasurements(const ExecutableFunction &EF,
+  runMeasurements(const ExecutableFunction &EF, ScratchSpace &Scratch,
                   const unsigned NumRepetitions) const override {
     return {};
   }




More information about the llvm-commits mailing list