OSDN Git Service

[llvm-exegesis][NFC] Return many CodeTemplates instead of one.
authorGuillaume Chatelet <gchatelet@google.com>
Mon, 15 Oct 2018 09:09:19 +0000 (09:09 +0000)
committerGuillaume Chatelet <gchatelet@google.com>
Mon, 15 Oct 2018 09:09:19 +0000 (09:09 +0000)
Summary: This is part one of the change where I simply changed the signature of the functions. More work need to be done to actually produce more than one CodeTemplate per instruction.

Reviewers: courbet

Subscribers: tschuett, llvm-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@344493 91177308-0d34-0410-b5e6-96231b3b80d8

tools/llvm-exegesis/lib/Latency.cpp
tools/llvm-exegesis/lib/Latency.h
tools/llvm-exegesis/lib/SnippetGenerator.cpp
tools/llvm-exegesis/lib/SnippetGenerator.h
tools/llvm-exegesis/lib/Uops.cpp
tools/llvm-exegesis/lib/Uops.h
tools/llvm-exegesis/lib/X86/Target.cpp
unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp

index f6786b1..040b42b 100644 (file)
@@ -22,9 +22,9 @@ namespace exegesis {
 
 LatencySnippetGenerator::~LatencySnippetGenerator() = default;
 
-llvm::Expected<CodeTemplate>
-LatencySnippetGenerator::generateTwoInstructionPrototype(
-    const Instruction &Instr) const {
+llvm::Expected<std::vector<CodeTemplate>>
+generateTwoInstructionPrototypes(const LLVMState &State,
+                                 const Instruction &Instr) {
   std::vector<unsigned> Opcodes;
   Opcodes.resize(State.getInstrInfo().getNumOpcodes());
   std::iota(Opcodes.begin(), Opcodes.end(), 0U);
@@ -50,23 +50,23 @@ LatencySnippetGenerator::generateTwoInstructionPrototype(
                             State.getInstrInfo().getName(OtherOpcode));
     CT.Instructions.push_back(std::move(ThisIT));
     CT.Instructions.push_back(std::move(OtherIT));
-    return std::move(CT);
+    return getSingleton(CT);
   }
   return llvm::make_error<BenchmarkFailure>(
       "Infeasible : Didn't find any scheme to make the instruction serial");
 }
 
-llvm::Expected<CodeTemplate>
-LatencySnippetGenerator::generateCodeTemplate(const Instruction &Instr) const {
+llvm::Expected<std::vector<CodeTemplate>>
+LatencySnippetGenerator::generateCodeTemplates(const Instruction &Instr) const {
   if (Instr.hasMemoryOperands())
     return llvm::make_error<BenchmarkFailure>(
         "Infeasible : has memory operands");
-  if (auto CT = generateSelfAliasingCodeTemplate(Instr))
-    return CT;
-  else
-    llvm::consumeError(CT.takeError());
-  // No self aliasing, trying to create a dependency through another opcode.
-  return generateTwoInstructionPrototype(Instr);
+  return llvm::handleExpected( //
+      generateSelfAliasingCodeTemplates(Instr),
+      [this, &Instr]() {
+        return generateTwoInstructionPrototypes(State, Instr);
+      },
+      [](const BenchmarkFailure &) { /*Consume Error*/ });
 }
 
 const char *LatencyBenchmarkRunner::getCounterName() const {
index 83c798f..f78f126 100644 (file)
@@ -26,12 +26,8 @@ public:
   LatencySnippetGenerator(const LLVMState &State) : SnippetGenerator(State) {}
   ~LatencySnippetGenerator() override;
 
-  llvm::Expected<CodeTemplate>
-  generateCodeTemplate(const Instruction &Instr) const override;
-
-private:
-  llvm::Expected<CodeTemplate>
-  generateTwoInstructionPrototype(const Instruction &Instr) const;
+  llvm::Expected<std::vector<CodeTemplate>>
+  generateCodeTemplates(const Instruction &Instr) const override;
 };
 
 class LatencyBenchmarkRunner : public BenchmarkRunner {
index f7a76d8..9b577fd 100644 (file)
 
 namespace exegesis {
 
+std::vector<CodeTemplate> getSingleton(CodeTemplate &CT) {
+  std::vector<CodeTemplate> Result;
+  Result.push_back(std::move(CT));
+  return Result;
+}
+
 SnippetGeneratorFailure::SnippetGeneratorFailure(const llvm::Twine &S)
     : llvm::StringError(S, llvm::inconvertibleErrorCode()) {}
 
@@ -31,26 +37,28 @@ SnippetGenerator::~SnippetGenerator() = default;
 
 llvm::Expected<std::vector<BenchmarkCode>>
 SnippetGenerator::generateConfigurations(const Instruction &Instr) const {
-  if (auto E = generateCodeTemplate(Instr)) {
-    CodeTemplate &CT = E.get();
+  if (auto E = generateCodeTemplates(Instr)) {
     const auto &RATC = State.getRATC();
-    const llvm::BitVector &ForbiddenRegs =
-        CT.ScratchSpacePointerInReg
-            ? RATC.getRegister(CT.ScratchSpacePointerInReg).aliasedBits()
-            : RATC.emptyRegisters();
     std::vector<BenchmarkCode> Output;
-    // TODO: Generate as many BenchmarkCode as needed.
-    {
-      BenchmarkCode BC;
-      BC.Info = CT.Info;
-      for (InstructionTemplate &IT : CT.Instructions) {
-        randomizeUnsetVariables(ForbiddenRegs, IT);
-        BC.Instructions.push_back(IT.build());
+    for (CodeTemplate &CT : E.get()) {
+      const llvm::BitVector &ForbiddenRegs =
+          CT.ScratchSpacePointerInReg
+              ? RATC.getRegister(CT.ScratchSpacePointerInReg).aliasedBits()
+              : RATC.emptyRegisters();
+      // TODO: Generate as many BenchmarkCode as needed.
+      {
+        BenchmarkCode BC;
+        BC.Info = CT.Info;
+        for (InstructionTemplate &IT : CT.Instructions) {
+          randomizeUnsetVariables(ForbiddenRegs, IT);
+          BC.Instructions.push_back(IT.build());
+        }
+        if (CT.ScratchSpacePointerInReg)
+          BC.LiveIns.push_back(CT.ScratchSpacePointerInReg);
+        BC.RegisterInitialValues =
+            computeRegisterInitialValues(CT.Instructions);
+        Output.push_back(std::move(BC));
       }
-      if (CT.ScratchSpacePointerInReg)
-        BC.LiveIns.push_back(CT.ScratchSpacePointerInReg);
-      BC.RegisterInitialValues = computeRegisterInitialValues(CT.Instructions);
-      Output.push_back(std::move(BC));
     }
     return Output;
   } else
@@ -99,13 +107,14 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
   return RIV;
 }
 
-llvm::Expected<CodeTemplate> SnippetGenerator::generateSelfAliasingCodeTemplate(
-    const Instruction &Instr) const {
+llvm::Expected<std::vector<CodeTemplate>>
+generateSelfAliasingCodeTemplates(const Instruction &Instr) {
   const AliasingConfigurations SelfAliasing(Instr, Instr);
-  if (SelfAliasing.empty()) {
+  if (SelfAliasing.empty())
     return llvm::make_error<SnippetGeneratorFailure>("empty self aliasing");
-  }
-  CodeTemplate CT;
+  std::vector<CodeTemplate> Result;
+  Result.emplace_back();
+  CodeTemplate &CT = Result.back();
   InstructionTemplate IT(Instr);
   if (SelfAliasing.hasImplicitAliasing()) {
     CT.Info = "implicit Self cycles, picking random values.";
@@ -116,16 +125,18 @@ llvm::Expected<CodeTemplate> SnippetGenerator::generateSelfAliasingCodeTemplate(
     setRandomAliasing(SelfAliasing, IT, IT);
   }
   CT.Instructions.push_back(std::move(IT));
-  return std::move(CT);
+  return Result;
 }
 
-llvm::Expected<CodeTemplate>
-SnippetGenerator::generateUnconstrainedCodeTemplate(const Instruction &Instr,
-                                                    llvm::StringRef Msg) const {
-  CodeTemplate CT;
+llvm::Expected<std::vector<CodeTemplate>>
+generateUnconstrainedCodeTemplates(const Instruction &Instr,
+                                   llvm::StringRef Msg) {
+  std::vector<CodeTemplate> Result;
+  Result.emplace_back();
+  CodeTemplate &CT = Result.back();
   CT.Info = llvm::formatv("{0}, repeating an unconstrained assignment", Msg);
   CT.Instructions.emplace_back(Instr);
-  return std::move(CT);
+  return Result;
 }
 
 std::mt19937 &randomGenerator() {
index c9a19cd..e48cf0c 100644 (file)
 
 namespace exegesis {
 
+std::vector<CodeTemplate> getSingleton(CodeTemplate &CT);
+
+// Generates code templates that has a self-dependency.
+llvm::Expected<std::vector<CodeTemplate>>
+generateSelfAliasingCodeTemplates(const Instruction &Instr);
+
+// Generates code templates without assignment constraints.
+llvm::Expected<std::vector<CodeTemplate>>
+generateUnconstrainedCodeTemplates(const Instruction &Instr,
+                                   llvm::StringRef Msg);
+
 // A class representing failures that happened during Benchmark, they are used
 // to report informations to the user.
 class SnippetGeneratorFailure : public llvm::StringError {
@@ -55,18 +66,10 @@ public:
 protected:
   const LLVMState &State;
 
-  // Generates a single code template that has a self-dependency.
-  llvm::Expected<CodeTemplate>
-  generateSelfAliasingCodeTemplate(const Instruction &Instr) const;
-  // Generates a single code template without assignment constraints.
-  llvm::Expected<CodeTemplate>
-  generateUnconstrainedCodeTemplate(const Instruction &Instr,
-                                    llvm::StringRef Msg) const;
-
 private:
   // API to be implemented by subclasses.
-  virtual llvm::Expected<CodeTemplate>
-  generateCodeTemplate(const Instruction &Instr) const = 0;
+  virtual llvm::Expected<std::vector<CodeTemplate>>
+  generateCodeTemplates(const Instruction &Instr) const = 0;
 };
 
 // A global Random Number Generator to randomize configurations.
index 1a701d1..a3ada77 100644 (file)
@@ -124,8 +124,8 @@ void UopsSnippetGenerator::instantiateMemoryOperands(
          "not enough scratch space");
 }
 
-llvm::Expected<CodeTemplate>
-UopsSnippetGenerator::generateCodeTemplate(const Instruction &Instr) const {
+llvm::Expected<std::vector<CodeTemplate>>
+UopsSnippetGenerator::generateCodeTemplates(const Instruction &Instr) const {
   CodeTemplate CT;
   const llvm::BitVector *ScratchSpaceAliasedRegs = nullptr;
   if (Instr.hasMemoryOperands()) {
@@ -153,13 +153,13 @@ UopsSnippetGenerator::generateCodeTemplate(const Instruction &Instr) const {
     CT.Info = "instruction is parallel, repeating a random one.";
     CT.Instructions.push_back(std::move(IT));
     instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
-    return std::move(CT);
+    return getSingleton(CT);
   }
   if (SelfAliasing.hasImplicitAliasing()) {
     CT.Info = "instruction is serial, repeating a random one.";
     CT.Instructions.push_back(std::move(IT));
     instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
-    return std::move(CT);
+    return getSingleton(CT);
   }
   const auto TiedVariables = getVariablesWithTiedOperands(Instr);
   if (!TiedVariables.empty()) {
@@ -181,7 +181,7 @@ UopsSnippetGenerator::generateCodeTemplate(const Instruction &Instr) const {
       CT.Instructions.push_back(std::move(TmpIT));
     }
     instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
-    return std::move(CT);
+    return getSingleton(CT);
   }
   const auto &ReservedRegisters = State.getRATC().reservedRegisters();
   // No tied variables, we pick random values for defs.
@@ -218,7 +218,7 @@ UopsSnippetGenerator::generateCodeTemplate(const Instruction &Instr) const {
       "instruction has no tied variables picking Uses different from defs";
   CT.Instructions.push_back(std::move(IT));
   instantiateMemoryOperands(CT.ScratchSpacePointerInReg, CT.Instructions);
-  return std::move(CT);
+  return getSingleton(CT);
 }
 
 std::vector<BenchmarkMeasure>
index 1cfa824..e6f6d4a 100644 (file)
@@ -25,8 +25,8 @@ public:
   UopsSnippetGenerator(const LLVMState &State) : SnippetGenerator(State) {}
   ~UopsSnippetGenerator() override;
 
-  llvm::Expected<CodeTemplate>
-  generateCodeTemplate(const Instruction &Instr) const override;
+  llvm::Expected<std::vector<CodeTemplate>>
+  generateCodeTemplates(const Instruction &Instr) const override;
 
   static constexpr const size_t kMinNumDifferentAddresses = 6;
 
index 0e9a6de..20bb65e 100644 (file)
@@ -38,14 +38,14 @@ class X86LatencySnippetGenerator : public LatencySnippetGenerator {
 public:
   using LatencySnippetGenerator::LatencySnippetGenerator;
 
-  llvm::Expected<CodeTemplate>
-  generateCodeTemplate(const Instruction &Instr) const override {
+  llvm::Expected<std::vector<CodeTemplate>>
+  generateCodeTemplates(const Instruction &Instr) const override {
     if (auto E = IsInvalidOpcode(Instr))
       return std::move(E);
 
     switch (GetX86FPFlags(Instr)) {
     case llvm::X86II::NotFP:
-      return LatencySnippetGenerator::generateCodeTemplate(Instr);
+      return LatencySnippetGenerator::generateCodeTemplates(Instr);
     case llvm::X86II::ZeroArgFP:
     case llvm::X86II::OneArgFP:
     case llvm::X86II::SpecialFP:
@@ -58,7 +58,7 @@ public:
       //   - `ST(0) = fsqrt(ST(0))` (OneArgFPRW)
       //   - `ST(0) = ST(0) + ST(i)` (TwoArgFP)
       // They are intrinsically serial and do not modify the state of the stack.
-      return generateSelfAliasingCodeTemplate(Instr);
+      return generateSelfAliasingCodeTemplates(Instr);
     default:
       llvm_unreachable("Unknown FP Type!");
     }
@@ -69,14 +69,14 @@ class X86UopsSnippetGenerator : public UopsSnippetGenerator {
 public:
   using UopsSnippetGenerator::UopsSnippetGenerator;
 
-  llvm::Expected<CodeTemplate>
-  generateCodeTemplate(const Instruction &Instr) const override {
+  llvm::Expected<std::vector<CodeTemplate>>
+  generateCodeTemplates(const Instruction &Instr) const override {
     if (auto E = IsInvalidOpcode(Instr))
       return std::move(E);
 
     switch (GetX86FPFlags(Instr)) {
     case llvm::X86II::NotFP:
-      return UopsSnippetGenerator::generateCodeTemplate(Instr);
+      return UopsSnippetGenerator::generateCodeTemplates(Instr);
     case llvm::X86II::ZeroArgFP:
     case llvm::X86II::OneArgFP:
     case llvm::X86II::SpecialFP:
@@ -88,12 +88,12 @@ public:
       //   - `ST(0) = ST(0) + ST(i)` (TwoArgFP)
       // They are intrinsically serial and do not modify the state of the stack.
       // We generate the same code for latency and uops.
-      return generateSelfAliasingCodeTemplate(Instr);
+      return generateSelfAliasingCodeTemplates(Instr);
     case llvm::X86II::CompareFP:
     case llvm::X86II::CondMovFP:
       // We can compute uops for any FP instruction that does not grow or shrink
       // the stack (either do not touch the stack or push as much as they pop).
-      return generateUnconstrainedCodeTemplate(
+      return generateUnconstrainedCodeTemplates(
           Instr, "instruction does not grow/shrink the FP stack");
     default:
       llvm_unreachable("Unknown FP Type!");
index 4df489d..6cc24a0 100644 (file)
@@ -60,9 +60,11 @@ protected:
   CodeTemplate checkAndGetCodeTemplate(unsigned Opcode) {
     randomGenerator().seed(0); // Initialize seed.
     const Instruction Instr(State, Opcode);
-    auto CodeTemplateOrError = Generator.generateCodeTemplate(Instr);
+    auto CodeTemplateOrError = Generator.generateCodeTemplates(Instr);
     EXPECT_FALSE(CodeTemplateOrError.takeError()); // Valid configuration.
-    return std::move(CodeTemplateOrError.get());
+    auto &CodeTemplate = CodeTemplateOrError.get();
+    EXPECT_EQ(CodeTemplate.size(), 1U);
+    return std::move(CodeTemplate.front());
   }
 
   SnippetGeneratorT Generator;
@@ -240,7 +242,7 @@ TEST_F(UopsSnippetGeneratorTest, MemoryUse_Movsb) {
   // MOVSB writes to scratch memory register.
   const unsigned Opcode = llvm::X86::MOVSB;
   const Instruction Instr(State, Opcode);
-  auto Error = Generator.generateCodeTemplate(Instr).takeError();
+  auto Error = Generator.generateCodeTemplates(Instr).takeError();
   EXPECT_TRUE((bool)Error);
   llvm::consumeError(std::move(Error));
 }
@@ -254,8 +256,8 @@ public:
   }
 
 private:
-  llvm::Expected<CodeTemplate>
-  generateCodeTemplate(const Instruction &Instr) const override {
+  llvm::Expected<std::vector<CodeTemplate>>
+  generateCodeTemplates(const Instruction &Instr) const override {
     return llvm::make_error<llvm::StringError>("not implemented",
                                                llvm::inconvertibleErrorCode());
   }