• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--------------------- 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 //
10 // This file defines abstractions used by the Pipeline to model register reads,
11 // 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 
19 namespace mca {
20 
21 using namespace llvm;
22 
writeStartEvent(unsigned Cycles)23 void ReadState::writeStartEvent(unsigned Cycles) {
24   assert(DependentWrites);
25   assert(CyclesLeft == UNKNOWN_CYCLES);
26 
27   // This read may be dependent on more than one write. This typically occurs
28   // when a definition is the result of multiple writes where at least one
29   // write does a partial register update.
30   // The HW is forced to do some extra bookkeeping to track of all the
31   // dependent writes, and implement a merging scheme for the partial writes.
32   --DependentWrites;
33   TotalCycles = std::max(TotalCycles, Cycles);
34 
35   if (!DependentWrites) {
36     CyclesLeft = TotalCycles;
37     IsReady = !CyclesLeft;
38   }
39 }
40 
onInstructionIssued()41 void WriteState::onInstructionIssued() {
42   assert(CyclesLeft == UNKNOWN_CYCLES);
43   // Update the number of cycles left based on the WriteDescriptor info.
44   CyclesLeft = getLatency();
45 
46   // Now that the time left before write-back is known, notify
47   // all the users.
48   for (const std::pair<ReadState *, int> &User : Users) {
49     ReadState *RS = User.first;
50     unsigned ReadCycles = std::max(0, CyclesLeft - User.second);
51     RS->writeStartEvent(ReadCycles);
52   }
53 }
54 
addUser(ReadState * User,int ReadAdvance)55 void WriteState::addUser(ReadState *User, int ReadAdvance) {
56   // If CyclesLeft is different than -1, then we don't need to
57   // update the list of users. We can just notify the user with
58   // the actual number of cycles left (which may be zero).
59   if (CyclesLeft != UNKNOWN_CYCLES) {
60     unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance);
61     User->writeStartEvent(ReadCycles);
62     return;
63   }
64 
65   std::pair<ReadState *, int> NewPair(User, ReadAdvance);
66   Users.insert(NewPair);
67 }
68 
cycleEvent()69 void WriteState::cycleEvent() {
70   // Note: CyclesLeft can be a negative number. It is an error to
71   // make it an unsigned quantity because users of this write may
72   // specify a negative ReadAdvance.
73   if (CyclesLeft != UNKNOWN_CYCLES)
74     CyclesLeft--;
75 }
76 
cycleEvent()77 void ReadState::cycleEvent() {
78   // Update the total number of cycles.
79   if (DependentWrites && TotalCycles) {
80     --TotalCycles;
81     return;
82   }
83 
84   // Bail out immediately if we don't know how many cycles are left.
85   if (CyclesLeft == UNKNOWN_CYCLES)
86     return;
87 
88   if (CyclesLeft) {
89     --CyclesLeft;
90     IsReady = !CyclesLeft;
91   }
92 }
93 
94 #ifndef NDEBUG
dump() const95 void WriteState::dump() const {
96   dbgs() << "{ OpIdx=" << WD.OpIndex << ", Lat=" << getLatency() << ", RegID "
97          << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }";
98 }
99 
dump() const100 void WriteRef::dump() const {
101   dbgs() << "IID=" << getSourceIndex() << ' ';
102   if (isValid())
103     getWriteState()->dump();
104   else
105     dbgs() << "(null)";
106 }
107 #endif
108 
dispatch(unsigned RCUToken)109 void Instruction::dispatch(unsigned RCUToken) {
110   assert(Stage == IS_INVALID);
111   Stage = IS_AVAILABLE;
112   RCUTokenID = RCUToken;
113 
114   // Check if input operands are already available.
115   update();
116 }
117 
execute()118 void Instruction::execute() {
119   assert(Stage == IS_READY);
120   Stage = IS_EXECUTING;
121 
122   // Set the cycles left before the write-back stage.
123   CyclesLeft = Desc.MaxLatency;
124 
125   for (UniqueDef &Def : Defs)
126     Def->onInstructionIssued();
127 
128   // Transition to the "executed" stage if this is a zero-latency instruction.
129   if (!CyclesLeft)
130     Stage = IS_EXECUTED;
131 }
132 
update()133 void Instruction::update() {
134   assert(isDispatched() && "Unexpected instruction stage found!");
135 
136   if (!llvm::all_of(Uses, [](const UniqueUse &Use) { return Use->isReady(); }))
137     return;
138 
139   // A partial register write cannot complete before a dependent write.
140   auto IsDefReady = [&](const UniqueDef &Def) {
141     if (const WriteState *Write = Def->getDependentWrite()) {
142       int WriteLatency = Write->getCyclesLeft();
143       if (WriteLatency == UNKNOWN_CYCLES)
144         return false;
145       return static_cast<unsigned>(WriteLatency) < Desc.MaxLatency;
146     }
147     return true;
148   };
149 
150   if (llvm::all_of(Defs, IsDefReady))
151     Stage = IS_READY;
152 }
153 
cycleEvent()154 void Instruction::cycleEvent() {
155   if (isReady())
156     return;
157 
158   if (isDispatched()) {
159     for (UniqueUse &Use : Uses)
160       Use->cycleEvent();
161 
162     update();
163     return;
164   }
165 
166   assert(isExecuting() && "Instruction not in-flight?");
167   assert(CyclesLeft && "Instruction already executed?");
168   for (UniqueDef &Def : Defs)
169     Def->cycleEvent();
170   CyclesLeft--;
171   if (!CyclesLeft)
172     Stage = IS_EXECUTED;
173 }
174 
175 const unsigned WriteRef::INVALID_IID = std::numeric_limits<unsigned>::max();
176 
177 } // namespace mca
178