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 | |
29 | namespace llvm { |
30 | |
31 | class MCContext; |
32 | class MCInst; |
33 | class MCInstrInfo; |
34 | class MCSubtargetInfo; |
35 | |
36 | // Insn resources. |
37 | class 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 | |
42 | public: |
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. |
70 | class HexagonCVIResource : public HexagonResource { |
71 | public: |
72 | using UnitsAndLanes = std::pair<unsigned, unsigned>; |
73 | |
74 | private: |
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 | |
86 | public: |
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. |
98 | class HexagonInstr { |
99 | friend class HexagonShuffler; |
100 | |
101 | MCInst const *ID; |
102 | MCInst const *Extender; |
103 | HexagonResource Core; |
104 | HexagonCVIResource CVI; |
105 | |
106 | public: |
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. |
132 | class 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 | |
161 | protected: |
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 | |
188 | public: |
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 | |