xref: /aosp_15_r20/external/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===----- HexagonShuffler.cpp - Instruction bundle shuffling -------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This implements the shuffling of insns inside a bundle according to the
11*9880d681SAndroid Build Coastguard Worker // packet formation rules of the Hexagon ISA.
12*9880d681SAndroid Build Coastguard Worker //
13*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*9880d681SAndroid Build Coastguard Worker 
15*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "hexagon-shuffle"
16*9880d681SAndroid Build Coastguard Worker 
17*9880d681SAndroid Build Coastguard Worker #include <algorithm>
18*9880d681SAndroid Build Coastguard Worker #include <utility>
19*9880d681SAndroid Build Coastguard Worker #include "Hexagon.h"
20*9880d681SAndroid Build Coastguard Worker #include "MCTargetDesc/HexagonBaseInfo.h"
21*9880d681SAndroid Build Coastguard Worker #include "MCTargetDesc/HexagonMCTargetDesc.h"
22*9880d681SAndroid Build Coastguard Worker #include "MCTargetDesc/HexagonMCInstrInfo.h"
23*9880d681SAndroid Build Coastguard Worker #include "HexagonShuffler.h"
24*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Debug.h"
25*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/MathExtras.h"
26*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h"
27*9880d681SAndroid Build Coastguard Worker 
28*9880d681SAndroid Build Coastguard Worker using namespace llvm;
29*9880d681SAndroid Build Coastguard Worker 
30*9880d681SAndroid Build Coastguard Worker namespace {
31*9880d681SAndroid Build Coastguard Worker // Insn shuffling priority.
32*9880d681SAndroid Build Coastguard Worker class HexagonBid {
33*9880d681SAndroid Build Coastguard Worker   // The priority is directly proportional to how restricted the insn is based
34*9880d681SAndroid Build Coastguard Worker   // on its flexibility to run on the available slots.  So, the fewer slots it
35*9880d681SAndroid Build Coastguard Worker   // may run on, the higher its priority.
36*9880d681SAndroid Build Coastguard Worker   enum { MAX = 360360 }; // LCD of 1/2, 1/3, 1/4,... 1/15.
37*9880d681SAndroid Build Coastguard Worker   unsigned Bid;
38*9880d681SAndroid Build Coastguard Worker 
39*9880d681SAndroid Build Coastguard Worker public:
HexagonBid()40*9880d681SAndroid Build Coastguard Worker   HexagonBid() : Bid(0){};
HexagonBid(unsigned B)41*9880d681SAndroid Build Coastguard Worker   HexagonBid(unsigned B) { Bid = B ? MAX / countPopulation(B) : 0; };
42*9880d681SAndroid Build Coastguard Worker 
43*9880d681SAndroid Build Coastguard Worker   // Check if the insn priority is overflowed.
isSold() const44*9880d681SAndroid Build Coastguard Worker   bool isSold() const { return (Bid >= MAX); };
45*9880d681SAndroid Build Coastguard Worker 
operator +=(const HexagonBid & B)46*9880d681SAndroid Build Coastguard Worker   HexagonBid &operator+=(const HexagonBid &B) {
47*9880d681SAndroid Build Coastguard Worker     Bid += B.Bid;
48*9880d681SAndroid Build Coastguard Worker     return *this;
49*9880d681SAndroid Build Coastguard Worker   };
50*9880d681SAndroid Build Coastguard Worker };
51*9880d681SAndroid Build Coastguard Worker 
52*9880d681SAndroid Build Coastguard Worker // Slot shuffling allocation.
53*9880d681SAndroid Build Coastguard Worker class HexagonUnitAuction {
54*9880d681SAndroid Build Coastguard Worker   HexagonBid Scores[HEXAGON_PACKET_SIZE];
55*9880d681SAndroid Build Coastguard Worker   // Mask indicating which slot is unavailable.
56*9880d681SAndroid Build Coastguard Worker   unsigned isSold : HEXAGON_PACKET_SIZE;
57*9880d681SAndroid Build Coastguard Worker 
58*9880d681SAndroid Build Coastguard Worker public:
HexagonUnitAuction()59*9880d681SAndroid Build Coastguard Worker   HexagonUnitAuction() : isSold(0){};
60*9880d681SAndroid Build Coastguard Worker 
61*9880d681SAndroid Build Coastguard Worker   // Allocate slots.
bid(unsigned B)62*9880d681SAndroid Build Coastguard Worker   bool bid(unsigned B) {
63*9880d681SAndroid Build Coastguard Worker     // Exclude already auctioned slots from the bid.
64*9880d681SAndroid Build Coastguard Worker     unsigned b = B & ~isSold;
65*9880d681SAndroid Build Coastguard Worker     if (b) {
66*9880d681SAndroid Build Coastguard Worker       for (unsigned i = 0; i < HEXAGON_PACKET_SIZE; ++i)
67*9880d681SAndroid Build Coastguard Worker         if (b & (1 << i)) {
68*9880d681SAndroid Build Coastguard Worker           // Request candidate slots.
69*9880d681SAndroid Build Coastguard Worker           Scores[i] += HexagonBid(b);
70*9880d681SAndroid Build Coastguard Worker           isSold |= Scores[i].isSold() << i;
71*9880d681SAndroid Build Coastguard Worker         }
72*9880d681SAndroid Build Coastguard Worker       return true;
73*9880d681SAndroid Build Coastguard Worker       ;
74*9880d681SAndroid Build Coastguard Worker     } else
75*9880d681SAndroid Build Coastguard Worker       // Error if the desired slots are already full.
76*9880d681SAndroid Build Coastguard Worker       return false;
77*9880d681SAndroid Build Coastguard Worker   };
78*9880d681SAndroid Build Coastguard Worker };
79*9880d681SAndroid Build Coastguard Worker } // end anonymous namespace
80*9880d681SAndroid Build Coastguard Worker 
setWeight(unsigned s)81*9880d681SAndroid Build Coastguard Worker unsigned HexagonResource::setWeight(unsigned s) {
82*9880d681SAndroid Build Coastguard Worker   const unsigned SlotWeight = 8;
83*9880d681SAndroid Build Coastguard Worker   const unsigned MaskWeight = SlotWeight - 1;
84*9880d681SAndroid Build Coastguard Worker   bool Key = (1 << s) & getUnits();
85*9880d681SAndroid Build Coastguard Worker 
86*9880d681SAndroid Build Coastguard Worker   // TODO: Improve this API so that we can prevent misuse statically.
87*9880d681SAndroid Build Coastguard Worker   assert(SlotWeight * s < 32 && "Argument to setWeight too large.");
88*9880d681SAndroid Build Coastguard Worker 
89*9880d681SAndroid Build Coastguard Worker   // Calculate relative weight of the insn for the given slot, weighing it the
90*9880d681SAndroid Build Coastguard Worker   // heavier the more restrictive the insn is and the lowest the slots that the
91*9880d681SAndroid Build Coastguard Worker   // insn may be executed in.
92*9880d681SAndroid Build Coastguard Worker   Weight =
93*9880d681SAndroid Build Coastguard Worker       (Key << (SlotWeight * s)) * ((MaskWeight - countPopulation(getUnits()))
94*9880d681SAndroid Build Coastguard Worker                                    << countTrailingZeros(getUnits()));
95*9880d681SAndroid Build Coastguard Worker   return (Weight);
96*9880d681SAndroid Build Coastguard Worker }
97*9880d681SAndroid Build Coastguard Worker 
SetupTUL(TypeUnitsAndLanes * TUL,StringRef CPU)98*9880d681SAndroid Build Coastguard Worker void HexagonCVIResource::SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU) {
99*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VA] =
100*9880d681SAndroid Build Coastguard Worker       UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1);
101*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VA_DV] = UnitsAndLanes(CVI_XLANE | CVI_MPY0, 2);
102*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VX] = UnitsAndLanes(CVI_MPY0 | CVI_MPY1, 1);
103*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VX_DV] = UnitsAndLanes(CVI_MPY0, 2);
104*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VP] = UnitsAndLanes(CVI_XLANE, 1);
105*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VP_VS] = UnitsAndLanes(CVI_XLANE, 2);
106*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VS] = UnitsAndLanes(CVI_SHIFT, 1);
107*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VINLANESAT] = UnitsAndLanes(CVI_SHIFT, 1);
108*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VM_LD] =
109*9880d681SAndroid Build Coastguard Worker       UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1);
110*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VM_TMP_LD] = UnitsAndLanes(CVI_NONE, 0);
111*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VM_CUR_LD] =
112*9880d681SAndroid Build Coastguard Worker       UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1);
113*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VM_VP_LDU] = UnitsAndLanes(CVI_XLANE, 1);
114*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VM_ST] =
115*9880d681SAndroid Build Coastguard Worker       UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1);
116*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VM_NEW_ST] = UnitsAndLanes(CVI_NONE, 0);
117*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_VM_STU] = UnitsAndLanes(CVI_XLANE, 1);
118*9880d681SAndroid Build Coastguard Worker   (*TUL)[HexagonII::TypeCVI_HIST] = UnitsAndLanes(CVI_XLANE, 4);
119*9880d681SAndroid Build Coastguard Worker }
120*9880d681SAndroid Build Coastguard Worker 
HexagonCVIResource(TypeUnitsAndLanes * TUL,MCInstrInfo const & MCII,unsigned s,MCInst const * id)121*9880d681SAndroid Build Coastguard Worker HexagonCVIResource::HexagonCVIResource(TypeUnitsAndLanes *TUL,
122*9880d681SAndroid Build Coastguard Worker                                        MCInstrInfo const &MCII, unsigned s,
123*9880d681SAndroid Build Coastguard Worker                                        MCInst const *id)
124*9880d681SAndroid Build Coastguard Worker     : HexagonResource(s), TUL(TUL) {
125*9880d681SAndroid Build Coastguard Worker   unsigned T = HexagonMCInstrInfo::getType(MCII, *id);
126*9880d681SAndroid Build Coastguard Worker 
127*9880d681SAndroid Build Coastguard Worker   if (TUL->count(T)) {
128*9880d681SAndroid Build Coastguard Worker     // For an HVX insn.
129*9880d681SAndroid Build Coastguard Worker     Valid = true;
130*9880d681SAndroid Build Coastguard Worker     setUnits((*TUL)[T].first);
131*9880d681SAndroid Build Coastguard Worker     setLanes((*TUL)[T].second);
132*9880d681SAndroid Build Coastguard Worker     setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad());
133*9880d681SAndroid Build Coastguard Worker     setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore());
134*9880d681SAndroid Build Coastguard Worker   } else {
135*9880d681SAndroid Build Coastguard Worker     // For core insns.
136*9880d681SAndroid Build Coastguard Worker     Valid = false;
137*9880d681SAndroid Build Coastguard Worker     setUnits(0);
138*9880d681SAndroid Build Coastguard Worker     setLanes(0);
139*9880d681SAndroid Build Coastguard Worker     setLoad(false);
140*9880d681SAndroid Build Coastguard Worker     setStore(false);
141*9880d681SAndroid Build Coastguard Worker   }
142*9880d681SAndroid Build Coastguard Worker }
143*9880d681SAndroid Build Coastguard Worker 
HexagonShuffler(MCInstrInfo const & MCII,MCSubtargetInfo const & STI)144*9880d681SAndroid Build Coastguard Worker HexagonShuffler::HexagonShuffler(MCInstrInfo const &MCII,
145*9880d681SAndroid Build Coastguard Worker                                  MCSubtargetInfo const &STI)
146*9880d681SAndroid Build Coastguard Worker     : MCII(MCII), STI(STI) {
147*9880d681SAndroid Build Coastguard Worker   reset();
148*9880d681SAndroid Build Coastguard Worker   HexagonCVIResource::SetupTUL(&TUL, STI.getCPU());
149*9880d681SAndroid Build Coastguard Worker }
150*9880d681SAndroid Build Coastguard Worker 
reset()151*9880d681SAndroid Build Coastguard Worker void HexagonShuffler::reset() {
152*9880d681SAndroid Build Coastguard Worker   Packet.clear();
153*9880d681SAndroid Build Coastguard Worker   BundleFlags = 0;
154*9880d681SAndroid Build Coastguard Worker   Error = SHUFFLE_SUCCESS;
155*9880d681SAndroid Build Coastguard Worker }
156*9880d681SAndroid Build Coastguard Worker 
append(MCInst const * ID,MCInst const * Extender,unsigned S,bool X)157*9880d681SAndroid Build Coastguard Worker void HexagonShuffler::append(MCInst const *ID, MCInst const *Extender,
158*9880d681SAndroid Build Coastguard Worker                              unsigned S, bool X) {
159*9880d681SAndroid Build Coastguard Worker   HexagonInstr PI(&TUL, MCII, ID, Extender, S, X);
160*9880d681SAndroid Build Coastguard Worker 
161*9880d681SAndroid Build Coastguard Worker   Packet.push_back(PI);
162*9880d681SAndroid Build Coastguard Worker }
163*9880d681SAndroid Build Coastguard Worker 
164*9880d681SAndroid Build Coastguard Worker /// Check that the packet is legal and enforce relative insn order.
check()165*9880d681SAndroid Build Coastguard Worker bool HexagonShuffler::check() {
166*9880d681SAndroid Build Coastguard Worker   // Descriptive slot masks.
167*9880d681SAndroid Build Coastguard Worker   const unsigned slotSingleLoad = 0x1, slotSingleStore = 0x1, slotOne = 0x2,
168*9880d681SAndroid Build Coastguard Worker                  slotThree = 0x8, slotFirstJump = 0x8, slotLastJump = 0x4,
169*9880d681SAndroid Build Coastguard Worker                  slotFirstLoadStore = 0x2, slotLastLoadStore = 0x1;
170*9880d681SAndroid Build Coastguard Worker   // Highest slots for branches and stores used to keep their original order.
171*9880d681SAndroid Build Coastguard Worker   unsigned slotJump = slotFirstJump;
172*9880d681SAndroid Build Coastguard Worker   unsigned slotLoadStore = slotFirstLoadStore;
173*9880d681SAndroid Build Coastguard Worker   // Number of branches, solo branches, indirect branches.
174*9880d681SAndroid Build Coastguard Worker   unsigned jumps = 0, jump1 = 0, jumpr = 0;
175*9880d681SAndroid Build Coastguard Worker   // Number of memory operations, loads, solo loads, stores, solo stores, single
176*9880d681SAndroid Build Coastguard Worker   // stores.
177*9880d681SAndroid Build Coastguard Worker   unsigned memory = 0, loads = 0, load0 = 0, stores = 0, store0 = 0, store1 = 0;
178*9880d681SAndroid Build Coastguard Worker   // Number of HVX loads, HVX stores.
179*9880d681SAndroid Build Coastguard Worker   unsigned CVIloads = 0, CVIstores = 0;
180*9880d681SAndroid Build Coastguard Worker   // Number of duplex insns, solo insns.
181*9880d681SAndroid Build Coastguard Worker   unsigned duplex = 0, solo = 0;
182*9880d681SAndroid Build Coastguard Worker   // Number of insns restricting other insns in the packet to A and X types,
183*9880d681SAndroid Build Coastguard Worker   // which is neither A or X types.
184*9880d681SAndroid Build Coastguard Worker   unsigned onlyAX = 0, neitherAnorX = 0;
185*9880d681SAndroid Build Coastguard Worker   // Number of insns restricting other insns in slot #1 to A type.
186*9880d681SAndroid Build Coastguard Worker   unsigned onlyAin1 = 0;
187*9880d681SAndroid Build Coastguard Worker   // Number of insns restricting any insn in slot #1, except A2_nop.
188*9880d681SAndroid Build Coastguard Worker   unsigned onlyNo1 = 0;
189*9880d681SAndroid Build Coastguard Worker   unsigned xtypeFloat = 0;
190*9880d681SAndroid Build Coastguard Worker   unsigned pSlot3Cnt = 0;
191*9880d681SAndroid Build Coastguard Worker   iterator slot3ISJ = end();
192*9880d681SAndroid Build Coastguard Worker 
193*9880d681SAndroid Build Coastguard Worker   // Collect information from the insns in the packet.
194*9880d681SAndroid Build Coastguard Worker   for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
195*9880d681SAndroid Build Coastguard Worker     MCInst const *ID = ISJ->getDesc();
196*9880d681SAndroid Build Coastguard Worker 
197*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::isSolo(MCII, *ID))
198*9880d681SAndroid Build Coastguard Worker       solo += !ISJ->isSoloException();
199*9880d681SAndroid Build Coastguard Worker     else if (HexagonMCInstrInfo::isSoloAX(MCII, *ID))
200*9880d681SAndroid Build Coastguard Worker       onlyAX += !ISJ->isSoloException();
201*9880d681SAndroid Build Coastguard Worker     else if (HexagonMCInstrInfo::isSoloAin1(MCII, *ID))
202*9880d681SAndroid Build Coastguard Worker       onlyAin1 += !ISJ->isSoloException();
203*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeALU32 &&
204*9880d681SAndroid Build Coastguard Worker         HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeXTYPE)
205*9880d681SAndroid Build Coastguard Worker       ++neitherAnorX;
206*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::prefersSlot3(MCII, *ID)) {
207*9880d681SAndroid Build Coastguard Worker       ++pSlot3Cnt;
208*9880d681SAndroid Build Coastguard Worker       slot3ISJ = ISJ;
209*9880d681SAndroid Build Coastguard Worker     }
210*9880d681SAndroid Build Coastguard Worker 
211*9880d681SAndroid Build Coastguard Worker     switch (HexagonMCInstrInfo::getType(MCII, *ID)) {
212*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeXTYPE:
213*9880d681SAndroid Build Coastguard Worker       if (HexagonMCInstrInfo::isFloat(MCII, *ID))
214*9880d681SAndroid Build Coastguard Worker         ++xtypeFloat;
215*9880d681SAndroid Build Coastguard Worker       break;
216*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeJR:
217*9880d681SAndroid Build Coastguard Worker       ++jumpr;
218*9880d681SAndroid Build Coastguard Worker     // Fall-through.
219*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeJ:
220*9880d681SAndroid Build Coastguard Worker       ++jumps;
221*9880d681SAndroid Build Coastguard Worker       break;
222*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCVI_VM_VP_LDU:
223*9880d681SAndroid Build Coastguard Worker       ++onlyNo1;
224*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCVI_VM_LD:
225*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCVI_VM_TMP_LD:
226*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCVI_VM_CUR_LD:
227*9880d681SAndroid Build Coastguard Worker       ++CVIloads;
228*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeLD:
229*9880d681SAndroid Build Coastguard Worker       ++loads;
230*9880d681SAndroid Build Coastguard Worker       ++memory;
231*9880d681SAndroid Build Coastguard Worker       if (ISJ->Core.getUnits() == slotSingleLoad)
232*9880d681SAndroid Build Coastguard Worker         ++load0;
233*9880d681SAndroid Build Coastguard Worker       if (HexagonMCInstrInfo::getDesc(MCII, *ID).isReturn())
234*9880d681SAndroid Build Coastguard Worker         ++jumps, ++jump1; // DEALLOC_RETURN is of type LD.
235*9880d681SAndroid Build Coastguard Worker       break;
236*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCVI_VM_STU:
237*9880d681SAndroid Build Coastguard Worker       ++onlyNo1;
238*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCVI_VM_ST:
239*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCVI_VM_NEW_ST:
240*9880d681SAndroid Build Coastguard Worker       ++CVIstores;
241*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeST:
242*9880d681SAndroid Build Coastguard Worker       ++stores;
243*9880d681SAndroid Build Coastguard Worker       ++memory;
244*9880d681SAndroid Build Coastguard Worker       if (ISJ->Core.getUnits() == slotSingleStore)
245*9880d681SAndroid Build Coastguard Worker         ++store0;
246*9880d681SAndroid Build Coastguard Worker       break;
247*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeMEMOP:
248*9880d681SAndroid Build Coastguard Worker       ++loads;
249*9880d681SAndroid Build Coastguard Worker       ++stores;
250*9880d681SAndroid Build Coastguard Worker       ++store1;
251*9880d681SAndroid Build Coastguard Worker       ++memory;
252*9880d681SAndroid Build Coastguard Worker       break;
253*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeNV:
254*9880d681SAndroid Build Coastguard Worker       ++memory; // NV insns are memory-like.
255*9880d681SAndroid Build Coastguard Worker       if (HexagonMCInstrInfo::getDesc(MCII, *ID).isBranch())
256*9880d681SAndroid Build Coastguard Worker         ++jumps, ++jump1;
257*9880d681SAndroid Build Coastguard Worker       break;
258*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeCR:
259*9880d681SAndroid Build Coastguard Worker     // Legacy conditional branch predicated on a register.
260*9880d681SAndroid Build Coastguard Worker     case HexagonII::TypeSYSTEM:
261*9880d681SAndroid Build Coastguard Worker       if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayLoad())
262*9880d681SAndroid Build Coastguard Worker         ++loads;
263*9880d681SAndroid Build Coastguard Worker       break;
264*9880d681SAndroid Build Coastguard Worker     }
265*9880d681SAndroid Build Coastguard Worker   }
266*9880d681SAndroid Build Coastguard Worker 
267*9880d681SAndroid Build Coastguard Worker   // Check if the packet is legal.
268*9880d681SAndroid Build Coastguard Worker   if ((load0 > 1 || store0 > 1 || CVIloads > 1 || CVIstores > 1) ||
269*9880d681SAndroid Build Coastguard Worker       (duplex > 1 || (duplex && memory)) || (solo && size() > 1) ||
270*9880d681SAndroid Build Coastguard Worker       (onlyAX && neitherAnorX > 1) || (onlyAX && xtypeFloat)) {
271*9880d681SAndroid Build Coastguard Worker     Error = SHUFFLE_ERROR_INVALID;
272*9880d681SAndroid Build Coastguard Worker     return false;
273*9880d681SAndroid Build Coastguard Worker   }
274*9880d681SAndroid Build Coastguard Worker 
275*9880d681SAndroid Build Coastguard Worker   if (jump1 && jumps > 1) {
276*9880d681SAndroid Build Coastguard Worker     // Error if single branch with another branch.
277*9880d681SAndroid Build Coastguard Worker     Error = SHUFFLE_ERROR_BRANCHES;
278*9880d681SAndroid Build Coastguard Worker     return false;
279*9880d681SAndroid Build Coastguard Worker   }
280*9880d681SAndroid Build Coastguard Worker 
281*9880d681SAndroid Build Coastguard Worker   // Modify packet accordingly.
282*9880d681SAndroid Build Coastguard Worker   // TODO: need to reserve slots #0 and #1 for duplex insns.
283*9880d681SAndroid Build Coastguard Worker   bool bOnlySlot3 = false;
284*9880d681SAndroid Build Coastguard Worker   for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
285*9880d681SAndroid Build Coastguard Worker     MCInst const *ID = ISJ->getDesc();
286*9880d681SAndroid Build Coastguard Worker 
287*9880d681SAndroid Build Coastguard Worker     if (!ISJ->Core.getUnits()) {
288*9880d681SAndroid Build Coastguard Worker       // Error if insn may not be executed in any slot.
289*9880d681SAndroid Build Coastguard Worker       Error = SHUFFLE_ERROR_UNKNOWN;
290*9880d681SAndroid Build Coastguard Worker       return false;
291*9880d681SAndroid Build Coastguard Worker     }
292*9880d681SAndroid Build Coastguard Worker 
293*9880d681SAndroid Build Coastguard Worker     // Exclude from slot #1 any insn but A2_nop.
294*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::getDesc(MCII, *ID).getOpcode() != Hexagon::A2_nop)
295*9880d681SAndroid Build Coastguard Worker       if (onlyNo1)
296*9880d681SAndroid Build Coastguard Worker         ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne);
297*9880d681SAndroid Build Coastguard Worker 
298*9880d681SAndroid Build Coastguard Worker     // Exclude from slot #1 any insn but A-type.
299*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeALU32)
300*9880d681SAndroid Build Coastguard Worker       if (onlyAin1)
301*9880d681SAndroid Build Coastguard Worker         ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne);
302*9880d681SAndroid Build Coastguard Worker 
303*9880d681SAndroid Build Coastguard Worker     // Branches must keep the original order.
304*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::getDesc(MCII, *ID).isBranch() ||
305*9880d681SAndroid Build Coastguard Worker         HexagonMCInstrInfo::getDesc(MCII, *ID).isCall())
306*9880d681SAndroid Build Coastguard Worker       if (jumps > 1) {
307*9880d681SAndroid Build Coastguard Worker         if (jumpr || slotJump < slotLastJump) {
308*9880d681SAndroid Build Coastguard Worker           // Error if indirect branch with another branch or
309*9880d681SAndroid Build Coastguard Worker           // no more slots available for branches.
310*9880d681SAndroid Build Coastguard Worker           Error = SHUFFLE_ERROR_BRANCHES;
311*9880d681SAndroid Build Coastguard Worker           return false;
312*9880d681SAndroid Build Coastguard Worker         }
313*9880d681SAndroid Build Coastguard Worker         // Pin the branch to the highest slot available to it.
314*9880d681SAndroid Build Coastguard Worker         ISJ->Core.setUnits(ISJ->Core.getUnits() & slotJump);
315*9880d681SAndroid Build Coastguard Worker         // Update next highest slot available to branches.
316*9880d681SAndroid Build Coastguard Worker         slotJump >>= 1;
317*9880d681SAndroid Build Coastguard Worker       }
318*9880d681SAndroid Build Coastguard Worker 
319*9880d681SAndroid Build Coastguard Worker     // A single load must use slot #0.
320*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayLoad()) {
321*9880d681SAndroid Build Coastguard Worker       if (loads == 1 && loads == memory)
322*9880d681SAndroid Build Coastguard Worker         // Pin the load to slot #0.
323*9880d681SAndroid Build Coastguard Worker         ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad);
324*9880d681SAndroid Build Coastguard Worker     }
325*9880d681SAndroid Build Coastguard Worker 
326*9880d681SAndroid Build Coastguard Worker     // A single store must use slot #0.
327*9880d681SAndroid Build Coastguard Worker     if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayStore()) {
328*9880d681SAndroid Build Coastguard Worker       if (!store0) {
329*9880d681SAndroid Build Coastguard Worker         if (stores == 1)
330*9880d681SAndroid Build Coastguard Worker           ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore);
331*9880d681SAndroid Build Coastguard Worker         else if (stores > 1) {
332*9880d681SAndroid Build Coastguard Worker           if (slotLoadStore < slotLastLoadStore) {
333*9880d681SAndroid Build Coastguard Worker             // Error if no more slots available for stores.
334*9880d681SAndroid Build Coastguard Worker             Error = SHUFFLE_ERROR_STORES;
335*9880d681SAndroid Build Coastguard Worker             return false;
336*9880d681SAndroid Build Coastguard Worker           }
337*9880d681SAndroid Build Coastguard Worker           // Pin the store to the highest slot available to it.
338*9880d681SAndroid Build Coastguard Worker           ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore);
339*9880d681SAndroid Build Coastguard Worker           // Update the next highest slot available to stores.
340*9880d681SAndroid Build Coastguard Worker           slotLoadStore >>= 1;
341*9880d681SAndroid Build Coastguard Worker         }
342*9880d681SAndroid Build Coastguard Worker       }
343*9880d681SAndroid Build Coastguard Worker       if (store1 && stores > 1) {
344*9880d681SAndroid Build Coastguard Worker         // Error if a single store with another store.
345*9880d681SAndroid Build Coastguard Worker         Error = SHUFFLE_ERROR_STORES;
346*9880d681SAndroid Build Coastguard Worker         return false;
347*9880d681SAndroid Build Coastguard Worker       }
348*9880d681SAndroid Build Coastguard Worker     }
349*9880d681SAndroid Build Coastguard Worker 
350*9880d681SAndroid Build Coastguard Worker     // flag if an instruction can only be executed in slot 3
351*9880d681SAndroid Build Coastguard Worker     if (ISJ->Core.getUnits() == slotThree)
352*9880d681SAndroid Build Coastguard Worker       bOnlySlot3 = true;
353*9880d681SAndroid Build Coastguard Worker 
354*9880d681SAndroid Build Coastguard Worker     if (!ISJ->Core.getUnits()) {
355*9880d681SAndroid Build Coastguard Worker       // Error if insn may not be executed in any slot.
356*9880d681SAndroid Build Coastguard Worker       Error = SHUFFLE_ERROR_NOSLOTS;
357*9880d681SAndroid Build Coastguard Worker       return false;
358*9880d681SAndroid Build Coastguard Worker     }
359*9880d681SAndroid Build Coastguard Worker   }
360*9880d681SAndroid Build Coastguard Worker 
361*9880d681SAndroid Build Coastguard Worker   bool validateSlots = true;
362*9880d681SAndroid Build Coastguard Worker   if (bOnlySlot3 == false && pSlot3Cnt == 1 && slot3ISJ != end()) {
363*9880d681SAndroid Build Coastguard Worker     // save off slot mask of instruction marked with A_PREFER_SLOT3
364*9880d681SAndroid Build Coastguard Worker     // and then pin it to slot #3
365*9880d681SAndroid Build Coastguard Worker     unsigned saveUnits = slot3ISJ->Core.getUnits();
366*9880d681SAndroid Build Coastguard Worker     slot3ISJ->Core.setUnits(saveUnits & slotThree);
367*9880d681SAndroid Build Coastguard Worker 
368*9880d681SAndroid Build Coastguard Worker     HexagonUnitAuction AuctionCore;
369*9880d681SAndroid Build Coastguard Worker     std::sort(begin(), end(), HexagonInstr::lessCore);
370*9880d681SAndroid Build Coastguard Worker 
371*9880d681SAndroid Build Coastguard Worker     // see if things ok with that instruction being pinned to slot #3
372*9880d681SAndroid Build Coastguard Worker     bool bFail = false;
373*9880d681SAndroid Build Coastguard Worker     for (iterator I = begin(); I != end() && bFail != true; ++I)
374*9880d681SAndroid Build Coastguard Worker       if (!AuctionCore.bid(I->Core.getUnits()))
375*9880d681SAndroid Build Coastguard Worker         bFail = true;
376*9880d681SAndroid Build Coastguard Worker 
377*9880d681SAndroid Build Coastguard Worker     // if yes, great, if not then restore original slot mask
378*9880d681SAndroid Build Coastguard Worker     if (!bFail)
379*9880d681SAndroid Build Coastguard Worker       validateSlots = false; // all good, no need to re-do auction
380*9880d681SAndroid Build Coastguard Worker     else
381*9880d681SAndroid Build Coastguard Worker       for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
382*9880d681SAndroid Build Coastguard Worker         MCInst const *ID = ISJ->getDesc();
383*9880d681SAndroid Build Coastguard Worker         if (HexagonMCInstrInfo::prefersSlot3(MCII, *ID))
384*9880d681SAndroid Build Coastguard Worker           ISJ->Core.setUnits(saveUnits);
385*9880d681SAndroid Build Coastguard Worker       }
386*9880d681SAndroid Build Coastguard Worker   }
387*9880d681SAndroid Build Coastguard Worker 
388*9880d681SAndroid Build Coastguard Worker   // Check if any slot, core, is over-subscribed.
389*9880d681SAndroid Build Coastguard Worker   // Verify the core slot subscriptions.
390*9880d681SAndroid Build Coastguard Worker   if (validateSlots) {
391*9880d681SAndroid Build Coastguard Worker     HexagonUnitAuction AuctionCore;
392*9880d681SAndroid Build Coastguard Worker 
393*9880d681SAndroid Build Coastguard Worker     std::sort(begin(), end(), HexagonInstr::lessCore);
394*9880d681SAndroid Build Coastguard Worker 
395*9880d681SAndroid Build Coastguard Worker     for (iterator I = begin(); I != end(); ++I)
396*9880d681SAndroid Build Coastguard Worker       if (!AuctionCore.bid(I->Core.getUnits())) {
397*9880d681SAndroid Build Coastguard Worker         Error = SHUFFLE_ERROR_SLOTS;
398*9880d681SAndroid Build Coastguard Worker         return false;
399*9880d681SAndroid Build Coastguard Worker       }
400*9880d681SAndroid Build Coastguard Worker   }
401*9880d681SAndroid Build Coastguard Worker   // Verify the CVI slot subscriptions.
402*9880d681SAndroid Build Coastguard Worker   {
403*9880d681SAndroid Build Coastguard Worker     HexagonUnitAuction AuctionCVI;
404*9880d681SAndroid Build Coastguard Worker 
405*9880d681SAndroid Build Coastguard Worker     std::sort(begin(), end(), HexagonInstr::lessCVI);
406*9880d681SAndroid Build Coastguard Worker 
407*9880d681SAndroid Build Coastguard Worker     for (iterator I = begin(); I != end(); ++I)
408*9880d681SAndroid Build Coastguard Worker       for (unsigned i = 0; i < I->CVI.getLanes(); ++i) // TODO: I->CVI.isValid?
409*9880d681SAndroid Build Coastguard Worker         if (!AuctionCVI.bid(I->CVI.getUnits() << i)) {
410*9880d681SAndroid Build Coastguard Worker           Error = SHUFFLE_ERROR_SLOTS;
411*9880d681SAndroid Build Coastguard Worker           return false;
412*9880d681SAndroid Build Coastguard Worker         }
413*9880d681SAndroid Build Coastguard Worker   }
414*9880d681SAndroid Build Coastguard Worker 
415*9880d681SAndroid Build Coastguard Worker   Error = SHUFFLE_SUCCESS;
416*9880d681SAndroid Build Coastguard Worker   return true;
417*9880d681SAndroid Build Coastguard Worker }
418*9880d681SAndroid Build Coastguard Worker 
shuffle()419*9880d681SAndroid Build Coastguard Worker bool HexagonShuffler::shuffle() {
420*9880d681SAndroid Build Coastguard Worker   if (size() > HEXAGON_PACKET_SIZE) {
421*9880d681SAndroid Build Coastguard Worker     // Ignore a packet with with more than what a packet can hold
422*9880d681SAndroid Build Coastguard Worker     // or with compound or duplex insns for now.
423*9880d681SAndroid Build Coastguard Worker     Error = SHUFFLE_ERROR_INVALID;
424*9880d681SAndroid Build Coastguard Worker     return false;
425*9880d681SAndroid Build Coastguard Worker   }
426*9880d681SAndroid Build Coastguard Worker 
427*9880d681SAndroid Build Coastguard Worker   // Check and prepare packet.
428*9880d681SAndroid Build Coastguard Worker   if (size() > 1 && check())
429*9880d681SAndroid Build Coastguard Worker     // Reorder the handles for each slot.
430*9880d681SAndroid Build Coastguard Worker     for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE;
431*9880d681SAndroid Build Coastguard Worker          ++nSlot) {
432*9880d681SAndroid Build Coastguard Worker       iterator ISJ, ISK;
433*9880d681SAndroid Build Coastguard Worker       unsigned slotSkip, slotWeight;
434*9880d681SAndroid Build Coastguard Worker 
435*9880d681SAndroid Build Coastguard Worker       // Prioritize the handles considering their restrictions.
436*9880d681SAndroid Build Coastguard Worker       for (ISJ = ISK = Packet.begin(), slotSkip = slotWeight = 0;
437*9880d681SAndroid Build Coastguard Worker            ISK != Packet.end(); ++ISK, ++slotSkip)
438*9880d681SAndroid Build Coastguard Worker         if (slotSkip < nSlot - emptySlots)
439*9880d681SAndroid Build Coastguard Worker           // Note which handle to begin at.
440*9880d681SAndroid Build Coastguard Worker           ++ISJ;
441*9880d681SAndroid Build Coastguard Worker         else
442*9880d681SAndroid Build Coastguard Worker           // Calculate the weight of the slot.
443*9880d681SAndroid Build Coastguard Worker           slotWeight += ISK->Core.setWeight(HEXAGON_PACKET_SIZE - nSlot - 1);
444*9880d681SAndroid Build Coastguard Worker 
445*9880d681SAndroid Build Coastguard Worker       if (slotWeight)
446*9880d681SAndroid Build Coastguard Worker         // Sort the packet, favoring source order,
447*9880d681SAndroid Build Coastguard Worker         // beginning after the previous slot.
448*9880d681SAndroid Build Coastguard Worker         std::sort(ISJ, Packet.end());
449*9880d681SAndroid Build Coastguard Worker       else
450*9880d681SAndroid Build Coastguard Worker         // Skip unused slot.
451*9880d681SAndroid Build Coastguard Worker         ++emptySlots;
452*9880d681SAndroid Build Coastguard Worker     }
453*9880d681SAndroid Build Coastguard Worker 
454*9880d681SAndroid Build Coastguard Worker   for (iterator ISJ = begin(); ISJ != end(); ++ISJ)
455*9880d681SAndroid Build Coastguard Worker     DEBUG(dbgs().write_hex(ISJ->Core.getUnits());
456*9880d681SAndroid Build Coastguard Worker           dbgs() << ':'
457*9880d681SAndroid Build Coastguard Worker                  << HexagonMCInstrInfo::getDesc(MCII, *ISJ->getDesc())
458*9880d681SAndroid Build Coastguard Worker                         .getOpcode();
459*9880d681SAndroid Build Coastguard Worker           dbgs() << '\n');
460*9880d681SAndroid Build Coastguard Worker   DEBUG(dbgs() << '\n');
461*9880d681SAndroid Build Coastguard Worker 
462*9880d681SAndroid Build Coastguard Worker   return (!getError());
463*9880d681SAndroid Build Coastguard Worker }
464