[Hexagon] Refactor HexagonShuffle
authorBrian Cain <bcain@quicinc.com>
Fri, 17 Jan 2020 18:18:59 +0000 (12:18 -0600)
committerKrzysztof Parzyszek <kparzysz@quicinc.com>
Fri, 17 Jan 2020 18:22:07 +0000 (12:22 -0600)
The check() in HexagonShuffle has been decomposed into smaller steps.
No functionality change is intended with this commit.

llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp
llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h
test/MC/Hexagon/PacketRules/restrict_slot1_aok.s [new file with mode: 0644]

index 18c7790..c665815 100644 (file)
@@ -207,6 +207,7 @@ HexagonShuffler::HexagonShuffler(MCContext &Context, bool ReportErrors,
 void HexagonShuffler::reset() {
   Packet.clear();
   BundleFlags = 0;
+  CheckFailure = false;
 }
 
 void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender,
@@ -216,227 +217,183 @@ 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:
@@ -451,13 +408,12 @@ bool HexagonShuffler::check() {
           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.
@@ -469,14 +425,15 @@ bool HexagonShuffler::check() {
 
     // 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.
@@ -485,136 +442,214 @@ bool HexagonShuffler::check() {
           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() {
@@ -653,20 +688,25 @@ 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();
index bf3bad3..63c314d 100644 (file)
 #include "MCTargetDesc/HexagonMCInstrInfo.h"
 #include "MCTargetDesc/HexagonMCTargetDesc.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/SMLoc.h"
 #include <cstdint>
+#include <functional>
 #include <utility>
 
 namespace llvm {
@@ -140,9 +142,30 @@ class HexagonShuffler {
   using HexagonPacket =
       SmallVector<HexagonInstr, HEXAGON_PRESHUFFLE_PACKET_SIZE>;
 
+  struct HexagonPacketSummary {
+    // Number of memory operations, loads, solo loads, stores, solo stores,
+    // single stores.
+    unsigned memory;
+    unsigned loads;
+    unsigned load0;
+    unsigned stores;
+    unsigned store0;
+    unsigned store1;
+    unsigned NonZCVIloads;
+    unsigned AllCVIloads;
+    unsigned CVIstores;
+    // Number of duplex insns
+    unsigned duplex;
+    unsigned pSlot3Cnt;
+    Optional<HexagonInstr *> PrefSlot3Inst;
+    unsigned memops;
+    unsigned ReservedSlotMask;
+    SmallVector<HexagonInstr *, HEXAGON_PRESHUFFLE_PACKET_SIZE> branchInsts;
+    Optional<SMLoc> Slot1AOKLoc;
+    Optional<SMLoc> NoSlot1StoreLoc;
+  };
   // Insn handles in a bundle.
   HexagonPacket Packet;
-  HexagonPacket PacketSave;
 
   HexagonCVIResource::TypeUnitsAndLanes TUL;
 
@@ -153,13 +176,28 @@ protected:
   MCSubtargetInfo const &STI;
   SMLoc Loc;
   bool ReportErrors;
+  bool CheckFailure;
   std::vector<std::pair<SMLoc, std::string>> AppliedRestrictions;
-  void applySlotRestrictions();
-  void restrictSlot1AOK();
-  void restrictNoSlot1Store();
+  bool applySlotRestrictions(HexagonPacketSummary const &Summary);
+  void restrictSlot1AOK(HexagonPacketSummary const &Summary);
+  void restrictNoSlot1Store(HexagonPacketSummary const &Summary);
+  void restrictNoSlot1();
+
+  Optional<HexagonPacket> tryAuction(HexagonPacketSummary const &Summary) const;
+
+  bool restrictStoreLoadOrder(HexagonPacketSummary const &Summary);
+  void restrictBranchOrder(HexagonPacketSummary const &Summary);
+  void restrictPreferSlot3(HexagonPacketSummary const &Summary);
+  HexagonPacketSummary GetPacketSummary();
+  bool ValidPacketMemoryOps(HexagonPacketSummary const &Summary) const;
+  bool ValidResourceUsage(HexagonPacketSummary const &Summary);
+  bool validPacketInsts() const;
 
 public:
   using iterator = HexagonPacket::iterator;
+  using const_iterator = HexagonPacket::const_iterator;
+  using packet_range = iterator_range<HexagonPacket::iterator>;
+  using const_packet_range = iterator_range<HexagonPacket::const_iterator>;
 
   HexagonShuffler(MCContext &Context, bool ReportErrors,
                   MCInstrInfo const &MCII, MCSubtargetInfo const &STI);
@@ -179,6 +217,26 @@ public:
 
   iterator begin() { return (Packet.begin()); }
   iterator end() { return (Packet.end()); }
+  const_iterator cbegin() const { return (Packet.begin()); }
+  const_iterator cend() const { return (Packet.end()); }
+  packet_range insts(HexagonPacket &P) {
+    return make_range(P.begin(), P.end());
+  }
+  const_packet_range insts(HexagonPacket const &P) const {
+    return make_range(P.begin(), P.end());
+  }
+  packet_range insts() { return make_range(begin(), end()); }
+  const_packet_range insts() const { return make_range(cbegin(), cend()); }
+
+  using InstPredicate = bool (*)(MCInstrInfo const &, MCInst const &);
+
+  bool HasInstWith(InstPredicate Pred) const {
+    return llvm::any_of(make_range(cbegin(), cend()),
+                        [&](HexagonInstr const &I) {
+                          MCInst const &Inst = I.getDesc();
+                          return (*Pred)(MCII, Inst);
+                        });
+  }
 
   // Add insn handle to the bundle .
   void append(MCInst const &ID, MCInst const *Extender, unsigned S);
diff --git a/test/MC/Hexagon/PacketRules/restrict_slot1_aok.s b/test/MC/Hexagon/PacketRules/restrict_slot1_aok.s
new file mode 100644 (file)
index 0000000..97b4d56
--- /dev/null
@@ -0,0 +1,9 @@
+# RUN: not llvm-mc -filetype=asm %s 2>&1 | FileCheck %s
+
+{ r0=sub(#1,r0)
+  r1=sub(#1, r0)
+  r2=memw(r0)
+  dczeroa(r0) }
+# CHECK: 5:3: note: Instruction was restricted from being in slot 1
+# CHECK: 6:3: note: Instruction can only be combined with an ALU instruction in slot 1
+# CHECK: 6:15: error: invalid instruction packet: slot error