1//===- HexagonShuffler.h - Instruction bundle shuffling ---------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This implements the shuffling of insns inside a bundle according to the
10// packet formation rules of the Hexagon ISA.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H
15#define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H
16
17#include "MCTargetDesc/HexagonMCInstrInfo.h"
18#include "MCTargetDesc/HexagonMCTargetDesc.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/SmallVector.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/MathExtras.h"
23#include "llvm/Support/SMLoc.h"
24#include <cstdint>
25#include <functional>
26#include <optional>
27#include <utility>
28
29namespace llvm {
30
31class MCContext;
32class MCInst;
33class MCInstrInfo;
34class MCSubtargetInfo;
35
36// Insn resources.
37class HexagonResource {
38 // Mask of the slots or units that may execute the insn and
39 // the weight or priority that the insn requires to be assigned a slot.
40 unsigned Slots, Weight;
41
42public:
43 HexagonResource(unsigned s) { setUnits(s); }
44
45 void setUnits(unsigned s) {
46 Slots = s & ((1u << HEXAGON_PACKET_SIZE) - 1);
47 setWeight(s);
48 }
49
50 void setAllUnits() {
51 setUnits(((1u << HEXAGON_PACKET_SIZE) - 1));
52 }
53 unsigned setWeight(unsigned s);
54
55 unsigned getUnits() const { return (Slots); }
56 unsigned getWeight() const { return (Weight); }
57
58 // Check if the resources are in ascending slot order.
59 static bool lessUnits(const HexagonResource &A, const HexagonResource &B) {
60 return (llvm::popcount(Value: A.getUnits()) < llvm::popcount(Value: B.getUnits()));
61 }
62
63 // Check if the resources are in ascending weight order.
64 static bool lessWeight(const HexagonResource &A, const HexagonResource &B) {
65 return (A.getWeight() < B.getWeight());
66 }
67};
68
69// HVX insn resources.
70class HexagonCVIResource : public HexagonResource {
71public:
72 using UnitsAndLanes = std::pair<unsigned, unsigned>;
73
74private:
75 // Count of adjacent slots that the insn requires to be executed.
76 unsigned Lanes;
77 // Flag whether the insn is a load or a store.
78 bool Load, Store;
79 // Flag whether the HVX resources are valid.
80 bool Valid;
81
82 void setLanes(unsigned l) { Lanes = l; }
83 void setLoad(bool f = true) { Load = f; }
84 void setStore(bool f = true) { Store = f; }
85
86public:
87 HexagonCVIResource(MCInstrInfo const &MCII,
88 MCSubtargetInfo const &STI,
89 unsigned s, MCInst const *id);
90
91 bool isValid() const { return Valid; }
92 unsigned getLanes() const { return Lanes; }
93 bool mayLoad() const { return Load; }
94 bool mayStore() const { return Store; }
95};
96
97// Handle to an insn used by the shuffling algorithm.
98class HexagonInstr {
99 friend class HexagonShuffler;
100
101 MCInst const *ID;
102 MCInst const *Extender;
103 HexagonResource Core;
104 HexagonCVIResource CVI;
105
106public:
107 HexagonInstr(MCInstrInfo const &MCII,
108 MCSubtargetInfo const &STI, MCInst const *id,
109 MCInst const *Extender, unsigned s)
110 : ID(id), Extender(Extender), Core(s), CVI(MCII, STI, s, id){};
111
112 MCInst const &getDesc() const { return *ID; }
113 MCInst const *getExtender() const { return Extender; }
114
115 // Check if the handles are in ascending order for shuffling purposes.
116 bool operator<(const HexagonInstr &B) const {
117 return (HexagonResource::lessWeight(A: B.Core, B: Core));
118 }
119
120 // Check if the handles are in ascending order by core slots.
121 static bool lessCore(const HexagonInstr &A, const HexagonInstr &B) {
122 return (HexagonResource::lessUnits(A: A.Core, B: B.Core));
123 }
124
125 // Check if the handles are in ascending order by HVX slots.
126 static bool lessCVI(const HexagonInstr &A, const HexagonInstr &B) {
127 return (HexagonResource::lessUnits(A: A.CVI, B: B.CVI));
128 }
129};
130
131// Bundle shuffler.
132class HexagonShuffler {
133 using HexagonPacket =
134 SmallVector<HexagonInstr, HEXAGON_PRESHUFFLE_PACKET_SIZE>;
135
136 struct HexagonPacketSummary {
137 // Number of memory operations, loads, solo loads, stores, solo stores,
138 // single stores.
139 unsigned memory;
140 unsigned loads;
141 unsigned load0;
142 unsigned stores;
143 unsigned store0;
144 unsigned store1;
145 unsigned NonZCVIloads;
146 unsigned AllCVIloads;
147 unsigned CVIstores;
148 // Number of duplex insns
149 unsigned duplex;
150 unsigned pSlot3Cnt;
151 std::optional<HexagonInstr *> PrefSlot3Inst;
152 unsigned memops;
153 unsigned ReservedSlotMask;
154 SmallVector<HexagonInstr *, HEXAGON_PRESHUFFLE_PACKET_SIZE> branchInsts;
155 std::optional<SMLoc> Slot1AOKLoc;
156 std::optional<SMLoc> NoSlot1StoreLoc;
157 };
158 // Insn handles in a bundle.
159 HexagonPacket Packet;
160
161protected:
162 MCContext &Context;
163 int64_t BundleFlags;
164 MCInstrInfo const &MCII;
165 MCSubtargetInfo const &STI;
166 SMLoc Loc;
167 bool ReportErrors;
168 bool CheckFailure;
169 std::vector<std::pair<SMLoc, std::string>> AppliedRestrictions;
170
171 bool applySlotRestrictions(HexagonPacketSummary const &Summary,
172 const bool DoShuffle);
173 void restrictSlot1AOK(HexagonPacketSummary const &Summary);
174 void restrictNoSlot1Store(HexagonPacketSummary const &Summary);
175 void restrictNoSlot1();
176 bool restrictStoreLoadOrder(HexagonPacketSummary const &Summary);
177 void restrictBranchOrder(HexagonPacketSummary const &Summary);
178 void restrictPreferSlot3(HexagonPacketSummary const &Summary,
179 const bool DoShuffle);
180 void permitNonSlot();
181
182 std::optional<HexagonPacket> tryAuction(HexagonPacketSummary const &Summary);
183
184 HexagonPacketSummary GetPacketSummary();
185 bool ValidPacketMemoryOps(HexagonPacketSummary const &Summary) const;
186 bool ValidResourceUsage(HexagonPacketSummary const &Summary);
187
188public:
189 using iterator = HexagonPacket::iterator;
190 using const_iterator = HexagonPacket::const_iterator;
191 using packet_range = iterator_range<HexagonPacket::iterator>;
192 using const_packet_range = iterator_range<HexagonPacket::const_iterator>;
193
194 HexagonShuffler(MCContext &Context, bool ReportErrors,
195 MCInstrInfo const &MCII, MCSubtargetInfo const &STI);
196
197 // Reset to initial state.
198 void reset();
199 // Check if the bundle may be validly shuffled.
200 bool check(const bool RequireShuffle = true);
201 // Reorder the insn handles in the bundle.
202 bool shuffle();
203
204 unsigned size() const { return (Packet.size()); }
205
206 bool isMemReorderDisabled() const {
207 return (BundleFlags & HexagonMCInstrInfo::memReorderDisabledMask) != 0;
208 }
209
210 iterator begin() { return (Packet.begin()); }
211 iterator end() { return (Packet.end()); }
212 const_iterator cbegin() const { return (Packet.begin()); }
213 const_iterator cend() const { return (Packet.end()); }
214 packet_range insts(HexagonPacket &P) {
215 return make_range(x: P.begin(), y: P.end());
216 }
217 const_packet_range insts(HexagonPacket const &P) const {
218 return make_range(x: P.begin(), y: P.end());
219 }
220 packet_range insts() { return make_range(x: begin(), y: end()); }
221 const_packet_range insts() const { return make_range(x: cbegin(), y: cend()); }
222
223 using InstPredicate = bool (*)(MCInstrInfo const &, MCInst const &);
224
225 bool HasInstWith(InstPredicate Pred) const {
226 return llvm::any_of(Range: insts(), P: [&](HexagonInstr const &I) {
227 MCInst const &Inst = I.getDesc();
228 return (*Pred)(MCII, Inst);
229 });
230 }
231
232 // Add insn handle to the bundle .
233 void append(MCInst const &ID, MCInst const *Extender, unsigned S);
234
235 // Return the error code for the last check or shuffling of the bundle.
236 void reportError(Twine const &Msg);
237 void reportResourceError(HexagonPacketSummary const &Summary, StringRef Err);
238 void reportResourceUsage(HexagonPacketSummary const &Summary);
239};
240
241} // end namespace llvm
242
243#endif // LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H
244