xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp (revision fe75646a0234a261c0013bf1840fdac4acaf0cec)
1 //===- HexagonShuffler.cpp - Instruction bundle shuffling -----------------===//
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 implements the shuffling of insns inside a bundle according to the
10 // packet formation rules of the Hexagon ISA.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "MCTargetDesc/HexagonShuffler.h"
15 #include "MCTargetDesc/HexagonBaseInfo.h"
16 #include "MCTargetDesc/HexagonMCInstrInfo.h"
17 #include "MCTargetDesc/HexagonMCTargetDesc.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/ADT/Twine.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrDesc.h"
24 #include "llvm/MC/MCSubtargetInfo.h"
25 #include "llvm/Support/Compiler.h"
26 #include "llvm/Support/Debug.h"
27 #include "llvm/Support/MathExtras.h"
28 #include "llvm/Support/SourceMgr.h"
29 #include "llvm/Support/raw_ostream.h"
30 #include <algorithm>
31 #include <cassert>
32 #include <optional>
33 #include <utility>
34 #include <vector>
35 
36 #define DEBUG_TYPE "hexagon-shuffle"
37 
38 using namespace llvm;
39 
40 namespace {
41 
42 // Insn shuffling priority.
43 class HexagonBid {
44   // The priority is directly proportional to how restricted the insn is based
45   // on its flexibility to run on the available slots.  So, the fewer slots it
46   // may run on, the higher its priority.
47   enum { MAX = 360360 }; // LCD of 1/2, 1/3, 1/4,... 1/15.
48   unsigned Bid = 0;
49 
50 public:
51   HexagonBid() = default;
52   HexagonBid(unsigned B) { Bid = B ? MAX / llvm::popcount(B) : 0; }
53 
54   // Check if the insn priority is overflowed.
55   bool isSold() const { return (Bid >= MAX); }
56 
57   HexagonBid &operator+=(const HexagonBid &B) {
58     Bid += B.Bid;
59     return *this;
60   }
61 };
62 
63 // Slot shuffling allocation.
64 class HexagonUnitAuction {
65   HexagonBid Scores[HEXAGON_PACKET_SIZE];
66   // Mask indicating which slot is unavailable.
67   unsigned isSold : HEXAGON_PACKET_SIZE;
68 
69 public:
70   HexagonUnitAuction(unsigned cs = 0) : isSold(cs) {}
71 
72   // Allocate slots.
73   bool bid(unsigned B) {
74     // Exclude already auctioned slots from the bid.
75     unsigned b = B & ~isSold;
76     if (b) {
77       for (unsigned i = 0; i < HEXAGON_PACKET_SIZE; ++i)
78         if (b & (1 << i)) {
79           // Request candidate slots.
80           Scores[i] += HexagonBid(b);
81           isSold |= Scores[i].isSold() << i;
82         }
83       return true;
84     } else
85       // Error if the desired slots are already full.
86       return false;
87   }
88 };
89 
90 } // end anonymous namespace
91 
92 unsigned HexagonResource::setWeight(unsigned s) {
93   const unsigned SlotWeight = 8;
94   const unsigned MaskWeight = SlotWeight - 1;
95   unsigned Units = getUnits();
96   unsigned Key = ((1u << s) & Units) != 0;
97 
98   // Calculate relative weight of the insn for the given slot, weighing it the
99   // heavier the more restrictive the insn is and the lowest the slots that the
100   // insn may be executed in.
101   if (Key == 0 || Units == 0 || (SlotWeight * s >= 32))
102     return Weight = 0;
103 
104   unsigned Ctpop = llvm::popcount(Units);
105   unsigned Cttz = llvm::countr_zero(Units);
106   Weight = (1u << (SlotWeight * s)) * ((MaskWeight - Ctpop) << Cttz);
107   return Weight;
108 }
109 
110 HexagonCVIResource::HexagonCVIResource(MCInstrInfo const &MCII,
111                                        MCSubtargetInfo const &STI,
112                                        unsigned s,
113                                        MCInst const *id)
114     : HexagonResource(s) {
115 
116   const unsigned ItinUnits = HexagonMCInstrInfo::getCVIResources(MCII, STI, *id);
117   unsigned Lanes;
118   const unsigned Units = HexagonConvertUnits(ItinUnits, &Lanes);
119 
120   if (Units == 0 && Lanes == 0) {
121     // For core insns.
122     Valid = false;
123     setUnits(0);
124     setLanes(0);
125     setLoad(false);
126     setStore(false);
127   } else {
128     // For an HVX insn.
129     Valid = true;
130     setUnits(Units);
131     setLanes(Lanes);
132     setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad());
133     setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore());
134   }
135 }
136 
137 struct CVIUnits {
138   unsigned Units;
139   unsigned Lanes;
140 };
141 using HVXInstsT = SmallVector<struct CVIUnits, 8>;
142 
143 static unsigned makeAllBits(unsigned startBit, unsigned Lanes)
144 {
145   for (unsigned i = 1; i < Lanes; ++i)
146     startBit = (startBit << 1) | startBit;
147   return startBit;
148 }
149 
150 static bool checkHVXPipes(const HVXInstsT &hvxInsts, unsigned startIdx,
151                           unsigned usedUnits) {
152   if (startIdx < hvxInsts.size()) {
153     if (!hvxInsts[startIdx].Units)
154       return checkHVXPipes(hvxInsts, startIdx + 1, usedUnits);
155     for (unsigned b = 0x1; b <= 0x8; b <<= 1) {
156       if ((hvxInsts[startIdx].Units & b) == 0)
157         continue;
158       unsigned allBits = makeAllBits(b, hvxInsts[startIdx].Lanes);
159       if ((allBits & usedUnits) == 0) {
160         if (checkHVXPipes(hvxInsts, startIdx + 1, usedUnits | allBits))
161           return true;
162       }
163     }
164     return false;
165   }
166   return true;
167 }
168 
169 HexagonShuffler::HexagonShuffler(MCContext &Context, bool ReportErrors,
170                                  MCInstrInfo const &MCII,
171                                  MCSubtargetInfo const &STI)
172     : Context(Context), BundleFlags(), MCII(MCII), STI(STI),
173       ReportErrors(ReportErrors), CheckFailure() {
174   reset();
175 }
176 
177 void HexagonShuffler::reset() {
178   Packet.clear();
179   BundleFlags = 0;
180   CheckFailure = false;
181 }
182 
183 void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender,
184                              unsigned S) {
185   HexagonInstr PI(MCII, STI, &ID, Extender, S);
186 
187   Packet.push_back(PI);
188 }
189 
190 
191 static const unsigned Slot0Mask = 1 << 0;
192 static const unsigned Slot1Mask = 1 << 1;
193 static const unsigned Slot3Mask = 1 << 3;
194 static const unsigned slotSingleLoad = Slot0Mask;
195 static const unsigned slotSingleStore = Slot0Mask;
196 
197 void HexagonShuffler::restrictSlot1AOK(HexagonPacketSummary const &Summary) {
198   if (Summary.Slot1AOKLoc)
199     for (HexagonInstr &ISJ : insts()) {
200       MCInst const &Inst = ISJ.getDesc();
201       const unsigned Type = HexagonMCInstrInfo::getType(MCII, Inst);
202       if (Type != HexagonII::TypeALU32_2op &&
203           Type != HexagonII::TypeALU32_3op &&
204           Type != HexagonII::TypeALU32_ADDI) {
205         const unsigned Units = ISJ.Core.getUnits();
206 
207         if (Units & Slot1Mask) {
208           AppliedRestrictions.push_back(std::make_pair(
209               Inst.getLoc(),
210               "Instruction was restricted from being in slot 1"));
211           AppliedRestrictions.push_back(std::make_pair(
212               *Summary.Slot1AOKLoc, "Instruction can only be combined "
213                                     "with an ALU instruction in slot 1"));
214           ISJ.Core.setUnits(Units & ~Slot1Mask);
215         }
216       }
217     }
218 }
219 
220 void HexagonShuffler::restrictNoSlot1Store(
221     HexagonPacketSummary const &Summary) {
222   // If this packet contains an instruction that bars slot-1 stores,
223   // we should mask off slot 1 from all of the store instructions in
224   // this packet.
225 
226   if (!Summary.NoSlot1StoreLoc)
227     return;
228 
229   bool AppliedRestriction = false;
230 
231   for (HexagonInstr &ISJ : insts()) {
232     MCInst const &Inst = ISJ.getDesc();
233     if (HexagonMCInstrInfo::getDesc(MCII, Inst).mayStore()) {
234       unsigned Units = ISJ.Core.getUnits();
235       if (Units & Slot1Mask) {
236         AppliedRestriction = true;
237         AppliedRestrictions.push_back(std::make_pair(
238             Inst.getLoc(), "Instruction was restricted from being in slot 1"));
239         ISJ.Core.setUnits(Units & ~Slot1Mask);
240       }
241     }
242   }
243 
244   if (AppliedRestriction)
245     AppliedRestrictions.push_back(
246         std::make_pair(*Summary.NoSlot1StoreLoc,
247                        "Instruction does not allow a store in slot 1"));
248 }
249 
250 bool HexagonShuffler::applySlotRestrictions(HexagonPacketSummary const &Summary,
251                                             const bool DoShuffle) {
252   // These restrictions can modify the slot masks in the instructions
253   // in the Packet member.  They should run unconditionally and their
254   // order does not matter.
255   restrictSlot1AOK(Summary);
256   restrictNoSlot1Store(Summary);
257 
258   permitNonSlot();
259 
260   // These restrictions can modify the slot masks in the instructions
261   // in the Packet member, but they can also detect constraint failures
262   // which are fatal.
263   if (!CheckFailure)
264     restrictStoreLoadOrder(Summary);
265   if (!CheckFailure)
266     restrictBranchOrder(Summary);
267   if (!CheckFailure)
268     restrictPreferSlot3(Summary, DoShuffle);
269   return !CheckFailure;
270 }
271 
272 void HexagonShuffler::restrictBranchOrder(HexagonPacketSummary const &Summary) {
273   // preserve branch order
274   const bool HasMultipleBranches = Summary.branchInsts.size() > 1;
275   if (!HasMultipleBranches)
276     return;
277 
278   if (Summary.branchInsts.size() > 2) {
279     reportError(Twine("too many branches in packet"));
280     return;
281   }
282 
283   const static std::pair<unsigned, unsigned> jumpSlots[] = {
284       {8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}};
285   // try all possible choices
286   for (std::pair<unsigned, unsigned> jumpSlot : jumpSlots) {
287     // validate first jump with this slot rule
288     if (!(jumpSlot.first & Summary.branchInsts[0]->Core.getUnits()))
289       continue;
290 
291     // validate second jump with this slot rule
292     if (!(jumpSlot.second & Summary.branchInsts[1]->Core.getUnits()))
293       continue;
294 
295     // both valid for this configuration, set new slot rules
296     const HexagonPacket PacketSave = Packet;
297     Summary.branchInsts[0]->Core.setUnits(jumpSlot.first);
298     Summary.branchInsts[1]->Core.setUnits(jumpSlot.second);
299 
300     const bool HasShuffledPacket = tryAuction(Summary).has_value();
301     if (HasShuffledPacket)
302       return;
303 
304     // if yes, great, if not then restore original slot mask
305     // restore original values
306     Packet = PacketSave;
307   }
308 
309   reportResourceError(Summary, "out of slots");
310 }
311 
312 void HexagonShuffler::permitNonSlot() {
313   for (HexagonInstr &ISJ : insts()) {
314     const bool RequiresSlot = HexagonMCInstrInfo::requiresSlot(STI, *ISJ.ID);
315     if (!RequiresSlot)
316       ISJ.Core.setAllUnits();
317   }
318 }
319 
320 bool HexagonShuffler::ValidResourceUsage(HexagonPacketSummary const &Summary) {
321   std::optional<HexagonPacket> ShuffledPacket = tryAuction(Summary);
322 
323   if (!ShuffledPacket) {
324     reportResourceError(Summary, "slot error");
325     return false;
326   }
327 
328   // Verify the CVI slot subscriptions.
329   llvm::stable_sort(*ShuffledPacket, HexagonInstr::lessCVI);
330   // create vector of hvx instructions to check
331   HVXInstsT hvxInsts;
332   hvxInsts.clear();
333   for (const auto &I : *ShuffledPacket) {
334     struct CVIUnits inst;
335     inst.Units = I.CVI.getUnits();
336     inst.Lanes = I.CVI.getLanes();
337     if (inst.Units == 0)
338       continue; // not an hvx inst or an hvx inst that doesn't uses any pipes
339     hvxInsts.push_back(inst);
340   }
341 
342   // if there are any hvx instructions in this packet, check pipe usage
343   if (hvxInsts.size() > 0) {
344     unsigned startIdx, usedUnits;
345     startIdx = usedUnits = 0x0;
346     if (!checkHVXPipes(hvxInsts, startIdx, usedUnits)) {
347       // too many pipes used to be valid
348       reportError(Twine("invalid instruction packet: slot error"));
349       return false;
350     }
351   }
352 
353   Packet = *ShuffledPacket;
354 
355   return true;
356 }
357 
358 bool HexagonShuffler::restrictStoreLoadOrder(
359     HexagonPacketSummary const &Summary) {
360   // Modify packet accordingly.
361   // TODO: need to reserve slots #0 and #1 for duplex insns.
362   static const unsigned slotFirstLoadStore = Slot1Mask;
363   static const unsigned slotLastLoadStore = Slot0Mask;
364   unsigned slotLoadStore = slotFirstLoadStore;
365 
366   for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
367     MCInst const &ID = ISJ->getDesc();
368 
369     if (!ISJ->Core.getUnits())
370       // Error if insn may not be executed in any slot.
371       return false;
372 
373     // A single load must use slot #0.
374     if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) {
375       if (Summary.loads == 1 && Summary.loads == Summary.memory &&
376           Summary.memops == 0)
377         // Pin the load to slot #0.
378         switch (ID.getOpcode()) {
379         case Hexagon::V6_vgathermw:
380         case Hexagon::V6_vgathermh:
381         case Hexagon::V6_vgathermhw:
382         case Hexagon::V6_vgathermwq:
383         case Hexagon::V6_vgathermhq:
384         case Hexagon::V6_vgathermhwq:
385           // Slot1 only loads
386           break;
387         default:
388           ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad);
389           break;
390         }
391       else if (Summary.loads >= 1 && isMemReorderDisabled()) { // }:mem_noshuf
392         // Loads must keep the original order ONLY if
393         // isMemReorderDisabled() == true
394         if (slotLoadStore < slotLastLoadStore) {
395           // Error if no more slots available for loads.
396           reportError("invalid instruction packet: too many loads");
397           return false;
398         }
399         // Pin the load to the highest slot available to it.
400         ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore);
401         // Update the next highest slot available to loads.
402         slotLoadStore >>= 1;
403       }
404     }
405 
406     // A single store must use slot #0.
407     if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) {
408       if (!Summary.store0) {
409         const bool PacketHasNoOnlySlot0 =
410             llvm::none_of(insts(), [&](HexagonInstr const &I) {
411               return I.Core.getUnits() == Slot0Mask &&
412                      I.ID->getOpcode() != ID.getOpcode();
413             });
414         const bool SafeToMoveToSlot0 =
415             (Summary.loads == 0) ||
416             (!isMemReorderDisabled() && PacketHasNoOnlySlot0);
417 
418         if (Summary.stores == 1 && SafeToMoveToSlot0)
419           // Pin the store to slot #0 only if isMemReorderDisabled() == false
420           ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore);
421         else if (Summary.stores >= 1) {
422           if (slotLoadStore < slotLastLoadStore) {
423             // Error if no more slots available for stores.
424             reportError("invalid instruction packet: too many stores");
425             return false;
426           }
427           // Pin the store to the highest slot available to it.
428           ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore);
429           // Update the next highest slot available to stores.
430           slotLoadStore >>= 1;
431         }
432       }
433       if (Summary.store1 && Summary.stores > 1) {
434         // Error if a single store with another store.
435         reportError("invalid instruction packet: too many stores");
436         return false;
437       }
438     }
439   }
440 
441   return true;
442 }
443 
444 static std::string SlotMaskToText(unsigned SlotMask) {
445     SmallVector<std::string, HEXAGON_PRESHUFFLE_PACKET_SIZE> Slots;
446     for (unsigned SlotNum = 0; SlotNum < HEXAGON_PACKET_SIZE; SlotNum++)
447         if ((SlotMask & (1 << SlotNum)) != 0)
448             Slots.push_back(utostr(SlotNum));
449 
450     return llvm::join(Slots, StringRef(", "));
451 }
452 
453 HexagonShuffler::HexagonPacketSummary HexagonShuffler::GetPacketSummary() {
454   HexagonPacketSummary Summary = HexagonPacketSummary();
455 
456   // Collect information from the insns in the packet.
457   for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
458     MCInst const &ID = ISJ->getDesc();
459 
460     if (HexagonMCInstrInfo::isRestrictSlot1AOK(MCII, ID))
461       Summary.Slot1AOKLoc = ID.getLoc();
462     if (HexagonMCInstrInfo::isRestrictNoSlot1Store(MCII, ID))
463       Summary.NoSlot1StoreLoc = ID.getLoc();
464 
465     if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) {
466       ++Summary.pSlot3Cnt;
467       Summary.PrefSlot3Inst = ISJ;
468     }
469     const unsigned ReservedSlots =
470         HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID);
471     Summary.ReservedSlotMask |= ReservedSlots;
472     if (ReservedSlots != 0)
473       AppliedRestrictions.push_back(std::make_pair(ID.getLoc(),
474                   (Twine("Instruction has reserved slots: ") +
475                    SlotMaskToText(ReservedSlots)).str()));
476 
477     switch (HexagonMCInstrInfo::getType(MCII, ID)) {
478     case HexagonII::TypeS_2op:
479     case HexagonII::TypeS_3op:
480     case HexagonII::TypeALU64:
481       break;
482     case HexagonII::TypeJ:
483       if (HexagonMCInstrInfo::IsABranchingInst(MCII, STI, *ISJ->ID))
484         Summary.branchInsts.push_back(ISJ);
485       break;
486     case HexagonII::TypeCVI_VM_VP_LDU:
487     case HexagonII::TypeCVI_VM_LD:
488     case HexagonII::TypeCVI_VM_TMP_LD:
489     case HexagonII::TypeCVI_GATHER:
490     case HexagonII::TypeCVI_GATHER_DV:
491     case HexagonII::TypeCVI_GATHER_RST:
492       ++Summary.NonZCVIloads;
493       [[fallthrough]];
494     case HexagonII::TypeCVI_ZW:
495       ++Summary.AllCVIloads;
496       [[fallthrough]];
497     case HexagonII::TypeLD:
498       ++Summary.loads;
499       ++Summary.memory;
500       if (ISJ->Core.getUnits() == slotSingleLoad ||
501           HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU)
502         ++Summary.load0;
503       if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn())
504         Summary.branchInsts.push_back(ISJ);
505       break;
506     case HexagonII::TypeCVI_VM_STU:
507     case HexagonII::TypeCVI_VM_ST:
508     case HexagonII::TypeCVI_VM_NEW_ST:
509     case HexagonII::TypeCVI_SCATTER:
510     case HexagonII::TypeCVI_SCATTER_DV:
511     case HexagonII::TypeCVI_SCATTER_RST:
512     case HexagonII::TypeCVI_SCATTER_NEW_RST:
513     case HexagonII::TypeCVI_SCATTER_NEW_ST:
514       ++Summary.CVIstores;
515       [[fallthrough]];
516     case HexagonII::TypeST:
517       ++Summary.stores;
518       ++Summary.memory;
519       if (ISJ->Core.getUnits() == slotSingleStore ||
520           HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_STU)
521         ++Summary.store0;
522       break;
523     case HexagonII::TypeV4LDST:
524       ++Summary.loads;
525       ++Summary.stores;
526       ++Summary.store1;
527       ++Summary.memops;
528       ++Summary.memory;
529       break;
530     case HexagonII::TypeNCJ:
531       ++Summary.memory; // NV insns are memory-like.
532       Summary.branchInsts.push_back(ISJ);
533       break;
534     case HexagonII::TypeV2LDST:
535       if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) {
536         ++Summary.loads;
537         ++Summary.memory;
538         if (ISJ->Core.getUnits() == slotSingleLoad ||
539             HexagonMCInstrInfo::getType(MCII, ID) ==
540                 HexagonII::TypeCVI_VM_VP_LDU)
541           ++Summary.load0;
542       } else {
543         assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore());
544         ++Summary.memory;
545         ++Summary.stores;
546       }
547       break;
548     case HexagonII::TypeCR:
549     // Legacy conditional branch predicated on a register.
550     case HexagonII::TypeCJ:
551       if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch())
552         Summary.branchInsts.push_back(ISJ);
553       break;
554     case HexagonII::TypeDUPLEX: {
555       ++Summary.duplex;
556       MCInst const &Inst0 = *ID.getOperand(0).getInst();
557       MCInst const &Inst1 = *ID.getOperand(1).getInst();
558       if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch())
559         Summary.branchInsts.push_back(ISJ);
560       if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch())
561         Summary.branchInsts.push_back(ISJ);
562       if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn())
563         Summary.branchInsts.push_back(ISJ);
564       if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn())
565         Summary.branchInsts.push_back(ISJ);
566       break;
567     }
568     }
569   }
570   return Summary;
571 }
572 
573 bool HexagonShuffler::ValidPacketMemoryOps(
574     HexagonPacketSummary const &Summary) const {
575   // Check if the packet is legal.
576   const unsigned ZCVIloads = Summary.AllCVIloads - Summary.NonZCVIloads;
577   const bool ValidHVXMem =
578       Summary.NonZCVIloads <= 1 && ZCVIloads <= 1 && Summary.CVIstores <= 1;
579   const bool InvalidPacket =
580       ((Summary.load0 > 1 || Summary.store0 > 1 || !ValidHVXMem) ||
581        (Summary.duplex > 1 || (Summary.duplex && Summary.memory)));
582 
583   return !InvalidPacket;
584 }
585 
586 void HexagonShuffler::restrictPreferSlot3(HexagonPacketSummary const &Summary,
587                                           const bool DoShuffle) {
588   // flag if an instruction requires to be in slot 3
589   const bool HasOnlySlot3 = llvm::any_of(insts(), [&](HexagonInstr const &I) {
590     return (I.Core.getUnits() == Slot3Mask);
591   });
592   const bool NeedsPrefSlot3Shuffle = Summary.branchInsts.size() <= 1 &&
593                                      !HasOnlySlot3 && Summary.pSlot3Cnt == 1 &&
594                                      Summary.PrefSlot3Inst && DoShuffle;
595 
596   if (!NeedsPrefSlot3Shuffle)
597     return;
598 
599   HexagonInstr *PrefSlot3Inst = *Summary.PrefSlot3Inst;
600   // save off slot mask of instruction marked with A_PREFER_SLOT3
601   // and then pin it to slot #3
602   const unsigned saveUnits = PrefSlot3Inst->Core.getUnits();
603   PrefSlot3Inst->Core.setUnits(saveUnits & Slot3Mask);
604   const bool HasShuffledPacket = tryAuction(Summary).has_value();
605   if (HasShuffledPacket)
606     return;
607 
608   PrefSlot3Inst->Core.setUnits(saveUnits);
609 }
610 
611 /// Check that the packet is legal and enforce relative insn order.
612 bool HexagonShuffler::check(const bool RequireShuffle) {
613   const HexagonPacketSummary Summary = GetPacketSummary();
614   if (!applySlotRestrictions(Summary, RequireShuffle))
615     return false;
616 
617   if (!ValidPacketMemoryOps(Summary)) {
618     reportError("invalid instruction packet");
619     return false;
620   }
621 
622   if (RequireShuffle)
623     ValidResourceUsage(Summary);
624 
625   return !CheckFailure;
626 }
627 
628 std::optional<HexagonShuffler::HexagonPacket>
629 HexagonShuffler::tryAuction(HexagonPacketSummary const &Summary) {
630   HexagonPacket PacketResult = Packet;
631   HexagonUnitAuction AuctionCore(Summary.ReservedSlotMask);
632   llvm::stable_sort(PacketResult, HexagonInstr::lessCore);
633 
634   const bool ValidSlots =
635       llvm::all_of(insts(PacketResult), [&AuctionCore](HexagonInstr const &I) {
636         return AuctionCore.bid(I.Core.getUnits());
637       });
638 
639   LLVM_DEBUG(
640     dbgs() << "Shuffle attempt: " << (ValidSlots ? "passed" : "failed")
641            << "\n";
642     for (HexagonInstr const &ISJ : insts(PacketResult))
643       dbgs() << "\t" << HexagonMCInstrInfo::getName(MCII, *ISJ.ID) << ": "
644              << llvm::format_hex(ISJ.Core.getUnits(), 4, true) << "\n";
645   );
646 
647   std::optional<HexagonPacket> Res;
648   if (ValidSlots)
649     Res = PacketResult;
650 
651   return Res;
652 }
653 
654 bool HexagonShuffler::shuffle() {
655   if (size() > HEXAGON_PACKET_SIZE) {
656     // Ignore a packet with with more than what a packet can hold
657     // or with compound or duplex insns for now.
658     reportError("invalid instruction packet");
659     return false;
660   }
661 
662   // Check and prepare packet.
663   bool Ok = check();
664   if (size() > 1 && Ok)
665     // Reorder the handles for each slot.
666     for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE;
667          ++nSlot) {
668       iterator ISJ, ISK;
669       unsigned slotSkip, slotWeight;
670 
671       // Prioritize the handles considering their restrictions.
672       for (ISJ = ISK = Packet.begin(), slotSkip = slotWeight = 0;
673            ISK != Packet.end(); ++ISK, ++slotSkip)
674         if (slotSkip < nSlot - emptySlots)
675           // Note which handle to begin at.
676           ++ISJ;
677         else
678           // Calculate the weight of the slot.
679           slotWeight += ISK->Core.setWeight(HEXAGON_PACKET_SIZE - nSlot - 1);
680 
681       if (slotWeight)
682         // Sort the packet, favoring source order,
683         // beginning after the previous slot.
684         std::stable_sort(ISJ, Packet.end());
685       else
686         // Skip unused slot.
687         ++emptySlots;
688     }
689 
690   LLVM_DEBUG(
691     for (HexagonInstr const &ISJ : insts()) {
692       dbgs().write_hex(ISJ.Core.getUnits());
693       if (ISJ.CVI.isValid()) {
694         dbgs() << '/';
695         dbgs().write_hex(ISJ.CVI.getUnits()) << '|';
696         dbgs() << ISJ.CVI.getLanes();
697       }
698       dbgs() << ':'
699              << HexagonMCInstrInfo::getDesc(MCII, ISJ.getDesc()).getOpcode()
700              << '\n';
701     } dbgs() << '\n';
702   );
703 
704   return Ok;
705 }
706 
707 void HexagonShuffler::reportResourceError(HexagonPacketSummary const &Summary, StringRef Err) {
708   if (ReportErrors)
709     reportResourceUsage(Summary);
710   reportError(Twine("invalid instruction packet: ") + Err);
711 }
712 
713 
714 void HexagonShuffler::reportResourceUsage(HexagonPacketSummary const &Summary) {
715   auto SM = Context.getSourceManager();
716   if (SM) {
717     for (HexagonInstr const &I : insts()) {
718       const unsigned Units = I.Core.getUnits();
719 
720       if (HexagonMCInstrInfo::requiresSlot(STI, *I.ID)) {
721         const std::string UnitsText = Units ? SlotMaskToText(Units) : "<None>";
722         SM->PrintMessage(I.ID->getLoc(), SourceMgr::DK_Note,
723                 Twine("Instruction can utilize slots: ") +
724                 UnitsText);
725       }
726       else if (!HexagonMCInstrInfo::isImmext(*I.ID))
727         SM->PrintMessage(I.ID->getLoc(), SourceMgr::DK_Note,
728                        "Instruction does not require a slot");
729     }
730   }
731 }
732 
733 void HexagonShuffler::reportError(Twine const &Msg) {
734   CheckFailure = true;
735   if (ReportErrors) {
736     for (auto const &I : AppliedRestrictions) {
737       auto SM = Context.getSourceManager();
738       if (SM)
739         SM->PrintMessage(I.first, SourceMgr::DK_Note, I.second);
740     }
741     Context.reportError(Loc, Msg);
742   }
743 }
744