[llvm] r335105 - [llvm-exegesis] Use a Prototype to defer picking a value for free vars.

Guillaume Chatelet via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 20 01:52:30 PDT 2018


Author: gchatelet
Date: Wed Jun 20 01:52:30 2018
New Revision: 335105

URL: http://llvm.org/viewvc/llvm-project?rev=335105&view=rev
Log:
[llvm-exegesis] Use a Prototype to defer picking a value for free vars.

Summary: Introducing a Prototype object to capture Variables that must be set but keeps degrees of freedom as Invalid. This allows exploring non constraint variables later on.

Reviewers: courbet

Subscribers: tschuett, llvm-commits

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

Modified:
    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/Uops.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Uops.h
    llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp Wed Jun 20 01:52:30 2018
@@ -47,7 +47,7 @@ BenchmarkRunner::run(unsigned Opcode, co
     return std::move(E);
 
   llvm::Expected<std::vector<BenchmarkConfiguration>> ConfigurationOrError =
-      createConfigurations(Opcode);
+      generateConfigurations(Opcode);
 
   if (llvm::Error E = ConfigurationOrError.takeError())
     return std::move(E);
@@ -113,6 +113,20 @@ BenchmarkRunner::runOne(const BenchmarkC
   return InstrBenchmark;
 }
 
+llvm::Expected<std::vector<BenchmarkConfiguration>>
+BenchmarkRunner::generateConfigurations(unsigned Opcode) const {
+  if (auto E = generatePrototype(Opcode)) {
+    SnippetPrototype &Prototype = E.get();
+    // 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());
+    return std::vector<BenchmarkConfiguration>{Configuration};
+  } else
+    return E.takeError();
+}
+
 llvm::Expected<std::string>
 BenchmarkRunner::writeObjectFile(llvm::ArrayRef<llvm::MCInst> Code) const {
   int ResultFD = 0;

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h Wed Jun 20 01:52:30 2018
@@ -19,6 +19,7 @@
 #include "Assembler.h"
 #include "BenchmarkResult.h"
 #include "LlvmState.h"
+#include "MCInstrDescView.h"
 #include "RegisterAliasing.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/Support/Error.h"
@@ -80,10 +81,15 @@ private:
   InstructionBenchmark runOne(const BenchmarkConfiguration &Configuration,
                               unsigned Opcode, unsigned NumRepetitions) const;
 
+  // Calls generatePrototype and expands the SnippetPrototype into one or more
+  // BenchmarkConfiguration.
+  llvm::Expected<std::vector<BenchmarkConfiguration>>
+  generateConfigurations(unsigned Opcode) const;
+
   virtual InstructionBenchmark::ModeE getMode() const = 0;
 
-  virtual llvm::Expected<std::vector<BenchmarkConfiguration>>
-  createConfigurations(unsigned Opcode) const = 0;
+  virtual llvm::Expected<SnippetPrototype>
+  generatePrototype(unsigned Opcode) const = 0;
 
   virtual std::vector<BenchmarkMeasure>
   runMeasurements(const ExecutableFunction &EF,

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp Wed Jun 20 01:52:30 2018
@@ -16,6 +16,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstBuilder.h"
+#include "llvm/Support/FormatVariadic.h"
 
 namespace exegesis {
 
@@ -47,26 +48,27 @@ llvm::Error LatencyBenchmarkRunner::isIn
   return llvm::Error::success();
 }
 
-llvm::Expected<BenchmarkConfiguration>
-LatencyBenchmarkRunner::generateSelfAliasingConfiguration(
+llvm::Expected<SnippetPrototype>
+LatencyBenchmarkRunner::generateSelfAliasingPrototype(
     const Instruction &Instr,
     const AliasingConfigurations &SelfAliasing) const {
-  BenchmarkConfiguration Conf;
+  SnippetPrototype Prototype;
   InstructionInstance II(Instr);
   if (SelfAliasing.hasImplicitAliasing()) {
-    Conf.Info = "implicit Self cycles, picking random values.";
+    Prototype.Explanation = "implicit Self cycles, picking random values.";
   } else {
-    Conf.Info = "explicit self cycles, selecting one aliasing Conf.";
+    Prototype.Explanation =
+        "explicit self cycles, selecting one aliasing Conf.";
     // This is a self aliasing instruction so defs and uses are from the same
     // instance, hence twice II in the following call.
     setRandomAliasing(SelfAliasing, II, II);
   }
-  Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
-  return Conf;
+  Prototype.Snippet.push_back(std::move(II));
+  return Prototype;
 }
 
-llvm::Expected<BenchmarkConfiguration>
-LatencyBenchmarkRunner::generateTwoInstructionConfiguration(
+llvm::Expected<SnippetPrototype>
+LatencyBenchmarkRunner::generateTwoInstructionPrototype(
     const Instruction &Instr,
     const AliasingConfigurations &SelfAliasing) const {
   std::vector<unsigned> Opcodes;
@@ -74,7 +76,7 @@ LatencyBenchmarkRunner::generateTwoInstr
   std::iota(Opcodes.begin(), Opcodes.end(), 0U);
   std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
   for (const unsigned OtherOpcode : Opcodes) {
-    if (OtherOpcode == Instr.Description.Opcode)
+    if (OtherOpcode == Instr.Description->Opcode)
       continue;
     const auto &OtherInstrDesc = MCInstrInfo.get(OtherOpcode);
     if (auto E = isInfeasible(OtherInstrDesc)) {
@@ -92,21 +94,19 @@ LatencyBenchmarkRunner::generateTwoInstr
       setRandomAliasing(Forward, ThisII, OtherII);
     if (!Back.hasImplicitAliasing())
       setRandomAliasing(Back, OtherII, ThisII);
-    BenchmarkConfiguration Conf;
-    Conf.Info = llvm::Twine("creating cycle through ")
-                    .concat(MCInstrInfo.getName(OtherOpcode))
-                    .concat(".")
-                    .str();
-    Conf.Snippet.push_back(ThisII.randomizeUnsetVariablesAndBuild());
-    Conf.Snippet.push_back(OtherII.randomizeUnsetVariablesAndBuild());
-    return Conf;
+    SnippetPrototype Prototype;
+    Prototype.Explanation = llvm::formatv("creating cycle through {0}.",
+                                          MCInstrInfo.getName(OtherOpcode));
+    Prototype.Snippet.push_back(std::move(ThisII));
+    Prototype.Snippet.push_back(std::move(OtherII));
+    return Prototype;
   }
   return llvm::make_error<BenchmarkFailure>(
       "Infeasible : Didn't find any scheme to make the instruction serial");
 }
 
-llvm::Expected<BenchmarkConfiguration>
-LatencyBenchmarkRunner::generateConfiguration(unsigned Opcode) const {
+llvm::Expected<SnippetPrototype>
+LatencyBenchmarkRunner::generatePrototype(unsigned Opcode) const {
   const auto &InstrDesc = MCInstrInfo.get(Opcode);
   if (auto E = isInfeasible(InstrDesc))
     return std::move(E);
@@ -114,20 +114,12 @@ LatencyBenchmarkRunner::generateConfigur
   const AliasingConfigurations SelfAliasing(Instr, Instr);
   if (SelfAliasing.empty()) {
     // No self aliasing, trying to create a dependency through another opcode.
-    return generateTwoInstructionConfiguration(Instr, SelfAliasing);
+    return generateTwoInstructionPrototype(Instr, SelfAliasing);
   } else {
-    return generateSelfAliasingConfiguration(Instr, SelfAliasing);
+    return generateSelfAliasingPrototype(Instr, SelfAliasing);
   }
 }
 
-llvm::Expected<std::vector<BenchmarkConfiguration>>
-LatencyBenchmarkRunner::createConfigurations(unsigned Opcode) const {
-  if (auto E = generateConfiguration(Opcode))
-    return std::vector<BenchmarkConfiguration>{E.get()};
-  else
-    return E.takeError();
-}
-
 std::vector<BenchmarkMeasure>
 LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
                                         const unsigned NumRepetitions) const {

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.h Wed Jun 20 01:52:30 2018
@@ -25,25 +25,22 @@ public:
   using BenchmarkRunner::BenchmarkRunner;
   ~LatencyBenchmarkRunner() override;
 
-  llvm::Expected<BenchmarkConfiguration>
-  generateConfiguration(unsigned Opcode) const;
+  llvm::Expected<SnippetPrototype>
+  generatePrototype(unsigned Opcode) const override;
 
 private:
   llvm::Error isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const;
 
-  llvm::Expected<BenchmarkConfiguration> generateSelfAliasingConfiguration(
+  llvm::Expected<SnippetPrototype> generateSelfAliasingPrototype(
       const Instruction &Instr,
       const AliasingConfigurations &SelfAliasing) const;
 
-  llvm::Expected<BenchmarkConfiguration> generateTwoInstructionConfiguration(
+  llvm::Expected<SnippetPrototype> generateTwoInstructionPrototype(
       const Instruction &Instr,
       const AliasingConfigurations &SelfAliasing) const;
 
   InstructionBenchmark::ModeE getMode() const override;
 
-  llvm::Expected<std::vector<BenchmarkConfiguration>>
-  createConfigurations(unsigned OpcodeIndex) const override;
-
   std::vector<BenchmarkMeasure>
   runMeasurements(const ExecutableFunction &EF,
                   const unsigned NumRepetitions) const override;

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.cpp Wed Jun 20 01:52:30 2018
@@ -19,7 +19,7 @@ namespace exegesis {
 
 Instruction::Instruction(const llvm::MCInstrDesc &MCInstrDesc,
                          const RegisterAliasingTrackerCache &RATC)
-    : Description(MCInstrDesc) {
+    : Description(&MCInstrDesc) {
   unsigned OpIndex = 0;
   for (; OpIndex < MCInstrDesc.getNumOperands(); ++OpIndex) {
     const auto &OpInfo = MCInstrDesc.opInfo_begin()[OpIndex];
@@ -71,7 +71,7 @@ Instruction::Instruction(const llvm::MCI
   // Assigning Operands to Variables.
   for (auto &Op : Operands)
     if (Op.VariableIndex >= 0)
-      Variables[Op.VariableIndex].TiedOperands.push_back(&Op);
+      Variables[Op.VariableIndex].TiedOperands.push_back(Op.Index);
   // Processing Aliasing.
   DefRegisters = RATC.emptyRegisters();
   UseRegisters = RATC.emptyRegisters();
@@ -86,6 +86,16 @@ Instruction::Instruction(const llvm::MCI
 InstructionInstance::InstructionInstance(const Instruction &Instr)
     : Instr(Instr), VariableValues(Instr.Variables.size()) {}
 
+InstructionInstance::InstructionInstance(InstructionInstance &&) noexcept =
+    default;
+
+InstructionInstance &InstructionInstance::
+operator=(InstructionInstance &&) noexcept = default;
+
+unsigned InstructionInstance::getOpcode() const {
+  return Instr.Description->getOpcode();
+}
+
 llvm::MCOperand &InstructionInstance::getValueFor(const Variable &Var) {
   return VariableValues[Var.Index];
 }
@@ -96,22 +106,37 @@ llvm::MCOperand &InstructionInstance::ge
 }
 
 // forward declaration.
-static void randomize(const Variable &Var, llvm::MCOperand &AssignedValue);
+static void randomize(const Instruction &Instr, const Variable &Var,
+                      llvm::MCOperand &AssignedValue);
+
+bool InstructionInstance::hasImmediateVariables() const {
+  return llvm::any_of(Instr.Variables, [this](const Variable &Var) {
+    assert(!Var.TiedOperands.empty());
+    const unsigned OpIndex = Var.TiedOperands[0];
+    const Operand &Op = Instr.Operands[OpIndex];
+    assert(Op.Info);
+    return Op.Info->OperandType == llvm::MCOI::OPERAND_IMMEDIATE;
+  });
+}
 
 llvm::MCInst InstructionInstance::randomizeUnsetVariablesAndBuild() {
   for (const Variable &Var : Instr.Variables) {
     llvm::MCOperand &AssignedValue = getValueFor(Var);
     if (!AssignedValue.isValid())
-      randomize(Var, AssignedValue);
+      randomize(Instr, Var, AssignedValue);
   }
   llvm::MCInst Result;
-  Result.setOpcode(Instr.Description.Opcode);
+  Result.setOpcode(Instr.Description->Opcode);
   for (const auto &Op : Instr.Operands)
     if (Op.IsExplicit)
       Result.addOperand(getValueFor(Op));
   return Result;
 }
 
+SnippetPrototype::SnippetPrototype(SnippetPrototype &&) = default;
+
+SnippetPrototype &SnippetPrototype::operator=(SnippetPrototype &&) = default;
+
 bool RegisterOperandAssignment::
 operator==(const RegisterOperandAssignment &Other) const {
   return std::tie(Op, Reg) == std::tie(Other.Op, Other.Reg);
@@ -183,10 +208,10 @@ static auto randomElement(const C &Conta
   return Container[randomIndex(Container.size())];
 }
 
-static void randomize(const Variable &Var, llvm::MCOperand &AssignedValue) {
+static void randomize(const Instruction &Instr, const Variable &Var,
+                      llvm::MCOperand &AssignedValue) {
   assert(!Var.TiedOperands.empty());
-  assert(Var.TiedOperands.front() != nullptr);
-  const Operand &Op = *Var.TiedOperands.front();
+  const Operand &Op = Instr.Operands[Var.TiedOperands.front()];
   assert(Op.Info != nullptr);
   const auto &OpInfo = *Op.Info;
   switch (OpInfo.OperandType) {

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/MCInstrDescView.h Wed Jun 20 01:52:30 2018
@@ -35,7 +35,8 @@ struct Operand; // forward declaration.
 // A variable represents the value associated to an Operand or a set of Operands
 // if they are tied together.
 struct Variable {
-  llvm::SmallVector<const Operand *, 2> TiedOperands;
+  // The indices of the operands tied to this Variable.
+  llvm::SmallVector<unsigned, 2> TiedOperands;
   llvm::MCOperand AssignedValue;
   // The index of this Variable in Instruction.Variables and its associated
   // Value in InstructionInstance.VariableValues.
@@ -71,7 +72,7 @@ struct Instruction {
   Instruction(const llvm::MCInstrDesc &MCInstrDesc,
               const RegisterAliasingTrackerCache &ATC);
 
-  const llvm::MCInstrDesc &Description;
+  const llvm::MCInstrDesc *Description; // Never nullptr.
   llvm::SmallVector<Operand, 8> Operands;
   llvm::SmallVector<Variable, 4> Variables;
   llvm::BitVector DefRegisters; // The union of the aliased def registers.
@@ -82,17 +83,46 @@ struct Instruction {
 struct InstructionInstance {
   InstructionInstance(const Instruction &Instr);
 
+  // No copy.
+  InstructionInstance(const InstructionInstance &) = delete;
+  InstructionInstance &operator=(const InstructionInstance &) = delete;
+
+  // Moving is OK.
+  InstructionInstance(InstructionInstance &&) noexcept;
+  InstructionInstance &operator=(InstructionInstance &&) noexcept;
+
+  unsigned getOpcode() const;
   llvm::MCOperand &getValueFor(const Variable &Var);
   llvm::MCOperand &getValueFor(const Operand &Op);
+  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();
 
-  const Instruction &Instr;
+  Instruction Instr;
   llvm::SmallVector<llvm::MCOperand, 4> VariableValues;
 };
 
+// A prototype is a set of InstructionInstances with an explanation of how
+// it's been built. The prototype can then be randomized to exercice several
+// immediate values. It is also used to gather the used registers and define
+// their initial values.
+struct SnippetPrototype {
+  SnippetPrototype() = default;
+
+  // No copy.
+  SnippetPrototype(const SnippetPrototype &) = delete;
+  SnippetPrototype &operator=(const SnippetPrototype &) = delete;
+
+  // Moving is OK.
+  SnippetPrototype(SnippetPrototype &&) noexcept;
+  SnippetPrototype &operator=(SnippetPrototype &&) noexcept;
+
+  std::string Explanation;
+  std::vector<InstructionInstance> Snippet;
+};
+
 // Represents the assignment of a Register to an Operand.
 struct RegisterOperandAssignment {
   RegisterOperandAssignment(const Operand *Operand, llvm::MCPhysReg Reg)

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp Wed Jun 20 01:52:30 2018
@@ -102,11 +102,12 @@ UopsBenchmarkRunner::isInfeasible(const
 }
 
 // Returns whether this Variable ties Use and Def operands together.
-static bool hasTiedOperands(const Variable &Var) {
+static bool hasTiedOperands(const Instruction &Instr, const Variable &Var) {
   bool HasUse = false;
   bool HasDef = false;
-  for (const Operand *Op : Var.TiedOperands) {
-    if (Op->IsDef)
+  for (const unsigned OpIndex : Var.TiedOperands) {
+    const Operand &Op = Instr.Operands[OpIndex];
+    if (Op.IsDef)
       HasDef = true;
     else
       HasUse = true;
@@ -118,7 +119,7 @@ static llvm::SmallVector<const Variable
 getTiedVariables(const Instruction &Instr) {
   llvm::SmallVector<const Variable *, 8> Result;
   for (const auto &Var : Instr.Variables)
-    if (hasTiedOperands(Var))
+    if (hasTiedOperands(Instr, Var))
       Result.push_back(&Var);
   return Result;
 }
@@ -135,26 +136,24 @@ InstructionBenchmark::ModeE UopsBenchmar
   return InstructionBenchmark::Uops;
 }
 
-llvm::Expected<BenchmarkConfiguration>
-UopsBenchmarkRunner::generateConfiguration(unsigned Opcode) const {
+llvm::Expected<SnippetPrototype>
+UopsBenchmarkRunner::generatePrototype(unsigned Opcode) const {
   const auto &InstrDesc = MCInstrInfo.get(Opcode);
   if (auto E = isInfeasible(InstrDesc))
     return std::move(E);
   const Instruction Instr(InstrDesc, RATC);
   const AliasingConfigurations SelfAliasing(Instr, Instr);
   if (SelfAliasing.empty()) {
-    InstructionInstance II(Instr);
-    BenchmarkConfiguration Conf;
-    Conf.Info = "instruction is parallel, repeating a random one.";
-    Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
-    return Conf;
+    SnippetPrototype Prototype;
+    Prototype.Explanation = "instruction is parallel, repeating a random one.";
+    Prototype.Snippet.emplace_back(Instr);
+    return Prototype;
   }
   if (SelfAliasing.hasImplicitAliasing()) {
-    InstructionInstance II(Instr);
-    BenchmarkConfiguration Conf;
-    Conf.Info = "instruction is serial, repeating a random one.";
-    Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
-    return Conf;
+    SnippetPrototype Prototype;
+    Prototype.Explanation = "instruction is serial, repeating a random one.";
+    Prototype.Snippet.emplace_back(Instr);
+    return Prototype;
   }
   const auto TiedVariables = getTiedVariables(Instr);
   if (!TiedVariables.empty()) {
@@ -162,19 +161,20 @@ UopsBenchmarkRunner::generateConfigurati
       return llvm::make_error<llvm::StringError>(
           "Infeasible : don't know how to handle several tied variables",
           llvm::inconvertibleErrorCode());
-    BenchmarkConfiguration Conf;
-    Conf.Info = "instruction has tied variables using static renaming.";
     const Variable *Var = TiedVariables.front();
     assert(Var);
     assert(!Var->TiedOperands.empty());
-    const Operand &Operand = *Var->TiedOperands.front();
-    assert(Operand.Tracker);
-    for (const llvm::MCPhysReg Reg : Operand.Tracker->sourceBits().set_bits()) {
-      InstructionInstance II(Instr);
-      II.getValueFor(*Var) = llvm::MCOperand::createReg(Reg);
-      Conf.Snippet.push_back(II.randomizeUnsetVariablesAndBuild());
+    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);
     }
-    return Conf;
+    return Prototype;
   }
   InstructionInstance II(Instr);
   // No tied variables, we pick random values for defs.
@@ -201,19 +201,11 @@ UopsBenchmarkRunner::generateConfigurati
       II.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
     }
   }
-  BenchmarkConfiguration Conf;
-  Conf.Info =
+  SnippetPrototype Prototype;
+  Prototype.Explanation =
       "instruction has no tied variables picking Uses different from defs";
-  Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
-  return Conf;
-}
-
-llvm::Expected<std::vector<BenchmarkConfiguration>>
-UopsBenchmarkRunner::createConfigurations(unsigned Opcode) const {
-  if (auto E = generateConfiguration(Opcode))
-    return std::vector<BenchmarkConfiguration>{E.get()};
-  else
-    return E.takeError();
+  Prototype.Snippet.push_back(std::move(II));
+  return Prototype;
 }
 
 std::vector<BenchmarkMeasure>

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.h Wed Jun 20 01:52:30 2018
@@ -24,17 +24,14 @@ public:
   using BenchmarkRunner::BenchmarkRunner;
   ~UopsBenchmarkRunner() override;
 
-  llvm::Expected<BenchmarkConfiguration>
-  generateConfiguration(unsigned Opcode) const;
+  llvm::Expected<SnippetPrototype>
+  generatePrototype(unsigned Opcode) const override;
 
 private:
   llvm::Error isInfeasible(const llvm::MCInstrDesc &MCInstrDesc) const;
 
   InstructionBenchmark::ModeE getMode() const override;
 
-  llvm::Expected<std::vector<BenchmarkConfiguration>>
-  createConfigurations(unsigned Opcode) const override;
-
   std::vector<BenchmarkMeasure>
   runMeasurements(const ExecutableFunction &EF,
                   const unsigned NumRepetitions) const override;

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=335105&r1=335104&r2=335105&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp Wed Jun 20 01:52:30 2018
@@ -20,6 +20,13 @@
 namespace exegesis {
 namespace {
 
+using testing::HasSubstr;
+using testing::Not;
+using testing::SizeIs;
+
+MATCHER(IsInvalid, "") { return !arg.isValid(); }
+MATCHER(IsReg, "") { return arg.isReg(); }
+
 class X86SnippetGeneratorTest : public ::testing::Test {
 protected:
   X86SnippetGeneratorTest()
@@ -38,20 +45,26 @@ protected:
   const llvm::MCRegisterInfo &MCRegisterInfo;
 };
 
-class LatencySnippetGeneratorTest : public X86SnippetGeneratorTest {
+template <typename BenchmarkRunner>
+class SnippetGeneratorTest : public X86SnippetGeneratorTest {
 protected:
-  LatencySnippetGeneratorTest() : Runner(State) {}
+  SnippetGeneratorTest() : Runner(State) {}
 
-  BenchmarkConfiguration checkAndGetConfiguration(unsigned Opcode) {
+  SnippetPrototype checkAndGetConfigurations(unsigned Opcode) {
     randomGenerator().seed(0); // Initialize seed.
-    auto ConfOrError = Runner.generateConfiguration(Opcode);
-    EXPECT_FALSE(ConfOrError.takeError()); // Valid configuration.
-    return ConfOrError.get();
+    auto ProtoOrError = Runner.generatePrototype(Opcode);
+    EXPECT_FALSE(ProtoOrError.takeError()); // Valid configuration.
+    return std::move(ProtoOrError.get());
   }
 
-  LatencyBenchmarkRunner Runner;
+  BenchmarkRunner Runner;
 };
 
+using LatencySnippetGeneratorTest =
+    SnippetGeneratorTest<LatencyBenchmarkRunner>;
+
+using UopsSnippetGeneratorTest = SnippetGeneratorTest<UopsBenchmarkRunner>;
+
 TEST_F(LatencySnippetGeneratorTest, ImplicitSelfDependency) {
   // ADC16i16 self alias because of implicit use and def.
 
@@ -61,17 +74,17 @@ TEST_F(LatencySnippetGeneratorTest, Impl
   // implicit use         : AX
   // implicit use         : EFLAGS
   const unsigned Opcode = llvm::X86::ADC16i16;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("implicit"));
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
-  const llvm::MCInst Instr = Conf.Snippet[0];
-  EXPECT_THAT(Instr.getOpcode(), Opcode);
-  EXPECT_THAT(Instr.getNumOperands(), 1);
-  EXPECT_TRUE(Instr.getOperand(0).isImm()); // Use
   EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::AX);
   EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[1], llvm::X86::EFLAGS);
   EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[0], llvm::X86::AX);
   EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitUses()[1], llvm::X86::EFLAGS);
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("implicit"));
+  ASSERT_THAT(Proto.Snippet, SizeIs(1));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(1)); // Imm.
+  EXPECT_THAT(II.VariableValues[0], IsInvalid()) << "Immediate is not set";
 }
 
 TEST_F(LatencySnippetGeneratorTest, ExplicitSelfDependency) {
@@ -82,18 +95,15 @@ TEST_F(LatencySnippetGeneratorTest, Expl
   // explicit use 2       : imm
   // implicit def         : EFLAGS
   const unsigned Opcode = llvm::X86::ADD16ri;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("explicit"));
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
-  const llvm::MCInst Instr = Conf.Snippet[0];
-  EXPECT_THAT(Instr.getOpcode(), Opcode);
-  EXPECT_THAT(Instr.getNumOperands(), 3);
-  EXPECT_TRUE(Instr.getOperand(0).isReg());
-  EXPECT_TRUE(Instr.getOperand(1).isReg());
-  EXPECT_THAT(Instr.getOperand(0).getReg(), Instr.getOperand(1).getReg())
-      << "Op0 and Op1 should have the same value";
-  EXPECT_TRUE(Instr.getOperand(2).isImm());
   EXPECT_THAT(MCInstrInfo.get(Opcode).getImplicitDefs()[0], llvm::X86::EFLAGS);
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("explicit"));
+  ASSERT_THAT(Proto.Snippet, SizeIs(1));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(2));
+  EXPECT_THAT(II.VariableValues[0], IsReg()) << "Operand 0 and 1";
+  EXPECT_THAT(II.VariableValues[1], IsInvalid()) << "Operand 2 is not set";
 }
 
 TEST_F(LatencySnippetGeneratorTest, DependencyThroughOtherOpcode) {
@@ -103,49 +113,43 @@ TEST_F(LatencySnippetGeneratorTest, Depe
   // implicit def         : EFLAGS
 
   const unsigned Opcode = llvm::X86::CMP64rr;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("cycle through"));
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(2));
-  const llvm::MCInst Instr = Conf.Snippet[0];
-  EXPECT_THAT(Instr.getOpcode(), Opcode);
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
+  ASSERT_THAT(Proto.Snippet, SizeIs(2));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(2));
+  EXPECT_THAT(II.VariableValues[0], IsReg());
+  EXPECT_THAT(II.VariableValues[1], IsInvalid());
+  EXPECT_THAT(Proto.Snippet[1].getOpcode(), Not(Opcode));
   // TODO: check that the two instructions alias each other.
 }
 
 TEST_F(LatencySnippetGeneratorTest, LAHF) {
   const unsigned Opcode = llvm::X86::LAHF;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("cycle through"));
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(2));
-  const llvm::MCInst Instr = Conf.Snippet[0];
-  EXPECT_THAT(Instr.getOpcode(), Opcode);
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("cycle through"));
+  ASSERT_THAT(Proto.Snippet, SizeIs(2));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(0));
 }
 
-class UopsSnippetGeneratorTest : public X86SnippetGeneratorTest {
-protected:
-  UopsSnippetGeneratorTest() : Runner(State) {}
-
-  BenchmarkConfiguration checkAndGetConfiguration(unsigned Opcode) {
-    randomGenerator().seed(0); // Initialize seed.
-    auto ConfOrError = Runner.generateConfiguration(Opcode);
-    EXPECT_FALSE(ConfOrError.takeError()); // Valid configuration.
-    return ConfOrError.get();
-  }
-
-  UopsBenchmarkRunner Runner;
-};
-
 TEST_F(UopsSnippetGeneratorTest, ParallelInstruction) {
-  // BNDCL32rr is parallelno matter what.
+  // BNDCL32rr is parallel no matter what.
 
   // explicit use 0       : reg RegClass=BNDR
   // explicit use 1       : reg RegClass=GR32
 
   const unsigned Opcode = llvm::X86::BNDCL32rr;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("parallel"));
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
-  const llvm::MCInst Instr = Conf.Snippet[0];
-  EXPECT_THAT(Instr.getOpcode(), Opcode);
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("parallel"));
+  ASSERT_THAT(Proto.Snippet, SizeIs(1));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(2));
+  EXPECT_THAT(II.VariableValues[0], IsInvalid());
+  EXPECT_THAT(II.VariableValues[1], IsInvalid());
 }
 
 TEST_F(UopsSnippetGeneratorTest, SerialInstruction) {
@@ -155,11 +159,12 @@ TEST_F(UopsSnippetGeneratorTest, SerialI
   // implicit def         : EDX
   // implicit use         : EAX
   const unsigned Opcode = llvm::X86::CDQ;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("serial"));
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
-  const llvm::MCInst Instr = Conf.Snippet[0];
-  EXPECT_THAT(Instr.getOpcode(), Opcode);
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("serial"));
+  ASSERT_THAT(Proto.Snippet, SizeIs(1));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(0));
 }
 
 TEST_F(UopsSnippetGeneratorTest, StaticRenaming) {
@@ -171,14 +176,16 @@ TEST_F(UopsSnippetGeneratorTest, StaticR
   // explicit use 2       : reg RegClass=GR32
   // implicit use         : EFLAGS
   const unsigned Opcode = llvm::X86::CMOVA32rr;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("static renaming"));
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("static renaming"));
   constexpr const unsigned kInstructionCount = 15;
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(kInstructionCount));
+  ASSERT_THAT(Proto.Snippet, SizeIs(kInstructionCount));
   std::unordered_set<unsigned> AllDefRegisters;
-  for (const auto &Inst : Conf.Snippet)
-    AllDefRegisters.insert(Inst.getOperand(0).getReg());
-  EXPECT_THAT(AllDefRegisters, testing::SizeIs(kInstructionCount))
+  for (const auto &II : Proto.Snippet) {
+    ASSERT_THAT(II.VariableValues, SizeIs(2));
+    AllDefRegisters.insert(II.VariableValues[0].getReg());
+  }
+  EXPECT_THAT(AllDefRegisters, SizeIs(kInstructionCount))
       << "Each instruction writes to a different register";
 }
 
@@ -192,19 +199,17 @@ TEST_F(UopsSnippetGeneratorTest, NoTiedV
   // explicit use 3       : imm
   // implicit use         : EFLAGS
   const unsigned Opcode = llvm::X86::CMOV_GR32;
-  auto Conf = checkAndGetConfiguration(Opcode);
-  EXPECT_THAT(Conf.Info, testing::HasSubstr("no tied variables"));
-  ASSERT_THAT(Conf.Snippet, testing::SizeIs(1));
-  const llvm::MCInst Instr = Conf.Snippet[0];
-  EXPECT_THAT(Instr.getOpcode(), Opcode);
-  EXPECT_THAT(Instr.getNumOperands(), 4);
-  EXPECT_THAT(Instr.getOperand(0).getReg(),
-              testing::Not(Instr.getOperand(1).getReg()))
+  const SnippetPrototype Proto = checkAndGetConfigurations(Opcode);
+  EXPECT_THAT(Proto.Explanation, HasSubstr("no tied variables"));
+  ASSERT_THAT(Proto.Snippet, SizeIs(1));
+  const InstructionInstance &II = Proto.Snippet[0];
+  EXPECT_THAT(II.getOpcode(), Opcode);
+  ASSERT_THAT(II.VariableValues, SizeIs(4));
+  EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[1].getReg()))
       << "Def is different from first Use";
-  EXPECT_THAT(Instr.getOperand(0).getReg(),
-              testing::Not(Instr.getOperand(2).getReg()))
+  EXPECT_THAT(II.VariableValues[0].getReg(), Not(II.VariableValues[2].getReg()))
       << "Def is different from second Use";
-  EXPECT_THAT(Instr.getOperand(3).getImm(), 1);
+  EXPECT_THAT(II.VariableValues[3], IsInvalid());
 }
 
 } // namespace




More information about the llvm-commits mailing list