Mercurial > hg > CbC > CbC_llvm
comparison lib/MCA/Instruction.cpp @ 148:63bd29f05246
merged
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 19:46:37 +0900 |
parents | c2174574ed3a |
children |
comparison
equal
deleted
inserted
replaced
146:3fc4d5c3e21e | 148:63bd29f05246 |
---|---|
1 //===--------------------- Instruction.cpp ----------------------*- C++ -*-===// | |
2 // | |
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
4 // See https://llvm.org/LICENSE.txt for license information. | |
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
6 // | |
7 //===----------------------------------------------------------------------===// | |
8 // | |
9 // This file defines abstractions used by the Pipeline to model register reads, | |
10 // register writes and instructions. | |
11 // | |
12 //===----------------------------------------------------------------------===// | |
13 | |
14 #include "llvm/MCA/Instruction.h" | |
15 #include "llvm/Support/Debug.h" | |
16 #include "llvm/Support/raw_ostream.h" | |
17 | |
18 namespace llvm { | |
19 namespace mca { | |
20 | |
21 void WriteState::writeStartEvent(unsigned IID, unsigned RegID, | |
22 unsigned Cycles) { | |
23 CRD.IID = IID; | |
24 CRD.RegID = RegID; | |
25 CRD.Cycles = Cycles; | |
26 DependentWriteCyclesLeft = Cycles; | |
27 DependentWrite = nullptr; | |
28 } | |
29 | |
30 void ReadState::writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles) { | |
31 assert(DependentWrites); | |
32 assert(CyclesLeft == UNKNOWN_CYCLES); | |
33 | |
34 // This read may be dependent on more than one write. This typically occurs | |
35 // when a definition is the result of multiple writes where at least one | |
36 // write does a partial register update. | |
37 // The HW is forced to do some extra bookkeeping to track of all the | |
38 // dependent writes, and implement a merging scheme for the partial writes. | |
39 --DependentWrites; | |
40 if (TotalCycles < Cycles) { | |
41 CRD.IID = IID; | |
42 CRD.RegID = RegID; | |
43 CRD.Cycles = Cycles; | |
44 TotalCycles = Cycles; | |
45 } | |
46 | |
47 if (!DependentWrites) { | |
48 CyclesLeft = TotalCycles; | |
49 IsReady = !CyclesLeft; | |
50 } | |
51 } | |
52 | |
53 void WriteState::onInstructionIssued(unsigned IID) { | |
54 assert(CyclesLeft == UNKNOWN_CYCLES); | |
55 // Update the number of cycles left based on the WriteDescriptor info. | |
56 CyclesLeft = getLatency(); | |
57 | |
58 // Now that the time left before write-back is known, notify | |
59 // all the users. | |
60 for (const std::pair<ReadState *, int> &User : Users) { | |
61 ReadState *RS = User.first; | |
62 unsigned ReadCycles = std::max(0, CyclesLeft - User.second); | |
63 RS->writeStartEvent(IID, RegisterID, ReadCycles); | |
64 } | |
65 | |
66 // Notify any writes that are in a false dependency with this write. | |
67 if (PartialWrite) | |
68 PartialWrite->writeStartEvent(IID, RegisterID, CyclesLeft); | |
69 } | |
70 | |
71 void WriteState::addUser(unsigned IID, ReadState *User, int ReadAdvance) { | |
72 // If CyclesLeft is different than -1, then we don't need to | |
73 // update the list of users. We can just notify the user with | |
74 // the actual number of cycles left (which may be zero). | |
75 if (CyclesLeft != UNKNOWN_CYCLES) { | |
76 unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance); | |
77 User->writeStartEvent(IID, RegisterID, ReadCycles); | |
78 return; | |
79 } | |
80 | |
81 Users.emplace_back(User, ReadAdvance); | |
82 } | |
83 | |
84 void WriteState::addUser(unsigned IID, WriteState *User) { | |
85 if (CyclesLeft != UNKNOWN_CYCLES) { | |
86 User->writeStartEvent(IID, RegisterID, std::max(0, CyclesLeft)); | |
87 return; | |
88 } | |
89 | |
90 assert(!PartialWrite && "PartialWrite already set!"); | |
91 PartialWrite = User; | |
92 User->setDependentWrite(this); | |
93 } | |
94 | |
95 void WriteState::cycleEvent() { | |
96 // Note: CyclesLeft can be a negative number. It is an error to | |
97 // make it an unsigned quantity because users of this write may | |
98 // specify a negative ReadAdvance. | |
99 if (CyclesLeft != UNKNOWN_CYCLES) | |
100 CyclesLeft--; | |
101 | |
102 if (DependentWriteCyclesLeft) | |
103 DependentWriteCyclesLeft--; | |
104 } | |
105 | |
106 void ReadState::cycleEvent() { | |
107 // Update the total number of cycles. | |
108 if (DependentWrites && TotalCycles) { | |
109 --TotalCycles; | |
110 return; | |
111 } | |
112 | |
113 // Bail out immediately if we don't know how many cycles are left. | |
114 if (CyclesLeft == UNKNOWN_CYCLES) | |
115 return; | |
116 | |
117 if (CyclesLeft) { | |
118 --CyclesLeft; | |
119 IsReady = !CyclesLeft; | |
120 } | |
121 } | |
122 | |
123 #ifndef NDEBUG | |
124 void WriteState::dump() const { | |
125 dbgs() << "{ OpIdx=" << WD->OpIndex << ", Lat=" << getLatency() << ", RegID " | |
126 << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }"; | |
127 } | |
128 | |
129 void WriteRef::dump() const { | |
130 dbgs() << "IID=" << getSourceIndex() << ' '; | |
131 if (isValid()) | |
132 getWriteState()->dump(); | |
133 else | |
134 dbgs() << "(null)"; | |
135 } | |
136 #endif | |
137 | |
138 const CriticalDependency &Instruction::computeCriticalRegDep() { | |
139 if (CriticalRegDep.Cycles) | |
140 return CriticalRegDep; | |
141 | |
142 unsigned MaxLatency = 0; | |
143 for (const WriteState &WS : getDefs()) { | |
144 const CriticalDependency &WriteCRD = WS.getCriticalRegDep(); | |
145 if (WriteCRD.Cycles > MaxLatency) | |
146 CriticalRegDep = WriteCRD; | |
147 } | |
148 | |
149 for (const ReadState &RS : getUses()) { | |
150 const CriticalDependency &ReadCRD = RS.getCriticalRegDep(); | |
151 if (ReadCRD.Cycles > MaxLatency) | |
152 CriticalRegDep = ReadCRD; | |
153 } | |
154 | |
155 return CriticalRegDep; | |
156 } | |
157 | |
158 void Instruction::dispatch(unsigned RCUToken) { | |
159 assert(Stage == IS_INVALID); | |
160 Stage = IS_DISPATCHED; | |
161 RCUTokenID = RCUToken; | |
162 | |
163 // Check if input operands are already available. | |
164 if (updateDispatched()) | |
165 updatePending(); | |
166 } | |
167 | |
168 void Instruction::execute(unsigned IID) { | |
169 assert(Stage == IS_READY); | |
170 Stage = IS_EXECUTING; | |
171 | |
172 // Set the cycles left before the write-back stage. | |
173 CyclesLeft = getLatency(); | |
174 | |
175 for (WriteState &WS : getDefs()) | |
176 WS.onInstructionIssued(IID); | |
177 | |
178 // Transition to the "executed" stage if this is a zero-latency instruction. | |
179 if (!CyclesLeft) | |
180 Stage = IS_EXECUTED; | |
181 } | |
182 | |
183 void Instruction::forceExecuted() { | |
184 assert(Stage == IS_READY && "Invalid internal state!"); | |
185 CyclesLeft = 0; | |
186 Stage = IS_EXECUTED; | |
187 } | |
188 | |
189 bool Instruction::updatePending() { | |
190 assert(isPending() && "Unexpected instruction stage found!"); | |
191 | |
192 if (!all_of(getUses(), [](const ReadState &Use) { return Use.isReady(); })) | |
193 return false; | |
194 | |
195 // A partial register write cannot complete before a dependent write. | |
196 if (!all_of(getDefs(), [](const WriteState &Def) { return Def.isReady(); })) | |
197 return false; | |
198 | |
199 Stage = IS_READY; | |
200 return true; | |
201 } | |
202 | |
203 bool Instruction::updateDispatched() { | |
204 assert(isDispatched() && "Unexpected instruction stage found!"); | |
205 | |
206 if (!all_of(getUses(), [](const ReadState &Use) { | |
207 return Use.isPending() || Use.isReady(); | |
208 })) | |
209 return false; | |
210 | |
211 // A partial register write cannot complete before a dependent write. | |
212 if (!all_of(getDefs(), | |
213 [](const WriteState &Def) { return !Def.getDependentWrite(); })) | |
214 return false; | |
215 | |
216 Stage = IS_PENDING; | |
217 return true; | |
218 } | |
219 | |
220 void Instruction::update() { | |
221 if (isDispatched()) | |
222 updateDispatched(); | |
223 if (isPending()) | |
224 updatePending(); | |
225 } | |
226 | |
227 void Instruction::cycleEvent() { | |
228 if (isReady()) | |
229 return; | |
230 | |
231 if (isDispatched() || isPending()) { | |
232 for (ReadState &Use : getUses()) | |
233 Use.cycleEvent(); | |
234 | |
235 for (WriteState &Def : getDefs()) | |
236 Def.cycleEvent(); | |
237 | |
238 update(); | |
239 return; | |
240 } | |
241 | |
242 assert(isExecuting() && "Instruction not in-flight?"); | |
243 assert(CyclesLeft && "Instruction already executed?"); | |
244 for (WriteState &Def : getDefs()) | |
245 Def.cycleEvent(); | |
246 CyclesLeft--; | |
247 if (!CyclesLeft) | |
248 Stage = IS_EXECUTED; | |
249 } | |
250 | |
251 const unsigned WriteRef::INVALID_IID = std::numeric_limits<unsigned>::max(); | |
252 | |
253 } // namespace mca | |
254 } // namespace llvm |