[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/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
index 26a5459..591edd2 100644
--- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
@@ -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 @@
     // 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