1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mad.h"
17 #include <string>
18 #if TARGAARCH64
19 #include "aarch64_operand.h"
20 #elif TARGRISCV64
21 #include "riscv64_operand.h"
22 #endif
23 #include "schedule.h"
24 #include "insn.h"
25
26 namespace maplebe {
27 const std::string kUnitName[] = {
28 #include "mplad_unit_name.def"
29 "None",
30 };
31 /* Unit */
Unit(enum UnitId theUnitId)32 Unit::Unit(enum UnitId theUnitId) : unitId(theUnitId), unitType(kUnitTypePrimart), occupancyTable(0), compositeUnits()
33 {
34 MAD::AddUnit(*this);
35 }
36
Unit(enum UnitType theUnitType,enum UnitId theUnitId,int numOfUnits,...)37 Unit::Unit(enum UnitType theUnitType, enum UnitId theUnitId, int numOfUnits, ...)
38 : unitId(theUnitId), unitType(theUnitType), occupancyTable(0)
39 {
40 DEBUG_ASSERT(numOfUnits > 1, "CG internal error, composite unit with less than 2 unit elements.");
41 va_list ap;
42 va_start(ap, numOfUnits);
43
44 for (int i = 0; i < numOfUnits; ++i) {
45 compositeUnits.emplace_back(static_cast<Unit *>(va_arg(ap, Unit *)));
46 }
47 va_end(ap);
48
49 MAD::AddUnit(*this);
50 }
51
52 /* return name of unit */
GetName() const53 std::string Unit::GetName() const
54 {
55 DEBUG_ASSERT(GetUnitId() <= kUnitIdLast, "Unexpected UnitID");
56 return kUnitName[GetUnitId()];
57 }
58
59 /* Check if unit is free at next "cycle" cycle. */
IsFree(uint32 cycle) const60 bool Unit::IsFree(uint32 cycle) const
61 {
62 if (GetUnitType() == kUnitTypeOr) {
63 for (auto unit : compositeUnits) {
64 if (unit->IsFree(cycle)) {
65 return true;
66 }
67 }
68 return false;
69 } else if (GetUnitType() == kUnitTypeAnd) {
70 for (auto unit : compositeUnits) {
71 if (!unit->IsFree(cycle)) {
72 return false;
73 }
74 }
75 return true;
76 }
77 if ((occupancyTable & (1u << cycle)) != 0) {
78 return false;
79 }
80 return true;
81 }
82
83 /* Occupy unit at next "cycle" cycle. */
Occupy(const Insn & insn,uint32 cycle)84 void Unit::Occupy(const Insn &insn, uint32 cycle)
85 {
86 if (GetUnitType() == kUnitTypeOr) {
87 for (auto unit : GetCompositeUnits()) {
88 if (unit->IsFree(cycle)) {
89 unit->Occupy(insn, cycle);
90 return;
91 }
92 }
93
94 DEBUG_ASSERT(false, "CG internal error, should not be reach here.");
95 return;
96 } else if (GetUnitType() == kUnitTypeAnd) {
97 for (auto unit : GetCompositeUnits()) {
98 unit->Occupy(insn, cycle);
99 }
100 return;
101 }
102 occupancyTable |= (1u << cycle);
103 }
104
105 /* Advance all units one cycle */
AdvanceCycle()106 void Unit::AdvanceCycle()
107 {
108 if (GetUnitType() != kUnitTypePrimart) {
109 return;
110 }
111 occupancyTable = (occupancyTable >> 1);
112 }
113
114 /* Release all units. */
Release()115 void Unit::Release()
116 {
117 if (GetUnitType() != kUnitTypePrimart) {
118 return;
119 }
120 occupancyTable = 0;
121 }
122
GetCompositeUnits() const123 const std::vector<Unit *> &Unit::GetCompositeUnits() const
124 {
125 return compositeUnits;
126 }
127
PrintIndent(int indent) const128 void Unit::PrintIndent(int indent) const
129 {
130 for (int i = 0; i < indent; ++i) {
131 LogInfo::MapleLogger() << " ";
132 }
133 }
134
Dump(int indent) const135 void Unit::Dump(int indent) const
136 {
137 PrintIndent(indent);
138 LogInfo::MapleLogger() << "Unit " << GetName() << " (ID " << GetUnitId() << "): ";
139 LogInfo::MapleLogger() << "occupancyTable = " << occupancyTable << '\n';
140 }
141
GetOccupancyTable() const142 uint32 Unit::GetOccupancyTable() const
143 {
144 return occupancyTable;
145 }
146
147 /* MAD */
148 int MAD::parallelism;
149 std::vector<Unit *> MAD::allUnits;
150 std::vector<Reservation *> MAD::allReservations;
151 std::array<std::array<MAD::BypassVector, kLtLast>, kLtLast> MAD::bypassArrays;
152
~MAD()153 MAD::~MAD()
154 {
155 for (auto unit : allUnits) {
156 delete unit;
157 }
158 for (auto rev : allReservations) {
159 delete rev;
160 }
161 for (auto &bypassArray : bypassArrays) {
162 for (auto &bypassVector : bypassArray) {
163 for (auto *bypass : bypassVector) {
164 delete bypass;
165 }
166 }
167 }
168 allUnits.clear();
169 allReservations.clear();
170 }
171
InitUnits() const172 void MAD::InitUnits() const
173 {
174 #include "mplad_unit_define.def"
175 }
176
InitReservation() const177 void MAD::InitReservation() const
178 {
179 #include "mplad_reservation_define.def"
180 }
181
InitParallelism() const182 void MAD::InitParallelism() const {
183 #include "mplad_arch_define.def"
184 }
185
186 /* according insn's insnType to get a reservation */
FindReservation(const Insn & insn) const187 Reservation *MAD::FindReservation(const Insn &insn) const
188 {
189 uint32 insnType = insn.GetLatencyType();
190 for (auto reservation : allReservations) {
191 if (reservation->IsEqual(insnType)) {
192 return reservation;
193 }
194 }
195 return nullptr;
196 }
197
198 /* Get latency that is def insn to use insn */
GetLatency(const Insn & def,const Insn & use) const199 int MAD::GetLatency(const Insn &def, const Insn &use) const
200 {
201 int latency = BypassLatency(def, use);
202 if (latency < 0) {
203 latency = DefaultLatency(def);
204 }
205 return latency;
206 }
207
208 /* Get bypass latency that is def insn to use insn */
BypassLatency(const Insn & def,const Insn & use) const209 int MAD::BypassLatency(const Insn &def, const Insn &use) const
210 {
211 int latency = -1;
212 DEBUG_ASSERT(def.GetLatencyType() < kLtLast, "out of range");
213 DEBUG_ASSERT(use.GetLatencyType() < kLtLast, "out of range");
214 BypassVector &bypassVec = bypassArrays[def.GetLatencyType()][use.GetLatencyType()];
215 for (auto bypass : bypassVec) {
216 if (bypass->CanBypass(def, use)) {
217 latency = bypass->GetLatency();
218 break;
219 }
220 }
221 return latency;
222 }
223
224 /* Get insn's default latency */
DefaultLatency(const Insn & insn) const225 int MAD::DefaultLatency(const Insn &insn) const
226 {
227 Reservation *res = insn.GetDepNode()->GetReservation();
228 return res != nullptr ? res->GetLatency() : 0;
229 }
230
AdvanceCycle() const231 void MAD::AdvanceCycle() const
232 {
233 for (auto unit : allUnits) {
234 unit->AdvanceCycle();
235 }
236 }
237
ReleaseAllUnits() const238 void MAD::ReleaseAllUnits() const
239 {
240 for (auto unit : allUnits) {
241 unit->Release();
242 }
243 }
244
SaveStates(std::vector<uint32> & occupyTable,int size) const245 void MAD::SaveStates(std::vector<uint32> &occupyTable, int size) const
246 {
247 int i = 0;
248 for (auto unit : allUnits) {
249 CHECK_FATAL(i < size, "unit number error");
250 occupyTable[i] = unit->GetOccupancyTable();
251 ++i;
252 }
253 }
254
255 #define ADDBYPASS(DEFLTTY, USELTTY, LT) AddBypass(*(new Bypass(DEFLTTY, USELTTY, LT)))
256 #define ADDALUSHIFTBYPASS(DEFLTTY, USELTTY, LT) AddBypass(*(new AluShiftBypass(DEFLTTY, USELTTY, LT)))
257 #define ADDACCUMULATORBYPASS(DEFLTTY, USELTTY, LT) AddBypass(*(new AccumulatorBypass(DEFLTTY, USELTTY, LT)))
258 #define ADDSTOREBYPASS(DEFLTTY, USELTTY, LT) AddBypass(*(new StoreBypass(DEFLTTY, USELTTY, LT)))
259
InitBypass() const260 void MAD::InitBypass() const
261 {
262 #include "mplad_bypass_define.def"
263 }
264
IsSlot0Free() const265 bool MAD::IsSlot0Free() const
266 {
267 if (GetUnitByUnitId(kUnitIdSlot0)->IsFree(0)) {
268 return false;
269 }
270 return true;
271 }
272
IsFullIssued() const273 bool MAD::IsFullIssued() const
274 {
275 if (GetUnitByUnitId(kUnitIdSlot0)->IsFree(0) || GetUnitByUnitId(kUnitIdSlot1)->IsFree(0)) {
276 return false;
277 }
278 return true;
279 }
280
RestoreStates(std::vector<uint32> & occupyTable,int size) const281 void MAD::RestoreStates(std::vector<uint32> &occupyTable, int size) const
282 {
283 int i = 0;
284 for (auto unit : allUnits) {
285 CHECK_FATAL(i < size, "unit number error");
286 unit->SetOccupancyTable(occupyTable[i]);
287 ++i;
288 }
289 }
290
CanBypass(const Insn & defInsn,const Insn & useInsn) const291 bool Bypass::CanBypass(const Insn &defInsn, const Insn &useInsn) const
292 {
293 (void)defInsn;
294 (void)useInsn;
295 return true;
296 }
297
CanBypass(const Insn & defInsn,const Insn & useInsn) const298 bool AluShiftBypass::CanBypass(const Insn &defInsn, const Insn &useInsn) const
299 {
300 /*
301 * hook condition
302 * true: r1=r2+x1 -> r3=r2<<0x2+r1
303 * false:r1=r2+x1 -> r3=r1<<0x2+r2
304 */
305 return &(defInsn.GetOperand(kInsnFirstOpnd)) != &(useInsn.GetOperand(kInsnSecondOpnd));
306 }
307
CanBypass(const Insn & defInsn,const Insn & useInsn) const308 bool AccumulatorBypass::CanBypass(const Insn &defInsn, const Insn &useInsn) const
309 {
310 /*
311 * hook condition
312 * true: r98=x0*x1 -> x0=x2*x3+r98
313 * false:r98=x0*x1 -> x0=x2*r98+x3
314 */
315 return (&(defInsn.GetOperand(kInsnFirstOpnd)) != &(useInsn.GetOperand(kInsnSecondOpnd)) &&
316 &(defInsn.GetOperand(kInsnFirstOpnd)) != &(useInsn.GetOperand(kInsnThirdOpnd)));
317 }
318
CanBypass(const Insn & defInsn,const Insn & useInsn) const319 bool StoreBypass::CanBypass(const Insn &defInsn, const Insn &useInsn) const
320 {
321 /*
322 * hook condition
323 * true: r96=r92+x2 -> str r96, [r92]
324 * false:r96=r92+x2 -> str r92, [r96]
325 * false:r96=r92+x2 -> str r92, [r94, r96]
326 */
327 #if TARGAARCH64
328 switch (useInsn.GetMachineOpcode()) {
329 case MOP_wstrb:
330 case MOP_wstrh:
331 case MOP_wstr:
332 case MOP_xstr:
333 case MOP_sstr:
334 case MOP_dstr: {
335 auto &useMemOpnd = static_cast<MemOperand &>(useInsn.GetOperand(kInsnSecondOpnd));
336 return (&(defInsn.GetOperand(kInsnFirstOpnd)) != useMemOpnd.GetOffset() &&
337 &(defInsn.GetOperand(kInsnFirstOpnd)) != useMemOpnd.GetBaseRegister());
338 }
339 case MOP_wstp:
340 case MOP_xstp: {
341 auto &useMemOpnd = static_cast<MemOperand &>(useInsn.GetOperand(kInsnThirdOpnd));
342 return (&(defInsn.GetOperand(kInsnFirstOpnd)) != useMemOpnd.GetOffset() &&
343 &(defInsn.GetOperand(kInsnFirstOpnd)) != useMemOpnd.GetBaseRegister());
344 }
345
346 default:
347 return false;
348 }
349 #endif
350 return false;
351 }
352
353 /* Reservation */
Reservation(LatencyType t,int l,int n,...)354 Reservation::Reservation(LatencyType t, int l, int n, ...) : type(t), latency(l), unitNum(n)
355 {
356 DEBUG_ASSERT(l >= 0, "CG internal error, latency and unitNum should not be less than 0.");
357 DEBUG_ASSERT(n >= 0, "CG internal error, latency and unitNum should not be less than 0.");
358
359 errno_t ret = memset_s(units, sizeof(Unit *) * kMaxUnit, 0, sizeof(Unit *) * kMaxUnit);
360 CHECK_FATAL(ret == EOK, "call memset_s failed in Reservation");
361
362 va_list ap;
363 va_start(ap, n);
364 for (uint32 i = 0; i < unitNum; ++i) {
365 units[i] = static_cast<Unit *>(va_arg(ap, Unit *));
366 }
367 va_end(ap);
368
369 MAD::AddReservation(*this);
370 /* init slot */
371 if (n > 0) {
372 /* if there are units, init slot by units[0] */
373 slot = GetSlotType(units[0]->GetUnitId());
374 } else {
375 slot = kSlotNone;
376 }
377 }
378
379 const std::string kSlotName[] = {
380 "SlotNone", "Slot0", "Slot1", "SlotAny", "Slots",
381 };
382
GetSlotName() const383 const std::string &Reservation::GetSlotName() const
384 {
385 DEBUG_ASSERT(GetSlot() <= kSlots, "Unexpected slot");
386 return kUnitName[GetSlot()];
387 }
388
389 /* Get slot type by unit id */
GetSlotType(UnitId unitID) const390 SlotType Reservation::GetSlotType(UnitId unitID) const
391 {
392 switch (unitID) {
393 case kUnitIdSlot0:
394 case kUnitIdSlot0LdAgu:
395 case kUnitIdSlot0StAgu:
396 return kSlot0;
397
398 case kUnitIdSlot1:
399 return kSlot1;
400
401 case kUnitIdSlotS:
402 case kUnitIdSlotSHazard:
403 case kUnitIdSlotSMul:
404 case kUnitIdSlotSBranch:
405 case kUnitIdSlotSAgen:
406 return kSlotAny;
407
408 case kUnitIdSlotD:
409 case kUnitIdSlotDAgen:
410 return kSlots;
411
412 default:
413 DEBUG_ASSERT(false, "unknown slot type!");
414 return kSlotNone;
415 }
416 }
417 } /* namespace maplebe */
418