blob: 832a6199f00ca363891cd3e5c780c2bb921f9b96 [file] [log] [blame]
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +00001//===--------------------- Instruction.cpp ----------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Matt Davisdea343d2018-06-25 16:53:00 +000010// This file defines abstractions used by the Pipeline to model register reads,
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000011// register writes and instructions.
12//
13//===----------------------------------------------------------------------===//
14
15#include "Instruction.h"
16#include "llvm/Support/Debug.h"
17#include "llvm/Support/raw_ostream.h"
18
Fangrui Song5a8fd652018-10-30 15:56:08 +000019namespace llvm {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000020namespace mca {
21
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000022void ReadState::writeStartEvent(unsigned Cycles) {
23 assert(DependentWrites);
24 assert(CyclesLeft == UNKNOWN_CYCLES);
25
26 // This read may be dependent on more than one write. This typically occurs
27 // when a definition is the result of multiple writes where at least one
28 // write does a partial register update.
29 // The HW is forced to do some extra bookkeeping to track of all the
30 // dependent writes, and implement a merging scheme for the partial writes.
31 --DependentWrites;
32 TotalCycles = std::max(TotalCycles, Cycles);
33
Andrea Di Biagioeb1bef62018-06-27 11:17:07 +000034 if (!DependentWrites) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000035 CyclesLeft = TotalCycles;
Andrea Di Biagioeb1bef62018-06-27 11:17:07 +000036 IsReady = !CyclesLeft;
37 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000038}
39
40void WriteState::onInstructionIssued() {
41 assert(CyclesLeft == UNKNOWN_CYCLES);
42 // Update the number of cycles left based on the WriteDescriptor info.
Andrea Di Biagiobb25e272018-07-06 13:46:10 +000043 CyclesLeft = getLatency();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000044
Andrea Di Biagio757600b2018-06-05 17:12:02 +000045 // Now that the time left before write-back is known, notify
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000046 // all the users.
47 for (const std::pair<ReadState *, int> &User : Users) {
48 ReadState *RS = User.first;
49 unsigned ReadCycles = std::max(0, CyclesLeft - User.second);
50 RS->writeStartEvent(ReadCycles);
51 }
52}
53
54void WriteState::addUser(ReadState *User, int ReadAdvance) {
55 // If CyclesLeft is different than -1, then we don't need to
56 // update the list of users. We can just notify the user with
57 // the actual number of cycles left (which may be zero).
58 if (CyclesLeft != UNKNOWN_CYCLES) {
59 unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance);
60 User->writeStartEvent(ReadCycles);
61 return;
62 }
63
64 std::pair<ReadState *, int> NewPair(User, ReadAdvance);
65 Users.insert(NewPair);
66}
67
68void WriteState::cycleEvent() {
69 // Note: CyclesLeft can be a negative number. It is an error to
70 // make it an unsigned quantity because users of this write may
71 // specify a negative ReadAdvance.
72 if (CyclesLeft != UNKNOWN_CYCLES)
73 CyclesLeft--;
74}
75
76void ReadState::cycleEvent() {
Andrea Di Biagio757600b2018-06-05 17:12:02 +000077 // Update the total number of cycles.
78 if (DependentWrites && TotalCycles) {
79 --TotalCycles;
80 return;
81 }
82
83 // Bail out immediately if we don't know how many cycles are left.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000084 if (CyclesLeft == UNKNOWN_CYCLES)
85 return;
86
Andrea Di Biagioeb1bef62018-06-27 11:17:07 +000087 if (CyclesLeft) {
Andrea Di Biagio757600b2018-06-05 17:12:02 +000088 --CyclesLeft;
Andrea Di Biagioeb1bef62018-06-27 11:17:07 +000089 IsReady = !CyclesLeft;
90 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000091}
92
93#ifndef NDEBUG
94void WriteState::dump() const {
Andrea Di Biagiodf4d65d2018-10-29 13:29:22 +000095 dbgs() << "{ OpIdx=" << WD->OpIndex << ", Lat=" << getLatency() << ", RegID "
Andrea Di Biagiofa2d16f2018-07-05 16:13:49 +000096 << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }";
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000097}
Andrea Di Biagio877f9a72018-06-28 15:50:26 +000098
99void WriteRef::dump() const {
Andrea Di Biagiofa2d16f2018-07-05 16:13:49 +0000100 dbgs() << "IID=" << getSourceIndex() << ' ';
Andrea Di Biagio877f9a72018-06-28 15:50:26 +0000101 if (isValid())
102 getWriteState()->dump();
103 else
104 dbgs() << "(null)";
105}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000106#endif
107
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000108void Instruction::dispatch(unsigned RCUToken) {
Andrea Di Biagio35622482018-03-22 10:19:20 +0000109 assert(Stage == IS_INVALID);
110 Stage = IS_AVAILABLE;
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000111 RCUTokenID = RCUToken;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000112
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000113 // Check if input operands are already available.
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000114 update();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000115}
116
117void Instruction::execute() {
118 assert(Stage == IS_READY);
119 Stage = IS_EXECUTING;
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000120
121 // Set the cycles left before the write-back stage.
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000122 CyclesLeft = getLatency();
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000123
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000124 for (WriteState &WS : getDefs())
125 WS.onInstructionIssued();
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000126
127 // Transition to the "executed" stage if this is a zero-latency instruction.
Andrea Di Biagio35622482018-03-22 10:19:20 +0000128 if (!CyclesLeft)
129 Stage = IS_EXECUTED;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000130}
131
Andrea Di Biagio207e0212018-10-03 15:02:44 +0000132void Instruction::forceExecuted() {
133 assert(Stage == IS_READY && "Invalid internal state!");
134 CyclesLeft = 0;
135 Stage = IS_EXECUTED;
136}
137
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000138void Instruction::update() {
Andrea Di Biagioeb1bef62018-06-27 11:17:07 +0000139 assert(isDispatched() && "Unexpected instruction stage found!");
Andrea Di Biagioff630c22018-07-15 11:01:38 +0000140
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000141 if (!all_of(getUses(), [](const ReadState &Use) { return Use.isReady(); }))
Andrea Di Biagioff630c22018-07-15 11:01:38 +0000142 return;
143
144 // A partial register write cannot complete before a dependent write.
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000145 auto IsDefReady = [&](const WriteState &Def) {
146 if (const WriteState *Write = Def.getDependentWrite()) {
Andrea Di Biagioff630c22018-07-15 11:01:38 +0000147 int WriteLatency = Write->getCyclesLeft();
148 if (WriteLatency == UNKNOWN_CYCLES)
149 return false;
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000150 return static_cast<unsigned>(WriteLatency) < getLatency();
Andrea Di Biagioff630c22018-07-15 11:01:38 +0000151 }
152 return true;
153 };
154
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000155 if (all_of(getDefs(), IsDefReady))
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000156 Stage = IS_READY;
157}
158
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000159void Instruction::cycleEvent() {
Andrea Di Biagio35622482018-03-22 10:19:20 +0000160 if (isReady())
161 return;
162
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000163 if (isDispatched()) {
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000164 for (ReadState &Use : getUses())
165 Use.cycleEvent();
Andrea Di Biagioeb1bef62018-06-27 11:17:07 +0000166
Andrea Di Biagioff630c22018-07-15 11:01:38 +0000167 update();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000168 return;
169 }
Andrea Di Biagio35622482018-03-22 10:19:20 +0000170
171 assert(isExecuting() && "Instruction not in-flight?");
172 assert(CyclesLeft && "Instruction already executed?");
Andrea Di Biagio1e6d0aa2018-10-25 17:03:51 +0000173 for (WriteState &Def : getDefs())
174 Def.cycleEvent();
Andrea Di Biagio35622482018-03-22 10:19:20 +0000175 CyclesLeft--;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000176 if (!CyclesLeft)
177 Stage = IS_EXECUTED;
178}
Andrea Di Biagio877f9a72018-06-28 15:50:26 +0000179
180const unsigned WriteRef::INVALID_IID = std::numeric_limits<unsigned>::max();
181
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000182} // namespace mca
Fangrui Song5a8fd652018-10-30 15:56:08 +0000183} // namespace llvm