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