1cc5e6a72SClement Courbet //===--------------------- Instruction.cpp ----------------------*- C++ -*-===//
2cc5e6a72SClement Courbet //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cc5e6a72SClement Courbet //
7cc5e6a72SClement Courbet //===----------------------------------------------------------------------===//
8cc5e6a72SClement Courbet //
9cc5e6a72SClement Courbet // This file defines abstractions used by the Pipeline to model register reads,
10cc5e6a72SClement Courbet // register writes and instructions.
11cc5e6a72SClement Courbet //
12cc5e6a72SClement Courbet //===----------------------------------------------------------------------===//
13cc5e6a72SClement Courbet
14cc5e6a72SClement Courbet #include "llvm/MCA/Instruction.h"
15cc5e6a72SClement Courbet #include "llvm/Support/Debug.h"
16cc5e6a72SClement Courbet #include "llvm/Support/raw_ostream.h"
17cc5e6a72SClement Courbet
18cc5e6a72SClement Courbet namespace llvm {
19cc5e6a72SClement Courbet namespace mca {
20cc5e6a72SClement Courbet
writeStartEvent(unsigned IID,MCPhysReg RegID,unsigned Cycles)21589cb004SAndrea Di Biagio void WriteState::writeStartEvent(unsigned IID, MCPhysReg RegID,
22a549dd25SAndrea Di Biagio unsigned Cycles) {
2327b3b5d9SAndrea Di Biagio CRD.IID = IID;
2427b3b5d9SAndrea Di Biagio CRD.RegID = RegID;
2527b3b5d9SAndrea Di Biagio CRD.Cycles = Cycles;
2627b3b5d9SAndrea Di Biagio DependentWriteCyclesLeft = Cycles;
2727b3b5d9SAndrea Di Biagio DependentWrite = nullptr;
2827b3b5d9SAndrea Di Biagio }
2927b3b5d9SAndrea Di Biagio
writeStartEvent(unsigned IID,MCPhysReg RegID,unsigned Cycles)30f5bdc88eSAndrea Di Biagio void ReadState::writeStartEvent(unsigned IID, MCPhysReg RegID,
31f5bdc88eSAndrea Di Biagio unsigned Cycles) {
32cc5e6a72SClement Courbet assert(DependentWrites);
33cc5e6a72SClement Courbet assert(CyclesLeft == UNKNOWN_CYCLES);
34cc5e6a72SClement Courbet
35cc5e6a72SClement Courbet // This read may be dependent on more than one write. This typically occurs
36cc5e6a72SClement Courbet // when a definition is the result of multiple writes where at least one
37cc5e6a72SClement Courbet // write does a partial register update.
38cc5e6a72SClement Courbet // The HW is forced to do some extra bookkeeping to track of all the
39cc5e6a72SClement Courbet // dependent writes, and implement a merging scheme for the partial writes.
40cc5e6a72SClement Courbet --DependentWrites;
4127b3b5d9SAndrea Di Biagio if (TotalCycles < Cycles) {
4227b3b5d9SAndrea Di Biagio CRD.IID = IID;
4327b3b5d9SAndrea Di Biagio CRD.RegID = RegID;
4427b3b5d9SAndrea Di Biagio CRD.Cycles = Cycles;
4527b3b5d9SAndrea Di Biagio TotalCycles = Cycles;
4627b3b5d9SAndrea Di Biagio }
47cc5e6a72SClement Courbet
48cc5e6a72SClement Courbet if (!DependentWrites) {
49cc5e6a72SClement Courbet CyclesLeft = TotalCycles;
50cc5e6a72SClement Courbet IsReady = !CyclesLeft;
51cc5e6a72SClement Courbet }
52cc5e6a72SClement Courbet }
53cc5e6a72SClement Courbet
onInstructionIssued(unsigned IID)547a950ed5SAndrea Di Biagio void WriteState::onInstructionIssued(unsigned IID) {
55cc5e6a72SClement Courbet assert(CyclesLeft == UNKNOWN_CYCLES);
56cc5e6a72SClement Courbet // Update the number of cycles left based on the WriteDescriptor info.
57cc5e6a72SClement Courbet CyclesLeft = getLatency();
58cc5e6a72SClement Courbet
59cc5e6a72SClement Courbet // Now that the time left before write-back is known, notify
60cc5e6a72SClement Courbet // all the users.
61cc5e6a72SClement Courbet for (const std::pair<ReadState *, int> &User : Users) {
62cc5e6a72SClement Courbet ReadState *RS = User.first;
63cc5e6a72SClement Courbet unsigned ReadCycles = std::max(0, CyclesLeft - User.second);
647a950ed5SAndrea Di Biagio RS->writeStartEvent(IID, RegisterID, ReadCycles);
65cc5e6a72SClement Courbet }
66cc5e6a72SClement Courbet
67cc5e6a72SClement Courbet // Notify any writes that are in a false dependency with this write.
68cc5e6a72SClement Courbet if (PartialWrite)
697a950ed5SAndrea Di Biagio PartialWrite->writeStartEvent(IID, RegisterID, CyclesLeft);
70cc5e6a72SClement Courbet }
71cc5e6a72SClement Courbet
addUser(unsigned IID,ReadState * User,int ReadAdvance)727a950ed5SAndrea Di Biagio void WriteState::addUser(unsigned IID, ReadState *User, int ReadAdvance) {
73cc5e6a72SClement Courbet // If CyclesLeft is different than -1, then we don't need to
74cc5e6a72SClement Courbet // update the list of users. We can just notify the user with
75cc5e6a72SClement Courbet // the actual number of cycles left (which may be zero).
76cc5e6a72SClement Courbet if (CyclesLeft != UNKNOWN_CYCLES) {
77cc5e6a72SClement Courbet unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance);
787a950ed5SAndrea Di Biagio User->writeStartEvent(IID, RegisterID, ReadCycles);
79cc5e6a72SClement Courbet return;
80cc5e6a72SClement Courbet }
81cc5e6a72SClement Courbet
82cc5e6a72SClement Courbet Users.emplace_back(User, ReadAdvance);
83cc5e6a72SClement Courbet }
84cc5e6a72SClement Courbet
addUser(unsigned IID,WriteState * User)857a950ed5SAndrea Di Biagio void WriteState::addUser(unsigned IID, WriteState *User) {
86cc5e6a72SClement Courbet if (CyclesLeft != UNKNOWN_CYCLES) {
877a950ed5SAndrea Di Biagio User->writeStartEvent(IID, RegisterID, std::max(0, CyclesLeft));
88cc5e6a72SClement Courbet return;
89cc5e6a72SClement Courbet }
90cc5e6a72SClement Courbet
91cc5e6a72SClement Courbet assert(!PartialWrite && "PartialWrite already set!");
92cc5e6a72SClement Courbet PartialWrite = User;
93cc5e6a72SClement Courbet User->setDependentWrite(this);
94cc5e6a72SClement Courbet }
95cc5e6a72SClement Courbet
cycleEvent()96cc5e6a72SClement Courbet void WriteState::cycleEvent() {
97cc5e6a72SClement Courbet // Note: CyclesLeft can be a negative number. It is an error to
98cc5e6a72SClement Courbet // make it an unsigned quantity because users of this write may
99cc5e6a72SClement Courbet // specify a negative ReadAdvance.
100cc5e6a72SClement Courbet if (CyclesLeft != UNKNOWN_CYCLES)
101cc5e6a72SClement Courbet CyclesLeft--;
102cc5e6a72SClement Courbet
103cc5e6a72SClement Courbet if (DependentWriteCyclesLeft)
104cc5e6a72SClement Courbet DependentWriteCyclesLeft--;
105cc5e6a72SClement Courbet }
106cc5e6a72SClement Courbet
cycleEvent()107cc5e6a72SClement Courbet void ReadState::cycleEvent() {
108cc5e6a72SClement Courbet // Update the total number of cycles.
109cc5e6a72SClement Courbet if (DependentWrites && TotalCycles) {
110cc5e6a72SClement Courbet --TotalCycles;
111cc5e6a72SClement Courbet return;
112cc5e6a72SClement Courbet }
113cc5e6a72SClement Courbet
114cc5e6a72SClement Courbet // Bail out immediately if we don't know how many cycles are left.
115cc5e6a72SClement Courbet if (CyclesLeft == UNKNOWN_CYCLES)
116cc5e6a72SClement Courbet return;
117cc5e6a72SClement Courbet
118cc5e6a72SClement Courbet if (CyclesLeft) {
119cc5e6a72SClement Courbet --CyclesLeft;
120cc5e6a72SClement Courbet IsReady = !CyclesLeft;
121cc5e6a72SClement Courbet }
122cc5e6a72SClement Courbet }
123cc5e6a72SClement Courbet
124cc5e6a72SClement Courbet #ifndef NDEBUG
dump() const125cc5e6a72SClement Courbet void WriteState::dump() const {
126cc5e6a72SClement Courbet dbgs() << "{ OpIdx=" << WD->OpIndex << ", Lat=" << getLatency() << ", RegID "
127cc5e6a72SClement Courbet << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }";
128cc5e6a72SClement Courbet }
129cc5e6a72SClement Courbet #endif
130cc5e6a72SClement Courbet
computeCriticalRegDep()131a549dd25SAndrea Di Biagio const CriticalDependency &Instruction::computeCriticalRegDep() {
132a549dd25SAndrea Di Biagio if (CriticalRegDep.Cycles)
133a549dd25SAndrea Di Biagio return CriticalRegDep;
134a549dd25SAndrea Di Biagio
13527b3b5d9SAndrea Di Biagio unsigned MaxLatency = 0;
136a549dd25SAndrea Di Biagio for (const WriteState &WS : getDefs()) {
137a549dd25SAndrea Di Biagio const CriticalDependency &WriteCRD = WS.getCriticalRegDep();
13827b3b5d9SAndrea Di Biagio if (WriteCRD.Cycles > MaxLatency)
139a549dd25SAndrea Di Biagio CriticalRegDep = WriteCRD;
14027b3b5d9SAndrea Di Biagio }
14127b3b5d9SAndrea Di Biagio
142a549dd25SAndrea Di Biagio for (const ReadState &RS : getUses()) {
143a549dd25SAndrea Di Biagio const CriticalDependency &ReadCRD = RS.getCriticalRegDep();
14427b3b5d9SAndrea Di Biagio if (ReadCRD.Cycles > MaxLatency)
145a549dd25SAndrea Di Biagio CriticalRegDep = ReadCRD;
14627b3b5d9SAndrea Di Biagio }
14727b3b5d9SAndrea Di Biagio
148a549dd25SAndrea Di Biagio return CriticalRegDep;
14927b3b5d9SAndrea Di Biagio }
15027b3b5d9SAndrea Di Biagio
reset()151*b847692eSMin-Yih Hsu void Instruction::reset() {
152*b847692eSMin-Yih Hsu // Note that this won't clear read/write descriptors
153*b847692eSMin-Yih Hsu // or other non-trivial fields
154*b847692eSMin-Yih Hsu Stage = IS_INVALID;
155*b847692eSMin-Yih Hsu CyclesLeft = UNKNOWN_CYCLES;
156*b847692eSMin-Yih Hsu clearOptimizableMove();
157*b847692eSMin-Yih Hsu RCUTokenID = 0;
158*b847692eSMin-Yih Hsu LSUTokenID = 0;
159*b847692eSMin-Yih Hsu CriticalResourceMask = 0;
160*b847692eSMin-Yih Hsu IsEliminated = false;
161*b847692eSMin-Yih Hsu }
162*b847692eSMin-Yih Hsu
dispatch(unsigned RCUToken)163cc5e6a72SClement Courbet void Instruction::dispatch(unsigned RCUToken) {
164cc5e6a72SClement Courbet assert(Stage == IS_INVALID);
1654bce783eSAndrea Di Biagio Stage = IS_DISPATCHED;
166cc5e6a72SClement Courbet RCUTokenID = RCUToken;
167cc5e6a72SClement Courbet
168cc5e6a72SClement Courbet // Check if input operands are already available.
1692187a4faSAndrea Di Biagio if (updateDispatched())
1702187a4faSAndrea Di Biagio updatePending();
171cc5e6a72SClement Courbet }
172cc5e6a72SClement Courbet
execute(unsigned IID)1737a950ed5SAndrea Di Biagio void Instruction::execute(unsigned IID) {
174cc5e6a72SClement Courbet assert(Stage == IS_READY);
175cc5e6a72SClement Courbet Stage = IS_EXECUTING;
176cc5e6a72SClement Courbet
177cc5e6a72SClement Courbet // Set the cycles left before the write-back stage.
178cc5e6a72SClement Courbet CyclesLeft = getLatency();
179cc5e6a72SClement Courbet
180cc5e6a72SClement Courbet for (WriteState &WS : getDefs())
1817a950ed5SAndrea Di Biagio WS.onInstructionIssued(IID);
182cc5e6a72SClement Courbet
183cc5e6a72SClement Courbet // Transition to the "executed" stage if this is a zero-latency instruction.
184cc5e6a72SClement Courbet if (!CyclesLeft)
185cc5e6a72SClement Courbet Stage = IS_EXECUTED;
186cc5e6a72SClement Courbet }
187cc5e6a72SClement Courbet
forceExecuted()188cc5e6a72SClement Courbet void Instruction::forceExecuted() {
189cc5e6a72SClement Courbet assert(Stage == IS_READY && "Invalid internal state!");
190cc5e6a72SClement Courbet CyclesLeft = 0;
191cc5e6a72SClement Courbet Stage = IS_EXECUTED;
192cc5e6a72SClement Courbet }
193cc5e6a72SClement Courbet
updatePending()194318f990aSAndrea Di Biagio bool Instruction::updatePending() {
195318f990aSAndrea Di Biagio assert(isPending() && "Unexpected instruction stage found!");
196cc5e6a72SClement Courbet
197cc5e6a72SClement Courbet if (!all_of(getUses(), [](const ReadState &Use) { return Use.isReady(); }))
198318f990aSAndrea Di Biagio return false;
199cc5e6a72SClement Courbet
200cc5e6a72SClement Courbet // A partial register write cannot complete before a dependent write.
201318f990aSAndrea Di Biagio if (!all_of(getDefs(), [](const WriteState &Def) { return Def.isReady(); }))
202cc5e6a72SClement Courbet return false;
203cc5e6a72SClement Courbet
204cc5e6a72SClement Courbet Stage = IS_READY;
205318f990aSAndrea Di Biagio return true;
206318f990aSAndrea Di Biagio }
207318f990aSAndrea Di Biagio
updateDispatched()208318f990aSAndrea Di Biagio bool Instruction::updateDispatched() {
209318f990aSAndrea Di Biagio assert(isDispatched() && "Unexpected instruction stage found!");
210318f990aSAndrea Di Biagio
211318f990aSAndrea Di Biagio if (!all_of(getUses(), [](const ReadState &Use) {
212318f990aSAndrea Di Biagio return Use.isPending() || Use.isReady();
213318f990aSAndrea Di Biagio }))
214318f990aSAndrea Di Biagio return false;
215318f990aSAndrea Di Biagio
216318f990aSAndrea Di Biagio // A partial register write cannot complete before a dependent write.
217318f990aSAndrea Di Biagio if (!all_of(getDefs(),
218318f990aSAndrea Di Biagio [](const WriteState &Def) { return !Def.getDependentWrite(); }))
219318f990aSAndrea Di Biagio return false;
220318f990aSAndrea Di Biagio
221318f990aSAndrea Di Biagio Stage = IS_PENDING;
222318f990aSAndrea Di Biagio return true;
223318f990aSAndrea Di Biagio }
224318f990aSAndrea Di Biagio
update()225318f990aSAndrea Di Biagio void Instruction::update() {
226318f990aSAndrea Di Biagio if (isDispatched())
227318f990aSAndrea Di Biagio updateDispatched();
228318f990aSAndrea Di Biagio if (isPending())
229318f990aSAndrea Di Biagio updatePending();
230cc5e6a72SClement Courbet }
231cc5e6a72SClement Courbet
cycleEvent()232cc5e6a72SClement Courbet void Instruction::cycleEvent() {
233cc5e6a72SClement Courbet if (isReady())
234cc5e6a72SClement Courbet return;
235cc5e6a72SClement Courbet
236318f990aSAndrea Di Biagio if (isDispatched() || isPending()) {
237cc5e6a72SClement Courbet for (ReadState &Use : getUses())
238cc5e6a72SClement Courbet Use.cycleEvent();
239cc5e6a72SClement Courbet
240cc5e6a72SClement Courbet for (WriteState &Def : getDefs())
241cc5e6a72SClement Courbet Def.cycleEvent();
242cc5e6a72SClement Courbet
243cc5e6a72SClement Courbet update();
244cc5e6a72SClement Courbet return;
245cc5e6a72SClement Courbet }
246cc5e6a72SClement Courbet
247cc5e6a72SClement Courbet assert(isExecuting() && "Instruction not in-flight?");
248cc5e6a72SClement Courbet assert(CyclesLeft && "Instruction already executed?");
249cc5e6a72SClement Courbet for (WriteState &Def : getDefs())
250cc5e6a72SClement Courbet Def.cycleEvent();
251cc5e6a72SClement Courbet CyclesLeft--;
252cc5e6a72SClement Courbet if (!CyclesLeft)
253cc5e6a72SClement Courbet Stage = IS_EXECUTED;
254cc5e6a72SClement Courbet }
255cc5e6a72SClement Courbet
256cc5e6a72SClement Courbet } // namespace mca
257cc5e6a72SClement Courbet } // namespace llvm
258