[llvm-exegesis] Serializes instruction's operand in BenchmarkResult's key.

Summary: Follow up patch to https://reviews.llvm.org/D47764.

Reviewers: courbet

Subscribers: tschuett, llvm-commits

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

llvm-svn: 334165
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 87b25b4..aac93ab 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -15,6 +15,78 @@
 #include "llvm/Support/Format.h"
 #include "llvm/Support/raw_ostream.h"
 
+static constexpr const char kIntegerFormat[] = "i_0x%" PRId64 "x";
+static constexpr const char kDoubleFormat[] = "f_%la";
+
+static void serialize(const exegesis::BenchmarkResultContext &Context,
+                      const llvm::MCOperand &MCOperand, llvm::raw_ostream &OS) {
+  if (MCOperand.isReg()) {
+    OS << Context.getRegName(MCOperand.getReg());
+  } else if (MCOperand.isImm()) {
+    OS << llvm::format(kIntegerFormat, MCOperand.getImm());
+  } else if (MCOperand.isFPImm()) {
+    OS << llvm::format(kDoubleFormat, MCOperand.getFPImm());
+  } else {
+    OS << "INVALID";
+  }
+}
+
+static void serialize(const exegesis::BenchmarkResultContext &Context,
+                      const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
+  OS << Context.getInstrName(MCInst.getOpcode());
+  for (const auto &Op : MCInst) {
+    OS << ' ';
+    serialize(Context, Op, OS);
+  }
+}
+
+static llvm::MCOperand
+deserialize(const exegesis::BenchmarkResultContext &Context,
+            llvm::StringRef String) {
+  assert(!String.empty());
+  int64_t IntValue = 0;
+  double DoubleValue = 0;
+  if (sscanf(String.data(), kIntegerFormat, &IntValue) == 1)
+    return llvm::MCOperand::createImm(IntValue);
+  if (sscanf(String.data(), kDoubleFormat, &DoubleValue) == 1)
+    return llvm::MCOperand::createFPImm(DoubleValue);
+  if (unsigned RegNo = Context.getRegNo(String)) // Returns 0 if invalid.
+    return llvm::MCOperand::createReg(RegNo);
+  return {};
+}
+
+static llvm::StringRef
+deserialize(const exegesis::BenchmarkResultContext &Context,
+            llvm::StringRef String, llvm::MCInst &Value) {
+  llvm::SmallVector<llvm::StringRef, 8> Pieces;
+  String.split(Pieces, " ");
+  if (Pieces.empty())
+    return "Invalid Instruction";
+  bool ProcessOpcode = true;
+  for (llvm::StringRef Piece : Pieces) {
+    if (ProcessOpcode) {
+      ProcessOpcode = false;
+      Value.setOpcode(Context.getInstrOpcode(Piece));
+      if (Value.getOpcode() == 0)
+        return "Unknown Opcode Name";
+    } else {
+      Value.addOperand(deserialize(Context, Piece));
+    }
+  }
+  return {};
+}
+
+// YAML IO requires a mutable pointer to Context but we guarantee to not
+// modify it.
+static void *getUntypedContext(const exegesis::BenchmarkResultContext &Ctx) {
+  return const_cast<exegesis::BenchmarkResultContext *>(&Ctx);
+}
+
+static const exegesis::BenchmarkResultContext &getTypedContext(void *Ctx) {
+  assert(Ctx);
+  return *static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
+}
+
 // Defining YAML traits for IO.
 namespace llvm {
 namespace yaml {
@@ -28,22 +100,11 @@
 
   static void output(const llvm::MCInst &Value, void *Ctx,
                      llvm::raw_ostream &Out) {
-    assert(Ctx);
-    auto *Context = static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
-    const StringRef Name = Context->getInstrName(Value.getOpcode());
-    assert(!Name.empty());
-    Out << Name;
+    serialize(getTypedContext(Ctx), Value, Out);
   }
 
   static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
-    assert(Ctx);
-    auto *Context = static_cast<const exegesis::BenchmarkResultContext *>(Ctx);
-    const unsigned Opcode = Context->getInstrOpcode(Scalar);
-    if (Opcode == 0) {
-      return "Unable to parse instruction";
-    }
-    Value.setOpcode(Opcode);
-    return StringRef();
+    return deserialize(getTypedContext(Ctx), Scalar, Value);
   }
 
   static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
@@ -153,10 +214,7 @@
                                         llvm::StringRef Filename) {
   std::unique_ptr<llvm::MemoryBuffer> MemBuffer = llvm::cantFail(
       llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename)));
-  // YAML IO requires a mutable pointer to Context but we guarantee to not
-  // modify it.
-  llvm::yaml::Input Yin(*MemBuffer,
-                        const_cast<BenchmarkResultContext *>(&Context));
+  llvm::yaml::Input Yin(*MemBuffer, getUntypedContext(Context));
   ObjectOrList Benchmark;
   Yin >> Benchmark;
   return Benchmark;
@@ -176,19 +234,14 @@
 }
 
 void InstructionBenchmark::writeYamlTo(const BenchmarkResultContext &Context,
-                                       llvm::raw_ostream &S) {
-  // YAML IO requires a mutable pointer to Context but we guarantee to not
-  // modify it.
-  llvm::yaml::Output Yout(S, const_cast<BenchmarkResultContext *>(&Context));
+                                       llvm::raw_ostream &OS) {
+  llvm::yaml::Output Yout(OS, getUntypedContext(Context));
   Yout << *this;
 }
 
 void InstructionBenchmark::readYamlFrom(const BenchmarkResultContext &Context,
                                         llvm::StringRef InputContent) {
-  // YAML IO requires a mutable pointer to Context but we guarantee to not
-  // modify it.
-  llvm::yaml::Input Yin(InputContent,
-                        const_cast<BenchmarkResultContext *>(&Context));
+  llvm::yaml::Input Yin(InputContent, getUntypedContext(Context));
   Yin >> *this;
 }