Coverage Report

Created: 2025-11-16 07:15

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