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