| //===- HexagonShuffler.cpp - Instruction bundle shuffling -----------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // 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 "Hexagon.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/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; | |
| } | |
| void HexagonCVIResource::SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU) { | |
| (*TUL)[HexagonII::TypeCVI_VA] = | |
| UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_VA_DV] = UnitsAndLanes(CVI_XLANE | CVI_MPY0, 2); | |
| (*TUL)[HexagonII::TypeCVI_VX] = UnitsAndLanes(CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_VX_LATE] = UnitsAndLanes(CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_VX_DV] = UnitsAndLanes(CVI_MPY0, 2); | |
| (*TUL)[HexagonII::TypeCVI_VP] = UnitsAndLanes(CVI_XLANE, 1); | |
| (*TUL)[HexagonII::TypeCVI_VP_VS] = UnitsAndLanes(CVI_XLANE, 2); | |
| (*TUL)[HexagonII::TypeCVI_VS] = UnitsAndLanes(CVI_SHIFT, 1); | |
| (*TUL)[HexagonII::TypeCVI_VS_VX] = UnitsAndLanes(CVI_XLANE | CVI_SHIFT, 1); | |
| (*TUL)[HexagonII::TypeCVI_VINLANESAT] = | |
| (CPU == "hexagonv60") | |
| ? UnitsAndLanes(CVI_SHIFT, 1) | |
| : UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_VM_LD] = | |
| UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_VM_TMP_LD] = UnitsAndLanes(CVI_NONE, 0); | |
| (*TUL)[HexagonII::TypeCVI_VM_VP_LDU] = UnitsAndLanes(CVI_XLANE, 1); | |
| (*TUL)[HexagonII::TypeCVI_VM_ST] = | |
| UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_VM_NEW_ST] = UnitsAndLanes(CVI_NONE, 0); | |
| (*TUL)[HexagonII::TypeCVI_VM_STU] = UnitsAndLanes(CVI_XLANE, 1); | |
| (*TUL)[HexagonII::TypeCVI_HIST] = UnitsAndLanes(CVI_XLANE, 4); | |
| (*TUL)[HexagonII::TypeCVI_GATHER] = | |
| UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_SCATTER] = | |
| UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); | |
| (*TUL)[HexagonII::TypeCVI_SCATTER_DV] = | |
| UnitsAndLanes(CVI_XLANE | CVI_MPY0, 2); | |
| (*TUL)[HexagonII::TypeCVI_SCATTER_NEW_ST] = | |
| UnitsAndLanes(CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1, 1); | |
| } | |
| HexagonCVIResource::HexagonCVIResource(TypeUnitsAndLanes *TUL, | |
| MCInstrInfo const &MCII, unsigned s, | |
| MCInst const *id) | |
| : HexagonResource(s) { | |
| unsigned T = HexagonMCInstrInfo::getType(MCII, *id); | |
| if (TUL->count(T)) { | |
| // For an HVX insn. | |
| Valid = true; | |
| setUnits((*TUL)[T].first); | |
| setLanes((*TUL)[T].second); | |
| setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad()); | |
| setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore()); | |
| } else { | |
| // For core insns. | |
| Valid = false; | |
| setUnits(0); | |
| setLanes(0); | |
| setLoad(false); | |
| setStore(false); | |
| } | |
| } | |
| 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(); | |
| HexagonCVIResource::SetupTUL(&TUL, STI.getCPU()); | |
| } | |
| void HexagonShuffler::reset() { | |
| Packet.clear(); | |
| BundleFlags = 0; | |
| } | |
| void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender, | |
| unsigned S) { | |
| HexagonInstr PI(&TUL, MCII, &ID, Extender, S); | |
| Packet.push_back(PI); | |
| } | |
| static struct { | |
| unsigned first; | |
| unsigned second; | |
| } jumpSlots[] = {{8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}}; | |
| #define MAX_JUMP_SLOTS (sizeof(jumpSlots) / sizeof(jumpSlots[0])) | |
| void HexagonShuffler::restrictSlot1AOK() { | |
| bool HasRestrictSlot1AOK = false; | |
| SMLoc RestrictLoc; | |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { | |
| MCInst const &Inst = ISJ->getDesc(); | |
| if (HexagonMCInstrInfo::isRestrictSlot1AOK(MCII, Inst)) { | |
| HasRestrictSlot1AOK = true; | |
| RestrictLoc = Inst.getLoc(); | |
| } | |
| } | |
| if (HasRestrictSlot1AOK) | |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { | |
| MCInst const &Inst = ISJ->getDesc(); | |
| unsigned Type = HexagonMCInstrInfo::getType(MCII, Inst); | |
| if (Type != HexagonII::TypeALU32_2op && | |
| Type != HexagonII::TypeALU32_3op && | |
| Type != HexagonII::TypeALU32_ADDI) { | |
| unsigned Units = ISJ->Core.getUnits(); | |
| if (Units & 2U) { | |
| AppliedRestrictions.push_back(std::make_pair( | |
| Inst.getLoc(), | |
| "Instruction was restricted from being in slot 1")); | |
| AppliedRestrictions.push_back( | |
| std::make_pair(RestrictLoc, "Instruction can only be combine " | |
| "with an ALU instruction in slot 1")); | |
| ISJ->Core.setUnits(Units & ~2U); | |
| } | |
| } | |
| } | |
| } | |
| void HexagonShuffler::restrictNoSlot1Store() { | |
| bool HasRestrictNoSlot1Store = false; | |
| SMLoc RestrictLoc; | |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { | |
| MCInst const &Inst = ISJ->getDesc(); | |
| if (HexagonMCInstrInfo::isRestrictNoSlot1Store(MCII, Inst)) { | |
| HasRestrictNoSlot1Store = true; | |
| RestrictLoc = Inst.getLoc(); | |
| } | |
| } | |
| if (HasRestrictNoSlot1Store) { | |
| bool AppliedRestriction = false; | |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { | |
| MCInst const &Inst = ISJ->getDesc(); | |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst).mayStore()) { | |
| unsigned Units = ISJ->Core.getUnits(); | |
| if (Units & 2U) { | |
| AppliedRestriction = true; | |
| AppliedRestrictions.push_back(std::make_pair( | |
| Inst.getLoc(), | |
| "Instruction was restricted from being in slot 1")); | |
| ISJ->Core.setUnits(Units & ~2U); | |
| } | |
| } | |
| } | |
| if (AppliedRestriction) | |
| AppliedRestrictions.push_back(std::make_pair( | |
| RestrictLoc, "Instruction does not allow a store in slot 1")); | |
| } | |
| } | |
| void HexagonShuffler::applySlotRestrictions() { | |
| restrictSlot1AOK(); | |
| restrictNoSlot1Store(); | |
| } | |
| /// Check that the packet is legal and enforce relative insn order. | |
| bool HexagonShuffler::check() { | |
| // Descriptive slot masks. | |
| const unsigned slotSingleLoad = 0x1, slotSingleStore = 0x1, | |
| slotThree = 0x8, // slotFirstJump = 0x8, | |
| slotFirstLoadStore = 0x2, slotLastLoadStore = 0x1; | |
| // Highest slots for branches and stores used to keep their original order. | |
| // unsigned slotJump = slotFirstJump; | |
| unsigned slotLoadStore = slotFirstLoadStore; | |
| // Number of memory operations, loads, solo loads, stores, solo stores, single | |
| // stores. | |
| unsigned memory = 0, loads = 0, load0 = 0, stores = 0, store0 = 0, store1 = 0; | |
| // Number of duplex insns | |
| unsigned duplex = 0; | |
| unsigned pSlot3Cnt = 0; | |
| unsigned memops = 0; | |
| iterator slot3ISJ = end(); | |
| std::vector<iterator> foundBranches; | |
| unsigned reservedSlots = 0; | |
| // Collect information from the insns in the packet. | |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { | |
| MCInst const &ID = ISJ->getDesc(); | |
| if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) { | |
| ++pSlot3Cnt; | |
| slot3ISJ = ISJ; | |
| } | |
| reservedSlots |= 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: | |
| foundBranches.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_RST: | |
| case HexagonII::TypeLD: | |
| ++loads; | |
| ++memory; | |
| if (ISJ->Core.getUnits() == slotSingleLoad || | |
| HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU) | |
| ++load0; | |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn()) | |
| foundBranches.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: | |
| case HexagonII::TypeST: | |
| ++stores; | |
| ++memory; | |
| if (ISJ->Core.getUnits() == slotSingleStore || | |
| HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_STU) | |
| ++store0; | |
| break; | |
| case HexagonII::TypeV4LDST: | |
| ++loads; | |
| ++stores; | |
| ++store1; | |
| ++memops; | |
| ++memory; | |
| break; | |
| case HexagonII::TypeNCJ: | |
| ++memory; // NV insns are memory-like. | |
| foundBranches.push_back(ISJ); | |
| break; | |
| case HexagonII::TypeV2LDST: | |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) { | |
| ++loads; | |
| ++memory; | |
| if (ISJ->Core.getUnits() == slotSingleLoad || | |
| HexagonMCInstrInfo::getType(MCII, ID) == | |
| HexagonII::TypeCVI_VM_VP_LDU) | |
| ++load0; | |
| } else { | |
| assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()); | |
| ++memory; | |
| ++stores; | |
| } | |
| break; | |
| case HexagonII::TypeCR: | |
| // Legacy conditional branch predicated on a register. | |
| case HexagonII::TypeCJ: | |
| if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch()) | |
| foundBranches.push_back(ISJ); | |
| break; | |
| case HexagonII::TypeDUPLEX: { | |
| ++duplex; | |
| MCInst const &Inst0 = *ID.getOperand(0).getInst(); | |
| MCInst const &Inst1 = *ID.getOperand(1).getInst(); | |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch()) | |
| foundBranches.push_back(ISJ); | |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch()) | |
| foundBranches.push_back(ISJ); | |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn()) | |
| foundBranches.push_back(ISJ); | |
| if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn()) | |
| foundBranches.push_back(ISJ); | |
| break; | |
| } | |
| } | |
| } | |
| applySlotRestrictions(); | |
| // Check if the packet is legal. | |
| if ((load0 > 1 || store0 > 1) || (duplex > 1 || (duplex && memory))) { | |
| reportError(llvm::Twine("invalid instruction packet")); | |
| return false; | |
| } | |
| // Modify packet accordingly. | |
| // TODO: need to reserve slots #0 and #1 for duplex insns. | |
| bool bOnlySlot3 = false; | |
| 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 (loads == 1 && loads == memory && 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 (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( | |
| llvm::Twine("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 (!store0) { | |
| if (stores == 1 && (loads == 0 || !isMemReorderDisabled())) | |
| // Pin the store to slot #0 only if isMemReorderDisabled() == false | |
| ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore); | |
| else if (stores >= 1) { | |
| if (slotLoadStore < slotLastLoadStore) { | |
| // Error if no more slots available for stores. | |
| reportError(Twine("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 (store1 && stores > 1) { | |
| // Error if a single store with another store. | |
| reportError(Twine("invalid instruction packet: too many stores")); | |
| return false; | |
| } | |
| } | |
| // flag if an instruction requires to be in slot 3 | |
| if (ISJ->Core.getUnits() == slotThree) | |
| bOnlySlot3 = true; | |
| if (!ISJ->Core.getUnits()) { | |
| // Error if insn may not be executed in any slot. | |
| reportError(Twine("invalid instruction packet: out of slots")); | |
| return false; | |
| } | |
| } | |
| // preserve branch order | |
| bool validateSlots = true; | |
| if (foundBranches.size() > 1) { | |
| if (foundBranches.size() > 2) { | |
| reportError(Twine("too many branches in packet")); | |
| return false; | |
| } | |
| // try all possible choices | |
| for (unsigned int i = 0; i < MAX_JUMP_SLOTS; ++i) { | |
| // validate first jump with this slot rule | |
| if (!(jumpSlots[i].first & foundBranches[0]->Core.getUnits())) | |
| continue; | |
| // validate second jump with this slot rule | |
| if (!(jumpSlots[i].second & foundBranches[1]->Core.getUnits())) | |
| continue; | |
| // both valid for this configuration, set new slot rules | |
| PacketSave = Packet; | |
| foundBranches[0]->Core.setUnits(jumpSlots[i].first); | |
| foundBranches[1]->Core.setUnits(jumpSlots[i].second); | |
| HexagonUnitAuction AuctionCore(reservedSlots); | |
| std::stable_sort(begin(), end(), HexagonInstr::lessCore); | |
| // see if things ok with that instruction being pinned to slot "slotJump" | |
| bool bFail = false; | |
| for (iterator I = begin(); I != end() && !bFail; ++I) | |
| if (!AuctionCore.bid(I->Core.getUnits())) | |
| bFail = true; | |
| // if yes, great, if not then restore original slot mask | |
| if (!bFail) { | |
| validateSlots = false; // all good, no need to re-do auction | |
| break; | |
| } else | |
| // restore original values | |
| Packet = PacketSave; | |
| } | |
| if (validateSlots) { | |
| reportError(Twine("invalid instruction packet: out of slots")); | |
| return false; | |
| } | |
| } | |
| if (foundBranches.size() <= 1 && bOnlySlot3 == false && pSlot3Cnt == 1 && | |
| slot3ISJ != end()) { | |
| validateSlots = true; | |
| // save off slot mask of instruction marked with A_PREFER_SLOT3 | |
| // and then pin it to slot #3 | |
| unsigned saveUnits = slot3ISJ->Core.getUnits(); | |
| slot3ISJ->Core.setUnits(saveUnits & slotThree); | |
| HexagonUnitAuction AuctionCore(reservedSlots); | |
| std::stable_sort(begin(), end(), HexagonInstr::lessCore); | |
| // see if things ok with that instruction being pinned to slot #3 | |
| bool bFail = false; | |
| for (iterator I = begin(); I != end() && !bFail; ++I) | |
| if (!AuctionCore.bid(I->Core.getUnits())) | |
| bFail = true; | |
| // if yes, great, if not then restore original slot mask | |
| if (!bFail) | |
| validateSlots = false; // all good, no need to re-do auction | |
| else | |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) { | |
| MCInst const &ID = ISJ->getDesc(); | |
| if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) | |
| ISJ->Core.setUnits(saveUnits); | |
| } | |
| } | |
| // Check if any slot, core or CVI, is over-subscribed. | |
| // Verify the core slot subscriptions. | |
| if (validateSlots) { | |
| HexagonUnitAuction AuctionCore(reservedSlots); | |
| std::stable_sort(begin(), end(), HexagonInstr::lessCore); | |
| for (iterator I = begin(); I != end(); ++I) | |
| if (!AuctionCore.bid(I->Core.getUnits())) { | |
| reportError(Twine("invalid instruction packet: slot error")); | |
| return false; | |
| } | |
| } | |
| // Verify the CVI slot subscriptions. | |
| std::stable_sort(begin(), end(), HexagonInstr::lessCVI); | |
| // create vector of hvx instructions to check | |
| HVXInstsT hvxInsts; | |
| hvxInsts.clear(); | |
| for (iterator I = begin(); I != end(); ++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::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; | |
| } | |
| for (iterator ISJ = begin(); ISJ != end(); ++ISJ) | |
| LLVM_DEBUG(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(); | |
| dbgs() << '\n'); | |
| LLVM_DEBUG(dbgs() << '\n'); | |
| return Ok; | |
| } | |
| void HexagonShuffler::reportError(Twine const &Msg) { | |
| 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); | |
| } | |
| } |