[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

llvm-svn: 335465
diff --git a/llvm/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h b/llvm/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h
index 217ecc2..52133b4 100644
--- a/llvm/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h
+++ b/llvm/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h
@@ -36,9 +36,16 @@
   }
 
   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 @@
   }
 
   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()));
   }
diff --git a/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
index d746bfc..f8a7ccd 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp
@@ -25,6 +25,7 @@
 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 @@
   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
diff --git a/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp
index f13e40c..547a78b 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/X86/TargetTest.cpp
@@ -3,6 +3,7 @@
 #include <cassert>
 #include <memory>
 
+#include "MCTargetDesc/X86MCTargetDesc.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -12,16 +13,31 @@
 
 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