• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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