[llvm-exegesis] Get the BenchmarkRunner from the ExegesisTarget.

Summary:
This allows targets to override code generation for some instructions.
As an example of override, this also moves ad-hoc instruction filtering
for X86 into the X86 ExegesisTarget.

Reviewers: gchatelet

Subscribers: mgorny, tschuett, llvm-commits

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

llvm-svn: 335582
diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
index 591edd2..5951752 100644
--- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
@@ -8,6 +8,8 @@
 //===----------------------------------------------------------------------===//
 #include "../Target.h"
 
+#include "../Latency.h"
+#include "../Uops.h"
 #include "MCTargetDesc/X86MCTargetDesc.h"
 #include "X86.h"
 #include "X86RegisterInfo.h"
@@ -15,8 +17,46 @@
 
 namespace exegesis {
 
+// Test whether we can generate a snippet for this instruction.
+static llvm::Error shouldRun(const LLVMState &State, const unsigned Opcode) {
+  const auto &InstrInfo = State.getInstrInfo();
+  const auto OpcodeName = InstrInfo.getName(Opcode);
+  if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") ||
+      OpcodeName.startswith("ADJCALLSTACK")) {
+    return llvm::make_error<BenchmarkFailure>(
+        "Unsupported opcode: Push/Pop/AdjCallStack");
+  }
+  return llvm::ErrorSuccess();
+}
+
 namespace {
 
+class X86LatencyBenchmarkRunner : public LatencyBenchmarkRunner {
+private:
+  using LatencyBenchmarkRunner::LatencyBenchmarkRunner;
+
+  llvm::Expected<SnippetPrototype>
+  generatePrototype(unsigned Opcode) const override {
+    if (llvm::Error E = shouldRun(State, Opcode)) {
+      return std::move(E);
+    }
+    return LatencyBenchmarkRunner::generatePrototype(Opcode);
+  }
+};
+
+class X86UopsBenchmarkRunner : public UopsBenchmarkRunner {
+private:
+  using UopsBenchmarkRunner::UopsBenchmarkRunner;
+
+  llvm::Expected<SnippetPrototype>
+  generatePrototype(unsigned Opcode) const override {
+    if (llvm::Error E = shouldRun(State, Opcode)) {
+      return std::move(E);
+    }
+    return UopsBenchmarkRunner::generatePrototype(Opcode);
+  }
+};
+
 class ExegesisX86Target : public ExegesisTarget {
   void addTargetSpecificPasses(llvm::PassManagerBase &PM) const override {
     // Lowers FP pseudo-instructions, e.g. ABS_Fp32 -> ABS_F.
@@ -55,6 +95,16 @@
     return {};
   }
 
+  std::unique_ptr<BenchmarkRunner>
+  createLatencyBenchmarkRunner(const LLVMState &State) const override {
+    return llvm::make_unique<X86LatencyBenchmarkRunner>(State);
+  }
+
+  std::unique_ptr<BenchmarkRunner>
+  createUopsBenchmarkRunner(const LLVMState &State) const override {
+    return llvm::make_unique<X86UopsBenchmarkRunner>(State);
+  }
+
   bool matchesArch(llvm::Triple::ArchType Arch) const override {
     return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86;
   }