[llvm-exegesis] Use BenchmarkResult::Instructions instead of OpcodeName

Summary:
Get rid of OpcodeName.

To remove the opcode name from an old file:
```
cat old_file | sed '/opcode_name.*/d'
```

Reviewers: gchatelet

Subscribers: tschuett, llvm-commits

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

llvm-svn: 334691
diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/llvm/tools/llvm-exegesis/lib/Analysis.cpp
index df353dc..842790d 100644
--- a/llvm/tools/llvm-exegesis/lib/Analysis.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Analysis.cpp
@@ -20,7 +20,7 @@
 
 namespace {
 
-enum EscapeTag { kEscapeCsv, kEscapeHtml };
+enum EscapeTag { kEscapeCsv, kEscapeHtml, kEscapeHtmlString };
 
 template <EscapeTag Tag>
 void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S);
@@ -56,6 +56,16 @@
   }
 }
 
+template <>
+void writeEscaped<kEscapeHtmlString>(llvm::raw_ostream &OS, const llvm::StringRef S) {
+  for (const char C : S) {
+    if (C == '"')
+      OS << "\\\"";
+    else
+      OS << C;
+  }
+}
+
 } // namespace
 
 template <EscapeTag Tag>
@@ -75,6 +85,19 @@
   writeEscaped<Tag>(OS, llvm::formatv("{0:F}", Value).str());
 }
 
+template <EscapeTag Tag>
+static void writeSnippet(llvm::raw_ostream &OS,
+                         const std::vector<llvm::MCInst> &Instructions,
+                         const llvm::MCInstrInfo &InstrInfo,
+                         const char* Separator) {
+  // FIXME: Print operands.
+  llvm::SmallVector<llvm::StringRef, 3> Opcodes;
+  for (const llvm::MCInst &Instr : Instructions) {
+    Opcodes.push_back(InstrInfo.getName(Instr.getOpcode()));
+  }
+  writeEscaped<Tag>(OS, llvm::join(Opcodes, Separator));
+}
+
 // Prints a row representing an instruction, along with scheduling info and
 // point coordinates (measurements).
 void Analysis::printInstructionRowCsv(const size_t PointId,
@@ -82,25 +105,22 @@
   const InstructionBenchmark &Point = Clustering_.getPoints()[PointId];
   writeClusterId<kEscapeCsv>(OS, Clustering_.getClusterIdForPoint(PointId));
   OS << kCsvSep;
-  writeEscaped<kEscapeCsv>(OS, Point.Key.OpcodeName);
+  writeSnippet<kEscapeCsv>(OS, Point.Key.Instructions, *InstrInfo_, "; ");
   OS << kCsvSep;
   writeEscaped<kEscapeCsv>(OS, Point.Key.Config);
   OS << kCsvSep;
-  const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
-  if (OpcodeIt != MnemonicToOpcode_.end()) {
-    const unsigned SchedClassId =
-        InstrInfo_->get(OpcodeIt->second).getSchedClass();
+  assert(!Point.Key.Instructions.empty());
+  // FIXME: Resolve variant classes.
+  const unsigned SchedClassId =
+      InstrInfo_->get(Point.Key.Instructions[0].getOpcode()).getSchedClass();
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-    const auto &SchedModel = SubtargetInfo_->getSchedModel();
-    const llvm::MCSchedClassDesc *const SCDesc =
-        SchedModel.getSchedClassDesc(SchedClassId);
-    writeEscaped<kEscapeCsv>(OS, SCDesc->Name);
+  const auto &SchedModel = SubtargetInfo_->getSchedModel();
+  const llvm::MCSchedClassDesc *const SCDesc =
+      SchedModel.getSchedClassDesc(SchedClassId);
+  writeEscaped<kEscapeCsv>(OS, SCDesc->Name);
 #else
-    OS << SchedClassId;
+  OS << SchedClassId;
 #endif
-  }
-  // FIXME: Print the sched class once InstructionBenchmark separates key into
-  // (mnemonic, mode, opaque).
   for (const auto &Measurement : Point.Measurements) {
     OS << kCsvSep;
     writeMeasurementValue<kEscapeCsv>(OS, Measurement.Value);
@@ -118,10 +138,6 @@
   const InstructionBenchmark &FirstPoint = Clustering.getPoints().front();
   SubtargetInfo_.reset(Target.createMCSubtargetInfo(FirstPoint.LLVMTriple,
                                                     FirstPoint.CpuName, ""));
-
-  // Build an index of mnemonic->opcode.
-  for (int I = 0, E = InstrInfo_->getNumOpcodes(); I < E; ++I)
-    MnemonicToOpcode_.emplace(InstrInfo_->getName(I), I);
 }
 
 template <>
@@ -158,16 +174,42 @@
     const InstructionBenchmark &Point = Points[PointId];
     if (!Point.Error.empty())
       continue;
-    const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
-    if (OpcodeIt == MnemonicToOpcode_.end())
-      continue;
-    const unsigned SchedClassId =
-        InstrInfo_->get(OpcodeIt->second).getSchedClass();
-    PointsPerSchedClass[SchedClassId].push_back(PointId);
+    assert(!Point.Key.Instructions.empty());
+    const auto Opcode = Point.Key.Instructions[0].getOpcode();
+    // FIXME: Resolve variant classes.
+    PointsPerSchedClass[InstrInfo_->get(Opcode).getSchedClass()].push_back(
+        PointId);
   }
   return PointsPerSchedClass;
 }
 
+// Uops repeat the same opcode over again. Just show this opcode and show the
+// whole snippet only on hover.
+static void writeUopsSnippetHtml(llvm::raw_ostream &OS,
+                                 const std::vector<llvm::MCInst> &Instructions,
+                                 const llvm::MCInstrInfo &InstrInfo) {
+  if (Instructions.empty())
+    return;
+  writeEscaped<kEscapeHtml>(OS, InstrInfo.getName(Instructions[0].getOpcode()));
+  if (Instructions.size() > 1)
+    OS << " (x" << Instructions.size() << ")";
+}
+
+// Latency tries to find a serial path. Just show the opcode path and show the
+// whole snippet only on hover.
+static void writeLatencySnippetHtml(llvm::raw_ostream &OS,
+                                 const std::vector<llvm::MCInst> &Instructions,
+                                 const llvm::MCInstrInfo &InstrInfo) {
+  bool First = true;
+  for (const llvm::MCInst &Instr : Instructions) {
+    if (First)
+      First = false;
+    else
+      OS << " &rarr; ";
+    writeEscaped<kEscapeHtml>(OS, InstrInfo.getName(Instr.getOpcode()));
+  }
+}
+
 void Analysis::printSchedClassClustersHtml(
     const std::vector<SchedClassCluster> &Clusters, const SchedClass &SC,
     llvm::raw_ostream &OS) const {
@@ -195,8 +237,19 @@
     OS << "</td><td><ul>";
     for (const size_t PointId : Cluster.getPointIds()) {
       const auto &Point = Points[PointId];
-      OS << "<li><span class=\"mono\">";
-      writeEscaped<kEscapeHtml>(OS, Point.Key.OpcodeName);
+      OS << "<li><span class=\"mono\" title=\"";
+      writeSnippet<kEscapeHtmlString>(OS, Point.Key.Instructions, *InstrInfo_, "\n");
+      OS << "\">";
+      switch (Point.Mode) {
+        case InstructionBenchmark::Latency:
+          writeLatencySnippetHtml(OS, Point.Key.Instructions, *InstrInfo_);
+          break;
+        case InstructionBenchmark::Uops:
+          writeUopsSnippetHtml(OS, Point.Key.Instructions, *InstrInfo_);
+          break;
+        default:
+          llvm_unreachable("invalid mode");
+      }
       OS << "</span> <span class=\"mono\">";
       writeEscaped<kEscapeHtml>(OS, Point.Key.Config);
       OS << "</span></li>";