10b57cec5SDimitry Andric //===- HexagonShuffler.h - Instruction bundle shuffling ---------*- C++ -*-===// 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 #ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H 150b57cec5SDimitry Andric #define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "MCTargetDesc/HexagonMCInstrInfo.h" 180b57cec5SDimitry Andric #include "MCTargetDesc/HexagonMCTargetDesc.h" 195ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h" 200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 210b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 220b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 230b57cec5SDimitry Andric #include "llvm/Support/SMLoc.h" 240b57cec5SDimitry Andric #include <cstdint> 255ffd83dbSDimitry Andric #include <functional> 26*bdd1243dSDimitry Andric #include <optional> 270b57cec5SDimitry Andric #include <utility> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric namespace llvm { 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric class MCContext; 320b57cec5SDimitry Andric class MCInst; 330b57cec5SDimitry Andric class MCInstrInfo; 340b57cec5SDimitry Andric class MCSubtargetInfo; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric // Insn resources. 370b57cec5SDimitry Andric class HexagonResource { 380b57cec5SDimitry Andric // Mask of the slots or units that may execute the insn and 390b57cec5SDimitry Andric // the weight or priority that the insn requires to be assigned a slot. 400b57cec5SDimitry Andric unsigned Slots, Weight; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric public: 430b57cec5SDimitry Andric HexagonResource(unsigned s) { setUnits(s); } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric void setUnits(unsigned s) { 460b57cec5SDimitry Andric Slots = s & ((1u << HEXAGON_PACKET_SIZE) - 1); 470b57cec5SDimitry Andric setWeight(s); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 505ffd83dbSDimitry Andric void setAllUnits() { 515ffd83dbSDimitry Andric setUnits(((1u << HEXAGON_PACKET_SIZE) - 1)); 525ffd83dbSDimitry Andric } 530b57cec5SDimitry Andric unsigned setWeight(unsigned s); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric unsigned getUnits() const { return (Slots); } 560b57cec5SDimitry Andric unsigned getWeight() const { return (Weight); } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric // Check if the resources are in ascending slot order. 590b57cec5SDimitry Andric static bool lessUnits(const HexagonResource &A, const HexagonResource &B) { 60*bdd1243dSDimitry Andric return (llvm::popcount(A.getUnits()) < llvm::popcount(B.getUnits())); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric // Check if the resources are in ascending weight order. 640b57cec5SDimitry Andric static bool lessWeight(const HexagonResource &A, const HexagonResource &B) { 650b57cec5SDimitry Andric return (A.getWeight() < B.getWeight()); 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric }; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // HVX insn resources. 700b57cec5SDimitry Andric class HexagonCVIResource : public HexagonResource { 710b57cec5SDimitry Andric public: 720b57cec5SDimitry Andric using UnitsAndLanes = std::pair<unsigned, unsigned>; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric private: 750b57cec5SDimitry Andric // Count of adjacent slots that the insn requires to be executed. 760b57cec5SDimitry Andric unsigned Lanes; 770b57cec5SDimitry Andric // Flag whether the insn is a load or a store. 780b57cec5SDimitry Andric bool Load, Store; 790b57cec5SDimitry Andric // Flag whether the HVX resources are valid. 800b57cec5SDimitry Andric bool Valid; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric void setLanes(unsigned l) { Lanes = l; } 830b57cec5SDimitry Andric void setLoad(bool f = true) { Load = f; } 840b57cec5SDimitry Andric void setStore(bool f = true) { Store = f; } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric public: 875ffd83dbSDimitry Andric HexagonCVIResource(MCInstrInfo const &MCII, 885ffd83dbSDimitry Andric MCSubtargetInfo const &STI, 890b57cec5SDimitry Andric unsigned s, MCInst const *id); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric bool isValid() const { return Valid; } 920b57cec5SDimitry Andric unsigned getLanes() const { return Lanes; } 930b57cec5SDimitry Andric bool mayLoad() const { return Load; } 940b57cec5SDimitry Andric bool mayStore() const { return Store; } 950b57cec5SDimitry Andric }; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric // Handle to an insn used by the shuffling algorithm. 980b57cec5SDimitry Andric class HexagonInstr { 990b57cec5SDimitry Andric friend class HexagonShuffler; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric MCInst const *ID; 1020b57cec5SDimitry Andric MCInst const *Extender; 1030b57cec5SDimitry Andric HexagonResource Core; 1040b57cec5SDimitry Andric HexagonCVIResource CVI; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric public: 1075ffd83dbSDimitry Andric HexagonInstr(MCInstrInfo const &MCII, 1085ffd83dbSDimitry Andric MCSubtargetInfo const &STI, MCInst const *id, 1090b57cec5SDimitry Andric MCInst const *Extender, unsigned s) 1105ffd83dbSDimitry Andric : ID(id), Extender(Extender), Core(s), CVI(MCII, STI, s, id){}; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric MCInst const &getDesc() const { return *ID; } 1130b57cec5SDimitry Andric MCInst const *getExtender() const { return Extender; } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric // Check if the handles are in ascending order for shuffling purposes. 1160b57cec5SDimitry Andric bool operator<(const HexagonInstr &B) const { 1170b57cec5SDimitry Andric return (HexagonResource::lessWeight(B.Core, Core)); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Check if the handles are in ascending order by core slots. 1210b57cec5SDimitry Andric static bool lessCore(const HexagonInstr &A, const HexagonInstr &B) { 1220b57cec5SDimitry Andric return (HexagonResource::lessUnits(A.Core, B.Core)); 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric // Check if the handles are in ascending order by HVX slots. 1260b57cec5SDimitry Andric static bool lessCVI(const HexagonInstr &A, const HexagonInstr &B) { 1270b57cec5SDimitry Andric return (HexagonResource::lessUnits(A.CVI, B.CVI)); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric }; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // Bundle shuffler. 1320b57cec5SDimitry Andric class HexagonShuffler { 1330b57cec5SDimitry Andric using HexagonPacket = 1340b57cec5SDimitry Andric SmallVector<HexagonInstr, HEXAGON_PRESHUFFLE_PACKET_SIZE>; 1350b57cec5SDimitry Andric 1365ffd83dbSDimitry Andric struct HexagonPacketSummary { 1375ffd83dbSDimitry Andric // Number of memory operations, loads, solo loads, stores, solo stores, 1385ffd83dbSDimitry Andric // single stores. 1395ffd83dbSDimitry Andric unsigned memory; 1405ffd83dbSDimitry Andric unsigned loads; 1415ffd83dbSDimitry Andric unsigned load0; 1425ffd83dbSDimitry Andric unsigned stores; 1435ffd83dbSDimitry Andric unsigned store0; 1445ffd83dbSDimitry Andric unsigned store1; 1455ffd83dbSDimitry Andric unsigned NonZCVIloads; 1465ffd83dbSDimitry Andric unsigned AllCVIloads; 1475ffd83dbSDimitry Andric unsigned CVIstores; 1485ffd83dbSDimitry Andric // Number of duplex insns 1495ffd83dbSDimitry Andric unsigned duplex; 1505ffd83dbSDimitry Andric unsigned pSlot3Cnt; 151*bdd1243dSDimitry Andric std::optional<HexagonInstr *> PrefSlot3Inst; 1525ffd83dbSDimitry Andric unsigned memops; 1535ffd83dbSDimitry Andric unsigned ReservedSlotMask; 1545ffd83dbSDimitry Andric SmallVector<HexagonInstr *, HEXAGON_PRESHUFFLE_PACKET_SIZE> branchInsts; 155*bdd1243dSDimitry Andric std::optional<SMLoc> Slot1AOKLoc; 156*bdd1243dSDimitry Andric std::optional<SMLoc> NoSlot1StoreLoc; 1575ffd83dbSDimitry Andric }; 1580b57cec5SDimitry Andric // Insn handles in a bundle. 1590b57cec5SDimitry Andric HexagonPacket Packet; 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric protected: 1620b57cec5SDimitry Andric MCContext &Context; 1630b57cec5SDimitry Andric int64_t BundleFlags; 1640b57cec5SDimitry Andric MCInstrInfo const &MCII; 1650b57cec5SDimitry Andric MCSubtargetInfo const &STI; 1660b57cec5SDimitry Andric SMLoc Loc; 1670b57cec5SDimitry Andric bool ReportErrors; 1685ffd83dbSDimitry Andric bool CheckFailure; 1690b57cec5SDimitry Andric std::vector<std::pair<SMLoc, std::string>> AppliedRestrictions; 17004eeddc0SDimitry Andric 17104eeddc0SDimitry Andric bool applySlotRestrictions(HexagonPacketSummary const &Summary, 17204eeddc0SDimitry Andric const bool DoShuffle); 1735ffd83dbSDimitry Andric void restrictSlot1AOK(HexagonPacketSummary const &Summary); 1745ffd83dbSDimitry Andric void restrictNoSlot1Store(HexagonPacketSummary const &Summary); 1755ffd83dbSDimitry Andric void restrictNoSlot1(); 1765ffd83dbSDimitry Andric bool restrictStoreLoadOrder(HexagonPacketSummary const &Summary); 1775ffd83dbSDimitry Andric void restrictBranchOrder(HexagonPacketSummary const &Summary); 17804eeddc0SDimitry Andric void restrictPreferSlot3(HexagonPacketSummary const &Summary, 17904eeddc0SDimitry Andric const bool DoShuffle); 1805ffd83dbSDimitry Andric void permitNonSlot(); 1815ffd83dbSDimitry Andric 182*bdd1243dSDimitry Andric std::optional<HexagonPacket> tryAuction(HexagonPacketSummary const &Summary); 1835ffd83dbSDimitry Andric 1845ffd83dbSDimitry Andric HexagonPacketSummary GetPacketSummary(); 1855ffd83dbSDimitry Andric bool ValidPacketMemoryOps(HexagonPacketSummary const &Summary) const; 1865ffd83dbSDimitry Andric bool ValidResourceUsage(HexagonPacketSummary const &Summary); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric public: 1890b57cec5SDimitry Andric using iterator = HexagonPacket::iterator; 1905ffd83dbSDimitry Andric using const_iterator = HexagonPacket::const_iterator; 1915ffd83dbSDimitry Andric using packet_range = iterator_range<HexagonPacket::iterator>; 1925ffd83dbSDimitry Andric using const_packet_range = iterator_range<HexagonPacket::const_iterator>; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric HexagonShuffler(MCContext &Context, bool ReportErrors, 1950b57cec5SDimitry Andric MCInstrInfo const &MCII, MCSubtargetInfo const &STI); 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Reset to initial state. 1980b57cec5SDimitry Andric void reset(); 1990b57cec5SDimitry Andric // Check if the bundle may be validly shuffled. 20004eeddc0SDimitry Andric bool check(const bool RequireShuffle = true); 2010b57cec5SDimitry Andric // Reorder the insn handles in the bundle. 2020b57cec5SDimitry Andric bool shuffle(); 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric unsigned size() const { return (Packet.size()); } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric bool isMemReorderDisabled() const { 2070b57cec5SDimitry Andric return (BundleFlags & HexagonMCInstrInfo::memReorderDisabledMask) != 0; 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric iterator begin() { return (Packet.begin()); } 2110b57cec5SDimitry Andric iterator end() { return (Packet.end()); } 2125ffd83dbSDimitry Andric const_iterator cbegin() const { return (Packet.begin()); } 2135ffd83dbSDimitry Andric const_iterator cend() const { return (Packet.end()); } 2145ffd83dbSDimitry Andric packet_range insts(HexagonPacket &P) { 2155ffd83dbSDimitry Andric return make_range(P.begin(), P.end()); 2165ffd83dbSDimitry Andric } 2175ffd83dbSDimitry Andric const_packet_range insts(HexagonPacket const &P) const { 2185ffd83dbSDimitry Andric return make_range(P.begin(), P.end()); 2195ffd83dbSDimitry Andric } 2205ffd83dbSDimitry Andric packet_range insts() { return make_range(begin(), end()); } 2215ffd83dbSDimitry Andric const_packet_range insts() const { return make_range(cbegin(), cend()); } 2225ffd83dbSDimitry Andric 2235ffd83dbSDimitry Andric using InstPredicate = bool (*)(MCInstrInfo const &, MCInst const &); 2245ffd83dbSDimitry Andric 2255ffd83dbSDimitry Andric bool HasInstWith(InstPredicate Pred) const { 2265ffd83dbSDimitry Andric return llvm::any_of(insts(), [&](HexagonInstr const &I) { 2275ffd83dbSDimitry Andric MCInst const &Inst = I.getDesc(); 2285ffd83dbSDimitry Andric return (*Pred)(MCII, Inst); 2295ffd83dbSDimitry Andric }); 2305ffd83dbSDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric // Add insn handle to the bundle . 2330b57cec5SDimitry Andric void append(MCInst const &ID, MCInst const *Extender, unsigned S); 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric // Return the error code for the last check or shuffling of the bundle. 2360b57cec5SDimitry Andric void reportError(Twine const &Msg); 23704eeddc0SDimitry Andric void reportResourceError(HexagonPacketSummary const &Summary, StringRef Err); 23804eeddc0SDimitry Andric void reportResourceUsage(HexagonPacketSummary const &Summary); 2390b57cec5SDimitry Andric }; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric } // end namespace llvm 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric #endif // LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H 244