summaryrefslogtreecommitdiffstats
path: root/llvm/lib/MCA
diff options
context:
space:
mode:
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>2019-03-29 12:15:37 +0000
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>2019-03-29 12:15:37 +0000
commite074ac60b452717166398db0044fad0899c85b13 (patch)
treeaeec0d0c76293d7d5261a6a0e949da3808ff0326 /llvm/lib/MCA
parent2b766ed774d4f0cf14f82c7e2eacb774d633fb77 (diff)
downloadbcm5719-llvm-e074ac60b452717166398db0044fad0899c85b13.tar.gz
bcm5719-llvm-e074ac60b452717166398db0044fad0899c85b13.zip
[MCA] Add an experimental MicroOpQueue stage.
This patch adds an experimental stage named MicroOpQueueStage. MicroOpQueueStage can be used to simulate a hardware micro-op queue (basically, a decoupling queue between 'decode' and 'dispatch'). Users can specify a queue size, as well as a optional MaxIPC (which - in the absence of a "Decoders" stage - can be used to simulate a different throughput from the decoders). This stage is added to the default pipeline between the EntryStage and the DispatchStage only if PipelineOption::MicroOpQueue is different than zero. By default, llvm-mca sets PipelineOption::MicroOpQueue to the value of hidden flag -micro-op-queue-size. Throughput from the decoder can be simulated via another hidden flag named -decoder-throughput. That flag allows us to quickly experiment with different frontend throughputs. For targets that declare a loop buffer, flag -decoder-throughput allows users to do multiple runs, each time simulating a different throughput from the decoders. This stage can/will be extended in future. For example, we could add a "buffer full" event to notify bottlenecks caused by backpressure. flag -decoder-throughput would probably go away if in future we delegate to another stage (DecoderStage?) the simulation of a (potentially variable) throughput from the decoders. For now, flag -decoder-throughput is "good enough" to run some simple experiments. Differential Revision: https://reviews.llvm.org/D59928 llvm-svn: 357248
Diffstat (limited to 'llvm/lib/MCA')
-rw-r--r--llvm/lib/MCA/CMakeLists.txt1
-rw-r--r--llvm/lib/MCA/Context.cpp4
-rw-r--r--llvm/lib/MCA/Stages/MicroOpQueueStage.cpp70
3 files changed, 75 insertions, 0 deletions
diff --git a/llvm/lib/MCA/CMakeLists.txt b/llvm/lib/MCA/CMakeLists.txt
index bfd0782d1f7..4965b6b31c1 100644
--- a/llvm/lib/MCA/CMakeLists.txt
+++ b/llvm/lib/MCA/CMakeLists.txt
@@ -14,6 +14,7 @@ add_llvm_library(LLVMMCA
Stages/EntryStage.cpp
Stages/ExecuteStage.cpp
Stages/InstructionTables.cpp
+ Stages/MicroOpQueueStage.cpp
Stages/RetireStage.cpp
Stages/Stage.cpp
Support.cpp
diff --git a/llvm/lib/MCA/Context.cpp b/llvm/lib/MCA/Context.cpp
index 8de675389df..f0e8dfab868 100644
--- a/llvm/lib/MCA/Context.cpp
+++ b/llvm/lib/MCA/Context.cpp
@@ -21,6 +21,7 @@
#include "llvm/MCA/Stages/DispatchStage.h"
#include "llvm/MCA/Stages/EntryStage.h"
#include "llvm/MCA/Stages/ExecuteStage.h"
+#include "llvm/MCA/Stages/MicroOpQueueStage.h"
#include "llvm/MCA/Stages/RetireStage.h"
namespace llvm {
@@ -55,6 +56,9 @@ Context::createDefaultPipeline(const PipelineOptions &Opts, InstrBuilder &IB,
// Build the pipeline.
auto StagePipeline = llvm::make_unique<Pipeline>();
StagePipeline->appendStage(std::move(Fetch));
+ if (Opts.MicroOpQueueSize)
+ StagePipeline->appendStage(llvm::make_unique<MicroOpQueueStage>(
+ Opts.MicroOpQueueSize, Opts.DecodersThroughput));
StagePipeline->appendStage(std::move(Dispatch));
StagePipeline->appendStage(std::move(Execute));
StagePipeline->appendStage(std::move(Retire));
diff --git a/llvm/lib/MCA/Stages/MicroOpQueueStage.cpp b/llvm/lib/MCA/Stages/MicroOpQueueStage.cpp
new file mode 100644
index 00000000000..cb3e4c6979a
--- /dev/null
+++ b/llvm/lib/MCA/Stages/MicroOpQueueStage.cpp
@@ -0,0 +1,70 @@
+//===---------------------- MicroOpQueueStage.cpp ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines the MicroOpQueueStage.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MCA/Stages/MicroOpQueueStage.h"
+
+namespace llvm {
+namespace mca {
+
+#define DEBUG_TYPE "llvm-mca"
+
+Error MicroOpQueueStage::moveInstructions() {
+ InstRef IR = Buffer[CurrentInstructionSlotIdx];
+ while (IR && checkNextStage(IR)) {
+ if (llvm::Error Val = moveToTheNextStage(IR))
+ return Val;
+
+ Buffer[CurrentInstructionSlotIdx].invalidate();
+ unsigned NormalizedOpcodes = getNormalizedOpcodes(IR);
+ CurrentInstructionSlotIdx += NormalizedOpcodes;
+ CurrentInstructionSlotIdx %= Buffer.size();
+ AvailableEntries += NormalizedOpcodes;
+ IR = Buffer[CurrentInstructionSlotIdx];
+ }
+
+ return llvm::ErrorSuccess();
+}
+
+MicroOpQueueStage::MicroOpQueueStage(unsigned Size, unsigned IPC,
+ bool ZeroLatencyStage)
+ : NextAvailableSlotIdx(0), CurrentInstructionSlotIdx(0), MaxIPC(IPC),
+ CurrentIPC(0), IsZeroLatencyStage(ZeroLatencyStage) {
+ Buffer.resize(Size ? Size : 1);
+ AvailableEntries = Buffer.size();
+}
+
+Error MicroOpQueueStage::execute(InstRef &IR) {
+ Buffer[NextAvailableSlotIdx] = IR;
+ unsigned NormalizedOpcodes = getNormalizedOpcodes(IR);
+ NextAvailableSlotIdx += NormalizedOpcodes;
+ NextAvailableSlotIdx %= Buffer.size();
+ AvailableEntries -= NormalizedOpcodes;
+ ++CurrentIPC;
+ return llvm::ErrorSuccess();
+}
+
+Error MicroOpQueueStage::cycleStart() {
+ CurrentIPC = 0;
+ if (!IsZeroLatencyStage)
+ return moveInstructions();
+ return llvm::ErrorSuccess();
+}
+
+Error MicroOpQueueStage::cycleEnd() {
+ if (IsZeroLatencyStage)
+ return moveInstructions();
+ return llvm::ErrorSuccess();
+}
+
+} // namespace mca
+} // namespace llvm
OpenPOWER on IntegriCloud