diff options
author | Andrea Di Biagio <Andrea_DiBiagio@sn.scee.net> | 2019-03-29 12:15:37 +0000 |
---|---|---|
committer | Andrea Di Biagio <Andrea_DiBiagio@sn.scee.net> | 2019-03-29 12:15:37 +0000 |
commit | e074ac60b452717166398db0044fad0899c85b13 (patch) | |
tree | aeec0d0c76293d7d5261a6a0e949da3808ff0326 /llvm/lib/MCA | |
parent | 2b766ed774d4f0cf14f82c7e2eacb774d633fb77 (diff) | |
download | bcm5719-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.txt | 1 | ||||
-rw-r--r-- | llvm/lib/MCA/Context.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/MCA/Stages/MicroOpQueueStage.cpp | 70 |
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 |