LLVM  3.7.0
HexagonShuffler.cpp
Go to the documentation of this file.
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"
23 #include "HexagonShuffler.h"
24 #include "llvm/Support/Debug.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:
39  HexagonBid() : Bid(0){};
40  HexagonBid(unsigned B) { Bid = B ? MAX / countPopulation(B) : 0; };
41 
42  // Check if the insn priority is overflowed.
43  bool isSold() const { return (Bid >= MAX); };
44 
46  Bid += B.Bid;
47  return *this;
48  };
49 };
50 
51 // Slot shuffling allocation.
54  // Mask indicating which slot is unavailable.
55  unsigned isSold : HEXAGON_PACKET_SIZE;
56 
57 public:
58  HexagonUnitAuction() : isSold(0){};
59 
60  // Allocate slots.
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 
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()))
93  return (Weight);
94 }
95 
97  MCSubtargetInfo const &STI)
98  : MCII(MCII), STI(STI) {
99  reset();
100 }
101 
103  Packet.clear();
104  BundleFlags = 0;
105  Error = SHUFFLE_SUCCESS;
106 }
107 
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.
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 
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();
154  ++neitherAnorX;
156  ++pSlot3Cnt;
157  slot3ISJ = ISJ;
158  }
159 
160  switch (HexagonMCInstrInfo::getType(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;
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;
186  ++loads;
187  ++stores;
188  ++store1;
189  ++memory;
190  break;
191  case HexagonII::TypeNV:
192  ++memory; // NV insns are memory-like.
194  ++jumps, ++jump1;
195  break;
196  case HexagonII::TypeCR:
197  // Legacy conditional branch predicated on a register.
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.
238  if (onlyAin1)
239  ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne);
240 
241  // Branches must keep the original order.
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.
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.
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();
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 
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 }
bool isSoloAin1(MCInstrInfo const &MCII, MCInst const &MCI)
Return whether the insn can be packaged only with an A-type insn in slot #1.
void push_back(const T &Elt)
Definition: SmallVector.h:222
static bool lessCore(const HexagonInstr &A, const HexagonInstr &B)
unsigned getError() const
bool isReturn() const
Return true if the instruction is a return.
Definition: MCInstrDesc.h:211
bool mayStore() const
Return true if this instruction could possibly modify memory.
Definition: MCInstrDesc.h:356
bool isSolo(MCInstrInfo const &MCII, MCInst const &MCI)
HexagonBid & operator+=(const HexagonBid &B)
unsigned setWeight(unsigned s)
No free slots for store insns.
#define HEXAGON_PACKET_SIZE
Definition: Hexagon.h:33
bool isBranch() const
Returns true if this is a conditional, unconditional, or indirect branch.
Definition: MCInstrDesc.h:233
bool isCall() const
Return true if the instruction is a call.
Definition: MCInstrDesc.h:214
HexagonShuffler(MCInstrInfo const &MCII, MCSubtargetInfo const &STI)
HexagonBid(unsigned B)
unsigned getUnits() const
raw_ostream & write_hex(unsigned long long N)
Output N in hexadecimal, without any prefix or padding.
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:150
bool bid(unsigned B)
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB=ZB_Width)
Count number of 0's from the least significant bit to the most stopping at the first 1...
Definition: MathExtras.h:109
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:24
unsigned size() const
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang","erlang-compatible garbage collector")
bool prefersSlot3(MCInstrInfo const &MCII, MCInst const &MCI)
unsigned getOpcode() const
Return the opcode number for this descriptor.
Definition: MCInstrDesc.h:178
void append(MCInst const *ID, MCInst const *Extender, unsigned S, bool X=false)
unsigned countPopulation(T Value)
Count the number of set bits in a value.
Definition: MathExtras.h:449
MCInstrInfo const & MCII
No free slots for branch insns.
bool mayLoad() const
Return true if this instruction could possibly read memory.
Definition: MCInstrDesc.h:350
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:123
bool isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI)
Return whether the insn can be packaged only with A and X-type insns.
#define I(x, y, z)
Definition: MD5.cpp:54
MCSubtargetInfo - Generic base class for all target subtargets.
MCInstrDesc const & getDesc(MCInstrInfo const &MCII, MCInst const &MCI)
bool isSold() const
bool isFloat(MCInstrInfo const &MCII, MCInst const &MCI)
Return whether it is a floating-point insn.
#define DEBUG(X)
Definition: Debug.h:92
unsigned getType(MCInstrInfo const &MCII, MCInst const &MCI)
bool check()
Check that the packet is legal and enforce relative insn order.