[llvm-mca] LLVM Machine Code Analyzer.

llvm-mca is an LLVM based performance analysis tool that can be used to
statically measure the performance of code, and to help triage potential
problems with target scheduling models.

llvm-mca uses information which is already available in LLVM (e.g. scheduling
models) to statically measure the performance of machine code in a specific cpu.
Performance is measured in terms of throughput as well as processor resource
consumption. The tool currently works for processors with an out-of-order
backend, for which there is a scheduling model available in LLVM.

The main goal of this tool is not just to predict the performance of the code
when run on the target, but also help with diagnosing potential performance
issues.

Given an assembly code sequence, llvm-mca estimates the IPC (instructions per
cycle), as well as hardware resources pressure. The analysis and reporting style
were mostly inspired by the IACA tool from Intel.

This patch is related to the RFC on llvm-dev visible at this link:
http://lists.llvm.org/pipermail/llvm-dev/2018-March/121490.html

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

llvm-svn: 326998
diff --git a/llvm/tools/llvm-mca/Backend.h b/llvm/tools/llvm-mca/Backend.h
new file mode 100644
index 0000000..6e2db08
--- /dev/null
+++ b/llvm/tools/llvm-mca/Backend.h
@@ -0,0 +1,141 @@
+//===--------------------- Backend.h ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file implements an OoO backend for the llvm-mca tool.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_MCA_BACKEND_H
+#define LLVM_TOOLS_LLVM_MCA_BACKEND_H
+
+#include "Dispatch.h"
+#include "InstrBuilder.h"
+#include "Scheduler.h"
+#include "SourceMgr.h"
+
+namespace mca {
+
+struct HWEventListener;
+
+/// \brief An out of order backend for a specific subtarget.
+///
+/// It emulates an out-of-order execution of instructions. Instructions are
+/// fetched from a MCInst sequence managed by an object of class SourceMgr.
+/// Instructions are firstly dispatched to the schedulers and then executed.
+/// This class tracks the lifetime of an instruction from the moment where
+/// it gets dispatched to the schedulers, to the moment where it finishes
+/// executing and register writes are architecturally committed.
+/// In particular, it monitors changes in the state of every instruction
+/// in flight.
+/// Instructions are executed in a loop of iterations. The number of iterations
+/// is defined by the SourceMgr object.
+/// The Backend entrypoint is method 'Run()' which execute cycles in a loop
+/// until there are new instructions to dispatch, and not every instruction
+/// has been retired.
+/// Internally, the Backend collects statistical information in the form of
+/// histograms. For example, it tracks how the dispatch group size changes
+/// over time.
+class Backend {
+  const llvm::MCSubtargetInfo &STI;
+
+  std::unique_ptr<InstrBuilder> IB;
+  std::unique_ptr<Scheduler> HWS;
+  std::unique_ptr<DispatchUnit> DU;
+  std::unique_ptr<SourceMgr> SM;
+  unsigned Cycles;
+
+  llvm::DenseMap<unsigned, std::unique_ptr<Instruction>> Instructions;
+  std::set<HWEventListener *> Listeners;
+
+  void runCycle(unsigned Cycle);
+
+public:
+  Backend(const llvm::MCSubtargetInfo &Subtarget, const llvm::MCInstrInfo &MCII,
+          const llvm::MCRegisterInfo &MRI, std::unique_ptr<SourceMgr> Source,
+          unsigned DispatchWidth = 0, unsigned RegisterFileSize = 0,
+          unsigned MaxRetirePerCycle = 0, unsigned LoadQueueSize = 0,
+          unsigned StoreQueueSize = 0, bool AssumeNoAlias = false)
+      : STI(Subtarget),
+        HWS(llvm::make_unique<Scheduler>(this, Subtarget.getSchedModel(),
+                                         LoadQueueSize, StoreQueueSize,
+                                         AssumeNoAlias)),
+        DU(llvm::make_unique<DispatchUnit>(
+            this, MRI, Subtarget.getSchedModel().MicroOpBufferSize,
+            RegisterFileSize, MaxRetirePerCycle, DispatchWidth, HWS.get())),
+        SM(std::move(Source)), Cycles(0) {
+    IB = llvm::make_unique<InstrBuilder>(MCII, getProcResourceMasks());
+  }
+
+  void run() {
+    while (SM->hasNext() || !DU->isRCUEmpty())
+      runCycle(Cycles++);
+  }
+
+  unsigned getNumIterations() const { return SM->getNumIterations(); }
+  unsigned getNumInstructions() const { return SM->size(); }
+  unsigned getNumCycles() const { return Cycles; }
+  unsigned getTotalRegisterMappingsCreated() const {
+    return DU->getTotalRegisterMappingsCreated();
+  }
+  unsigned getMaxUsedRegisterMappings() const {
+    return DU->getMaxUsedRegisterMappings();
+  }
+  unsigned getDispatchWidth() const { return DU->getDispatchWidth(); }
+
+  const llvm::MCSubtargetInfo &getSTI() const { return STI; }
+  const llvm::MCSchedModel &getSchedModel() const {
+    return STI.getSchedModel();
+  }
+  const llvm::ArrayRef<uint64_t> getProcResourceMasks() const {
+    return HWS->getProcResourceMasks();
+  }
+
+  double getRThroughput(const InstrDesc &ID) const {
+    return HWS->getRThroughput(ID);
+  }
+  void getBuffersUsage(std::vector<BufferUsageEntry> &Usage) const {
+    return HWS->getBuffersUsage(Usage);
+  }
+
+  unsigned getNumRATStalls() const { return DU->getNumRATStalls(); }
+  unsigned getNumRCUStalls() const { return DU->getNumRCUStalls(); }
+  unsigned getNumSQStalls() const { return DU->getNumSQStalls(); }
+  unsigned getNumLDQStalls() const { return DU->getNumLDQStalls(); }
+  unsigned getNumSTQStalls() const { return DU->getNumSTQStalls(); }
+  unsigned getNumDispatchGroupStalls() const {
+    return DU->getNumDispatchGroupStalls();
+  }
+
+  const llvm::MCInst &getMCInstFromIndex(unsigned Index) const {
+    return SM->getMCInstFromIndex(Index);
+  }
+
+  const InstrDesc &getInstrDesc(const llvm::MCInst &Inst) const {
+    return IB->getOrCreateInstrDesc(STI, Inst);
+  }
+
+  const SourceMgr &getSourceMgr() const { return *SM; }
+
+  void addEventListener(HWEventListener *Listener);
+  void notifyCycleBegin(unsigned Cycle);
+  void notifyInstructionDispatched(unsigned Index);
+  void notifyInstructionReady(unsigned Index);
+  void notifyInstructionIssued(
+      unsigned Index,
+      const llvm::ArrayRef<std::pair<ResourceRef, unsigned>> &Used);
+  void notifyInstructionExecuted(unsigned Index);
+  void notifyResourceAvailable(const ResourceRef &RR);
+  void notifyInstructionRetired(unsigned Index);
+  void notifyCycleEnd(unsigned Cycle);
+};
+
+} // namespace mca
+
+#endif