[llvm-mca][NFC] Refactor handling of views that examine individual instructions,
authorWolfgang Pieb <wolfgang_pieb@playstation.sony.com>
Fri, 21 Aug 2020 22:52:02 +0000 (15:52 -0700)
committerWolfgang Pieb <wolfgang_pieb@playstation.sony.com>
Tue, 25 Aug 2020 19:12:37 +0000 (12:12 -0700)
including printing them.

Reviewers: andreadb, lebedev.ri

Differential Review: https://reviews.llvm.org/D86390

Introduces a new base class "InstructionView" that such views derive from.
Other views still use the "View" base class.

llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
llvm/tools/llvm-mca/Views/BottleneckAnalysis.h
llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
llvm/tools/llvm-mca/Views/InstructionInfoView.h
llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
llvm/tools/llvm-mca/Views/ResourcePressureView.h
llvm/tools/llvm-mca/Views/TimelineView.cpp
llvm/tools/llvm-mca/Views/TimelineView.h
llvm/tools/llvm-mca/Views/View.cpp
llvm/tools/llvm-mca/Views/View.h

index 99deed6..519b928 100644 (file)
@@ -16,7 +16,6 @@
 #include "llvm/MC/MCInst.h"
 #include "llvm/MCA/Support.h"
 #include "llvm/Support/Format.h"
-#include "llvm/Support/FormattedStream.h"
 
 namespace llvm {
 namespace mca {
@@ -284,21 +283,14 @@ void DependencyGraph::getCriticalSequence(
   }
 }
 
-static void printInstruction(formatted_raw_ostream &FOS,
-                             const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
-                             const MCInst &MCI,
-                             bool UseDifferentColor = false) {
-  std::string Instruction;
-  raw_string_ostream InstrStream(Instruction);
-
+void BottleneckAnalysis::printInstruction(formatted_raw_ostream &FOS,
+                                          const MCInst &MCI,
+                                          bool UseDifferentColor) const {
   FOS.PadToColumn(14);
 
-  MCIP.printInst(&MCI, 0, "", STI, InstrStream);
-  InstrStream.flush();
-
   if (UseDifferentColor)
     FOS.changeColor(raw_ostream::CYAN, true, false);
-  FOS << StringRef(Instruction).ltrim();
+  FOS << printInstructionString(MCI);
   if (UseDifferentColor)
     FOS.resetColor();
 }
@@ -316,6 +308,7 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
   OS << "\nCritical sequence based on the simulation:\n\n";
 
   const DependencyEdge &FirstEdge = *Seq[0];
+  ArrayRef<llvm::MCInst> Source = getSource();
   unsigned FromIID = FirstEdge.FromIID % Source.size();
   unsigned ToIID = FirstEdge.ToIID % Source.size();
   bool IsLoopCarried = FromIID >= ToIID;
@@ -331,17 +324,17 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
   unsigned CurrentIID = 0;
   if (IsLoopCarried) {
     FOS << "\n +----< " << FromIID << ".";
-    printInstruction(FOS, STI, MCIP, Source[FromIID], HasColors);
+    printInstruction(FOS, Source[FromIID], HasColors);
     FOS << "\n |\n |    < loop carried > \n |";
   } else {
     while (CurrentIID < FromIID) {
       FOS << "\n        " << CurrentIID << ".";
-      printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
+      printInstruction(FOS, Source[CurrentIID]);
       CurrentIID++;
     }
 
     FOS << "\n +----< " << CurrentIID << ".";
-    printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors);
+    printInstruction(FOS, Source[CurrentIID], HasColors);
     CurrentIID++;
   }
 
@@ -351,17 +344,17 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
 
     while (CurrentIID < LastIID) {
       FOS << "\n |      " << CurrentIID << ".";
-      printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
+      printInstruction(FOS, Source[CurrentIID]);
       CurrentIID++;
     }
 
     if (CurrentIID == ToIID) {
       FOS << "\n +----> " << ToIID << ".";
-      printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors);
+      printInstruction(FOS, Source[CurrentIID], HasColors);
     } else {
       FOS << "\n |\n |    < loop carried > \n |"
           << "\n +----> " << ToIID << ".";
-      printInstruction(FOS, STI, MCIP, Source[ToIID], HasColors);
+      printInstruction(FOS, Source[ToIID], HasColors);
     }
     FOS.PadToColumn(58);
 
@@ -373,7 +366,7 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
       FOS << "## REGISTER dependency:  ";
       if (HasColors)
         FOS.changeColor(raw_ostream::MAGENTA, true, false);
-      MCIP.printRegName(FOS, Dep.ResourceOrRegID);
+      getInstPrinter().printRegName(FOS, Dep.ResourceOrRegID);
     } else if (Dep.Type == DependencyEdge::DT_MEMORY) {
       FOS << "## MEMORY dependency.";
     } else {
@@ -397,7 +390,7 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
 
   while (CurrentIID < Source.size()) {
     FOS << "\n        " << CurrentIID << ".";
-    printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
+    printInstruction(FOS, Source[CurrentIID]);
     CurrentIID++;
   }
 
@@ -451,8 +444,8 @@ void DependencyGraph::addDependency(unsigned From, unsigned To,
 BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti,
                                        MCInstPrinter &Printer,
                                        ArrayRef<MCInst> S, unsigned NumIter)
-    : STI(sti), MCIP(Printer), Tracker(STI.getSchedModel()), DG(S.size() * 3),
-      Source(S), Iterations(NumIter), TotalCycles(0),
+    : InstructionView(sti, Printer, S), Tracker(sti.getSchedModel()),
+      DG(S.size() * 3), Iterations(NumIter), TotalCycles(0),
       PressureIncreasedBecauseOfResources(false),
       PressureIncreasedBecauseOfRegisterDependencies(false),
       PressureIncreasedBecauseOfMemoryDependencies(false),
@@ -461,7 +454,7 @@ BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti,
 void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,
                                         unsigned RegID, unsigned Cost) {
   bool IsLoopCarried = From >= To;
-  unsigned SourceSize = Source.size();
+  unsigned SourceSize = getSource().size();
   if (IsLoopCarried) {
     DG.addRegisterDep(From, To + SourceSize, RegID, Cost);
     DG.addRegisterDep(From + SourceSize, To + (SourceSize * 2), RegID, Cost);
@@ -473,7 +466,7 @@ void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,
 void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To,
                                       unsigned Cost) {
   bool IsLoopCarried = From >= To;
-  unsigned SourceSize = Source.size();
+  unsigned SourceSize = getSource().size();
   if (IsLoopCarried) {
     DG.addMemoryDep(From, To + SourceSize, Cost);
     DG.addMemoryDep(From + SourceSize, To + (SourceSize * 2), Cost);
@@ -485,7 +478,7 @@ void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To,
 void BottleneckAnalysis::addResourceDep(unsigned From, unsigned To,
                                         uint64_t Mask, unsigned Cost) {
   bool IsLoopCarried = From >= To;
-  unsigned SourceSize = Source.size();
+  unsigned SourceSize = getSource().size();
   if (IsLoopCarried) {
     DG.addResourceDep(From, To + SourceSize, Mask, Cost);
     DG.addResourceDep(From + SourceSize, To + (SourceSize * 2), Mask, Cost);
@@ -508,6 +501,7 @@ void BottleneckAnalysis::onEvent(const HWInstructionEvent &Event) {
   if (Event.Type != HWInstructionEvent::Issued)
     return;
 
+  ArrayRef<llvm::MCInst> Source = getSource();
   const Instruction &IS = *Event.IR.getInstruction();
   unsigned To = IID % Source.size();
 
@@ -617,7 +611,7 @@ void BottleneckAnalysis::printBottleneckHints(raw_ostream &OS) const {
 
   if (BPI.PressureIncreaseCycles) {
     ArrayRef<unsigned> Distribution = Tracker.getResourcePressureDistribution();
-    const MCSchedModel &SM = STI.getSchedModel();
+    const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
     for (unsigned I = 0, E = Distribution.size(); I < E; ++I) {
       unsigned ResourceCycles = Distribution[I];
       if (ResourceCycles) {
index 9e3bd59..a0aad9f 100644 (file)
@@ -87,6 +87,7 @@
 #include "llvm/MC/MCSchedule.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/FormattedStream.h"
 
 namespace llvm {
 namespace mca {
@@ -282,13 +283,10 @@ public:
 };
 
 /// A view that collects and prints a few performance numbers.
-class BottleneckAnalysis : public View {
-  const MCSubtargetInfo &STI;
-  MCInstPrinter &MCIP;
+class BottleneckAnalysis : public InstructionView {
   PressureTracker Tracker;
   DependencyGraph DG;
 
-  ArrayRef<MCInst> Source;
   unsigned Iterations;
   unsigned TotalCycles;
 
@@ -317,6 +315,9 @@ class BottleneckAnalysis : public View {
   void addMemoryDep(unsigned From, unsigned To, unsigned Cy);
   void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy);
 
+  void printInstruction(formatted_raw_ostream &FOS, const MCInst &MCI,
+                        bool UseDifferentColor = false) const;
+
   // Prints a bottleneck message to OS.
   void printBottleneckHints(raw_ostream &OS) const;
   void printCriticalSequence(raw_ostream &OS) const;
index 548f0b3..da53f16 100644 (file)
@@ -20,9 +20,8 @@ namespace mca {
 void InstructionInfoView::printView(raw_ostream &OS) const {
   std::string Buffer;
   raw_string_ostream TempStream(Buffer);
-  std::string Instruction;
-  raw_string_ostream InstrStream(Instruction);
 
+  ArrayRef<llvm::MCInst> Source = getSource();
   if (!Source.size())
     return;
 
@@ -82,14 +81,7 @@ void InstructionInfoView::printView(raw_ostream &OS) const {
     }
 
     const MCInst &Inst = std::get<1>(I.value());
-    MCIP.printInst(&Inst, 0, "", STI, InstrStream);
-    InstrStream.flush();
-
-    // Consume any tabs or spaces at the beginning of the string.
-    StringRef Str(Instruction);
-    Str = Str.ltrim();
-    TempStream << Str << '\n';
-    Instruction = "";
+    TempStream << printInstructionString(Inst) << '\n';
   }
 
   TempStream.flush();
@@ -98,8 +90,9 @@ void InstructionInfoView::printView(raw_ostream &OS) const {
 
 void InstructionInfoView::collectData(
     MutableArrayRef<InstructionInfoViewData> IIVD) const {
+  const llvm::MCSubtargetInfo &STI = getSubTargetInfo();
   const MCSchedModel &SM = STI.getSchedModel();
-  for (auto I : zip(Source, IIVD)) {
+  for (auto I : zip(getSource(), IIVD)) {
     const MCInst &Inst = std::get<0>(I);
     InstructionInfoViewData &IIVDEntry = std::get<1>(I);
     const MCInstrDesc &MCDesc = MCII.get(Inst.getOpcode());
index aca7e58..c2093b2 100644 (file)
@@ -50,13 +50,10 @@ namespace llvm {
 namespace mca {
 
 /// A view that prints out generic instruction information.
-class InstructionInfoView : public View {
-  const llvm::MCSubtargetInfo &STI;
+class InstructionInfoView : public InstructionView {
   const llvm::MCInstrInfo &MCII;
   CodeEmitter &CE;
   bool PrintEncodings;
-  llvm::ArrayRef<llvm::MCInst> Source;
-  llvm::MCInstPrinter &MCIP;
 
   struct InstructionInfoViewData {
     unsigned NumMicroOpcodes = 0;
@@ -76,8 +73,8 @@ public:
                       const llvm::MCInstrInfo &II, CodeEmitter &C,
                       bool ShouldPrintEncodings, llvm::ArrayRef<llvm::MCInst> S,
                       llvm::MCInstPrinter &IP)
-      : STI(ST), MCII(II), CE(C), PrintEncodings(ShouldPrintEncodings),
-        Source(S), MCIP(IP) {}
+      : InstructionView(ST, IP, S), MCII(II), CE(C),
+        PrintEncodings(ShouldPrintEncodings) {}
 
   void printView(llvm::raw_ostream &OS) const override;
 };
index bdb9dc2..a5a7421 100644 (file)
@@ -21,10 +21,10 @@ namespace mca {
 ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
                                            MCInstPrinter &Printer,
                                            ArrayRef<MCInst> S)
-    : STI(sti), MCIP(Printer), Source(S), LastInstructionIdx(0) {
+    : InstructionView(sti, Printer, S), LastInstructionIdx(0) {
   // Populate the map of resource descriptors.
   unsigned R2VIndex = 0;
-  const MCSchedModel &SM = STI.getSchedModel();
+  const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
   for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
     unsigned NumUnits = ProcResource.NumUnits;
@@ -37,7 +37,7 @@ ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
   }
 
   NumResourceUnits = R2VIndex;
-  ResourceUsage.resize(NumResourceUnits * (Source.size() + 1));
+  ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));
   std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
 }
 
@@ -52,6 +52,7 @@ void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
     return;
 
   const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
+  ArrayRef<llvm::MCInst> Source = getSource();
   const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
   for (const std::pair<ResourceRef, ResourceCycles> &Use :
        IssueEvent.UsedResources) {
@@ -105,7 +106,7 @@ void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
   formatted_raw_ostream FOS(TempStream);
 
   FOS << "\n\nResources:\n";
-  const MCSchedModel &SM = STI.getSchedModel();
+  const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
   for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
        I < E; ++I) {
     const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
@@ -132,6 +133,7 @@ void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
   FOS << '\n';
   FOS.flush();
 
+  ArrayRef<llvm::MCInst> Source = getSource();
   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
   for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
     double Usage = ResourceUsage[I + Source.size() * E];
@@ -148,13 +150,11 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
   formatted_raw_ostream FOS(TempStream);
 
   FOS << "\n\nResource pressure by instruction:\n";
-  printColumnNames(FOS, STI.getSchedModel());
+  printColumnNames(FOS, getSubTargetInfo().getSchedModel());
   FOS << "Instructions:\n";
 
-  std::string Instruction;
-  raw_string_ostream InstrStream(Instruction);
-
   unsigned InstrIndex = 0;
+  ArrayRef<llvm::MCInst> Source = getSource();
   const unsigned Executions = LastInstructionIdx / Source.size() + 1;
   for (const MCInst &MCI : Source) {
     unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
@@ -163,16 +163,7 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
       printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
     }
 
-    MCIP.printInst(&MCI, 0, "", STI, InstrStream);
-    InstrStream.flush();
-    StringRef Str(Instruction);
-
-    // Remove any tabs or spaces at the beginning of the instruction.
-    Str = Str.ltrim();
-
-    FOS << Str << '\n';
-    Instruction = "";
-
+    FOS << printInstructionString(MCI) << '\n';
     FOS.flush();
     OS << Buffer;
     Buffer = "";
index 0fa0b9a..39914f9 100644 (file)
@@ -69,10 +69,7 @@ namespace mca {
 
 /// This class collects resource pressure statistics and it is able to print
 /// out all the collected information as a table to an output stream.
-class ResourcePressureView : public View {
-  const llvm::MCSubtargetInfo &STI;
-  llvm::MCInstPrinter &MCIP;
-  llvm::ArrayRef<llvm::MCInst> Source;
+class ResourcePressureView : public InstructionView {
   unsigned LastInstructionIdx;
 
   // Map to quickly obtain the ResourceUsage column index from a processor
index cf5b48e..f520c5c 100644 (file)
@@ -20,10 +20,10 @@ namespace mca {
 TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
                            llvm::ArrayRef<llvm::MCInst> S, unsigned Iterations,
                            unsigned Cycles)
-    : STI(sti), MCIP(Printer), Source(S), CurrentCycle(0),
+    : InstructionView(sti, Printer, S), CurrentCycle(0),
       MaxCycle(Cycles == 0 ? 80 : Cycles), LastCycle(0), WaitTime(S.size()),
       UsedBuffer(S.size()) {
-  unsigned NumInstructions = Source.size();
+  unsigned NumInstructions = getSource().size();
   assert(Iterations && "Invalid number of iterations specified!");
   NumInstructions *= Iterations;
   Timeline.resize(NumInstructions);
@@ -40,10 +40,10 @@ TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
 
 void TimelineView::onReservedBuffers(const InstRef &IR,
                                      ArrayRef<unsigned> Buffers) {
-  if (IR.getSourceIndex() >= Source.size())
+  if (IR.getSourceIndex() >= getSource().size())
     return;
 
-  const MCSchedModel &SM = STI.getSchedModel();
+  const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
   std::pair<unsigned, int> BufferInfo = {0, -1};
   for (const unsigned Buffer : Buffers) {
     const MCProcResourceDesc &MCDesc = *SM.getProcResource(Buffer);
@@ -70,7 +70,7 @@ void TimelineView::onEvent(const HWInstructionEvent &Event) {
     // Update the WaitTime entry which corresponds to this Index.
     assert(TVEntry.CycleDispatched >= 0 && "Invalid TVEntry found!");
     unsigned CycleDispatched = static_cast<unsigned>(TVEntry.CycleDispatched);
-    WaitTimeEntry &WTEntry = WaitTime[Index % Source.size()];
+    WaitTimeEntry &WTEntry = WaitTime[Index % getSource().size()];
     WTEntry.CyclesSpentInSchedulerQueue +=
         TVEntry.CycleIssued - CycleDispatched;
     assert(CycleDispatched <= TVEntry.CycleReady &&
@@ -133,7 +133,7 @@ void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
                                       const WaitTimeEntry &Entry,
                                       unsigned SourceIndex,
                                       unsigned Executions) const {
-  bool PrintingTotals = SourceIndex == Source.size();
+  bool PrintingTotals = SourceIndex == getSource().size();
   unsigned CumulativeExecutions = PrintingTotals ? Timeline.size() : Executions;
 
   if (!PrintingTotals)
@@ -164,7 +164,8 @@ void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
   OS.PadToColumn(27);
   if (!PrintingTotals)
     tryChangeColor(OS, Entry.CyclesSpentAfterWBAndBeforeRetire,
-                   CumulativeExecutions, STI.getSchedModel().MicroOpBufferSize);
+                   CumulativeExecutions,
+                   getSubTargetInfo().getSchedModel().MicroOpBufferSize);
   OS << format("%.1f", floor((AverageTime3 * 10) + 0.5) / 10);
 
   if (OS.has_colors())
@@ -181,33 +182,19 @@ void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
       "[3]: Average time elapsed from WB until retire stage\n\n"
       "      [0]    [1]    [2]    [3]\n";
   OS << Header;
-
-  // Use a different string stream for printing instructions.
-  std::string Instruction;
-  raw_string_ostream InstrStream(Instruction);
-
   formatted_raw_ostream FOS(OS);
-  unsigned Executions = Timeline.size() / Source.size();
+  unsigned Executions = Timeline.size() / getSource().size();
   unsigned IID = 0;
-  for (const MCInst &Inst : Source) {
+  for (const MCInst &Inst : getSource()) {
     printWaitTimeEntry(FOS, WaitTime[IID], IID, Executions);
-    // Append the instruction info at the end of the line.
-    MCIP.printInst(&Inst, 0, "", STI, InstrStream);
-    InstrStream.flush();
-
-    // Consume any tabs or spaces at the beginning of the string.
-    StringRef Str(Instruction);
-    Str = Str.ltrim();
-    FOS << "   " << Str << '\n';
+    FOS << "   " << printInstructionString(Inst) << '\n';
     FOS.flush();
-    Instruction = "";
-
     ++IID;
   }
 
   // If the timeline contains more than one instruction,
   // let's also print global averages.
-  if (Source.size() != 1) {
+  if (getSource().size() != 1) {
     WaitTimeEntry TotalWaitTime = std::accumulate(
         WaitTime.begin(), WaitTime.end(), WaitTimeEntry{0, 0, 0},
         [](const WaitTimeEntry &A, const WaitTimeEntry &B) {
@@ -220,7 +207,7 @@ void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
     printWaitTimeEntry(FOS, TotalWaitTime, IID, Executions);
     FOS << "   "
         << "<total>" << '\n';
-    InstrStream.flush();
+    FOS.flush();
   }
 }
 
@@ -292,11 +279,8 @@ void TimelineView::printTimeline(raw_ostream &OS) const {
   printTimelineHeader(FOS, LastCycle);
   FOS.flush();
 
-  // Use a different string stream for the instruction.
-  std::string Instruction;
-  raw_string_ostream InstrStream(Instruction);
-
   unsigned IID = 0;
+  ArrayRef<llvm::MCInst> Source = getSource();
   const unsigned Iterations = Timeline.size() / Source.size();
   for (unsigned Iteration = 0; Iteration < Iterations; ++Iteration) {
     for (const MCInst &Inst : Source) {
@@ -306,16 +290,8 @@ void TimelineView::printTimeline(raw_ostream &OS) const {
 
       unsigned SourceIndex = IID % Source.size();
       printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex);
-      // Append the instruction info at the end of the line.
-      MCIP.printInst(&Inst, 0, "", STI, InstrStream);
-      InstrStream.flush();
-
-      // Consume any tabs or spaces at the beginning of the string.
-      StringRef Str(Instruction);
-      Str = Str.ltrim();
-      FOS << "   " << Str << '\n';
+      FOS << "   " << printInstructionString(Inst) << '\n';
       FOS.flush();
-      Instruction = "";
 
       ++IID;
     }
index 9bec3b8..528579e 100644 (file)
@@ -118,11 +118,7 @@ namespace mca {
 /// a TimelineViewEntry object. TimelineViewEntry objects are then used
 /// to print the timeline information, as well as the "average wait times"
 /// for every instruction in the input assembly sequence.
-class TimelineView : public View {
-  const llvm::MCSubtargetInfo &STI;
-  llvm::MCInstPrinter &MCIP;
-  llvm::ArrayRef<llvm::MCInst> Source;
-
+class TimelineView : public InstructionView {
   unsigned CurrentCycle;
   unsigned MaxCycle;
   unsigned LastCycle;
index 8e5c34d..4cef745 100644 (file)
@@ -17,5 +17,13 @@ namespace llvm {
 namespace mca {
 
 void View::anchor() {}
+
+StringRef InstructionView::printInstructionString(const llvm::MCInst &MCI) const {
+    InstructionString = "";
+    MCIP.printInst(&MCI, 0, "", STI, InstrStream);
+    InstrStream.flush();
+    // Remove any tabs or spaces at the beginning of the instruction.
+    return StringRef(InstructionString).ltrim();
+  }
 } // namespace mca
 } // namespace llvm
index 3b52511..1af6e59 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef LLVM_TOOLS_LLVM_MCA_VIEW_H
 #define LLVM_TOOLS_LLVM_MCA_VIEW_H
 
+#include "llvm/MC/MCInstPrinter.h"
 #include "llvm/MCA/HWEventListener.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -27,6 +28,33 @@ public:
   virtual ~View() = default;
   void anchor() override;
 };
+
+// The base class for views that deal with individual machine instructions.
+class InstructionView : public View {
+  const llvm::MCSubtargetInfo &STI;
+  llvm::MCInstPrinter &MCIP;
+  llvm::ArrayRef<llvm::MCInst> Source;
+
+  mutable std::string InstructionString;
+  mutable raw_string_ostream InstrStream;
+
+protected:
+  InstructionView(const llvm::MCSubtargetInfo &STI,
+                  llvm::MCInstPrinter &Printer,
+                  llvm::ArrayRef<llvm::MCInst> S)
+      : STI(STI), MCIP(Printer), Source(S), InstrStream(InstructionString) {}
+
+  virtual ~InstructionView() = default;
+
+  // Return a reference to a string representing a given machine instruction.
+  // The result should be used or copied before the next call to
+  // printInstructionString() as it will overwrite the previous result.
+  StringRef printInstructionString(const llvm::MCInst &MCI) const;
+  
+  const llvm::MCSubtargetInfo &getSubTargetInfo() const { return STI; }
+  llvm::MCInstPrinter &getInstPrinter() const { return MCIP; }
+  llvm::ArrayRef<llvm::MCInst> getSource() const { return Source; }
+};
 } // namespace mca
 } // namespace llvm