[llvm-exegesis] Print the whole snippet in analysis.

Summary:
On hover, the whole asm snippet is displayed, including operands.

This requires the actual assembly output instead of just the MCInsts:
This is because some pseudo-instructions get lowered to actual target
instructions during codegen (e.g. ABS_Fp32 -> SSE or X87).

Reviewers: gchatelet

Subscribers: mgorny, tschuett, llvm-commits

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

llvm-svn: 334805
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index bed802d..188ee2d 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -74,24 +74,41 @@
     return InstrBenchmark;
   }
 
-  for (const auto &MCInst : Snippet)
-    InstrBenchmark.Key.Instructions.push_back(MCInst);
+  InstrBenchmark.Key.Instructions = Snippet;
 
-  std::vector<llvm::MCInst> Code;
-  for (int I = 0; I < InstrBenchmark.NumRepetitions; ++I)
-    Code.push_back(Snippet[I % Snippet.size()]);
+  // Repeat the snippet until there are at least NumInstructions in the
+  // resulting code. The snippet is always repeated at least once.
+  const auto GenerateInstructions = [&Snippet](const int MinInstructions) {
+    std::vector<llvm::MCInst> Code = Snippet;
+    for (int I = 0; I < MinInstructions; ++I)
+      Code.push_back(Snippet[I % Snippet.size()]);
+    return Code;
+  };
 
-  auto ExpectedObjectPath = writeObjectFile(Code);
-  if (llvm::Error E = ExpectedObjectPath.takeError()) {
+  // Assemble at least kMinInstructionsForSnippet instructions by repeating the
+  // snippet for debug/analysis. This is so that the user clearly understands
+  // that the inside instructions are repeated.
+  constexpr const int kMinInstructionsForSnippet = 16;
+  {
+    auto EF = createExecutableFunction(
+        GenerateInstructions(kMinInstructionsForSnippet));
+    if (llvm::Error E = EF.takeError()) {
+      InstrBenchmark.Error = llvm::toString(std::move(E));
+      return InstrBenchmark;
+    }
+    const auto FnBytes = EF->getFunctionBytes();
+    InstrBenchmark.AssembledSnippet.assign(FnBytes.begin(), FnBytes.end());
+  }
+
+  // Assemble NumRepetitions instructions repetitions of the snippet for
+  // measurements.
+  auto EF = createExecutableFunction(
+      GenerateInstructions(InstrBenchmark.NumRepetitions));
+  if (llvm::Error E = EF.takeError()) {
     InstrBenchmark.Error = llvm::toString(std::move(E));
     return InstrBenchmark;
   }
-
-  // FIXME: Check if TargetMachine or ExecutionEngine can be reused instead of
-  // creating one everytime.
-  const ExecutableFunction EF(State.createTargetMachine(),
-                              getObjectFromFile(*ExpectedObjectPath));
-  InstrBenchmark.Measurements = runMeasurements(EF, NumRepetitions);
+  InstrBenchmark.Measurements = runMeasurements(*EF, NumRepetitions);
 
   return InstrBenchmark;
 }
@@ -110,4 +127,17 @@
   return ResultPath.str();
 }
 
+llvm::Expected<ExecutableFunction> BenchmarkRunner::createExecutableFunction(
+    llvm::ArrayRef<llvm::MCInst> Code) const {
+  auto ExpectedObjectPath = writeObjectFile(Code);
+  if (llvm::Error E = ExpectedObjectPath.takeError()) {
+    return std::move(E);
+  }
+
+  // FIXME: Check if TargetMachine or ExecutionEngine can be reused instead of
+  // creating one everytime.
+  return ExecutableFunction(State.createTargetMachine(),
+                            getObjectFromFile(*ExpectedObjectPath));
+}
+
 } // namespace exegesis