[llvm] r335465 - [llvm-exegesis] Generate snippet setup code.

Clement Courbet via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 25 06:12:02 PDT 2018


Author: courbet
Date: Mon Jun 25 06:12:02 2018
New Revision: 335465

URL: http://llvm.org/viewvc/llvm-project?rev=335465&view=rev
Log:
[llvm-exegesis] Generate snippet setup code.

Summary:
This ensures that the snippet always sees the same values for registers,
making measurements reproducible.
This will also allow exploring different values.

Reviewers: gchatelet

Subscribers: tschuett, llvm-commits

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

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/LlvmState.cpp
    llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h
    llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp
    llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h
    llvm/trunk/tools/llvm-exegesis/lib/Target.h
    llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h
    llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
    llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp Mon Jun 25 06:12:02 2018
@@ -28,6 +28,21 @@ namespace exegesis {
 static constexpr const char ModuleID[] = "ExegesisInfoTest";
 static constexpr const char FunctionID[] = "foo";
 
+static std::vector<llvm::MCInst>
+generateSnippetSetupCode(const llvm::ArrayRef<unsigned> RegsToDef,
+                         const ExegesisTarget &ET, bool &IsComplete) {
+  IsComplete = true;
+  std::vector<llvm::MCInst> Result;
+  for (const unsigned Reg : RegsToDef) {
+    // Load a constant in the register.
+    const auto Code = ET.setRegToConstant(Reg);
+    if (Code.empty())
+      IsComplete = false;
+    Result.insert(Result.end(), Code.begin(), Code.end());
+  }
+  return Result;
+}
+
 // Small utility function to add named passes.
 static bool addPass(llvm::PassManagerBase &PM, llvm::StringRef PassName,
                     llvm::TargetPassConfig &TPC) {
@@ -123,7 +138,9 @@ llvm::BitVector getFunctionReservedRegs(
   return MF.getSubtarget().getRegisterInfo()->getReservedRegs(MF);
 }
 
-void assembleToStream(std::unique_ptr<llvm::LLVMTargetMachine> TM,
+void assembleToStream(const ExegesisTarget *ET,
+                      std::unique_ptr<llvm::LLVMTargetMachine> TM,
+                      llvm::ArrayRef<unsigned> RegsToDef,
                       llvm::ArrayRef<llvm::MCInst> Instructions,
                       llvm::raw_pwrite_stream &AsmStream) {
   std::unique_ptr<llvm::LLVMContext> Context =
@@ -140,9 +157,20 @@ void assembleToStream(std::unique_ptr<ll
   auto &Properties = MF.getProperties();
   Properties.set(llvm::MachineFunctionProperties::Property::NoVRegs);
   Properties.reset(llvm::MachineFunctionProperties::Property::IsSSA);
-  // FIXME: Remove this when we assign all used registers as config step. This
-  // essentially disables checks that used registers are def'ed somewhere.
-  Properties.reset(llvm::MachineFunctionProperties::Property::TracksLiveness);
+  std::vector<llvm::MCInst> SnippetWithSetup;
+  bool IsSnippetSetupComplete;
+  if (ET) {
+    SnippetWithSetup =
+        generateSnippetSetupCode(RegsToDef, *ET, IsSnippetSetupComplete);
+    SnippetWithSetup.insert(SnippetWithSetup.end(), Instructions.begin(),
+                            Instructions.end());
+    Instructions = SnippetWithSetup;
+  }
+  // If the snippet setup is not complete, we disable liveliness tracking. This
+  // means that we won't know what values are in the registers.
+  if (!IsSnippetSetupComplete)
+    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);
@@ -162,7 +190,7 @@ void assembleToStream(std::unique_ptr<ll
   PM.add(MMI.release());
   TPC->printAndVerify("MachineFunctionGenerator::assemble");
   // Add target-specific passes.
-  if (const auto *ET = ExegesisTarget::lookup(TM->getTargetTriple())) {
+  if (ET) {
     ET->addTargetSpecificPasses(PM);
     TPC->printAndVerify("After ExegesisTarget::addTargetSpecificPasses");
   }

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Assembler.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Assembler.h Mon Jun 25 06:12:02 2018
@@ -33,6 +33,8 @@
 
 namespace exegesis {
 
+class ExegesisTarget;
+
 // Gather the set of reserved registers (depends on function's calling
 // convention and target machine).
 llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM);
@@ -41,7 +43,9 @@ llvm::BitVector getFunctionReservedRegs(
 // 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(std::unique_ptr<llvm::LLVMTargetMachine> TM,
+void assembleToStream(const ExegesisTarget *ET,
+                      std::unique_ptr<llvm::LLVMTargetMachine> TM,
+                      llvm::ArrayRef<unsigned> RegsToDef,
                       llvm::ArrayRef<llvm::MCInst> Instructions,
                       llvm::raw_pwrite_stream &AsmStream);
 

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp Mon Jun 25 06:12:02 2018
@@ -78,10 +78,11 @@ BenchmarkRunner::runOne(const BenchmarkC
 
   // Repeat the snippet until there are at least NumInstructions in the
   // resulting code. The snippet is always repeated at least once.
-  const auto GenerateInstructions = [&Snippet](const int MinInstructions) {
-    std::vector<llvm::MCInst> Code = Snippet;
+  const auto GenerateInstructions = [&Configuration](
+                                        const int MinInstructions) {
+    std::vector<llvm::MCInst> Code = Configuration.Snippet;
     for (int I = 0; I < MinInstructions; ++I)
-      Code.push_back(Snippet[I % Snippet.size()]);
+      Code.push_back(Configuration.Snippet[I % Configuration.Snippet.size()]);
     return Code;
   };
 
@@ -91,7 +92,8 @@ BenchmarkRunner::runOne(const BenchmarkC
   constexpr const int kMinInstructionsForSnippet = 16;
   {
     auto ObjectFilePath =
-        writeObjectFile(GenerateInstructions(kMinInstructionsForSnippet));
+        writeObjectFile(Configuration.SnippetSetup,
+                        GenerateInstructions(kMinInstructionsForSnippet));
     if (llvm::Error E = ObjectFilePath.takeError()) {
       InstrBenchmark.Error = llvm::toString(std::move(E));
       return InstrBenchmark;
@@ -105,7 +107,8 @@ BenchmarkRunner::runOne(const BenchmarkC
   // Assemble NumRepetitions instructions repetitions of the snippet for
   // measurements.
   auto ObjectFilePath =
-      writeObjectFile(GenerateInstructions(InstrBenchmark.NumRepetitions));
+      writeObjectFile(Configuration.SnippetSetup,
+                      GenerateInstructions(InstrBenchmark.NumRepetitions));
   if (llvm::Error E = ObjectFilePath.takeError()) {
     InstrBenchmark.Error = llvm::toString(std::move(E));
     return InstrBenchmark;
@@ -126,22 +129,68 @@ BenchmarkRunner::generateConfigurations(
     // TODO: Generate as many configurations as needed here.
     BenchmarkConfiguration Configuration;
     Configuration.Info = Prototype.Explanation;
-    for (InstructionInstance &II : Prototype.Snippet)
-      Configuration.Snippet.push_back(II.randomizeUnsetVariablesAndBuild());
+    for (InstructionInstance &II : Prototype.Snippet) {
+      II.randomizeUnsetVariables();
+      Configuration.Snippet.push_back(II.build());
+    }
+    Configuration.SnippetSetup.RegsToDef = computeRegsToDef(Prototype.Snippet);
     return std::vector<BenchmarkConfiguration>{Configuration};
   } else
     return E.takeError();
 }
 
+std::vector<unsigned> BenchmarkRunner::computeRegsToDef(
+    const std::vector<InstructionInstance> &Snippet) const {
+  // Collect all register uses and create an assignment for each of them.
+  // Loop invariant: DefinedRegs[i] is true iif it has been set at least once
+  // before the current instruction.
+  llvm::BitVector DefinedRegs = RATC.emptyRegisters();
+  std::vector<unsigned> RegsToDef;
+  for (const InstructionInstance &II : Snippet) {
+    // 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) {
+        return *Op.ImplicitReg;
+      } else if (Op.IsExplicit && II.getValueFor(Op).isReg()) {
+        return II.getValueFor(Op).getReg();
+      }
+      return 0;
+    };
+    // Collect used registers that have never been def'ed.
+    for (const Operand &Op : II.Instr.Operands) {
+      if (!Op.IsDef) {
+        const unsigned Reg = GetOpReg(Op);
+        if (Reg > 0 && !DefinedRegs.test(Reg)) {
+          RegsToDef.push_back(Reg);
+          DefinedRegs.set(Reg);
+        }
+      }
+    }
+    // Mark defs as having been def'ed.
+    for (const Operand &Op : II.Instr.Operands) {
+      if (Op.IsDef) {
+        const unsigned Reg = GetOpReg(Op);
+        if (Reg > 0) {
+          DefinedRegs.set(Reg);
+        }
+      }
+    }
+  }
+  return RegsToDef;
+}
+
 llvm::Expected<std::string>
-BenchmarkRunner::writeObjectFile(llvm::ArrayRef<llvm::MCInst> Code) const {
+BenchmarkRunner::writeObjectFile(const BenchmarkConfiguration::Setup &Setup,
+                                 llvm::ArrayRef<llvm::MCInst> Code) const {
   int ResultFD = 0;
   llvm::SmallString<256> ResultPath;
   if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
           "snippet", "o", ResultFD, ResultPath)))
     return std::move(E);
   llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
-  assembleToStream(State.createTargetMachine(), Code, OFS);
+  assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
+                   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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h Mon Jun 25 06:12:02 2018
@@ -39,7 +39,10 @@ struct BenchmarkConfiguration {
   // This code is run before the Snippet is iterated. Since it is part of the
   // measurement it should be as short as possible. It is usually used to setup
   // the content of the Registers.
-  std::vector<llvm::MCInst> SnippetSetup;
+  struct Setup {
+    std::vector<unsigned> RegsToDef;
+  };
+  Setup SnippetSetup;
 
   // The sequence of instructions that are to be repeated.
   std::vector<llvm::MCInst> Snippet;
@@ -71,6 +74,10 @@ public:
   run(unsigned Opcode, const InstructionFilter &Filter,
       unsigned NumRepetitions);
 
+  // Given a snippet, computes which registers the setup code needs to define.
+  std::vector<unsigned>
+  computeRegsToDef(const std::vector<InstructionInstance> &Snippet) const;
+
 protected:
   const LLVMState &State;
   const llvm::MCInstrInfo &MCInstrInfo;
@@ -96,9 +103,8 @@ private:
                   const unsigned NumRepetitions) const = 0;
 
   llvm::Expected<std::string>
-  writeObjectFile(llvm::ArrayRef<llvm::MCInst> Code) const;
-  llvm::Expected<ExecutableFunction>
-  createExecutableFunction(llvm::ArrayRef<llvm::MCInst> Code) const;
+  writeObjectFile(const BenchmarkConfiguration::Setup &Setup,
+                  llvm::ArrayRef<llvm::MCInst> Code) const;
 };
 
 } // namespace exegesis

Modified: llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp?rev=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/LlvmState.cpp Mon Jun 25 06:12:02 2018
@@ -29,6 +29,7 @@ LLVMState::LLVMState(const std::string &
   TargetMachine.reset(static_cast<llvm::LLVMTargetMachine *>(
       TheTarget->createTargetMachine(Triple, CpuName, /*Features*/ "", Options,
                                      llvm::Reloc::Model::Static)));
+  TheExegesisTarget = ExegesisTarget::lookup(TargetMachine->getTargetTriple());
 }
 
 LLVMState::LLVMState()

Modified: llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h?rev=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/LlvmState.h Mon Jun 25 06:12:02 2018
@@ -15,6 +15,7 @@
 #ifndef LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H
 #define LLVM_TOOLS_LLVM_EXEGESIS_LLVMSTATE_H
 
+#include "Target.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrInfo.h"

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp Mon Jun 25 06:12:02 2018
@@ -99,11 +99,22 @@ llvm::MCOperand &InstructionInstance::ge
   return VariableValues[Var.Index];
 }
 
+const llvm::MCOperand &
+InstructionInstance::getValueFor(const Variable &Var) const {
+  return VariableValues[Var.Index];
+}
+
 llvm::MCOperand &InstructionInstance::getValueFor(const Operand &Op) {
   assert(Op.VariableIndex >= 0);
   return getValueFor(Instr.Variables[Op.VariableIndex]);
 }
 
+const llvm::MCOperand &
+InstructionInstance::getValueFor(const Operand &Op) const {
+  assert(Op.VariableIndex >= 0);
+  return getValueFor(Instr.Variables[Op.VariableIndex]);
+}
+
 // forward declaration.
 static void randomize(const Instruction &Instr, const Variable &Var,
                       llvm::MCOperand &AssignedValue);
@@ -118,12 +129,15 @@ bool InstructionInstance::hasImmediateVa
   });
 }
 
-llvm::MCInst InstructionInstance::randomizeUnsetVariablesAndBuild() {
+void InstructionInstance::randomizeUnsetVariables() {
   for (const Variable &Var : Instr.Variables) {
     llvm::MCOperand &AssignedValue = getValueFor(Var);
     if (!AssignedValue.isValid())
       randomize(Instr, Var, AssignedValue);
   }
+}
+
+llvm::MCInst InstructionInstance::build() const {
   llvm::MCInst Result;
   Result.setOpcode(Instr.Description->Opcode);
   for (const auto &Op : Instr.Operands)

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h Mon Jun 25 06:12:02 2018
@@ -93,12 +93,17 @@ struct InstructionInstance {
 
   unsigned getOpcode() const;
   llvm::MCOperand &getValueFor(const Variable &Var);
+  const llvm::MCOperand &getValueFor(const Variable &Var) const;
   llvm::MCOperand &getValueFor(const Operand &Op);
+  const llvm::MCOperand &getValueFor(const Operand &Op) const;
   bool hasImmediateVariables() const;
 
-  // Assigns a Random Value to all Variables that are still Invalid and returns
-  // the instance as an llvm::MCInst.
-  llvm::MCInst randomizeUnsetVariablesAndBuild();
+  // Assigns a Random Value to all Variables that are still Invalid.
+  void randomizeUnsetVariables();
+
+  // Returns the instance as an llvm::MCInst. The InstructionInstance must be
+  // fully allocated (no invalid variables).
+  llvm::MCInst build() const;
 
   Instruction Instr;
   llvm::SmallVector<llvm::MCOperand, 4> VariableValues;

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Target.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Target.h Mon Jun 25 06:12:02 2018
@@ -20,6 +20,8 @@
 #include "llvm/ADT/Triple.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/LegacyPassManager.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
 
 namespace exegesis {
 
@@ -28,6 +30,11 @@ public:
   // Targets can use this to add target-specific passes in assembleToStream();
   virtual void addTargetSpecificPasses(llvm::PassManagerBase &PM) const {}
 
+  // Generates code to move a constant into a the given register.
+  virtual std::vector<llvm::MCInst> setRegToConstant(unsigned Reg) const {
+    return {};
+  }
+
   // Returns the ExegesisTarget for the given triple or nullptr if the target
   // does not exist.
   static const ExegesisTarget *lookup(llvm::Triple TT);

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp Mon Jun 25 06:12:02 2018
@@ -8,7 +8,10 @@
 //===----------------------------------------------------------------------===//
 #include "../Target.h"
 
+#include "MCTargetDesc/X86MCTargetDesc.h"
 #include "X86.h"
+#include "X86RegisterInfo.h"
+#include "llvm/MC/MCInstBuilder.h"
 
 namespace exegesis {
 
@@ -22,9 +25,88 @@ class ExegesisX86Target : public Exegesi
     // PM.add(llvm::createX86FloatingPointStackifierPass());
   }
 
+  std::vector<llvm::MCInst>
+  setRegToConstant(const unsigned Reg) const override {
+    // FIXME: Handle FP stack:
+    // llvm::X86::RFP32RegClass
+    // llvm::X86::RFP64RegClass
+    // llvm::X86::RFP80RegClass
+    if (llvm::X86::GR8RegClass.contains(Reg)) {
+      return {llvm::MCInstBuilder(llvm::X86::MOV8ri).addReg(Reg).addImm(1)};
+    }
+    if (llvm::X86::GR16RegClass.contains(Reg)) {
+      return {llvm::MCInstBuilder(llvm::X86::MOV16ri).addReg(Reg).addImm(1)};
+    }
+    if (llvm::X86::GR32RegClass.contains(Reg)) {
+      return {llvm::MCInstBuilder(llvm::X86::MOV32ri).addReg(Reg).addImm(1)};
+    }
+    if (llvm::X86::GR64RegClass.contains(Reg)) {
+      return {llvm::MCInstBuilder(llvm::X86::MOV64ri32).addReg(Reg).addImm(1)};
+    }
+    if (llvm::X86::VR128XRegClass.contains(Reg)) {
+      return setVectorRegToConstant(Reg, 16, llvm::X86::VMOVDQUrm);
+    }
+    if (llvm::X86::VR256XRegClass.contains(Reg)) {
+      return setVectorRegToConstant(Reg, 32, llvm::X86::VMOVDQUYrm);
+    }
+    if (llvm::X86::VR512RegClass.contains(Reg)) {
+      return setVectorRegToConstant(Reg, 64, llvm::X86::VMOVDQU64Zrm);
+    }
+    return {};
+  }
+
   bool matchesArch(llvm::Triple::ArchType Arch) const override {
     return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86;
   }
+
+private:
+  // setRegToConstant() specialized for a vector register of size
+  // `RegSizeBytes`. `RMOpcode` is the opcode used to do a memory -> vector
+  // register load.
+  static std::vector<llvm::MCInst>
+  setVectorRegToConstant(const unsigned Reg, const unsigned RegSizeBytes,
+                         const unsigned RMOpcode) {
+    // There is no instruction to directly set XMM, go through memory.
+    // Since vector values can be interpreted as integers of various sizes (8
+    // to 64 bits) as well as floats and double, so we chose an immediate
+    // value that has set bits for all byte values and is a normal float/
+    // double. 0x40404040 is ~32.5 when interpreted as a double and ~3.0f when
+    // interpreted as a float.
+    constexpr const uint64_t kImmValue = 0x40404040ull;
+    std::vector<llvm::MCInst> Result;
+    // Allocate scratch memory on the stack.
+    Result.push_back(llvm::MCInstBuilder(llvm::X86::SUB64ri8)
+                         .addReg(llvm::X86::RSP)
+                         .addReg(llvm::X86::RSP)
+                         .addImm(RegSizeBytes));
+    // Fill scratch memory.
+    for (unsigned Disp = 0; Disp < RegSizeBytes; Disp += 4) {
+      Result.push_back(llvm::MCInstBuilder(llvm::X86::MOV32mi)
+                           // Address = ESP
+                           .addReg(llvm::X86::RSP) // BaseReg
+                           .addImm(1)              // ScaleAmt
+                           .addReg(0)              // IndexReg
+                           .addImm(Disp)           // Disp
+                           .addReg(0)              // Segment
+                           // Immediate.
+                           .addImm(kImmValue));
+    }
+    // Load Reg from scratch memory.
+    Result.push_back(llvm::MCInstBuilder(RMOpcode)
+                         .addReg(Reg)
+                         // Address = ESP
+                         .addReg(llvm::X86::RSP) // BaseReg
+                         .addImm(1)              // ScaleAmt
+                         .addReg(0)              // IndexReg
+                         .addImm(0)              // Disp
+                         .addReg(0));            // Segment
+    // Release scratch memory.
+    Result.push_back(llvm::MCInstBuilder(llvm::X86::ADD64ri8)
+                         .addReg(llvm::X86::RSP)
+                         .addReg(llvm::X86::RSP)
+                         .addImm(RegSizeBytes));
+    return Result;
+  }
 };
 
 } // namespace

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h Mon Jun 25 06:12:02 2018
@@ -36,9 +36,16 @@ protected:
   }
 
   template <class... Bs> inline void Check(llvm::MCInst MCInst, Bs... Bytes) {
-    ExecutableFunction Function = (MCInst.getOpcode() == 0)
-                                      ? assembleToFunction({})
-                                      : assembleToFunction({MCInst});
+    CheckWithSetup(nullptr, {}, MCInst, Bytes...);
+  }
+
+  template <class... Bs>
+  inline void CheckWithSetup(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)
@@ -60,10 +67,13 @@ private:
   }
 
   ExecutableFunction
-  assembleToFunction(llvm::ArrayRef<llvm::MCInst> Instructions) {
+  assembleToFunction(const ExegesisTarget *ET,
+                     llvm::ArrayRef<unsigned> RegsToDef,
+                     llvm::ArrayRef<llvm::MCInst> Instructions) {
     llvm::SmallString<256> Buffer;
     llvm::raw_svector_ostream AsmStream(Buffer);
-    assembleToStream(createTargetMachine(), Instructions, AsmStream);
+    assembleToStream(ET, createTargetMachine(), RegsToDef, Instructions,
+                     AsmStream);
     return ExecutableFunction(createTargetMachine(),
                               getObjectFromBuffer(AsmStream.str()));
   }

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=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp Mon Jun 25 06:12:02 2018
@@ -25,6 +25,7 @@ using testing::ElementsAre;
 using testing::HasSubstr;
 using testing::Not;
 using testing::SizeIs;
+using testing::UnorderedElementsAre;
 
 MATCHER(IsInvalid, "") { return !arg.isValid(); }
 MATCHER(IsReg, "") { return arg.isReg(); }
@@ -214,5 +215,74 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedV
   EXPECT_THAT(II.VariableValues[3], IsInvalid());
 }
 
+class FakeBenchmarkRunner : public BenchmarkRunner {
+public:
+  using BenchmarkRunner::BenchmarkRunner;
+
+  Instruction createInstruction(unsigned Opcode) {
+    return Instruction(MCInstrInfo.get(Opcode), RATC);
+  }
+
+private:
+  InstructionBenchmark::ModeE getMode() const override {
+    return InstructionBenchmark::Unknown;
+  }
+
+  llvm::Expected<SnippetPrototype>
+  generatePrototype(unsigned Opcode) const override {
+    return llvm::make_error<llvm::StringError>("not implemented",
+                                               llvm::inconvertibleErrorCode());
+  }
+
+  std::vector<BenchmarkMeasure>
+  runMeasurements(const ExecutableFunction &EF,
+                  const unsigned NumRepetitions) const override {
+    return {};
+  }
+};
+
+using FakeSnippetGeneratorTest = SnippetGeneratorTest<FakeBenchmarkRunner>;
+
+TEST_F(FakeSnippetGeneratorTest, ComputeRegsToDefAdd16ri) {
+  // ADD16ri:
+  // explicit def 0       : reg RegClass=GR16
+  // explicit use 1       : reg RegClass=GR16 | TIED_TO:0
+  // explicit use 2       : imm
+  // implicit def         : EFLAGS
+  InstructionInstance II(Runner.createInstruction(llvm::X86::ADD16ri));
+  II.getValueFor(II.Instr.Variables[0]) =
+      llvm::MCOperand::createReg(llvm::X86::AX);
+  std::vector<InstructionInstance> Snippet;
+  Snippet.push_back(std::move(II));
+  const auto RegsToDef = Runner.computeRegsToDef(Snippet);
+  EXPECT_THAT(RegsToDef, UnorderedElementsAre(llvm::X86::AX));
+}
+
+TEST_F(FakeSnippetGeneratorTest, ComputeRegsToDefAdd64rr) {
+  // ADD64rr:
+  //  mov64ri rax, 42
+  //  add64rr rax, rax, rbx
+  // -> only rbx needs defining.
+  std::vector<InstructionInstance> Snippet;
+  {
+    InstructionInstance Mov(Runner.createInstruction(llvm::X86::MOV64ri));
+    Mov.getValueFor(Mov.Instr.Variables[0]) =
+        llvm::MCOperand::createReg(llvm::X86::RAX);
+    Mov.getValueFor(Mov.Instr.Variables[1]) = llvm::MCOperand::createImm(42);
+    Snippet.push_back(std::move(Mov));
+  }
+  {
+    InstructionInstance Add(Runner.createInstruction(llvm::X86::ADD64rr));
+    Add.getValueFor(Add.Instr.Variables[0]) =
+        llvm::MCOperand::createReg(llvm::X86::RAX);
+    Add.getValueFor(Add.Instr.Variables[1]) =
+        llvm::MCOperand::createReg(llvm::X86::RBX);
+    Snippet.push_back(std::move(Add));
+  }
+
+  const auto RegsToDef = Runner.computeRegsToDef(Snippet);
+  EXPECT_THAT(RegsToDef, UnorderedElementsAre(llvm::X86::RBX));
+}
+
 } // namespace
 } // namespace exegesis

Modified: llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.cpp?rev=335465&r1=335464&r2=335465&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.cpp Mon Jun 25 06:12:02 2018
@@ -3,6 +3,7 @@
 #include <cassert>
 #include <memory>
 
+#include "MCTargetDesc/X86MCTargetDesc.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -12,16 +13,31 @@ void InitializeX86ExegesisTarget();
 
 namespace {
 
+using testing::Gt;
 using testing::NotNull;
+using testing::SizeIs;
 
 class X86TargetTest : public ::testing::Test {
 protected:
+  X86TargetTest()
+      : Target_(ExegesisTarget::lookup(llvm::Triple("x86_64-unknown-linux"))) {
+    EXPECT_THAT(Target_, NotNull());
+  }
   static void SetUpTestCase() { InitializeX86ExegesisTarget(); }
+
+  const ExegesisTarget *const Target_;
 };
 
-TEST_F(X86TargetTest, Lookup) {
-  EXPECT_THAT(ExegesisTarget::lookup(llvm::Triple("x86_64-unknown-linux")),
-              NotNull());
+TEST_F(X86TargetTest, SetRegToConstantGPR) {
+  const auto Insts = Target_->setRegToConstant(llvm::X86::EAX);
+  EXPECT_THAT(Insts, SizeIs(1));
+  EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::MOV32ri);
+  EXPECT_EQ(Insts[0].getOperand(0).getReg(), llvm::X86::EAX);
+}
+
+TEST_F(X86TargetTest, SetRegToConstantXMM) {
+  const auto Insts = Target_->setRegToConstant(llvm::X86::XMM1);
+  EXPECT_THAT(Insts, SizeIs(Gt(0)));
 }
 
 } // namespace




More information about the llvm-commits mailing list