//===- HexagonShuffler.h - Instruction bundle shuffling ---------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This implements the shuffling of insns inside a bundle according to the // packet formation rules of the Hexagon ISA. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H #define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H #include "MCTargetDesc/HexagonMCInstrInfo.h" #include "MCTargetDesc/HexagonMCTargetDesc.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 #include #include #include namespace llvm { class MCContext; class MCInst; class MCInstrInfo; class MCSubtargetInfo; // Insn resources. class HexagonResource { // Mask of the slots or units that may execute the insn and // the weight or priority that the insn requires to be assigned a slot. unsigned Slots, Weight; public: HexagonResource(unsigned s) { setUnits(s); } void setUnits(unsigned s) { Slots = s & ((1u << HEXAGON_PACKET_SIZE) - 1); setWeight(s); } void setAllUnits() { setUnits(((1u << HEXAGON_PACKET_SIZE) - 1)); } unsigned setWeight(unsigned s); unsigned getUnits() const { return (Slots); } unsigned getWeight() const { return (Weight); } // Check if the resources are in ascending slot order. static bool lessUnits(const HexagonResource &A, const HexagonResource &B) { return (llvm::popcount(A.getUnits()) < llvm::popcount(B.getUnits())); } // Check if the resources are in ascending weight order. static bool lessWeight(const HexagonResource &A, const HexagonResource &B) { return (A.getWeight() < B.getWeight()); } }; // HVX insn resources. class HexagonCVIResource : public HexagonResource { public: using UnitsAndLanes = std::pair; private: // Count of adjacent slots that the insn requires to be executed. unsigned Lanes; // Flag whether the insn is a load or a store. bool Load, Store; // Flag whether the HVX resources are valid. bool Valid; void setLanes(unsigned l) { Lanes = l; } void setLoad(bool f = true) { Load = f; } void setStore(bool f = true) { Store = f; } public: HexagonCVIResource(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, unsigned s, MCInst const *id); bool isValid() const { return Valid; } unsigned getLanes() const { return Lanes; } bool mayLoad() const { return Load; } bool mayStore() const { return Store; } }; // Handle to an insn used by the shuffling algorithm. class HexagonInstr { friend class HexagonShuffler; MCInst const *ID; MCInst const *Extender; HexagonResource Core; HexagonCVIResource CVI; public: HexagonInstr(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst const *id, MCInst const *Extender, unsigned s) : ID(id), Extender(Extender), Core(s), CVI(MCII, STI, s, id){}; MCInst const &getDesc() const { return *ID; } MCInst const *getExtender() const { return Extender; } // Check if the handles are in ascending order for shuffling purposes. bool operator<(const HexagonInstr &B) const { return (HexagonResource::lessWeight(B.Core, Core)); } // Check if the handles are in ascending order by core slots. static bool lessCore(const HexagonInstr &A, const HexagonInstr &B) { return (HexagonResource::lessUnits(A.Core, B.Core)); } // Check if the handles are in ascending order by HVX slots. static bool lessCVI(const HexagonInstr &A, const HexagonInstr &B) { return (HexagonResource::lessUnits(A.CVI, B.CVI)); } }; // Bundle shuffler. class HexagonShuffler { using HexagonPacket = SmallVector; 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; std::optional PrefSlot3Inst; unsigned memops; unsigned ReservedSlotMask; SmallVector branchInsts; std::optional Slot1AOKLoc; std::optional NoSlot1StoreLoc; }; // Insn handles in a bundle. HexagonPacket Packet; protected: MCContext &Context; int64_t BundleFlags; MCInstrInfo const &MCII; MCSubtargetInfo const &STI; SMLoc Loc; bool ReportErrors; bool CheckFailure; std::vector> AppliedRestrictions; bool applySlotRestrictions(HexagonPacketSummary const &Summary, const bool DoShuffle); void restrictSlot1AOK(HexagonPacketSummary const &Summary); void restrictNoSlot1Store(HexagonPacketSummary const &Summary); void restrictNoSlot1(); bool restrictStoreLoadOrder(HexagonPacketSummary const &Summary); void restrictBranchOrder(HexagonPacketSummary const &Summary); void restrictPreferSlot3(HexagonPacketSummary const &Summary, const bool DoShuffle); void permitNonSlot(); std::optional tryAuction(HexagonPacketSummary const &Summary); HexagonPacketSummary GetPacketSummary(); bool ValidPacketMemoryOps(HexagonPacketSummary const &Summary) const; bool ValidResourceUsage(HexagonPacketSummary const &Summary); public: using iterator = HexagonPacket::iterator; using const_iterator = HexagonPacket::const_iterator; using packet_range = iterator_range; using const_packet_range = iterator_range; HexagonShuffler(MCContext &Context, bool ReportErrors, MCInstrInfo const &MCII, MCSubtargetInfo const &STI); // Reset to initial state. void reset(); // Check if the bundle may be validly shuffled. bool check(const bool RequireShuffle = true); // Reorder the insn handles in the bundle. bool shuffle(); unsigned size() const { return (Packet.size()); } bool isMemReorderDisabled() const { return (BundleFlags & HexagonMCInstrInfo::memReorderDisabledMask) != 0; } 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(insts(), [&](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); // Return the error code for the last check or shuffling of the bundle. void reportError(Twine const &Msg); void reportResourceError(HexagonPacketSummary const &Summary, StringRef Err); void reportResourceUsage(HexagonPacketSummary const &Summary); }; } // end namespace llvm #endif // LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H