| //===- HexagonShuffler.cpp - Instruction bundle shuffling -----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This implements the shuffling of insns inside a bundle according to the |
| // packet formation rules of the Hexagon ISA. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "hexagon-shuffle" |
| |
| #include "MCTargetDesc/HexagonShuffler.h" |
| #include "MCTargetDesc/HexagonBaseInfo.h" |
| #include "MCTargetDesc/HexagonMCInstrInfo.h" |
| #include "MCTargetDesc/HexagonMCTargetDesc.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/MC/MCContext.h" |
| #include "llvm/MC/MCInst.h" |
| #include "llvm/MC/MCInstrDesc.h" |
| #include "llvm/MC/MCSubtargetInfo.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/MathExtras.h" |
| #include "llvm/Support/SourceMgr.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <utility> |
| #include <vector> |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| // Insn shuffling priority. |
| class HexagonBid { |
| // The priority is directly proportional to how restricted the insn is based |
| // on its flexibility to run on the available slots. So, the fewer slots it |
| // may run on, the higher its priority. |
| enum { MAX = 360360 }; // LCD of 1/2, 1/3, 1/4,... 1/15. |
| unsigned Bid = 0; |
| |
| public: |
| HexagonBid() = default; |
| HexagonBid(unsigned B) { Bid = B ? MAX / countPopulation(B) : 0; } |
| |
| // Check if the insn priority is overflowed. |
| bool isSold() const { return (Bid >= MAX); } |
| |
| HexagonBid &operator+=(const HexagonBid &B) { |
| Bid += B.Bid; |
| return *this; |
| } |
| }; |
| |
| // Slot shuffling allocation. |
| class HexagonUnitAuction { |
| HexagonBid Scores[HEXAGON_PACKET_SIZE]; |
| // Mask indicating which slot is unavailable. |
| unsigned isSold : HEXAGON_PACKET_SIZE; |
| |
| public: |
| HexagonUnitAuction(unsigned cs = 0) : isSold(cs) {} |
| |
| // Allocate slots. |
| bool bid(unsigned B) { |
| // Exclude already auctioned slots from the bid. |
| unsigned b = B & ~isSold; |
| if (b) { |
| for (unsigned i = 0; i < HEXAGON_PACKET_SIZE; ++i) |
| if (b & (1 << i)) { |
| // Request candidate slots. |
| Scores[i] += HexagonBid(b); |
| isSold |= Scores[i].isSold() << i; |
| } |
| return true; |
| } else |
| // Error if the desired slots are already full. |
| return false; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| unsigned HexagonResource::setWeight(unsigned s) { |
| const unsigned SlotWeight = 8; |
| const unsigned MaskWeight = SlotWeight - 1; |
| unsigned Units = getUnits(); |
| unsigned Key = ((1u << s) & Units) != 0; |
| |
| // Calculate relative weight of the insn for the given slot, weighing it the |
| // heavier the more restrictive the insn is and the lowest the slots that the |
| // insn may be executed in. |
| if (Key == 0 || Units == 0 || (SlotWeight * s >= 32)) |
| return Weight = 0; |
| |
| unsigned Ctpop = countPopulation(Units); |
| unsigned Cttz = countTrailingZeros(Units); |
| Weight = (1u << (SlotWeight * s)) * ((MaskWeight - Ctpop) << Cttz); |
| return Weight; |
| } |
| |
| HexagonCVIResource::HexagonCVIResource(MCInstrInfo const &MCII, |
| MCSubtargetInfo const &STI, |
| unsigned s, |
| MCInst const *id) |
| : HexagonResource(s) { |
| |
| const unsigned ItinUnits = HexagonMCInstrInfo::getCVIResources(MCII, STI, *id); |
| unsigned Lanes; |
| const unsigned Units = HexagonConvertUnits(ItinUnits, &Lanes); |
| |
| if (Units == 0 && Lanes == 0) { |
| // For core insns. |
| Valid = false; |
| setUnits(0); |
| setLanes(0); |
| setLoad(false); |
| setStore(false); |
| } else { |
| // For an HVX insn. |
| Valid = true; |
| setUnits(Units); |
| setLanes(Lanes); |
| setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad()); |
| setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore()); |
| } |
| } |
| |
| struct CVIUnits { |
| unsigned Units; |
| unsigned Lanes; |
| }; |
| using HVXInstsT = SmallVector<struct CVIUnits, 8>; |
| |
| static unsigned makeAllBits(unsigned startBit, unsigned Lanes) |
| { |
| for (unsigned i = 1; i < Lanes; ++i) |
| startBit = (startBit << 1) | startBit; |
| return startBit; |
| } |
| |
| static bool checkHVXPipes(const HVXInstsT &hvxInsts, unsigned startIdx, |
| unsigned usedUnits) { |
| if (startIdx < hvxInsts.size()) { |
| if (!hvxInsts[startIdx].Units) |
| return checkHVXPipes(hvxInsts, startIdx + 1, usedUnits); |
| for (unsigned b = 0x1; b <= 0x8; b <<= 1) { |
| if ((hvxInsts[startIdx].Units & b) == 0) |
| continue; |
| unsigned allBits = makeAllBits(b, hvxInsts[startIdx].Lanes); |
| if ((allBits & usedUnits) == 0) { |
| if (checkHVXPipes(hvxInsts, startIdx + 1, usedUnits | allBits)) |
| return true; |
| } |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| HexagonShuffler::HexagonShuffler(MCContext &Context, bool ReportErrors, |
| MCInstrInfo const &MCII, |
| MCSubtargetInfo const &STI) |
| : Context(Context), MCII(MCII), STI(STI), ReportErrors(ReportErrors) { |
| reset(); |
| } |
| |
| void HexagonShuffler::reset() { |
| Packet.clear(); |
| BundleFlags = 0; |
| CheckFailure = false; |
| } |
| |
| void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender, |
| unsigned S) { |
| HexagonInstr PI(MCII, STI, &ID, Extender, S); |
| |
| Packet.push_back(PI); |
| } |
| |
| |
| static const unsigned Slot0Mask = 1 << 0; |
| static const unsigned Slot1Mask = 1 << 1; |
| static const unsigned Slot3Mask = 1 << 3; |
| static const unsigned slotSingleLoad = Slot0Mask; |
| static const unsigned slotSingleStore = Slot0Mask; |
| |
| void HexagonShuffler::restrictSlot1AOK(HexagonPacketSummary const &Summary) { |
| if (Summary.Slot1AOKLoc) |
| for (HexagonInstr &ISJ : insts()) { |
| MCInst const &Inst = ISJ.getDesc(); |
| const unsigned Type = HexagonMCInstrInfo::getType(MCII, Inst); |
| if (Type != HexagonII::TypeALU32_2op && |
| Type != HexagonII::TypeALU32_3op && |
| Type != HexagonII::TypeALU32_ADDI) { |
| const unsigned Units = ISJ.Core.getUnits(); |
| |
| if (Units & Slot1Mask) { |
| AppliedRestrictions.push_back(std::make_pair( |
| Inst.getLoc(), |
| "Instruction was restricted from being in slot 1")); |
| AppliedRestrictions.push_back(std::make_pair( |
| *Summary.Slot1AOKLoc, "Instruction can only be combined " |
| "with an ALU instruction in slot 1")); |
| ISJ.Core.setUnits(Units & ~Slot1Mask); |
| } |
| } |
| } |
| } |
| |
| void HexagonShuffler::restrictNoSlot1Store( |
| HexagonPacketSummary const &Summary) { |
| // If this packet contains an instruction that bars slot-1 stores, |
| // we should mask off slot 1 from all of the store instructions in |
| // this packet. |
| |
| if (!Summary.NoSlot1StoreLoc) |
| return; |
| |
| bool AppliedRestriction = false; |
| |
| for (HexagonInstr &ISJ : insts()) { |
| MCInst const &Inst = ISJ.getDesc(); |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst).mayStore()) { |
| unsigned Units = ISJ.Core.getUnits(); |
| if (Units & Slot1Mask) { |
| AppliedRestriction = true; |
| AppliedRestrictions.push_back(std::make_pair( |
| Inst.getLoc(), "Instruction was restricted from being in slot 1")); |
| ISJ.Core.setUnits(Units & ~Slot1Mask); |
| } |
| } |
| } |
| |
| if (AppliedRestriction) |
| AppliedRestrictions.push_back( |
| std::make_pair(*Summary.NoSlot1StoreLoc, |
| "Instruction does not allow a store in slot 1")); |
| } |
| |
| bool HexagonShuffler::applySlotRestrictions( |
| HexagonPacketSummary const &Summary) { |
| // These restrictions can modify the slot masks in the instructions |
| // in the Packet member. They should run unconditionally and their |
| // order does not matter. |
| restrictSlot1AOK(Summary); |
| restrictNoSlot1Store(Summary); |
| |
| permitNonSlot(); |
| |
| // These restrictions can modify the slot masks in the instructions |
| // in the Packet member, but they can also detect constraint failures |
| // which are fatal. |
| if (!CheckFailure) |
| restrictStoreLoadOrder(Summary); |
| if (!CheckFailure) |
| restrictBranchOrder(Summary); |
| if (!CheckFailure) |
| restrictPreferSlot3(Summary); |
| return !CheckFailure; |
| } |
| |
| void HexagonShuffler::restrictBranchOrder(HexagonPacketSummary const &Summary) { |
| // preserve branch order |
| const bool HasMultipleBranches = Summary.branchInsts.size() > 1; |
| if (!HasMultipleBranches) |
| return; |
| |
| if (Summary.branchInsts.size() > 2) { |
| reportError(Twine("too many branches in packet")); |
| return; |
| } |
| |
| const static std::pair<unsigned, unsigned> jumpSlots[] = { |
| {8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}}; |
| // try all possible choices |
| for (std::pair<unsigned, unsigned> jumpSlot : jumpSlots) { |
| // validate first jump with this slot rule |
| if (!(jumpSlot.first & Summary.branchInsts[0]->Core.getUnits())) |
| continue; |
| |
| // validate second jump with this slot rule |
| if (!(jumpSlot.second & Summary.branchInsts[1]->Core.getUnits())) |
| continue; |
| |
| // both valid for this configuration, set new slot rules |
| const HexagonPacket PacketSave = Packet; |
| Summary.branchInsts[0]->Core.setUnits(jumpSlot.first); |
| Summary.branchInsts[1]->Core.setUnits(jumpSlot.second); |
| |
| const bool HasShuffledPacket = tryAuction(Summary).hasValue(); |
| if (HasShuffledPacket) |
| return; |
| |
| // if yes, great, if not then restore original slot mask |
| // restore original values |
| Packet = PacketSave; |
| } |
| |
| reportError("invalid instruction packet: out of slots"); |
| } |
| |
| |
| void HexagonShuffler::permitNonSlot() { |
| for (HexagonInstr &ISJ : insts()) { |
| const bool RequiresSlot = HexagonMCInstrInfo::requiresSlot(STI, *ISJ.ID); |
| if (!RequiresSlot) |
| ISJ.Core.setAllUnits(); |
| } |
| } |
| |
| bool HexagonShuffler::ValidResourceUsage(HexagonPacketSummary const &Summary) { |
| Optional<HexagonPacket> ShuffledPacket = tryAuction(Summary); |
| |
| if (!ShuffledPacket) { |
| reportError("invalid instruction packet: slot error"); |
| return false; |
| } else { |
| Packet = *ShuffledPacket; |
| } |
| |
| // Verify the CVI slot subscriptions. |
| std::stable_sort(begin(), end(), HexagonInstr::lessCVI); |
| // create vector of hvx instructions to check |
| HVXInstsT hvxInsts; |
| hvxInsts.clear(); |
| for (const_iterator I = cbegin(); I != cend(); ++I) { |
| struct CVIUnits inst; |
| inst.Units = I->CVI.getUnits(); |
| inst.Lanes = I->CVI.getLanes(); |
| if (inst.Units == 0) |
| continue; // not an hvx inst or an hvx inst that doesn't uses any pipes |
| hvxInsts.push_back(inst); |
| } |
| |
| // if there are any hvx instructions in this packet, check pipe usage |
| if (hvxInsts.size() > 0) { |
| unsigned startIdx, usedUnits; |
| startIdx = usedUnits = 0x0; |
| if (!checkHVXPipes(hvxInsts, startIdx, usedUnits)) { |
| // too many pipes used to be valid |
| reportError(Twine("invalid instruction packet: slot error")); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool HexagonShuffler::restrictStoreLoadOrder( |
| HexagonPacketSummary const &Summary) { |
| // Modify packet accordingly. |
| // TODO: need to reserve slots #0 and #1 for duplex insns. |
| static const unsigned slotFirstLoadStore = Slot1Mask; |
| static const unsigned slotLastLoadStore = Slot0Mask; |
| unsigned slotLoadStore = slotFirstLoadStore; |
| |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { |
| MCInst const &ID = ISJ->getDesc(); |
| |
| if (!ISJ->Core.getUnits()) |
| // Error if insn may not be executed in any slot. |
| return false; |
| |
| // A single load must use slot #0. |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { |
| if (Summary.loads == 1 && Summary.loads == Summary.memory && |
| Summary.memops == 0) |
| // Pin the load to slot #0. |
| switch (ID.getOpcode()) { |
| case Hexagon::V6_vgathermw: |
| case Hexagon::V6_vgathermh: |
| case Hexagon::V6_vgathermhw: |
| case Hexagon::V6_vgathermwq: |
| case Hexagon::V6_vgathermhq: |
| case Hexagon::V6_vgathermhwq: |
| // Slot1 only loads |
| break; |
| default: |
| ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad); |
| break; |
| } |
| else if (Summary.loads >= 1 && isMemReorderDisabled()) { // }:mem_noshuf |
| // Loads must keep the original order ONLY if |
| // isMemReorderDisabled() == true |
| if (slotLoadStore < slotLastLoadStore) { |
| // Error if no more slots available for loads. |
| reportError("invalid instruction packet: too many loads"); |
| return false; |
| } |
| // Pin the load to the highest slot available to it. |
| ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); |
| // Update the next highest slot available to loads. |
| slotLoadStore >>= 1; |
| } |
| } |
| |
| // A single store must use slot #0. |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) { |
| if (!Summary.store0) { |
| const bool PacketHasNoOnlySlot0 = |
| llvm::none_of(insts(), [&](HexagonInstr const &I) { |
| return I.Core.getUnits() == Slot0Mask && |
| I.ID->getOpcode() != ID.getOpcode(); |
| }); |
| const bool SafeToMoveToSlot0 = |
| (Summary.loads == 0) || |
| (!isMemReorderDisabled() && PacketHasNoOnlySlot0); |
| |
| if (Summary.stores == 1 && SafeToMoveToSlot0) |
| // Pin the store to slot #0 only if isMemReorderDisabled() == false |
| ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore); |
| else if (Summary.stores >= 1) { |
| if (slotLoadStore < slotLastLoadStore) { |
| // Error if no more slots available for stores. |
| reportError("invalid instruction packet: too many stores"); |
| return false; |
| } |
| // Pin the store to the highest slot available to it. |
| ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore); |
| // Update the next highest slot available to stores. |
| slotLoadStore >>= 1; |
| } |
| } |
| if (Summary.store1 && Summary.stores > 1) { |
| // Error if a single store with another store. |
| reportError("invalid instruction packet: too many stores"); |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| HexagonShuffler::HexagonPacketSummary HexagonShuffler::GetPacketSummary() { |
| HexagonPacketSummary Summary = HexagonPacketSummary(); |
| |
| // Collect information from the insns in the packet. |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { |
| MCInst const &ID = ISJ->getDesc(); |
| |
| if (HexagonMCInstrInfo::isRestrictSlot1AOK(MCII, ID)) |
| Summary.Slot1AOKLoc = ID.getLoc(); |
| if (HexagonMCInstrInfo::isRestrictNoSlot1Store(MCII, ID)) |
| Summary.NoSlot1StoreLoc = ID.getLoc(); |
| |
| if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) { |
| ++Summary.pSlot3Cnt; |
| Summary.PrefSlot3Inst = ISJ; |
| } |
| Summary.ReservedSlotMask |= |
| HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID); |
| |
| switch (HexagonMCInstrInfo::getType(MCII, ID)) { |
| case HexagonII::TypeS_2op: |
| case HexagonII::TypeS_3op: |
| case HexagonII::TypeALU64: |
| break; |
| case HexagonII::TypeJ: |
| Summary.branchInsts.push_back(ISJ); |
| break; |
| case HexagonII::TypeCVI_VM_VP_LDU: |
| case HexagonII::TypeCVI_VM_LD: |
| case HexagonII::TypeCVI_VM_TMP_LD: |
| case HexagonII::TypeCVI_GATHER: |
| case HexagonII::TypeCVI_GATHER_DV: |
| case HexagonII::TypeCVI_GATHER_RST: |
| ++Summary.NonZCVIloads; |
| LLVM_FALLTHROUGH; |
| case HexagonII::TypeCVI_ZW: |
| ++Summary.AllCVIloads; |
| LLVM_FALLTHROUGH; |
| case HexagonII::TypeLD: |
| ++Summary.loads; |
| ++Summary.memory; |
| if (ISJ->Core.getUnits() == slotSingleLoad || |
| HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU) |
| ++Summary.load0; |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn()) |
| Summary.branchInsts.push_back(ISJ); |
| break; |
| case HexagonII::TypeCVI_VM_STU: |
| case HexagonII::TypeCVI_VM_ST: |
| case HexagonII::TypeCVI_VM_NEW_ST: |
| case HexagonII::TypeCVI_SCATTER: |
| case HexagonII::TypeCVI_SCATTER_DV: |
| case HexagonII::TypeCVI_SCATTER_RST: |
| case HexagonII::TypeCVI_SCATTER_NEW_RST: |
| case HexagonII::TypeCVI_SCATTER_NEW_ST: |
| ++Summary.CVIstores; |
| LLVM_FALLTHROUGH; |
| case HexagonII::TypeST: |
| ++Summary.stores; |
| ++Summary.memory; |
| if (ISJ->Core.getUnits() == slotSingleStore || |
| HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_STU) |
| ++Summary.store0; |
| break; |
| case HexagonII::TypeV4LDST: |
| ++Summary.loads; |
| ++Summary.stores; |
| ++Summary.store1; |
| ++Summary.memops; |
| ++Summary.memory; |
| break; |
| case HexagonII::TypeNCJ: |
| ++Summary.memory; // NV insns are memory-like. |
| Summary.branchInsts.push_back(ISJ); |
| break; |
| case HexagonII::TypeV2LDST: |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { |
| ++Summary.loads; |
| ++Summary.memory; |
| if (ISJ->Core.getUnits() == slotSingleLoad || |
| HexagonMCInstrInfo::getType(MCII, ID) == |
| HexagonII::TypeCVI_VM_VP_LDU) |
| ++Summary.load0; |
| } else { |
| assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()); |
| ++Summary.memory; |
| ++Summary.stores; |
| } |
| break; |
| case HexagonII::TypeCR: |
| // Legacy conditional branch predicated on a register. |
| case HexagonII::TypeCJ: |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch()) |
| Summary.branchInsts.push_back(ISJ); |
| break; |
| case HexagonII::TypeDUPLEX: { |
| ++Summary.duplex; |
| MCInst const &Inst0 = *ID.getOperand(0).getInst(); |
| MCInst const &Inst1 = *ID.getOperand(1).getInst(); |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch()) |
| Summary.branchInsts.push_back(ISJ); |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch()) |
| Summary.branchInsts.push_back(ISJ); |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn()) |
| Summary.branchInsts.push_back(ISJ); |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn()) |
| Summary.branchInsts.push_back(ISJ); |
| break; |
| } |
| } |
| } |
| return Summary; |
| } |
| |
| bool HexagonShuffler::ValidPacketMemoryOps( |
| HexagonPacketSummary const &Summary) const { |
| // Check if the packet is legal. |
| const unsigned ZCVIloads = Summary.AllCVIloads - Summary.NonZCVIloads; |
| const bool ValidHVXMem = |
| Summary.NonZCVIloads <= 1 && ZCVIloads <= 1 && Summary.CVIstores <= 1; |
| const bool InvalidPacket = |
| ((Summary.load0 > 1 || Summary.store0 > 1 || !ValidHVXMem) || |
| (Summary.duplex > 1 || (Summary.duplex && Summary.memory))); |
| |
| return !InvalidPacket; |
| } |
| |
| void HexagonShuffler::restrictPreferSlot3(HexagonPacketSummary const &Summary) { |
| // flag if an instruction requires to be in slot 3 |
| const bool HasOnlySlot3 = llvm::any_of(insts(), [&](HexagonInstr const &I) { |
| return (I.Core.getUnits() == Slot3Mask); |
| }); |
| const bool NeedsPrefSlot3Shuffle = |
| (Summary.branchInsts.size() <= 1 && !HasOnlySlot3 && |
| Summary.pSlot3Cnt == 1 && Summary.PrefSlot3Inst); |
| |
| if (!NeedsPrefSlot3Shuffle) |
| return; |
| |
| HexagonInstr *PrefSlot3Inst = *Summary.PrefSlot3Inst; |
| // save off slot mask of instruction marked with A_PREFER_SLOT3 |
| // and then pin it to slot #3 |
| const unsigned saveUnits = PrefSlot3Inst->Core.getUnits(); |
| PrefSlot3Inst->Core.setUnits(saveUnits & Slot3Mask); |
| const bool HasShuffledPacket = tryAuction(Summary).hasValue(); |
| if (HasShuffledPacket) |
| return; |
| |
| PrefSlot3Inst->Core.setUnits(saveUnits); |
| } |
| |
| /// Check that the packet is legal and enforce relative insn order. |
| bool HexagonShuffler::check() { |
| const HexagonPacketSummary Summary = GetPacketSummary(); |
| if (!applySlotRestrictions(Summary)) |
| return false; |
| |
| if (!ValidPacketMemoryOps(Summary)) { |
| reportError("invalid instruction packet"); |
| return false; |
| } |
| |
| ValidResourceUsage(Summary); |
| |
| return !CheckFailure; |
| } |
| |
| llvm::Optional<HexagonShuffler::HexagonPacket> |
| HexagonShuffler::tryAuction(HexagonPacketSummary const &Summary) const { |
| HexagonPacket PacketResult = Packet; |
| HexagonUnitAuction AuctionCore(Summary.ReservedSlotMask); |
| std::stable_sort(PacketResult.begin(), PacketResult.end(), |
| HexagonInstr::lessCore); |
| |
| const bool ValidSlots = |
| llvm::all_of(insts(PacketResult), [&AuctionCore](HexagonInstr const &I) { |
| return AuctionCore.bid(I.Core.getUnits()); |
| }); |
| |
| LLVM_DEBUG( |
| dbgs() << "Shuffle attempt: " << (ValidSlots ? "passed" : "failed") |
| << "\n"; |
| for (HexagonInstr const &ISJ : insts(PacketResult)) |
| dbgs() << "\t" << HexagonMCInstrInfo::getName(MCII, *ISJ.ID) << ": " |
| << llvm::format_hex(ISJ.Core.getUnits(), 4, true) << "\n"; |
| ); |
| |
| Optional<HexagonPacket> Res; |
| if (ValidSlots) |
| Res = PacketResult; |
| |
| return Res; |
| } |
| |
| bool HexagonShuffler::shuffle() { |
| if (size() > HEXAGON_PACKET_SIZE) { |
| // Ignore a packet with with more than what a packet can hold |
| // or with compound or duplex insns for now. |
| reportError(Twine("invalid instruction packet")); |
| return false; |
| } |
| |
| // Check and prepare packet. |
| bool Ok = true; |
| if (size() > 1 && (Ok = check())) |
| // Reorder the handles for each slot. |
| for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE; |
| ++nSlot) { |
| iterator ISJ, ISK; |
| unsigned slotSkip, slotWeight; |
| |
| // Prioritize the handles considering their restrictions. |
| for (ISJ = ISK = Packet.begin(), slotSkip = slotWeight = 0; |
| ISK != Packet.end(); ++ISK, ++slotSkip) |
| if (slotSkip < nSlot - emptySlots) |
| // Note which handle to begin at. |
| ++ISJ; |
| else |
| // Calculate the weight of the slot. |
| slotWeight += ISK->Core.setWeight(HEXAGON_PACKET_SIZE - nSlot - 1); |
| |
| if (slotWeight) |
| // Sort the packet, favoring source order, |
| // beginning after the previous slot. |
| std::stable_sort(ISJ, Packet.end()); |
| else |
| // Skip unused slot. |
| ++emptySlots; |
| } |
| |
| LLVM_DEBUG( |
| for (HexagonInstr const &ISJ : insts()) { |
| dbgs().write_hex(ISJ.Core.getUnits()); |
| if (ISJ.CVI.isValid()) { |
| dbgs() << '/'; |
| dbgs().write_hex(ISJ.CVI.getUnits()) << '|'; |
| dbgs() << ISJ.CVI.getLanes(); |
| } |
| dbgs() << ':' |
| << HexagonMCInstrInfo::getDesc(MCII, ISJ.getDesc()).getOpcode() |
| << '\n'; |
| } dbgs() << '\n'; |
| ); |
| |
| return Ok; |
| } |
| |
| void HexagonShuffler::reportError(Twine const &Msg) { |
| CheckFailure = true; |
| if (ReportErrors) { |
| for (auto const &I : AppliedRestrictions) { |
| auto SM = Context.getSourceManager(); |
| if (SM) |
| SM->PrintMessage(I.first, SourceMgr::DK_Note, I.second); |
| } |
| Context.reportError(Loc, Msg); |
| } |
| } |