void HexagonShuffler::reset() {
Packet.clear();
BundleFlags = 0;
+ CheckFailure = false;
}
void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender,
Packet.push_back(PI);
}
-static struct {
+const 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);
+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) {
- unsigned Units = ISJ->Core.getUnits();
- if (Units & 2U) {
+ 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(RestrictLoc, "Instruction can only be combine "
- "with an ALU instruction in slot 1"));
- ISJ->Core.setUnits(Units & ~2U);
+ 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() {
- 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);
- }
+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(
- RestrictLoc, "Instruction does not allow a store in slot 1"));
}
+
+ if (AppliedRestriction)
+ AppliedRestrictions.push_back(
+ std::make_pair(*Summary.NoSlot1StoreLoc,
+ "Instruction does not allow a store in slot 1"));
}
-void HexagonShuffler::applySlotRestrictions() {
- restrictSlot1AOK();
- restrictNoSlot1Store();
+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);
+
+ // 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;
}
-/// 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;
- unsigned NonZCVIloads = 0, AllCVIloads = 0, CVIstores = 0;
- // Number of duplex insns
- unsigned duplex = 0;
- unsigned pSlot3Cnt = 0;
- unsigned memops = 0;
- iterator slot3ISJ = end();
- std::vector<iterator> foundBranches;
- unsigned reservedSlots = 0;
+void HexagonShuffler::restrictBranchOrder(HexagonPacketSummary const &Summary) {
+ // preserve branch order
+ const bool HasMultipleBranches = Summary.branchInsts.size() > 1;
+ if (!HasMultipleBranches)
+ return;
- // Collect information from the insns in the packet.
- for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
- MCInst const &ID = ISJ->getDesc();
+ if (Summary.branchInsts.size() > 2) {
+ reportError(Twine("too many branches in packet"));
+ return;
+ }
- if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) {
- ++pSlot3Cnt;
- slot3ISJ = ISJ;
- }
- reservedSlots |= HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID);
+ // try all possible choices
+ for (unsigned int i = 0; i < array_lengthof(jumpSlots); ++i) {
+ // validate first jump with this slot rule
+ if (!(jumpSlots[i].first & Summary.branchInsts[0]->Core.getUnits()))
+ continue;
- 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:
- ++NonZCVIloads;
- LLVM_FALLTHROUGH;
- case HexagonII::TypeCVI_ZW:
- ++AllCVIloads;
- LLVM_FALLTHROUGH;
- 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:
- ++CVIstores;
- LLVM_FALLTHROUGH;
- 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;
- }
- }
+ // validate second jump with this slot rule
+ if (!(jumpSlots[i].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(jumpSlots[i].first);
+ Summary.branchInsts[1]->Core.setUnits(jumpSlots[i].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;
}
- applySlotRestrictions();
- // Check if the packet is legal.
- const unsigned ZCVIloads = AllCVIloads - NonZCVIloads;
- const bool ValidHVXMem =
- NonZCVIloads <= 1 && ZCVIloads <= 1 && CVIstores <= 1;
- if ((load0 > 1 || store0 > 1 || !ValidHVXMem) ||
- (duplex > 1 || (duplex && memory))) {
- reportError(llvm::Twine("invalid instruction packet"));
+ reportError("invalid instruction packet: out of slots");
+}
+
+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.
- bool bOnlySlot3 = false;
+ 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()) {
+ 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)
+ if (Summary.loads == 1 && Summary.loads == Summary.memory &&
+ Summary.memops == 0)
// Pin the load to slot #0.
switch (ID.getOpcode()) {
case Hexagon::V6_vgathermw:
ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad);
break;
}
- else if (loads >= 1 && isMemReorderDisabled()) { // }:mem_noshuf
+ 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(
- llvm::Twine("invalid instruction packet: too many loads"));
+ reportError("invalid instruction packet: too many loads");
return false;
}
// Pin the load to the highest slot available to it.
// A single store must use slot #0.
if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) {
- if (!store0) {
- if (stores == 1 && (loads == 0 || !isMemReorderDisabled()))
+ if (!Summary.store0) {
+ if (Summary.stores == 1 &&
+ (Summary.loads == 0 || !isMemReorderDisabled()))
// Pin the store to slot #0 only if isMemReorderDisabled() == false
ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore);
- else if (stores >= 1) {
+ else if (Summary.stores >= 1) {
if (slotLoadStore < slotLastLoadStore) {
// Error if no more slots available for stores.
- reportError(Twine("invalid instruction packet: too many stores"));
+ reportError("invalid instruction packet: too many stores");
return false;
}
// Pin the store to the highest slot available to it.
slotLoadStore >>= 1;
}
}
- if (store1 && stores > 1) {
+ if (Summary.store1 && Summary.stores > 1) {
// Error if a single store with another store.
- reportError(Twine("invalid instruction packet: too many stores"));
+ reportError("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"));
+ reportError("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;
- }
+ return true;
+}
- // 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;
+HexagonShuffler::HexagonPacketSummary HexagonShuffler::GetPacketSummary() {
+ HexagonPacketSummary Summary = HexagonPacketSummary();
- // validate second jump with this slot rule
- if (!(jumpSlots[i].second & foundBranches[1]->Core.getUnits()))
- continue;
+ // 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();
- // 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 (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_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;
}
- if (validateSlots) {
- reportError(Twine("invalid instruction packet: out of slots"));
- return false;
}
}
+ return Summary;
+}
- 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);
+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)));
- HexagonUnitAuction AuctionCore(reservedSlots);
- std::stable_sort(begin(), end(), HexagonInstr::lessCore);
+ return !InvalidPacket;
+}
- // 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;
+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);
+}
- // 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 that the packet is legal and enforce relative insn order.
+bool HexagonShuffler::check() {
+ const HexagonPacketSummary Summary = GetPacketSummary();
+ if (!applySlotRestrictions(Summary))
+ return false;
- // Check if any slot, core or CVI, is over-subscribed.
- // Verify the core slot subscriptions.
- if (validateSlots) {
- HexagonUnitAuction AuctionCore(reservedSlots);
+ if (!ValidPacketMemoryOps(Summary)) {
+ reportError("invalid instruction packet");
+ return false;
+ }
- std::stable_sort(begin(), end(), HexagonInstr::lessCore);
+ ValidResourceUsage(Summary);
- 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 !CheckFailure;
+}
- return true;
+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() {
++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');
+ 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();