1 //===- HexagonShuffler.cpp - Instruction bundle shuffling -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This implements the shuffling of insns inside a bundle according to the 10 // packet formation rules of the Hexagon ISA. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "MCTargetDesc/HexagonShuffler.h" 15 #include "MCTargetDesc/HexagonBaseInfo.h" 16 #include "MCTargetDesc/HexagonMCInstrInfo.h" 17 #include "MCTargetDesc/HexagonMCTargetDesc.h" 18 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/ADT/Twine.h" 21 #include "llvm/MC/MCContext.h" 22 #include "llvm/MC/MCInst.h" 23 #include "llvm/MC/MCInstrDesc.h" 24 #include "llvm/MC/MCSubtargetInfo.h" 25 #include "llvm/Support/Compiler.h" 26 #include "llvm/Support/Debug.h" 27 #include "llvm/Support/MathExtras.h" 28 #include "llvm/Support/SourceMgr.h" 29 #include "llvm/Support/raw_ostream.h" 30 #include <algorithm> 31 #include <cassert> 32 #include <optional> 33 #include <utility> 34 #include <vector> 35 36 #define DEBUG_TYPE "hexagon-shuffle" 37 38 using namespace llvm; 39 40 namespace { 41 42 // Insn shuffling priority. 43 class HexagonBid { 44 // The priority is directly proportional to how restricted the insn is based 45 // on its flexibility to run on the available slots. So, the fewer slots it 46 // may run on, the higher its priority. 47 enum { MAX = 360360 }; // LCD of 1/2, 1/3, 1/4,... 1/15. 48 unsigned Bid = 0; 49 50 public: 51 HexagonBid() = default; 52 HexagonBid(unsigned B) { Bid = B ? MAX / llvm::popcount(B) : 0; } 53 54 // Check if the insn priority is overflowed. 55 bool isSold() const { return (Bid >= MAX); } 56 57 HexagonBid &operator+=(const HexagonBid &B) { 58 Bid += B.Bid; 59 return *this; 60 } 61 }; 62 63 // Slot shuffling allocation. 64 class HexagonUnitAuction { 65 HexagonBid Scores[HEXAGON_PACKET_SIZE]; 66 // Mask indicating which slot is unavailable. 67 unsigned isSold : HEXAGON_PACKET_SIZE; 68 69 public: 70 HexagonUnitAuction(unsigned cs = 0) : isSold(cs) {} 71 72 // Allocate slots. 73 bool bid(unsigned B) { 74 // Exclude already auctioned slots from the bid. 75 unsigned b = B & ~isSold; 76 if (b) { 77 for (unsigned i = 0; i < HEXAGON_PACKET_SIZE; ++i) 78 if (b & (1 << i)) { 79 // Request candidate slots. 80 Scores[i] += HexagonBid(b); 81 isSold |= Scores[i].isSold() << i; 82 } 83 return true; 84 } else 85 // Error if the desired slots are already full. 86 return false; 87 } 88 }; 89 90 } // end anonymous namespace 91 92 unsigned HexagonResource::setWeight(unsigned s) { 93 const unsigned SlotWeight = 8; 94 const unsigned MaskWeight = SlotWeight - 1; 95 unsigned Units = getUnits(); 96 unsigned Key = ((1u << s) & Units) != 0; 97 98 // Calculate relative weight of the insn for the given slot, weighing it the 99 // heavier the more restrictive the insn is and the lowest the slots that the 100 // insn may be executed in. 101 if (Key == 0 || Units == 0 || (SlotWeight * s >= 32)) 102 return Weight = 0; 103 104 unsigned Ctpop = llvm::popcount(Units); 105 unsigned Cttz = llvm::countr_zero(Units); 106 Weight = (1u << (SlotWeight * s)) * ((MaskWeight - Ctpop) << Cttz); 107 return Weight; 108 } 109 110 HexagonCVIResource::HexagonCVIResource(MCInstrInfo const &MCII, 111 MCSubtargetInfo const &STI, 112 unsigned s, 113 MCInst const *id) 114 : HexagonResource(s) { 115 116 const unsigned ItinUnits = HexagonMCInstrInfo::getCVIResources(MCII, STI, *id); 117 unsigned Lanes; 118 const unsigned Units = HexagonConvertUnits(ItinUnits, &Lanes); 119 120 if (Units == 0 && Lanes == 0) { 121 // For core insns. 122 Valid = false; 123 setUnits(0); 124 setLanes(0); 125 setLoad(false); 126 setStore(false); 127 } else { 128 // For an HVX insn. 129 Valid = true; 130 setUnits(Units); 131 setLanes(Lanes); 132 setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad()); 133 setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore()); 134 } 135 } 136 137 struct CVIUnits { 138 unsigned Units; 139 unsigned Lanes; 140 }; 141 using HVXInstsT = SmallVector<struct CVIUnits, 8>; 142 143 static unsigned makeAllBits(unsigned startBit, unsigned Lanes) 144 { 145 for (unsigned i = 1; i < Lanes; ++i) 146 startBit = (startBit << 1) | startBit; 147 return startBit; 148 } 149 150 static bool checkHVXPipes(const HVXInstsT &hvxInsts, unsigned startIdx, 151 unsigned usedUnits) { 152 if (startIdx < hvxInsts.size()) { 153 if (!hvxInsts[startIdx].Units) 154 return checkHVXPipes(hvxInsts, startIdx + 1, usedUnits); 155 for (unsigned b = 0x1; b <= 0x8; b <<= 1) { 156 if ((hvxInsts[startIdx].Units & b) == 0) 157 continue; 158 unsigned allBits = makeAllBits(b, hvxInsts[startIdx].Lanes); 159 if ((allBits & usedUnits) == 0) { 160 if (checkHVXPipes(hvxInsts, startIdx + 1, usedUnits | allBits)) 161 return true; 162 } 163 } 164 return false; 165 } 166 return true; 167 } 168 169 HexagonShuffler::HexagonShuffler(MCContext &Context, bool ReportErrors, 170 MCInstrInfo const &MCII, 171 MCSubtargetInfo const &STI) 172 : Context(Context), BundleFlags(), MCII(MCII), STI(STI), 173 ReportErrors(ReportErrors), CheckFailure() { 174 reset(); 175 } 176 177 void HexagonShuffler::reset() { 178 Packet.clear(); 179 BundleFlags = 0; 180 CheckFailure = false; 181 } 182 183 void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender, 184 unsigned S) { 185 HexagonInstr PI(MCII, STI, &ID, Extender, S); 186 187 Packet.push_back(PI); 188 } 189 190 191 static const unsigned Slot0Mask = 1 << 0; 192 static const unsigned Slot1Mask = 1 << 1; 193 static const unsigned Slot3Mask = 1 << 3; 194 static const unsigned slotSingleLoad = Slot0Mask; 195 static const unsigned slotSingleStore = Slot0Mask; 196 197 void HexagonShuffler::restrictSlot1AOK(HexagonPacketSummary const &Summary) { 198 if (Summary.Slot1AOKLoc) 199 for (HexagonInstr &ISJ : insts()) { 200 MCInst const &Inst = ISJ.getDesc(); 201 const unsigned Type = HexagonMCInstrInfo::getType(MCII, Inst); 202 if (Type != HexagonII::TypeALU32_2op && 203 Type != HexagonII::TypeALU32_3op && 204 Type != HexagonII::TypeALU32_ADDI) { 205 const unsigned Units = ISJ.Core.getUnits(); 206 207 if (Units & Slot1Mask) { 208 AppliedRestrictions.push_back(std::make_pair( 209 Inst.getLoc(), 210 "Instruction was restricted from being in slot 1")); 211 AppliedRestrictions.push_back(std::make_pair( 212 *Summary.Slot1AOKLoc, "Instruction can only be combined " 213 "with an ALU instruction in slot 1")); 214 ISJ.Core.setUnits(Units & ~Slot1Mask); 215 } 216 } 217 } 218 } 219 220 void HexagonShuffler::restrictNoSlot1Store( 221 HexagonPacketSummary const &Summary) { 222 // If this packet contains an instruction that bars slot-1 stores, 223 // we should mask off slot 1 from all of the store instructions in 224 // this packet. 225 226 if (!Summary.NoSlot1StoreLoc) 227 return; 228 229 bool AppliedRestriction = false; 230 231 for (HexagonInstr &ISJ : insts()) { 232 MCInst const &Inst = ISJ.getDesc(); 233 if (HexagonMCInstrInfo::getDesc(MCII, Inst).mayStore()) { 234 unsigned Units = ISJ.Core.getUnits(); 235 if (Units & Slot1Mask) { 236 AppliedRestriction = true; 237 AppliedRestrictions.push_back(std::make_pair( 238 Inst.getLoc(), "Instruction was restricted from being in slot 1")); 239 ISJ.Core.setUnits(Units & ~Slot1Mask); 240 } 241 } 242 } 243 244 if (AppliedRestriction) 245 AppliedRestrictions.push_back( 246 std::make_pair(*Summary.NoSlot1StoreLoc, 247 "Instruction does not allow a store in slot 1")); 248 } 249 250 bool HexagonShuffler::applySlotRestrictions(HexagonPacketSummary const &Summary, 251 const bool DoShuffle) { 252 // These restrictions can modify the slot masks in the instructions 253 // in the Packet member. They should run unconditionally and their 254 // order does not matter. 255 restrictSlot1AOK(Summary); 256 restrictNoSlot1Store(Summary); 257 258 permitNonSlot(); 259 260 // These restrictions can modify the slot masks in the instructions 261 // in the Packet member, but they can also detect constraint failures 262 // which are fatal. 263 if (!CheckFailure) 264 restrictStoreLoadOrder(Summary); 265 if (!CheckFailure) 266 restrictBranchOrder(Summary); 267 if (!CheckFailure) 268 restrictPreferSlot3(Summary, DoShuffle); 269 return !CheckFailure; 270 } 271 272 void HexagonShuffler::restrictBranchOrder(HexagonPacketSummary const &Summary) { 273 // preserve branch order 274 const bool HasMultipleBranches = Summary.branchInsts.size() > 1; 275 if (!HasMultipleBranches) 276 return; 277 278 if (Summary.branchInsts.size() > 2) { 279 reportError(Twine("too many branches in packet")); 280 return; 281 } 282 283 const static std::pair<unsigned, unsigned> jumpSlots[] = { 284 {8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}}; 285 // try all possible choices 286 for (std::pair<unsigned, unsigned> jumpSlot : jumpSlots) { 287 // validate first jump with this slot rule 288 if (!(jumpSlot.first & Summary.branchInsts[0]->Core.getUnits())) 289 continue; 290 291 // validate second jump with this slot rule 292 if (!(jumpSlot.second & Summary.branchInsts[1]->Core.getUnits())) 293 continue; 294 295 // both valid for this configuration, set new slot rules 296 const HexagonPacket PacketSave = Packet; 297 Summary.branchInsts[0]->Core.setUnits(jumpSlot.first); 298 Summary.branchInsts[1]->Core.setUnits(jumpSlot.second); 299 300 const bool HasShuffledPacket = tryAuction(Summary).has_value(); 301 if (HasShuffledPacket) 302 return; 303 304 // if yes, great, if not then restore original slot mask 305 // restore original values 306 Packet = PacketSave; 307 } 308 309 reportResourceError(Summary, "out of slots"); 310 } 311 312 void HexagonShuffler::permitNonSlot() { 313 for (HexagonInstr &ISJ : insts()) { 314 const bool RequiresSlot = HexagonMCInstrInfo::requiresSlot(STI, *ISJ.ID); 315 if (!RequiresSlot) 316 ISJ.Core.setAllUnits(); 317 } 318 } 319 320 bool HexagonShuffler::ValidResourceUsage(HexagonPacketSummary const &Summary) { 321 std::optional<HexagonPacket> ShuffledPacket = tryAuction(Summary); 322 323 if (!ShuffledPacket) { 324 reportResourceError(Summary, "slot error"); 325 return false; 326 } 327 328 // Verify the CVI slot subscriptions. 329 llvm::stable_sort(*ShuffledPacket, HexagonInstr::lessCVI); 330 // create vector of hvx instructions to check 331 HVXInstsT hvxInsts; 332 hvxInsts.clear(); 333 for (const auto &I : *ShuffledPacket) { 334 struct CVIUnits inst; 335 inst.Units = I.CVI.getUnits(); 336 inst.Lanes = I.CVI.getLanes(); 337 if (inst.Units == 0) 338 continue; // not an hvx inst or an hvx inst that doesn't uses any pipes 339 hvxInsts.push_back(inst); 340 } 341 342 // if there are any hvx instructions in this packet, check pipe usage 343 if (hvxInsts.size() > 0) { 344 unsigned startIdx, usedUnits; 345 startIdx = usedUnits = 0x0; 346 if (!checkHVXPipes(hvxInsts, startIdx, usedUnits)) { 347 // too many pipes used to be valid 348 reportError(Twine("invalid instruction packet: slot error")); 349 return false; 350 } 351 } 352 353 Packet = *ShuffledPacket; 354 355 return true; 356 } 357 358 bool HexagonShuffler::restrictStoreLoadOrder( 359 HexagonPacketSummary const &Summary) { 360 // Modify packet accordingly. 361 // TODO: need to reserve slots #0 and #1 for duplex insns. 362 static const unsigned slotFirstLoadStore = Slot1Mask; 363 static const unsigned slotLastLoadStore = Slot0Mask; 364 unsigned slotLoadStore = slotFirstLoadStore; 365 366 for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { 367 MCInst const &ID = ISJ->getDesc(); 368 369 if (!ISJ->Core.getUnits()) 370 // Error if insn may not be executed in any slot. 371 return false; 372 373 // A single load must use slot #0. 374 if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { 375 if (Summary.loads == 1 && Summary.loads == Summary.memory && 376 Summary.memops == 0) 377 // Pin the load to slot #0. 378 switch (ID.getOpcode()) { 379 case Hexagon::V6_vgathermw: 380 case Hexagon::V6_vgathermh: 381 case Hexagon::V6_vgathermhw: 382 case Hexagon::V6_vgathermwq: 383 case Hexagon::V6_vgathermhq: 384 case Hexagon::V6_vgathermhwq: 385 // Slot1 only loads 386 break; 387 default: 388 ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad); 389 break; 390 } 391 else if (Summary.loads >= 1 && isMemReorderDisabled()) { // }:mem_noshuf 392 // Loads must keep the original order ONLY if 393 // isMemReorderDisabled() == true 394 if (slotLoadStore < slotLastLoadStore) { 395 // Error if no more slots available for loads. 396 reportError("invalid instruction packet: too many loads"); 397 return false; 398 } 399 // Pin the load to the highest slot available to it. 400 ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); 401 // Update the next highest slot available to loads. 402 slotLoadStore >>= 1; 403 } 404 } 405 406 // A single store must use slot #0. 407 if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) { 408 if (!Summary.store0) { 409 const bool PacketHasNoOnlySlot0 = 410 llvm::none_of(insts(), [&](HexagonInstr const &I) { 411 return I.Core.getUnits() == Slot0Mask && 412 I.ID->getOpcode() != ID.getOpcode(); 413 }); 414 const bool SafeToMoveToSlot0 = 415 (Summary.loads == 0) || 416 (!isMemReorderDisabled() && PacketHasNoOnlySlot0); 417 418 if (Summary.stores == 1 && SafeToMoveToSlot0) 419 // Pin the store to slot #0 only if isMemReorderDisabled() == false 420 ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore); 421 else if (Summary.stores >= 1) { 422 if (slotLoadStore < slotLastLoadStore) { 423 // Error if no more slots available for stores. 424 reportError("invalid instruction packet: too many stores"); 425 return false; 426 } 427 // Pin the store to the highest slot available to it. 428 ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); 429 // Update the next highest slot available to stores. 430 slotLoadStore >>= 1; 431 } 432 } 433 if (Summary.store1 && Summary.stores > 1) { 434 // Error if a single store with another store. 435 reportError("invalid instruction packet: too many stores"); 436 return false; 437 } 438 } 439 } 440 441 return true; 442 } 443 444 static std::string SlotMaskToText(unsigned SlotMask) { 445 SmallVector<std::string, HEXAGON_PRESHUFFLE_PACKET_SIZE> Slots; 446 for (unsigned SlotNum = 0; SlotNum < HEXAGON_PACKET_SIZE; SlotNum++) 447 if ((SlotMask & (1 << SlotNum)) != 0) 448 Slots.push_back(utostr(SlotNum)); 449 450 return llvm::join(Slots, StringRef(", ")); 451 } 452 453 HexagonShuffler::HexagonPacketSummary HexagonShuffler::GetPacketSummary() { 454 HexagonPacketSummary Summary = HexagonPacketSummary(); 455 456 // Collect information from the insns in the packet. 457 for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { 458 MCInst const &ID = ISJ->getDesc(); 459 460 if (HexagonMCInstrInfo::isRestrictSlot1AOK(MCII, ID)) 461 Summary.Slot1AOKLoc = ID.getLoc(); 462 if (HexagonMCInstrInfo::isRestrictNoSlot1Store(MCII, ID)) 463 Summary.NoSlot1StoreLoc = ID.getLoc(); 464 465 if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) { 466 ++Summary.pSlot3Cnt; 467 Summary.PrefSlot3Inst = ISJ; 468 } 469 const unsigned ReservedSlots = 470 HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID); 471 Summary.ReservedSlotMask |= ReservedSlots; 472 if (ReservedSlots != 0) 473 AppliedRestrictions.push_back(std::make_pair(ID.getLoc(), 474 (Twine("Instruction has reserved slots: ") + 475 SlotMaskToText(ReservedSlots)).str())); 476 477 switch (HexagonMCInstrInfo::getType(MCII, ID)) { 478 case HexagonII::TypeS_2op: 479 case HexagonII::TypeS_3op: 480 case HexagonII::TypeALU64: 481 break; 482 case HexagonII::TypeJ: 483 if (HexagonMCInstrInfo::IsABranchingInst(MCII, STI, *ISJ->ID)) 484 Summary.branchInsts.push_back(ISJ); 485 break; 486 case HexagonII::TypeCVI_VM_VP_LDU: 487 case HexagonII::TypeCVI_VM_LD: 488 case HexagonII::TypeCVI_VM_TMP_LD: 489 case HexagonII::TypeCVI_GATHER: 490 case HexagonII::TypeCVI_GATHER_DV: 491 case HexagonII::TypeCVI_GATHER_RST: 492 ++Summary.NonZCVIloads; 493 [[fallthrough]]; 494 case HexagonII::TypeCVI_ZW: 495 ++Summary.AllCVIloads; 496 [[fallthrough]]; 497 case HexagonII::TypeLD: 498 ++Summary.loads; 499 ++Summary.memory; 500 if (ISJ->Core.getUnits() == slotSingleLoad || 501 HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU) 502 ++Summary.load0; 503 if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn()) 504 Summary.branchInsts.push_back(ISJ); 505 break; 506 case HexagonII::TypeCVI_VM_STU: 507 case HexagonII::TypeCVI_VM_ST: 508 case HexagonII::TypeCVI_VM_NEW_ST: 509 case HexagonII::TypeCVI_SCATTER: 510 case HexagonII::TypeCVI_SCATTER_DV: 511 case HexagonII::TypeCVI_SCATTER_RST: 512 case HexagonII::TypeCVI_SCATTER_NEW_RST: 513 case HexagonII::TypeCVI_SCATTER_NEW_ST: 514 ++Summary.CVIstores; 515 [[fallthrough]]; 516 case HexagonII::TypeST: 517 ++Summary.stores; 518 ++Summary.memory; 519 if (ISJ->Core.getUnits() == slotSingleStore || 520 HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_STU) 521 ++Summary.store0; 522 break; 523 case HexagonII::TypeV4LDST: 524 ++Summary.loads; 525 ++Summary.stores; 526 ++Summary.store1; 527 ++Summary.memops; 528 ++Summary.memory; 529 break; 530 case HexagonII::TypeNCJ: 531 ++Summary.memory; // NV insns are memory-like. 532 Summary.branchInsts.push_back(ISJ); 533 break; 534 case HexagonII::TypeV2LDST: 535 if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { 536 ++Summary.loads; 537 ++Summary.memory; 538 if (ISJ->Core.getUnits() == slotSingleLoad || 539 HexagonMCInstrInfo::getType(MCII, ID) == 540 HexagonII::TypeCVI_VM_VP_LDU) 541 ++Summary.load0; 542 } else { 543 assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()); 544 ++Summary.memory; 545 ++Summary.stores; 546 } 547 break; 548 case HexagonII::TypeCR: 549 // Legacy conditional branch predicated on a register. 550 case HexagonII::TypeCJ: 551 if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch()) 552 Summary.branchInsts.push_back(ISJ); 553 break; 554 case HexagonII::TypeDUPLEX: { 555 ++Summary.duplex; 556 MCInst const &Inst0 = *ID.getOperand(0).getInst(); 557 MCInst const &Inst1 = *ID.getOperand(1).getInst(); 558 if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch()) 559 Summary.branchInsts.push_back(ISJ); 560 if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch()) 561 Summary.branchInsts.push_back(ISJ); 562 if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn()) 563 Summary.branchInsts.push_back(ISJ); 564 if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn()) 565 Summary.branchInsts.push_back(ISJ); 566 break; 567 } 568 } 569 } 570 return Summary; 571 } 572 573 bool HexagonShuffler::ValidPacketMemoryOps( 574 HexagonPacketSummary const &Summary) const { 575 // Check if the packet is legal. 576 const unsigned ZCVIloads = Summary.AllCVIloads - Summary.NonZCVIloads; 577 const bool ValidHVXMem = 578 Summary.NonZCVIloads <= 1 && ZCVIloads <= 1 && Summary.CVIstores <= 1; 579 const bool InvalidPacket = 580 ((Summary.load0 > 1 || Summary.store0 > 1 || !ValidHVXMem) || 581 (Summary.duplex > 1 || (Summary.duplex && Summary.memory))); 582 583 return !InvalidPacket; 584 } 585 586 void HexagonShuffler::restrictPreferSlot3(HexagonPacketSummary const &Summary, 587 const bool DoShuffle) { 588 // flag if an instruction requires to be in slot 3 589 const bool HasOnlySlot3 = llvm::any_of(insts(), [&](HexagonInstr const &I) { 590 return (I.Core.getUnits() == Slot3Mask); 591 }); 592 const bool NeedsPrefSlot3Shuffle = Summary.branchInsts.size() <= 1 && 593 !HasOnlySlot3 && Summary.pSlot3Cnt == 1 && 594 Summary.PrefSlot3Inst && DoShuffle; 595 596 if (!NeedsPrefSlot3Shuffle) 597 return; 598 599 HexagonInstr *PrefSlot3Inst = *Summary.PrefSlot3Inst; 600 // save off slot mask of instruction marked with A_PREFER_SLOT3 601 // and then pin it to slot #3 602 const unsigned saveUnits = PrefSlot3Inst->Core.getUnits(); 603 PrefSlot3Inst->Core.setUnits(saveUnits & Slot3Mask); 604 const bool HasShuffledPacket = tryAuction(Summary).has_value(); 605 if (HasShuffledPacket) 606 return; 607 608 PrefSlot3Inst->Core.setUnits(saveUnits); 609 } 610 611 /// Check that the packet is legal and enforce relative insn order. 612 bool HexagonShuffler::check(const bool RequireShuffle) { 613 const HexagonPacketSummary Summary = GetPacketSummary(); 614 if (!applySlotRestrictions(Summary, RequireShuffle)) 615 return false; 616 617 if (!ValidPacketMemoryOps(Summary)) { 618 reportError("invalid instruction packet"); 619 return false; 620 } 621 622 if (RequireShuffle) 623 ValidResourceUsage(Summary); 624 625 return !CheckFailure; 626 } 627 628 std::optional<HexagonShuffler::HexagonPacket> 629 HexagonShuffler::tryAuction(HexagonPacketSummary const &Summary) { 630 HexagonPacket PacketResult = Packet; 631 HexagonUnitAuction AuctionCore(Summary.ReservedSlotMask); 632 llvm::stable_sort(PacketResult, HexagonInstr::lessCore); 633 634 const bool ValidSlots = 635 llvm::all_of(insts(PacketResult), [&AuctionCore](HexagonInstr const &I) { 636 return AuctionCore.bid(I.Core.getUnits()); 637 }); 638 639 LLVM_DEBUG( 640 dbgs() << "Shuffle attempt: " << (ValidSlots ? "passed" : "failed") 641 << "\n"; 642 for (HexagonInstr const &ISJ : insts(PacketResult)) 643 dbgs() << "\t" << HexagonMCInstrInfo::getName(MCII, *ISJ.ID) << ": " 644 << llvm::format_hex(ISJ.Core.getUnits(), 4, true) << "\n"; 645 ); 646 647 std::optional<HexagonPacket> Res; 648 if (ValidSlots) 649 Res = PacketResult; 650 651 return Res; 652 } 653 654 bool HexagonShuffler::shuffle() { 655 if (size() > HEXAGON_PACKET_SIZE) { 656 // Ignore a packet with with more than what a packet can hold 657 // or with compound or duplex insns for now. 658 reportError("invalid instruction packet"); 659 return false; 660 } 661 662 // Check and prepare packet. 663 bool Ok = check(); 664 if (size() > 1 && Ok) 665 // Reorder the handles for each slot. 666 for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE; 667 ++nSlot) { 668 iterator ISJ, ISK; 669 unsigned slotSkip, slotWeight; 670 671 // Prioritize the handles considering their restrictions. 672 for (ISJ = ISK = Packet.begin(), slotSkip = slotWeight = 0; 673 ISK != Packet.end(); ++ISK, ++slotSkip) 674 if (slotSkip < nSlot - emptySlots) 675 // Note which handle to begin at. 676 ++ISJ; 677 else 678 // Calculate the weight of the slot. 679 slotWeight += ISK->Core.setWeight(HEXAGON_PACKET_SIZE - nSlot - 1); 680 681 if (slotWeight) 682 // Sort the packet, favoring source order, 683 // beginning after the previous slot. 684 std::stable_sort(ISJ, Packet.end()); 685 else 686 // Skip unused slot. 687 ++emptySlots; 688 } 689 690 LLVM_DEBUG( 691 for (HexagonInstr const &ISJ : insts()) { 692 dbgs().write_hex(ISJ.Core.getUnits()); 693 if (ISJ.CVI.isValid()) { 694 dbgs() << '/'; 695 dbgs().write_hex(ISJ.CVI.getUnits()) << '|'; 696 dbgs() << ISJ.CVI.getLanes(); 697 } 698 dbgs() << ':' 699 << HexagonMCInstrInfo::getDesc(MCII, ISJ.getDesc()).getOpcode() 700 << '\n'; 701 } dbgs() << '\n'; 702 ); 703 704 return Ok; 705 } 706 707 void HexagonShuffler::reportResourceError(HexagonPacketSummary const &Summary, StringRef Err) { 708 if (ReportErrors) 709 reportResourceUsage(Summary); 710 reportError(Twine("invalid instruction packet: ") + Err); 711 } 712 713 714 void HexagonShuffler::reportResourceUsage(HexagonPacketSummary const &Summary) { 715 auto SM = Context.getSourceManager(); 716 if (SM) { 717 for (HexagonInstr const &I : insts()) { 718 const unsigned Units = I.Core.getUnits(); 719 720 if (HexagonMCInstrInfo::requiresSlot(STI, *I.ID)) { 721 const std::string UnitsText = Units ? SlotMaskToText(Units) : "<None>"; 722 SM->PrintMessage(I.ID->getLoc(), SourceMgr::DK_Note, 723 Twine("Instruction can utilize slots: ") + 724 UnitsText); 725 } 726 else if (!HexagonMCInstrInfo::isImmext(*I.ID)) 727 SM->PrintMessage(I.ID->getLoc(), SourceMgr::DK_Note, 728 "Instruction does not require a slot"); 729 } 730 } 731 } 732 733 void HexagonShuffler::reportError(Twine const &Msg) { 734 CheckFailure = true; 735 if (ReportErrors) { 736 for (auto const &I : AppliedRestrictions) { 737 auto SM = Context.getSourceManager(); 738 if (SM) 739 SM->PrintMessage(I.first, SourceMgr::DK_Note, I.second); 740 } 741 Context.reportError(Loc, Msg); 742 } 743 } 744