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