10b57cec5SDimitry Andric //===- HexagonShuffler.cpp - Instruction bundle shuffling -----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This implements the shuffling of insns inside a bundle according to the
100b57cec5SDimitry Andric // packet formation rules of the Hexagon ISA.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "MCTargetDesc/HexagonShuffler.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/HexagonBaseInfo.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/HexagonMCInstrInfo.h"
170b57cec5SDimitry Andric #include "MCTargetDesc/HexagonMCTargetDesc.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
1906c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
250b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
260b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
270b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
280b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h"
290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
300b57cec5SDimitry Andric #include <algorithm>
310b57cec5SDimitry Andric #include <cassert>
32bdd1243dSDimitry Andric #include <optional>
330b57cec5SDimitry Andric #include <utility>
340b57cec5SDimitry Andric
35fe6060f1SDimitry Andric #define DEBUG_TYPE "hexagon-shuffle"
36fe6060f1SDimitry Andric
370b57cec5SDimitry Andric using namespace llvm;
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric namespace {
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric // Insn shuffling priority.
420b57cec5SDimitry Andric class HexagonBid {
430b57cec5SDimitry Andric // The priority is directly proportional to how restricted the insn is based
440b57cec5SDimitry Andric // on its flexibility to run on the available slots. So, the fewer slots it
450b57cec5SDimitry Andric // may run on, the higher its priority.
460b57cec5SDimitry Andric enum { MAX = 360360 }; // LCD of 1/2, 1/3, 1/4,... 1/15.
470b57cec5SDimitry Andric unsigned Bid = 0;
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric public:
500b57cec5SDimitry Andric HexagonBid() = default;
HexagonBid(unsigned B)51bdd1243dSDimitry Andric HexagonBid(unsigned B) { Bid = B ? MAX / llvm::popcount(B) : 0; }
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric // Check if the insn priority is overflowed.
isSold() const540b57cec5SDimitry Andric bool isSold() const { return (Bid >= MAX); }
550b57cec5SDimitry Andric
operator +=(const HexagonBid & B)560b57cec5SDimitry Andric HexagonBid &operator+=(const HexagonBid &B) {
570b57cec5SDimitry Andric Bid += B.Bid;
580b57cec5SDimitry Andric return *this;
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric };
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric // Slot shuffling allocation.
630b57cec5SDimitry Andric class HexagonUnitAuction {
640b57cec5SDimitry Andric HexagonBid Scores[HEXAGON_PACKET_SIZE];
650b57cec5SDimitry Andric // Mask indicating which slot is unavailable.
660b57cec5SDimitry Andric unsigned isSold : HEXAGON_PACKET_SIZE;
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric public:
HexagonUnitAuction(unsigned cs=0)690b57cec5SDimitry Andric HexagonUnitAuction(unsigned cs = 0) : isSold(cs) {}
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric // Allocate slots.
bid(unsigned B)720b57cec5SDimitry Andric bool bid(unsigned B) {
730b57cec5SDimitry Andric // Exclude already auctioned slots from the bid.
740b57cec5SDimitry Andric unsigned b = B & ~isSold;
750b57cec5SDimitry Andric if (b) {
760b57cec5SDimitry Andric for (unsigned i = 0; i < HEXAGON_PACKET_SIZE; ++i)
770b57cec5SDimitry Andric if (b & (1 << i)) {
780b57cec5SDimitry Andric // Request candidate slots.
790b57cec5SDimitry Andric Scores[i] += HexagonBid(b);
800b57cec5SDimitry Andric isSold |= Scores[i].isSold() << i;
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric return true;
830b57cec5SDimitry Andric } else
840b57cec5SDimitry Andric // Error if the desired slots are already full.
850b57cec5SDimitry Andric return false;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric };
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric } // end anonymous namespace
900b57cec5SDimitry Andric
setWeight(unsigned s)910b57cec5SDimitry Andric unsigned HexagonResource::setWeight(unsigned s) {
920b57cec5SDimitry Andric const unsigned SlotWeight = 8;
930b57cec5SDimitry Andric const unsigned MaskWeight = SlotWeight - 1;
940b57cec5SDimitry Andric unsigned Units = getUnits();
950b57cec5SDimitry Andric unsigned Key = ((1u << s) & Units) != 0;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric // Calculate relative weight of the insn for the given slot, weighing it the
980b57cec5SDimitry Andric // heavier the more restrictive the insn is and the lowest the slots that the
990b57cec5SDimitry Andric // insn may be executed in.
1000b57cec5SDimitry Andric if (Key == 0 || Units == 0 || (SlotWeight * s >= 32))
1010b57cec5SDimitry Andric return Weight = 0;
1020b57cec5SDimitry Andric
103bdd1243dSDimitry Andric unsigned Ctpop = llvm::popcount(Units);
10406c3fb27SDimitry Andric unsigned Cttz = llvm::countr_zero(Units);
1050b57cec5SDimitry Andric Weight = (1u << (SlotWeight * s)) * ((MaskWeight - Ctpop) << Cttz);
1060b57cec5SDimitry Andric return Weight;
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric
HexagonCVIResource(MCInstrInfo const & MCII,MCSubtargetInfo const & STI,unsigned s,MCInst const * id)1095ffd83dbSDimitry Andric HexagonCVIResource::HexagonCVIResource(MCInstrInfo const &MCII,
1105ffd83dbSDimitry Andric MCSubtargetInfo const &STI,
1115ffd83dbSDimitry Andric unsigned s,
1120b57cec5SDimitry Andric MCInst const *id)
1130b57cec5SDimitry Andric : HexagonResource(s) {
1140b57cec5SDimitry Andric
1155ffd83dbSDimitry Andric const unsigned ItinUnits = HexagonMCInstrInfo::getCVIResources(MCII, STI, *id);
1165ffd83dbSDimitry Andric unsigned Lanes;
1175ffd83dbSDimitry Andric const unsigned Units = HexagonConvertUnits(ItinUnits, &Lanes);
1185ffd83dbSDimitry Andric
1195ffd83dbSDimitry Andric if (Units == 0 && Lanes == 0) {
1200b57cec5SDimitry Andric // For core insns.
1210b57cec5SDimitry Andric Valid = false;
1220b57cec5SDimitry Andric setUnits(0);
1230b57cec5SDimitry Andric setLanes(0);
1240b57cec5SDimitry Andric setLoad(false);
1250b57cec5SDimitry Andric setStore(false);
1265ffd83dbSDimitry Andric } else {
1275ffd83dbSDimitry Andric // For an HVX insn.
1285ffd83dbSDimitry Andric Valid = true;
1295ffd83dbSDimitry Andric setUnits(Units);
1305ffd83dbSDimitry Andric setLanes(Lanes);
1315ffd83dbSDimitry Andric setLoad(HexagonMCInstrInfo::getDesc(MCII, *id).mayLoad());
1325ffd83dbSDimitry Andric setStore(HexagonMCInstrInfo::getDesc(MCII, *id).mayStore());
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric struct CVIUnits {
1370b57cec5SDimitry Andric unsigned Units;
1380b57cec5SDimitry Andric unsigned Lanes;
1390b57cec5SDimitry Andric };
1400b57cec5SDimitry Andric using HVXInstsT = SmallVector<struct CVIUnits, 8>;
1410b57cec5SDimitry Andric
makeAllBits(unsigned startBit,unsigned Lanes)1420b57cec5SDimitry Andric static unsigned makeAllBits(unsigned startBit, unsigned Lanes)
1430b57cec5SDimitry Andric {
1440b57cec5SDimitry Andric for (unsigned i = 1; i < Lanes; ++i)
1450b57cec5SDimitry Andric startBit = (startBit << 1) | startBit;
1460b57cec5SDimitry Andric return startBit;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric
checkHVXPipes(const HVXInstsT & hvxInsts,unsigned startIdx,unsigned usedUnits)1490b57cec5SDimitry Andric static bool checkHVXPipes(const HVXInstsT &hvxInsts, unsigned startIdx,
1500b57cec5SDimitry Andric unsigned usedUnits) {
1510b57cec5SDimitry Andric if (startIdx < hvxInsts.size()) {
1520b57cec5SDimitry Andric if (!hvxInsts[startIdx].Units)
1530b57cec5SDimitry Andric return checkHVXPipes(hvxInsts, startIdx + 1, usedUnits);
1540b57cec5SDimitry Andric for (unsigned b = 0x1; b <= 0x8; b <<= 1) {
1550b57cec5SDimitry Andric if ((hvxInsts[startIdx].Units & b) == 0)
1560b57cec5SDimitry Andric continue;
1570b57cec5SDimitry Andric unsigned allBits = makeAllBits(b, hvxInsts[startIdx].Lanes);
1580b57cec5SDimitry Andric if ((allBits & usedUnits) == 0) {
1590b57cec5SDimitry Andric if (checkHVXPipes(hvxInsts, startIdx + 1, usedUnits | allBits))
1600b57cec5SDimitry Andric return true;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric return false;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric return true;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
HexagonShuffler(MCContext & Context,bool ReportErrors,MCInstrInfo const & MCII,MCSubtargetInfo const & STI)1680b57cec5SDimitry Andric HexagonShuffler::HexagonShuffler(MCContext &Context, bool ReportErrors,
1690b57cec5SDimitry Andric MCInstrInfo const &MCII,
1700b57cec5SDimitry Andric MCSubtargetInfo const &STI)
17104eeddc0SDimitry Andric : Context(Context), BundleFlags(), MCII(MCII), STI(STI),
17204eeddc0SDimitry Andric ReportErrors(ReportErrors), CheckFailure() {
1730b57cec5SDimitry Andric reset();
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric
reset()1760b57cec5SDimitry Andric void HexagonShuffler::reset() {
1770b57cec5SDimitry Andric Packet.clear();
1780b57cec5SDimitry Andric BundleFlags = 0;
1795ffd83dbSDimitry Andric CheckFailure = false;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
append(MCInst const & ID,MCInst const * Extender,unsigned S)1820b57cec5SDimitry Andric void HexagonShuffler::append(MCInst const &ID, MCInst const *Extender,
1830b57cec5SDimitry Andric unsigned S) {
1845ffd83dbSDimitry Andric HexagonInstr PI(MCII, STI, &ID, Extender, S);
1850b57cec5SDimitry Andric
1860b57cec5SDimitry Andric Packet.push_back(PI);
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric
1905ffd83dbSDimitry Andric static const unsigned Slot0Mask = 1 << 0;
1915ffd83dbSDimitry Andric static const unsigned Slot1Mask = 1 << 1;
1925ffd83dbSDimitry Andric static const unsigned Slot3Mask = 1 << 3;
1935ffd83dbSDimitry Andric static const unsigned slotSingleLoad = Slot0Mask;
1945ffd83dbSDimitry Andric static const unsigned slotSingleStore = Slot0Mask;
1955ffd83dbSDimitry Andric
restrictSlot1AOK(HexagonPacketSummary const & Summary)1965ffd83dbSDimitry Andric void HexagonShuffler::restrictSlot1AOK(HexagonPacketSummary const &Summary) {
1975ffd83dbSDimitry Andric if (Summary.Slot1AOKLoc)
1985ffd83dbSDimitry Andric for (HexagonInstr &ISJ : insts()) {
1995ffd83dbSDimitry Andric MCInst const &Inst = ISJ.getDesc();
2005ffd83dbSDimitry Andric const unsigned Type = HexagonMCInstrInfo::getType(MCII, Inst);
2010b57cec5SDimitry Andric if (Type != HexagonII::TypeALU32_2op &&
2020b57cec5SDimitry Andric Type != HexagonII::TypeALU32_3op &&
2030b57cec5SDimitry Andric Type != HexagonII::TypeALU32_ADDI) {
2045ffd83dbSDimitry Andric const unsigned Units = ISJ.Core.getUnits();
2055ffd83dbSDimitry Andric
2065ffd83dbSDimitry Andric if (Units & Slot1Mask) {
2070b57cec5SDimitry Andric AppliedRestrictions.push_back(std::make_pair(
2080b57cec5SDimitry Andric Inst.getLoc(),
2090b57cec5SDimitry Andric "Instruction was restricted from being in slot 1"));
2105ffd83dbSDimitry Andric AppliedRestrictions.push_back(std::make_pair(
2115ffd83dbSDimitry Andric *Summary.Slot1AOKLoc, "Instruction can only be combined "
2120b57cec5SDimitry Andric "with an ALU instruction in slot 1"));
2135ffd83dbSDimitry Andric ISJ.Core.setUnits(Units & ~Slot1Mask);
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
restrictNoSlot1Store(HexagonPacketSummary const & Summary)2195ffd83dbSDimitry Andric void HexagonShuffler::restrictNoSlot1Store(
2205ffd83dbSDimitry Andric HexagonPacketSummary const &Summary) {
2215ffd83dbSDimitry Andric // If this packet contains an instruction that bars slot-1 stores,
2225ffd83dbSDimitry Andric // we should mask off slot 1 from all of the store instructions in
2235ffd83dbSDimitry Andric // this packet.
2245ffd83dbSDimitry Andric
2255ffd83dbSDimitry Andric if (!Summary.NoSlot1StoreLoc)
2265ffd83dbSDimitry Andric return;
2275ffd83dbSDimitry Andric
2280b57cec5SDimitry Andric bool AppliedRestriction = false;
2295ffd83dbSDimitry Andric
2305ffd83dbSDimitry Andric for (HexagonInstr &ISJ : insts()) {
2315ffd83dbSDimitry Andric MCInst const &Inst = ISJ.getDesc();
2320b57cec5SDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, Inst).mayStore()) {
2335ffd83dbSDimitry Andric unsigned Units = ISJ.Core.getUnits();
2345ffd83dbSDimitry Andric if (Units & Slot1Mask) {
2350b57cec5SDimitry Andric AppliedRestriction = true;
2360b57cec5SDimitry Andric AppliedRestrictions.push_back(std::make_pair(
2375ffd83dbSDimitry Andric Inst.getLoc(), "Instruction was restricted from being in slot 1"));
2385ffd83dbSDimitry Andric ISJ.Core.setUnits(Units & ~Slot1Mask);
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric }
2425ffd83dbSDimitry Andric
2430b57cec5SDimitry Andric if (AppliedRestriction)
2445ffd83dbSDimitry Andric AppliedRestrictions.push_back(
2455ffd83dbSDimitry Andric std::make_pair(*Summary.NoSlot1StoreLoc,
2465ffd83dbSDimitry Andric "Instruction does not allow a store in slot 1"));
2475ffd83dbSDimitry Andric }
2485ffd83dbSDimitry Andric
applySlotRestrictions(HexagonPacketSummary const & Summary,const bool DoShuffle)24904eeddc0SDimitry Andric bool HexagonShuffler::applySlotRestrictions(HexagonPacketSummary const &Summary,
25004eeddc0SDimitry Andric const bool DoShuffle) {
2515ffd83dbSDimitry Andric // These restrictions can modify the slot masks in the instructions
2525ffd83dbSDimitry Andric // in the Packet member. They should run unconditionally and their
2535ffd83dbSDimitry Andric // order does not matter.
2545ffd83dbSDimitry Andric restrictSlot1AOK(Summary);
2555ffd83dbSDimitry Andric restrictNoSlot1Store(Summary);
2565ffd83dbSDimitry Andric
2575ffd83dbSDimitry Andric permitNonSlot();
2585ffd83dbSDimitry Andric
2595ffd83dbSDimitry Andric // These restrictions can modify the slot masks in the instructions
2605ffd83dbSDimitry Andric // in the Packet member, but they can also detect constraint failures
2615ffd83dbSDimitry Andric // which are fatal.
2625ffd83dbSDimitry Andric if (!CheckFailure)
2635ffd83dbSDimitry Andric restrictStoreLoadOrder(Summary);
2645ffd83dbSDimitry Andric if (!CheckFailure)
2655ffd83dbSDimitry Andric restrictBranchOrder(Summary);
2665ffd83dbSDimitry Andric if (!CheckFailure)
26704eeddc0SDimitry Andric restrictPreferSlot3(Summary, DoShuffle);
2685ffd83dbSDimitry Andric return !CheckFailure;
2695ffd83dbSDimitry Andric }
2705ffd83dbSDimitry Andric
restrictBranchOrder(HexagonPacketSummary const & Summary)2715ffd83dbSDimitry Andric void HexagonShuffler::restrictBranchOrder(HexagonPacketSummary const &Summary) {
2725ffd83dbSDimitry Andric // preserve branch order
2735ffd83dbSDimitry Andric const bool HasMultipleBranches = Summary.branchInsts.size() > 1;
2745ffd83dbSDimitry Andric if (!HasMultipleBranches)
2755ffd83dbSDimitry Andric return;
2765ffd83dbSDimitry Andric
2775ffd83dbSDimitry Andric if (Summary.branchInsts.size() > 2) {
2785ffd83dbSDimitry Andric reportError(Twine("too many branches in packet"));
2795ffd83dbSDimitry Andric return;
2805ffd83dbSDimitry Andric }
2815ffd83dbSDimitry Andric
2825ffd83dbSDimitry Andric const static std::pair<unsigned, unsigned> jumpSlots[] = {
2835ffd83dbSDimitry Andric {8, 4}, {8, 2}, {8, 1}, {4, 2}, {4, 1}, {2, 1}};
2845ffd83dbSDimitry Andric // try all possible choices
2855ffd83dbSDimitry Andric for (std::pair<unsigned, unsigned> jumpSlot : jumpSlots) {
2865ffd83dbSDimitry Andric // validate first jump with this slot rule
2875ffd83dbSDimitry Andric if (!(jumpSlot.first & Summary.branchInsts[0]->Core.getUnits()))
2885ffd83dbSDimitry Andric continue;
2895ffd83dbSDimitry Andric
2905ffd83dbSDimitry Andric // validate second jump with this slot rule
2915ffd83dbSDimitry Andric if (!(jumpSlot.second & Summary.branchInsts[1]->Core.getUnits()))
2925ffd83dbSDimitry Andric continue;
2935ffd83dbSDimitry Andric
2945ffd83dbSDimitry Andric // both valid for this configuration, set new slot rules
2955ffd83dbSDimitry Andric const HexagonPacket PacketSave = Packet;
2965ffd83dbSDimitry Andric Summary.branchInsts[0]->Core.setUnits(jumpSlot.first);
2975ffd83dbSDimitry Andric Summary.branchInsts[1]->Core.setUnits(jumpSlot.second);
2985ffd83dbSDimitry Andric
29981ad6265SDimitry Andric const bool HasShuffledPacket = tryAuction(Summary).has_value();
3005ffd83dbSDimitry Andric if (HasShuffledPacket)
3015ffd83dbSDimitry Andric return;
3025ffd83dbSDimitry Andric
3035ffd83dbSDimitry Andric // if yes, great, if not then restore original slot mask
3045ffd83dbSDimitry Andric // restore original values
3055ffd83dbSDimitry Andric Packet = PacketSave;
3065ffd83dbSDimitry Andric }
3075ffd83dbSDimitry Andric
30804eeddc0SDimitry Andric reportResourceError(Summary, "out of slots");
3095ffd83dbSDimitry Andric }
3105ffd83dbSDimitry Andric
permitNonSlot()3115ffd83dbSDimitry Andric void HexagonShuffler::permitNonSlot() {
3125ffd83dbSDimitry Andric for (HexagonInstr &ISJ : insts()) {
3135ffd83dbSDimitry Andric const bool RequiresSlot = HexagonMCInstrInfo::requiresSlot(STI, *ISJ.ID);
3145ffd83dbSDimitry Andric if (!RequiresSlot)
3155ffd83dbSDimitry Andric ISJ.Core.setAllUnits();
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric
ValidResourceUsage(HexagonPacketSummary const & Summary)3195ffd83dbSDimitry Andric bool HexagonShuffler::ValidResourceUsage(HexagonPacketSummary const &Summary) {
320bdd1243dSDimitry Andric std::optional<HexagonPacket> ShuffledPacket = tryAuction(Summary);
3210b57cec5SDimitry Andric
3225ffd83dbSDimitry Andric if (!ShuffledPacket) {
32304eeddc0SDimitry Andric reportResourceError(Summary, "slot error");
3245ffd83dbSDimitry Andric return false;
3250b57cec5SDimitry Andric }
3260b57cec5SDimitry Andric
3275ffd83dbSDimitry Andric // Verify the CVI slot subscriptions.
32804eeddc0SDimitry Andric llvm::stable_sort(*ShuffledPacket, HexagonInstr::lessCVI);
3295ffd83dbSDimitry Andric // create vector of hvx instructions to check
3305ffd83dbSDimitry Andric HVXInstsT hvxInsts;
3315ffd83dbSDimitry Andric hvxInsts.clear();
33204eeddc0SDimitry Andric for (const auto &I : *ShuffledPacket) {
3335ffd83dbSDimitry Andric struct CVIUnits inst;
33404eeddc0SDimitry Andric inst.Units = I.CVI.getUnits();
33504eeddc0SDimitry Andric inst.Lanes = I.CVI.getLanes();
3365ffd83dbSDimitry Andric if (inst.Units == 0)
3375ffd83dbSDimitry Andric continue; // not an hvx inst or an hvx inst that doesn't uses any pipes
3385ffd83dbSDimitry Andric hvxInsts.push_back(inst);
3395ffd83dbSDimitry Andric }
3405ffd83dbSDimitry Andric
3415ffd83dbSDimitry Andric // if there are any hvx instructions in this packet, check pipe usage
3425ffd83dbSDimitry Andric if (hvxInsts.size() > 0) {
3435ffd83dbSDimitry Andric unsigned startIdx, usedUnits;
3445ffd83dbSDimitry Andric startIdx = usedUnits = 0x0;
3455ffd83dbSDimitry Andric if (!checkHVXPipes(hvxInsts, startIdx, usedUnits)) {
3465ffd83dbSDimitry Andric // too many pipes used to be valid
3475ffd83dbSDimitry Andric reportError(Twine("invalid instruction packet: slot error"));
3480b57cec5SDimitry Andric return false;
3490b57cec5SDimitry Andric }
3505ffd83dbSDimitry Andric }
35104eeddc0SDimitry Andric
35204eeddc0SDimitry Andric Packet = *ShuffledPacket;
35304eeddc0SDimitry Andric
3545ffd83dbSDimitry Andric return true;
3555ffd83dbSDimitry Andric }
3560b57cec5SDimitry Andric
restrictStoreLoadOrder(HexagonPacketSummary const & Summary)3575ffd83dbSDimitry Andric bool HexagonShuffler::restrictStoreLoadOrder(
3585ffd83dbSDimitry Andric HexagonPacketSummary const &Summary) {
3590b57cec5SDimitry Andric // Modify packet accordingly.
3600b57cec5SDimitry Andric // TODO: need to reserve slots #0 and #1 for duplex insns.
3615ffd83dbSDimitry Andric static const unsigned slotFirstLoadStore = Slot1Mask;
3625ffd83dbSDimitry Andric static const unsigned slotLastLoadStore = Slot0Mask;
3635ffd83dbSDimitry Andric unsigned slotLoadStore = slotFirstLoadStore;
3645ffd83dbSDimitry Andric
3650b57cec5SDimitry Andric for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
3660b57cec5SDimitry Andric MCInst const &ID = ISJ->getDesc();
3670b57cec5SDimitry Andric
3685ffd83dbSDimitry Andric if (!ISJ->Core.getUnits())
3690b57cec5SDimitry Andric // Error if insn may not be executed in any slot.
3700b57cec5SDimitry Andric return false;
3710b57cec5SDimitry Andric
3720b57cec5SDimitry Andric // A single load must use slot #0.
3730b57cec5SDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) {
3745ffd83dbSDimitry Andric if (Summary.loads == 1 && Summary.loads == Summary.memory &&
3755ffd83dbSDimitry Andric Summary.memops == 0)
3760b57cec5SDimitry Andric // Pin the load to slot #0.
3770b57cec5SDimitry Andric switch (ID.getOpcode()) {
3780b57cec5SDimitry Andric case Hexagon::V6_vgathermw:
3790b57cec5SDimitry Andric case Hexagon::V6_vgathermh:
3800b57cec5SDimitry Andric case Hexagon::V6_vgathermhw:
3810b57cec5SDimitry Andric case Hexagon::V6_vgathermwq:
3820b57cec5SDimitry Andric case Hexagon::V6_vgathermhq:
3830b57cec5SDimitry Andric case Hexagon::V6_vgathermhwq:
3840b57cec5SDimitry Andric // Slot1 only loads
3850b57cec5SDimitry Andric break;
3860b57cec5SDimitry Andric default:
3870b57cec5SDimitry Andric ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad);
3880b57cec5SDimitry Andric break;
3890b57cec5SDimitry Andric }
3905ffd83dbSDimitry Andric else if (Summary.loads >= 1 && isMemReorderDisabled()) { // }:mem_noshuf
3910b57cec5SDimitry Andric // Loads must keep the original order ONLY if
3920b57cec5SDimitry Andric // isMemReorderDisabled() == true
3930b57cec5SDimitry Andric if (slotLoadStore < slotLastLoadStore) {
3940b57cec5SDimitry Andric // Error if no more slots available for loads.
3955ffd83dbSDimitry Andric reportError("invalid instruction packet: too many loads");
3960b57cec5SDimitry Andric return false;
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric // Pin the load to the highest slot available to it.
3990b57cec5SDimitry Andric ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore);
4000b57cec5SDimitry Andric // Update the next highest slot available to loads.
4010b57cec5SDimitry Andric slotLoadStore >>= 1;
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric
4050b57cec5SDimitry Andric // A single store must use slot #0.
4060b57cec5SDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, ID).mayStore()) {
4075ffd83dbSDimitry Andric if (!Summary.store0) {
4085ffd83dbSDimitry Andric const bool PacketHasNoOnlySlot0 =
4095ffd83dbSDimitry Andric llvm::none_of(insts(), [&](HexagonInstr const &I) {
4105ffd83dbSDimitry Andric return I.Core.getUnits() == Slot0Mask &&
4115ffd83dbSDimitry Andric I.ID->getOpcode() != ID.getOpcode();
4125ffd83dbSDimitry Andric });
4135ffd83dbSDimitry Andric const bool SafeToMoveToSlot0 =
4145ffd83dbSDimitry Andric (Summary.loads == 0) ||
4155ffd83dbSDimitry Andric (!isMemReorderDisabled() && PacketHasNoOnlySlot0);
4165ffd83dbSDimitry Andric
4175ffd83dbSDimitry Andric if (Summary.stores == 1 && SafeToMoveToSlot0)
4180b57cec5SDimitry Andric // Pin the store to slot #0 only if isMemReorderDisabled() == false
4190b57cec5SDimitry Andric ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore);
4205ffd83dbSDimitry Andric else if (Summary.stores >= 1) {
4210b57cec5SDimitry Andric if (slotLoadStore < slotLastLoadStore) {
4220b57cec5SDimitry Andric // Error if no more slots available for stores.
4235ffd83dbSDimitry Andric reportError("invalid instruction packet: too many stores");
4240b57cec5SDimitry Andric return false;
4250b57cec5SDimitry Andric }
4260b57cec5SDimitry Andric // Pin the store to the highest slot available to it.
4270b57cec5SDimitry Andric ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore);
4280b57cec5SDimitry Andric // Update the next highest slot available to stores.
4290b57cec5SDimitry Andric slotLoadStore >>= 1;
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric }
4325ffd83dbSDimitry Andric if (Summary.store1 && Summary.stores > 1) {
4330b57cec5SDimitry Andric // Error if a single store with another store.
4345ffd83dbSDimitry Andric reportError("invalid instruction packet: too many stores");
4350b57cec5SDimitry Andric return false;
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric
4400b57cec5SDimitry Andric return true;
4410b57cec5SDimitry Andric }
4420b57cec5SDimitry Andric
SlotMaskToText(unsigned SlotMask)44304eeddc0SDimitry Andric static std::string SlotMaskToText(unsigned SlotMask) {
44404eeddc0SDimitry Andric SmallVector<std::string, HEXAGON_PRESHUFFLE_PACKET_SIZE> Slots;
44504eeddc0SDimitry Andric for (unsigned SlotNum = 0; SlotNum < HEXAGON_PACKET_SIZE; SlotNum++)
44604eeddc0SDimitry Andric if ((SlotMask & (1 << SlotNum)) != 0)
44704eeddc0SDimitry Andric Slots.push_back(utostr(SlotNum));
44804eeddc0SDimitry Andric
44904eeddc0SDimitry Andric return llvm::join(Slots, StringRef(", "));
45004eeddc0SDimitry Andric }
45104eeddc0SDimitry Andric
GetPacketSummary()4525ffd83dbSDimitry Andric HexagonShuffler::HexagonPacketSummary HexagonShuffler::GetPacketSummary() {
4535ffd83dbSDimitry Andric HexagonPacketSummary Summary = HexagonPacketSummary();
4545ffd83dbSDimitry Andric
4555ffd83dbSDimitry Andric // Collect information from the insns in the packet.
4565ffd83dbSDimitry Andric for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
4575ffd83dbSDimitry Andric MCInst const &ID = ISJ->getDesc();
4585ffd83dbSDimitry Andric
4595ffd83dbSDimitry Andric if (HexagonMCInstrInfo::isRestrictSlot1AOK(MCII, ID))
4605ffd83dbSDimitry Andric Summary.Slot1AOKLoc = ID.getLoc();
4615ffd83dbSDimitry Andric if (HexagonMCInstrInfo::isRestrictNoSlot1Store(MCII, ID))
4625ffd83dbSDimitry Andric Summary.NoSlot1StoreLoc = ID.getLoc();
4635ffd83dbSDimitry Andric
4645ffd83dbSDimitry Andric if (HexagonMCInstrInfo::prefersSlot3(MCII, ID)) {
4655ffd83dbSDimitry Andric ++Summary.pSlot3Cnt;
4665ffd83dbSDimitry Andric Summary.PrefSlot3Inst = ISJ;
4675ffd83dbSDimitry Andric }
46804eeddc0SDimitry Andric const unsigned ReservedSlots =
4695ffd83dbSDimitry Andric HexagonMCInstrInfo::getOtherReservedSlots(MCII, STI, ID);
47004eeddc0SDimitry Andric Summary.ReservedSlotMask |= ReservedSlots;
47104eeddc0SDimitry Andric if (ReservedSlots != 0)
47204eeddc0SDimitry Andric AppliedRestrictions.push_back(std::make_pair(ID.getLoc(),
47304eeddc0SDimitry Andric (Twine("Instruction has reserved slots: ") +
47404eeddc0SDimitry Andric SlotMaskToText(ReservedSlots)).str()));
4755ffd83dbSDimitry Andric
4765ffd83dbSDimitry Andric switch (HexagonMCInstrInfo::getType(MCII, ID)) {
4775ffd83dbSDimitry Andric case HexagonII::TypeS_2op:
4785ffd83dbSDimitry Andric case HexagonII::TypeS_3op:
4795ffd83dbSDimitry Andric case HexagonII::TypeALU64:
4805ffd83dbSDimitry Andric break;
4815ffd83dbSDimitry Andric case HexagonII::TypeJ:
48204eeddc0SDimitry Andric if (HexagonMCInstrInfo::IsABranchingInst(MCII, STI, *ISJ->ID))
4835ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
4845ffd83dbSDimitry Andric break;
4855ffd83dbSDimitry Andric case HexagonII::TypeCVI_VM_VP_LDU:
4865ffd83dbSDimitry Andric case HexagonII::TypeCVI_VM_LD:
4875ffd83dbSDimitry Andric case HexagonII::TypeCVI_VM_TMP_LD:
4885ffd83dbSDimitry Andric case HexagonII::TypeCVI_GATHER:
4895ffd83dbSDimitry Andric case HexagonII::TypeCVI_GATHER_DV:
4905ffd83dbSDimitry Andric case HexagonII::TypeCVI_GATHER_RST:
4915ffd83dbSDimitry Andric ++Summary.NonZCVIloads;
492bdd1243dSDimitry Andric [[fallthrough]];
4935ffd83dbSDimitry Andric case HexagonII::TypeCVI_ZW:
4945ffd83dbSDimitry Andric ++Summary.AllCVIloads;
495bdd1243dSDimitry Andric [[fallthrough]];
4965ffd83dbSDimitry Andric case HexagonII::TypeLD:
4975ffd83dbSDimitry Andric ++Summary.loads;
4985ffd83dbSDimitry Andric ++Summary.memory;
4995ffd83dbSDimitry Andric if (ISJ->Core.getUnits() == slotSingleLoad ||
5005ffd83dbSDimitry Andric HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_VP_LDU)
5015ffd83dbSDimitry Andric ++Summary.load0;
5025ffd83dbSDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, ID).isReturn())
5035ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
5045ffd83dbSDimitry Andric break;
5055ffd83dbSDimitry Andric case HexagonII::TypeCVI_VM_STU:
5065ffd83dbSDimitry Andric case HexagonII::TypeCVI_VM_ST:
5075ffd83dbSDimitry Andric case HexagonII::TypeCVI_VM_NEW_ST:
5085ffd83dbSDimitry Andric case HexagonII::TypeCVI_SCATTER:
5095ffd83dbSDimitry Andric case HexagonII::TypeCVI_SCATTER_DV:
5105ffd83dbSDimitry Andric case HexagonII::TypeCVI_SCATTER_RST:
5115ffd83dbSDimitry Andric case HexagonII::TypeCVI_SCATTER_NEW_RST:
5125ffd83dbSDimitry Andric case HexagonII::TypeCVI_SCATTER_NEW_ST:
5135ffd83dbSDimitry Andric ++Summary.CVIstores;
514bdd1243dSDimitry Andric [[fallthrough]];
5155ffd83dbSDimitry Andric case HexagonII::TypeST:
5165ffd83dbSDimitry Andric ++Summary.stores;
5175ffd83dbSDimitry Andric ++Summary.memory;
5185ffd83dbSDimitry Andric if (ISJ->Core.getUnits() == slotSingleStore ||
5195ffd83dbSDimitry Andric HexagonMCInstrInfo::getType(MCII, ID) == HexagonII::TypeCVI_VM_STU)
5205ffd83dbSDimitry Andric ++Summary.store0;
5215ffd83dbSDimitry Andric break;
5225ffd83dbSDimitry Andric case HexagonII::TypeV4LDST:
5235ffd83dbSDimitry Andric ++Summary.loads;
5245ffd83dbSDimitry Andric ++Summary.stores;
5255ffd83dbSDimitry Andric ++Summary.store1;
5265ffd83dbSDimitry Andric ++Summary.memops;
5275ffd83dbSDimitry Andric ++Summary.memory;
5285ffd83dbSDimitry Andric break;
5295ffd83dbSDimitry Andric case HexagonII::TypeNCJ:
5305ffd83dbSDimitry Andric ++Summary.memory; // NV insns are memory-like.
5315ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
5325ffd83dbSDimitry Andric break;
5335ffd83dbSDimitry Andric case HexagonII::TypeV2LDST:
5345ffd83dbSDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, ID).mayLoad()) {
5355ffd83dbSDimitry Andric ++Summary.loads;
5365ffd83dbSDimitry Andric ++Summary.memory;
5375ffd83dbSDimitry Andric if (ISJ->Core.getUnits() == slotSingleLoad ||
5385ffd83dbSDimitry Andric HexagonMCInstrInfo::getType(MCII, ID) ==
5395ffd83dbSDimitry Andric HexagonII::TypeCVI_VM_VP_LDU)
5405ffd83dbSDimitry Andric ++Summary.load0;
5415ffd83dbSDimitry Andric } else {
5425ffd83dbSDimitry Andric assert(HexagonMCInstrInfo::getDesc(MCII, ID).mayStore());
5435ffd83dbSDimitry Andric ++Summary.memory;
5445ffd83dbSDimitry Andric ++Summary.stores;
5455ffd83dbSDimitry Andric }
5465ffd83dbSDimitry Andric break;
5475ffd83dbSDimitry Andric case HexagonII::TypeCR:
5485ffd83dbSDimitry Andric // Legacy conditional branch predicated on a register.
5495ffd83dbSDimitry Andric case HexagonII::TypeCJ:
5505ffd83dbSDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, ID).isBranch())
5515ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
5525ffd83dbSDimitry Andric break;
5535ffd83dbSDimitry Andric case HexagonII::TypeDUPLEX: {
5545ffd83dbSDimitry Andric ++Summary.duplex;
5555ffd83dbSDimitry Andric MCInst const &Inst0 = *ID.getOperand(0).getInst();
5565ffd83dbSDimitry Andric MCInst const &Inst1 = *ID.getOperand(1).getInst();
5575ffd83dbSDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isBranch())
5585ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
5595ffd83dbSDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isBranch())
5605ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
5615ffd83dbSDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, Inst0).isReturn())
5625ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
5635ffd83dbSDimitry Andric if (HexagonMCInstrInfo::getDesc(MCII, Inst1).isReturn())
5645ffd83dbSDimitry Andric Summary.branchInsts.push_back(ISJ);
5655ffd83dbSDimitry Andric break;
5665ffd83dbSDimitry Andric }
5675ffd83dbSDimitry Andric }
5685ffd83dbSDimitry Andric }
5695ffd83dbSDimitry Andric return Summary;
5705ffd83dbSDimitry Andric }
5715ffd83dbSDimitry Andric
ValidPacketMemoryOps(HexagonPacketSummary const & Summary) const5725ffd83dbSDimitry Andric bool HexagonShuffler::ValidPacketMemoryOps(
5735ffd83dbSDimitry Andric HexagonPacketSummary const &Summary) const {
5745ffd83dbSDimitry Andric // Check if the packet is legal.
5755ffd83dbSDimitry Andric const unsigned ZCVIloads = Summary.AllCVIloads - Summary.NonZCVIloads;
5765ffd83dbSDimitry Andric const bool ValidHVXMem =
5775ffd83dbSDimitry Andric Summary.NonZCVIloads <= 1 && ZCVIloads <= 1 && Summary.CVIstores <= 1;
5785ffd83dbSDimitry Andric const bool InvalidPacket =
5795ffd83dbSDimitry Andric ((Summary.load0 > 1 || Summary.store0 > 1 || !ValidHVXMem) ||
5805ffd83dbSDimitry Andric (Summary.duplex > 1 || (Summary.duplex && Summary.memory)));
5815ffd83dbSDimitry Andric
5825ffd83dbSDimitry Andric return !InvalidPacket;
5835ffd83dbSDimitry Andric }
5845ffd83dbSDimitry Andric
restrictPreferSlot3(HexagonPacketSummary const & Summary,const bool DoShuffle)58504eeddc0SDimitry Andric void HexagonShuffler::restrictPreferSlot3(HexagonPacketSummary const &Summary,
58604eeddc0SDimitry Andric const bool DoShuffle) {
5875ffd83dbSDimitry Andric // flag if an instruction requires to be in slot 3
5885ffd83dbSDimitry Andric const bool HasOnlySlot3 = llvm::any_of(insts(), [&](HexagonInstr const &I) {
5895ffd83dbSDimitry Andric return (I.Core.getUnits() == Slot3Mask);
5905ffd83dbSDimitry Andric });
59104eeddc0SDimitry Andric const bool NeedsPrefSlot3Shuffle = Summary.branchInsts.size() <= 1 &&
59204eeddc0SDimitry Andric !HasOnlySlot3 && Summary.pSlot3Cnt == 1 &&
59304eeddc0SDimitry Andric Summary.PrefSlot3Inst && DoShuffle;
5945ffd83dbSDimitry Andric
5955ffd83dbSDimitry Andric if (!NeedsPrefSlot3Shuffle)
5965ffd83dbSDimitry Andric return;
5975ffd83dbSDimitry Andric
5985ffd83dbSDimitry Andric HexagonInstr *PrefSlot3Inst = *Summary.PrefSlot3Inst;
5995ffd83dbSDimitry Andric // save off slot mask of instruction marked with A_PREFER_SLOT3
6005ffd83dbSDimitry Andric // and then pin it to slot #3
6015ffd83dbSDimitry Andric const unsigned saveUnits = PrefSlot3Inst->Core.getUnits();
6025ffd83dbSDimitry Andric PrefSlot3Inst->Core.setUnits(saveUnits & Slot3Mask);
60381ad6265SDimitry Andric const bool HasShuffledPacket = tryAuction(Summary).has_value();
6045ffd83dbSDimitry Andric if (HasShuffledPacket)
6055ffd83dbSDimitry Andric return;
6065ffd83dbSDimitry Andric
6075ffd83dbSDimitry Andric PrefSlot3Inst->Core.setUnits(saveUnits);
6085ffd83dbSDimitry Andric }
6095ffd83dbSDimitry Andric
6105ffd83dbSDimitry Andric /// Check that the packet is legal and enforce relative insn order.
check(const bool RequireShuffle)61104eeddc0SDimitry Andric bool HexagonShuffler::check(const bool RequireShuffle) {
6125ffd83dbSDimitry Andric const HexagonPacketSummary Summary = GetPacketSummary();
61304eeddc0SDimitry Andric if (!applySlotRestrictions(Summary, RequireShuffle))
6145ffd83dbSDimitry Andric return false;
6155ffd83dbSDimitry Andric
6165ffd83dbSDimitry Andric if (!ValidPacketMemoryOps(Summary)) {
6175ffd83dbSDimitry Andric reportError("invalid instruction packet");
6185ffd83dbSDimitry Andric return false;
6195ffd83dbSDimitry Andric }
6205ffd83dbSDimitry Andric
62104eeddc0SDimitry Andric if (RequireShuffle)
6225ffd83dbSDimitry Andric ValidResourceUsage(Summary);
6235ffd83dbSDimitry Andric
6245ffd83dbSDimitry Andric return !CheckFailure;
6255ffd83dbSDimitry Andric }
6265ffd83dbSDimitry Andric
627bdd1243dSDimitry Andric std::optional<HexagonShuffler::HexagonPacket>
tryAuction(HexagonPacketSummary const & Summary)62804eeddc0SDimitry Andric HexagonShuffler::tryAuction(HexagonPacketSummary const &Summary) {
6295ffd83dbSDimitry Andric HexagonPacket PacketResult = Packet;
6305ffd83dbSDimitry Andric HexagonUnitAuction AuctionCore(Summary.ReservedSlotMask);
631e8d8bef9SDimitry Andric llvm::stable_sort(PacketResult, HexagonInstr::lessCore);
6325ffd83dbSDimitry Andric
6335ffd83dbSDimitry Andric const bool ValidSlots =
6345ffd83dbSDimitry Andric llvm::all_of(insts(PacketResult), [&AuctionCore](HexagonInstr const &I) {
6355ffd83dbSDimitry Andric return AuctionCore.bid(I.Core.getUnits());
6365ffd83dbSDimitry Andric });
6375ffd83dbSDimitry Andric
6385ffd83dbSDimitry Andric LLVM_DEBUG(
6395ffd83dbSDimitry Andric dbgs() << "Shuffle attempt: " << (ValidSlots ? "passed" : "failed")
6405ffd83dbSDimitry Andric << "\n";
6415ffd83dbSDimitry Andric for (HexagonInstr const &ISJ : insts(PacketResult))
6425ffd83dbSDimitry Andric dbgs() << "\t" << HexagonMCInstrInfo::getName(MCII, *ISJ.ID) << ": "
6435ffd83dbSDimitry Andric << llvm::format_hex(ISJ.Core.getUnits(), 4, true) << "\n";
6445ffd83dbSDimitry Andric );
6455ffd83dbSDimitry Andric
646bdd1243dSDimitry Andric std::optional<HexagonPacket> Res;
6475ffd83dbSDimitry Andric if (ValidSlots)
6485ffd83dbSDimitry Andric Res = PacketResult;
6495ffd83dbSDimitry Andric
6505ffd83dbSDimitry Andric return Res;
6515ffd83dbSDimitry Andric }
6525ffd83dbSDimitry Andric
shuffle()6530b57cec5SDimitry Andric bool HexagonShuffler::shuffle() {
6540b57cec5SDimitry Andric if (size() > HEXAGON_PACKET_SIZE) {
655*5f757f3fSDimitry Andric // Ignore a packet with more than what a packet can hold
6560b57cec5SDimitry Andric // or with compound or duplex insns for now.
65704eeddc0SDimitry Andric reportError("invalid instruction packet");
6580b57cec5SDimitry Andric return false;
6590b57cec5SDimitry Andric }
6600b57cec5SDimitry Andric
6610b57cec5SDimitry Andric // Check and prepare packet.
66204eeddc0SDimitry Andric bool Ok = check();
66304eeddc0SDimitry Andric if (size() > 1 && Ok)
6640b57cec5SDimitry Andric // Reorder the handles for each slot.
6650b57cec5SDimitry Andric for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE;
6660b57cec5SDimitry Andric ++nSlot) {
6670b57cec5SDimitry Andric iterator ISJ, ISK;
6680b57cec5SDimitry Andric unsigned slotSkip, slotWeight;
6690b57cec5SDimitry Andric
6700b57cec5SDimitry Andric // Prioritize the handles considering their restrictions.
6710b57cec5SDimitry Andric for (ISJ = ISK = Packet.begin(), slotSkip = slotWeight = 0;
6720b57cec5SDimitry Andric ISK != Packet.end(); ++ISK, ++slotSkip)
6730b57cec5SDimitry Andric if (slotSkip < nSlot - emptySlots)
6740b57cec5SDimitry Andric // Note which handle to begin at.
6750b57cec5SDimitry Andric ++ISJ;
6760b57cec5SDimitry Andric else
6770b57cec5SDimitry Andric // Calculate the weight of the slot.
6780b57cec5SDimitry Andric slotWeight += ISK->Core.setWeight(HEXAGON_PACKET_SIZE - nSlot - 1);
6790b57cec5SDimitry Andric
6800b57cec5SDimitry Andric if (slotWeight)
6810b57cec5SDimitry Andric // Sort the packet, favoring source order,
6820b57cec5SDimitry Andric // beginning after the previous slot.
6830b57cec5SDimitry Andric std::stable_sort(ISJ, Packet.end());
6840b57cec5SDimitry Andric else
6850b57cec5SDimitry Andric // Skip unused slot.
6860b57cec5SDimitry Andric ++emptySlots;
6870b57cec5SDimitry Andric }
6880b57cec5SDimitry Andric
6895ffd83dbSDimitry Andric LLVM_DEBUG(
6905ffd83dbSDimitry Andric for (HexagonInstr const &ISJ : insts()) {
6915ffd83dbSDimitry Andric dbgs().write_hex(ISJ.Core.getUnits());
6925ffd83dbSDimitry Andric if (ISJ.CVI.isValid()) {
6930b57cec5SDimitry Andric dbgs() << '/';
6945ffd83dbSDimitry Andric dbgs().write_hex(ISJ.CVI.getUnits()) << '|';
6955ffd83dbSDimitry Andric dbgs() << ISJ.CVI.getLanes();
6965ffd83dbSDimitry Andric }
6975ffd83dbSDimitry Andric dbgs() << ':'
6985ffd83dbSDimitry Andric << HexagonMCInstrInfo::getDesc(MCII, ISJ.getDesc()).getOpcode()
6995ffd83dbSDimitry Andric << '\n';
7005ffd83dbSDimitry Andric } dbgs() << '\n';
7015ffd83dbSDimitry Andric );
7020b57cec5SDimitry Andric
7030b57cec5SDimitry Andric return Ok;
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric
reportResourceError(HexagonPacketSummary const & Summary,StringRef Err)70604eeddc0SDimitry Andric void HexagonShuffler::reportResourceError(HexagonPacketSummary const &Summary, StringRef Err) {
70704eeddc0SDimitry Andric if (ReportErrors)
70804eeddc0SDimitry Andric reportResourceUsage(Summary);
70904eeddc0SDimitry Andric reportError(Twine("invalid instruction packet: ") + Err);
71004eeddc0SDimitry Andric }
71104eeddc0SDimitry Andric
71204eeddc0SDimitry Andric
reportResourceUsage(HexagonPacketSummary const & Summary)71304eeddc0SDimitry Andric void HexagonShuffler::reportResourceUsage(HexagonPacketSummary const &Summary) {
71404eeddc0SDimitry Andric auto SM = Context.getSourceManager();
71504eeddc0SDimitry Andric if (SM) {
71604eeddc0SDimitry Andric for (HexagonInstr const &I : insts()) {
71704eeddc0SDimitry Andric const unsigned Units = I.Core.getUnits();
71804eeddc0SDimitry Andric
71904eeddc0SDimitry Andric if (HexagonMCInstrInfo::requiresSlot(STI, *I.ID)) {
72004eeddc0SDimitry Andric const std::string UnitsText = Units ? SlotMaskToText(Units) : "<None>";
72104eeddc0SDimitry Andric SM->PrintMessage(I.ID->getLoc(), SourceMgr::DK_Note,
72204eeddc0SDimitry Andric Twine("Instruction can utilize slots: ") +
72304eeddc0SDimitry Andric UnitsText);
72404eeddc0SDimitry Andric }
72504eeddc0SDimitry Andric else if (!HexagonMCInstrInfo::isImmext(*I.ID))
72604eeddc0SDimitry Andric SM->PrintMessage(I.ID->getLoc(), SourceMgr::DK_Note,
72704eeddc0SDimitry Andric "Instruction does not require a slot");
72804eeddc0SDimitry Andric }
72904eeddc0SDimitry Andric }
73004eeddc0SDimitry Andric }
73104eeddc0SDimitry Andric
reportError(Twine const & Msg)7320b57cec5SDimitry Andric void HexagonShuffler::reportError(Twine const &Msg) {
7335ffd83dbSDimitry Andric CheckFailure = true;
7340b57cec5SDimitry Andric if (ReportErrors) {
7350b57cec5SDimitry Andric for (auto const &I : AppliedRestrictions) {
7360b57cec5SDimitry Andric auto SM = Context.getSourceManager();
7370b57cec5SDimitry Andric if (SM)
7380b57cec5SDimitry Andric SM->PrintMessage(I.first, SourceMgr::DK_Note, I.second);
7390b57cec5SDimitry Andric }
7400b57cec5SDimitry Andric Context.reportError(Loc, Msg);
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric }
743