summaryrefslogtreecommitdiffstats
path: root/llvm/lib/MCA/Instruction.cpp
diff options
context:
space:
mode:
authorClement Courbet <courbet@google.com>2018-12-17 08:08:31 +0000
committerClement Courbet <courbet@google.com>2018-12-17 08:08:31 +0000
commitcc5e6a72de590bff4f1e68b7271d9f82bc66b995 (patch)
tree38daf2528d9f190e3ba1743d0cb592fa782698b4 /llvm/lib/MCA/Instruction.cpp
parent792d4f130d6fcfebc14f0e4e20d3111a24852da2 (diff)
downloadbcm5719-llvm-cc5e6a72de590bff4f1e68b7271d9f82bc66b995.tar.gz
bcm5719-llvm-cc5e6a72de590bff4f1e68b7271d9f82bc66b995.zip
[llvm-mca] Move llvm-mca library to llvm/lib/MCA.
Summary: See PR38731. Reviewers: andreadb Subscribers: mgorny, javed.absar, tschuett, gbedwell, andreadb, RKSimon, llvm-commits Differential Revision: https://reviews.llvm.org/D55557 llvm-svn: 349332
Diffstat (limited to 'llvm/lib/MCA/Instruction.cpp')
-rw-r--r--llvm/lib/MCA/Instruction.cpp205
1 files changed, 205 insertions, 0 deletions
diff --git a/llvm/lib/MCA/Instruction.cpp b/llvm/lib/MCA/Instruction.cpp
new file mode 100644
index 00000000000..057e95ca999
--- /dev/null
+++ b/llvm/lib/MCA/Instruction.cpp
@@ -0,0 +1,205 @@
+//===--------------------- Instruction.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines abstractions used by the Pipeline to model register reads,
+// register writes and instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MCA/Instruction.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace mca {
+
+void ReadState::writeStartEvent(unsigned Cycles) {
+ assert(DependentWrites);
+ assert(CyclesLeft == UNKNOWN_CYCLES);
+
+ // This read may be dependent on more than one write. This typically occurs
+ // when a definition is the result of multiple writes where at least one
+ // write does a partial register update.
+ // The HW is forced to do some extra bookkeeping to track of all the
+ // dependent writes, and implement a merging scheme for the partial writes.
+ --DependentWrites;
+ TotalCycles = std::max(TotalCycles, Cycles);
+
+ if (!DependentWrites) {
+ CyclesLeft = TotalCycles;
+ IsReady = !CyclesLeft;
+ }
+}
+
+void WriteState::onInstructionIssued() {
+ assert(CyclesLeft == UNKNOWN_CYCLES);
+ // Update the number of cycles left based on the WriteDescriptor info.
+ CyclesLeft = getLatency();
+
+ // Now that the time left before write-back is known, notify
+ // all the users.
+ for (const std::pair<ReadState *, int> &User : Users) {
+ ReadState *RS = User.first;
+ unsigned ReadCycles = std::max(0, CyclesLeft - User.second);
+ RS->writeStartEvent(ReadCycles);
+ }
+
+ // Notify any writes that are in a false dependency with this write.
+ if (PartialWrite)
+ PartialWrite->writeStartEvent(CyclesLeft);
+}
+
+void WriteState::addUser(ReadState *User, int ReadAdvance) {
+ // If CyclesLeft is different than -1, then we don't need to
+ // update the list of users. We can just notify the user with
+ // the actual number of cycles left (which may be zero).
+ if (CyclesLeft != UNKNOWN_CYCLES) {
+ unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance);
+ User->writeStartEvent(ReadCycles);
+ return;
+ }
+
+ if (llvm::find_if(Users, [&User](const std::pair<ReadState *, int> &Use) {
+ return Use.first == User;
+ }) == Users.end()) {
+ Users.emplace_back(User, ReadAdvance);
+ }
+}
+
+void WriteState::addUser(WriteState *User) {
+ if (CyclesLeft != UNKNOWN_CYCLES) {
+ User->writeStartEvent(std::max(0, CyclesLeft));
+ return;
+ }
+
+ assert(!PartialWrite && "PartialWrite already set!");
+ PartialWrite = User;
+ User->setDependentWrite(this);
+}
+
+void WriteState::cycleEvent() {
+ // Note: CyclesLeft can be a negative number. It is an error to
+ // make it an unsigned quantity because users of this write may
+ // specify a negative ReadAdvance.
+ if (CyclesLeft != UNKNOWN_CYCLES)
+ CyclesLeft--;
+
+ if (DependentWriteCyclesLeft)
+ DependentWriteCyclesLeft--;
+}
+
+void ReadState::cycleEvent() {
+ // Update the total number of cycles.
+ if (DependentWrites && TotalCycles) {
+ --TotalCycles;
+ return;
+ }
+
+ // Bail out immediately if we don't know how many cycles are left.
+ if (CyclesLeft == UNKNOWN_CYCLES)
+ return;
+
+ if (CyclesLeft) {
+ --CyclesLeft;
+ IsReady = !CyclesLeft;
+ }
+}
+
+#ifndef NDEBUG
+void WriteState::dump() const {
+ dbgs() << "{ OpIdx=" << WD->OpIndex << ", Lat=" << getLatency() << ", RegID "
+ << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }";
+}
+
+void WriteRef::dump() const {
+ dbgs() << "IID=" << getSourceIndex() << ' ';
+ if (isValid())
+ getWriteState()->dump();
+ else
+ dbgs() << "(null)";
+}
+#endif
+
+void Instruction::dispatch(unsigned RCUToken) {
+ assert(Stage == IS_INVALID);
+ Stage = IS_AVAILABLE;
+ RCUTokenID = RCUToken;
+
+ // Check if input operands are already available.
+ update();
+}
+
+void Instruction::execute() {
+ assert(Stage == IS_READY);
+ Stage = IS_EXECUTING;
+
+ // Set the cycles left before the write-back stage.
+ CyclesLeft = getLatency();
+
+ for (WriteState &WS : getDefs())
+ WS.onInstructionIssued();
+
+ // Transition to the "executed" stage if this is a zero-latency instruction.
+ if (!CyclesLeft)
+ Stage = IS_EXECUTED;
+}
+
+void Instruction::forceExecuted() {
+ assert(Stage == IS_READY && "Invalid internal state!");
+ CyclesLeft = 0;
+ Stage = IS_EXECUTED;
+}
+
+void Instruction::update() {
+ assert(isDispatched() && "Unexpected instruction stage found!");
+
+ if (!all_of(getUses(), [](const ReadState &Use) { return Use.isReady(); }))
+ return;
+
+ // A partial register write cannot complete before a dependent write.
+ auto IsDefReady = [&](const WriteState &Def) {
+ if (!Def.getDependentWrite()) {
+ unsigned CyclesLeft = Def.getDependentWriteCyclesLeft();
+ return !CyclesLeft || CyclesLeft < getLatency();
+ }
+ return false;
+ };
+
+ if (all_of(getDefs(), IsDefReady))
+ Stage = IS_READY;
+}
+
+void Instruction::cycleEvent() {
+ if (isReady())
+ return;
+
+ if (isDispatched()) {
+ for (ReadState &Use : getUses())
+ Use.cycleEvent();
+
+ for (WriteState &Def : getDefs())
+ Def.cycleEvent();
+
+ update();
+ return;
+ }
+
+ assert(isExecuting() && "Instruction not in-flight?");
+ assert(CyclesLeft && "Instruction already executed?");
+ for (WriteState &Def : getDefs())
+ Def.cycleEvent();
+ CyclesLeft--;
+ if (!CyclesLeft)
+ Stage = IS_EXECUTED;
+}
+
+const unsigned WriteRef::INVALID_IID = std::numeric_limits<unsigned>::max();
+
+} // namespace mca
+} // namespace llvm
OpenPOWER on IntegriCloud