1 | //===- MCSubtargetInfo.cpp - Subtarget Information ------------------------===// |
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 | #include "llvm/MC/MCSubtargetInfo.h" |
10 | #include "llvm/ADT/ArrayRef.h" |
11 | #include "llvm/ADT/StringRef.h" |
12 | #include "llvm/MC/MCInstrItineraries.h" |
13 | #include "llvm/MC/MCSchedule.h" |
14 | #include "llvm/Support/Format.h" |
15 | #include "llvm/Support/raw_ostream.h" |
16 | #include "llvm/TargetParser/SubtargetFeature.h" |
17 | #include <algorithm> |
18 | #include <cassert> |
19 | #include <cstring> |
20 | #include <optional> |
21 | |
22 | using namespace llvm; |
23 | |
24 | /// Find KV in array using binary search. |
25 | template <typename T> |
26 | static const T *Find(StringRef S, ArrayRef<T> A) { |
27 | // Binary search the array |
28 | auto F = llvm::lower_bound(A, S); |
29 | // If not found then return NULL |
30 | if (F == A.end() || StringRef(F->Key) != S) return nullptr; |
31 | // Return the found array item |
32 | return F; |
33 | } |
34 | |
35 | /// For each feature that is (transitively) implied by this feature, set it. |
36 | static |
37 | void SetImpliedBits(FeatureBitset &Bits, const FeatureBitset &Implies, |
38 | ArrayRef<SubtargetFeatureKV> FeatureTable) { |
39 | // OR the Implies bits in outside the loop. This allows the Implies for CPUs |
40 | // which might imply features not in FeatureTable to use this. |
41 | Bits |= Implies; |
42 | for (const SubtargetFeatureKV &FE : FeatureTable) |
43 | if (Implies.test(I: FE.Value)) |
44 | SetImpliedBits(Bits, Implies: FE.Implies.getAsBitset(), FeatureTable); |
45 | } |
46 | |
47 | /// For each feature that (transitively) implies this feature, clear it. |
48 | static |
49 | void ClearImpliedBits(FeatureBitset &Bits, unsigned Value, |
50 | ArrayRef<SubtargetFeatureKV> FeatureTable) { |
51 | for (const SubtargetFeatureKV &FE : FeatureTable) { |
52 | if (FE.Implies.getAsBitset().test(I: Value)) { |
53 | Bits.reset(I: FE.Value); |
54 | ClearImpliedBits(Bits, Value: FE.Value, FeatureTable); |
55 | } |
56 | } |
57 | } |
58 | |
59 | static void ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature, |
60 | ArrayRef<SubtargetFeatureKV> FeatureTable) { |
61 | assert(SubtargetFeatures::hasFlag(Feature) && |
62 | "Feature flags should start with '+' or '-'" ); |
63 | |
64 | // Find feature in table. |
65 | const SubtargetFeatureKV *FeatureEntry = |
66 | Find(S: SubtargetFeatures::StripFlag(Feature), A: FeatureTable); |
67 | // If there is a match |
68 | if (FeatureEntry) { |
69 | // Enable/disable feature in bits |
70 | if (SubtargetFeatures::isEnabled(Feature)) { |
71 | Bits.set(FeatureEntry->Value); |
72 | |
73 | // For each feature that this implies, set it. |
74 | SetImpliedBits(Bits, Implies: FeatureEntry->Implies.getAsBitset(), FeatureTable); |
75 | } else { |
76 | Bits.reset(I: FeatureEntry->Value); |
77 | |
78 | // For each feature that implies this, clear it. |
79 | ClearImpliedBits(Bits, Value: FeatureEntry->Value, FeatureTable); |
80 | } |
81 | } else { |
82 | errs() << "'" << Feature << "' is not a recognized feature for this target" |
83 | << " (ignoring feature)\n" ; |
84 | } |
85 | } |
86 | |
87 | /// Return the length of the longest entry in the table. |
88 | template <typename T> |
89 | static size_t getLongestEntryLength(ArrayRef<T> Table) { |
90 | size_t MaxLen = 0; |
91 | for (auto &I : Table) |
92 | MaxLen = std::max(MaxLen, std::strlen(s: I.Key)); |
93 | return MaxLen; |
94 | } |
95 | |
96 | /// Display help for feature and mcpu choices. |
97 | static void Help(ArrayRef<SubtargetSubTypeKV> CPUTable, |
98 | ArrayRef<SubtargetFeatureKV> FeatTable) { |
99 | // the static variable ensures that the help information only gets |
100 | // printed once even though a target machine creates multiple subtargets |
101 | static bool PrintOnce = false; |
102 | if (PrintOnce) { |
103 | return; |
104 | } |
105 | |
106 | // Determine the length of the longest CPU and Feature entries. |
107 | unsigned MaxCPULen = getLongestEntryLength(Table: CPUTable); |
108 | unsigned MaxFeatLen = getLongestEntryLength(Table: FeatTable); |
109 | |
110 | // Print the CPU table. |
111 | errs() << "Available CPUs for this target:\n\n" ; |
112 | for (auto &CPU : CPUTable) |
113 | errs() << format(Fmt: " %-*s - Select the %s processor.\n" , Vals: MaxCPULen, Vals: CPU.Key, |
114 | Vals: CPU.Key); |
115 | errs() << '\n'; |
116 | |
117 | // Print the Feature table. |
118 | errs() << "Available features for this target:\n\n" ; |
119 | for (auto &Feature : FeatTable) |
120 | errs() << format(Fmt: " %-*s - %s.\n" , Vals: MaxFeatLen, Vals: Feature.Key, Vals: Feature.Desc); |
121 | errs() << '\n'; |
122 | |
123 | errs() << "Use +feature to enable a feature, or -feature to disable it.\n" |
124 | "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n" ; |
125 | |
126 | PrintOnce = true; |
127 | } |
128 | |
129 | /// Display help for mcpu choices only |
130 | static void cpuHelp(ArrayRef<SubtargetSubTypeKV> CPUTable) { |
131 | // the static variable ensures that the help information only gets |
132 | // printed once even though a target machine creates multiple subtargets |
133 | static bool PrintOnce = false; |
134 | if (PrintOnce) { |
135 | return; |
136 | } |
137 | |
138 | // Print the CPU table. |
139 | errs() << "Available CPUs for this target:\n\n" ; |
140 | for (auto &CPU : CPUTable) |
141 | errs() << "\t" << CPU.Key << "\n" ; |
142 | errs() << '\n'; |
143 | |
144 | errs() << "Use -mcpu or -mtune to specify the target's processor.\n" |
145 | "For example, clang --target=aarch64-unknown-linux-gnu " |
146 | "-mcpu=cortex-a35\n" ; |
147 | |
148 | PrintOnce = true; |
149 | } |
150 | |
151 | static FeatureBitset getFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS, |
152 | ArrayRef<SubtargetSubTypeKV> ProcDesc, |
153 | ArrayRef<SubtargetFeatureKV> ProcFeatures) { |
154 | SubtargetFeatures Features(FS); |
155 | |
156 | if (ProcDesc.empty() || ProcFeatures.empty()) |
157 | return FeatureBitset(); |
158 | |
159 | assert(llvm::is_sorted(ProcDesc) && "CPU table is not sorted" ); |
160 | assert(llvm::is_sorted(ProcFeatures) && "CPU features table is not sorted" ); |
161 | // Resulting bits |
162 | FeatureBitset Bits; |
163 | |
164 | // Check if help is needed |
165 | if (CPU == "help" ) |
166 | Help(CPUTable: ProcDesc, FeatTable: ProcFeatures); |
167 | |
168 | // Find CPU entry if CPU name is specified. |
169 | else if (!CPU.empty()) { |
170 | const SubtargetSubTypeKV *CPUEntry = Find(S: CPU, A: ProcDesc); |
171 | |
172 | // If there is a match |
173 | if (CPUEntry) { |
174 | // Set the features implied by this CPU feature, if any. |
175 | SetImpliedBits(Bits, Implies: CPUEntry->Implies.getAsBitset(), FeatureTable: ProcFeatures); |
176 | } else { |
177 | errs() << "'" << CPU << "' is not a recognized processor for this target" |
178 | << " (ignoring processor)\n" ; |
179 | } |
180 | } |
181 | |
182 | if (!TuneCPU.empty()) { |
183 | const SubtargetSubTypeKV *CPUEntry = Find(S: TuneCPU, A: ProcDesc); |
184 | |
185 | // If there is a match |
186 | if (CPUEntry) { |
187 | // Set the features implied by this CPU feature, if any. |
188 | SetImpliedBits(Bits, Implies: CPUEntry->TuneImplies.getAsBitset(), FeatureTable: ProcFeatures); |
189 | } else if (TuneCPU != CPU) { |
190 | errs() << "'" << TuneCPU << "' is not a recognized processor for this " |
191 | << "target (ignoring processor)\n" ; |
192 | } |
193 | } |
194 | |
195 | // Iterate through each feature |
196 | for (const std::string &Feature : Features.getFeatures()) { |
197 | // Check for help |
198 | if (Feature == "+help" ) |
199 | Help(CPUTable: ProcDesc, FeatTable: ProcFeatures); |
200 | else if (Feature == "+cpuhelp" ) |
201 | cpuHelp(CPUTable: ProcDesc); |
202 | else |
203 | ApplyFeatureFlag(Bits, Feature, FeatureTable: ProcFeatures); |
204 | } |
205 | |
206 | return Bits; |
207 | } |
208 | |
209 | void MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef TuneCPU, |
210 | StringRef FS) { |
211 | FeatureBits = getFeatures(CPU, TuneCPU, FS, ProcDesc, ProcFeatures); |
212 | FeatureString = std::string(FS); |
213 | |
214 | if (!TuneCPU.empty()) |
215 | CPUSchedModel = &getSchedModelForCPU(CPU: TuneCPU); |
216 | else |
217 | CPUSchedModel = &MCSchedModel::Default; |
218 | } |
219 | |
220 | void MCSubtargetInfo::setDefaultFeatures(StringRef CPU, StringRef TuneCPU, |
221 | StringRef FS) { |
222 | FeatureBits = getFeatures(CPU, TuneCPU, FS, ProcDesc, ProcFeatures); |
223 | FeatureString = std::string(FS); |
224 | } |
225 | |
226 | MCSubtargetInfo::MCSubtargetInfo(const Triple &TT, StringRef C, StringRef TC, |
227 | StringRef FS, ArrayRef<SubtargetFeatureKV> PF, |
228 | ArrayRef<SubtargetSubTypeKV> PD, |
229 | const MCWriteProcResEntry *WPR, |
230 | const MCWriteLatencyEntry *WL, |
231 | const MCReadAdvanceEntry *RA, |
232 | const InstrStage *IS, const unsigned *OC, |
233 | const unsigned *FP) |
234 | : TargetTriple(TT), CPU(std::string(C)), TuneCPU(std::string(TC)), |
235 | ProcFeatures(PF), ProcDesc(PD), WriteProcResTable(WPR), |
236 | WriteLatencyTable(WL), ReadAdvanceTable(RA), Stages(IS), |
237 | OperandCycles(OC), ForwardingPaths(FP) { |
238 | InitMCProcessorInfo(CPU, TuneCPU, FS); |
239 | } |
240 | |
241 | FeatureBitset MCSubtargetInfo::ToggleFeature(uint64_t FB) { |
242 | FeatureBits.flip(I: FB); |
243 | return FeatureBits; |
244 | } |
245 | |
246 | FeatureBitset MCSubtargetInfo::ToggleFeature(const FeatureBitset &FB) { |
247 | FeatureBits ^= FB; |
248 | return FeatureBits; |
249 | } |
250 | |
251 | FeatureBitset MCSubtargetInfo::SetFeatureBitsTransitively( |
252 | const FeatureBitset &FB) { |
253 | SetImpliedBits(Bits&: FeatureBits, Implies: FB, FeatureTable: ProcFeatures); |
254 | return FeatureBits; |
255 | } |
256 | |
257 | FeatureBitset MCSubtargetInfo::ClearFeatureBitsTransitively( |
258 | const FeatureBitset &FB) { |
259 | for (unsigned I = 0, E = FB.size(); I < E; I++) { |
260 | if (FB[I]) { |
261 | FeatureBits.reset(I); |
262 | ClearImpliedBits(Bits&: FeatureBits, Value: I, FeatureTable: ProcFeatures); |
263 | } |
264 | } |
265 | return FeatureBits; |
266 | } |
267 | |
268 | FeatureBitset MCSubtargetInfo::ToggleFeature(StringRef Feature) { |
269 | // Find feature in table. |
270 | const SubtargetFeatureKV *FeatureEntry = |
271 | Find(S: SubtargetFeatures::StripFlag(Feature), A: ProcFeatures); |
272 | // If there is a match |
273 | if (FeatureEntry) { |
274 | if (FeatureBits.test(I: FeatureEntry->Value)) { |
275 | FeatureBits.reset(I: FeatureEntry->Value); |
276 | // For each feature that implies this, clear it. |
277 | ClearImpliedBits(Bits&: FeatureBits, Value: FeatureEntry->Value, FeatureTable: ProcFeatures); |
278 | } else { |
279 | FeatureBits.set(FeatureEntry->Value); |
280 | |
281 | // For each feature that this implies, set it. |
282 | SetImpliedBits(Bits&: FeatureBits, Implies: FeatureEntry->Implies.getAsBitset(), |
283 | FeatureTable: ProcFeatures); |
284 | } |
285 | } else { |
286 | errs() << "'" << Feature << "' is not a recognized feature for this target" |
287 | << " (ignoring feature)\n" ; |
288 | } |
289 | |
290 | return FeatureBits; |
291 | } |
292 | |
293 | FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) { |
294 | ::ApplyFeatureFlag(Bits&: FeatureBits, Feature: FS, FeatureTable: ProcFeatures); |
295 | return FeatureBits; |
296 | } |
297 | |
298 | bool MCSubtargetInfo::checkFeatures(StringRef FS) const { |
299 | SubtargetFeatures T(FS); |
300 | FeatureBitset Set, All; |
301 | for (std::string F : T.getFeatures()) { |
302 | ::ApplyFeatureFlag(Bits&: Set, Feature: F, FeatureTable: ProcFeatures); |
303 | if (F[0] == '-') |
304 | F[0] = '+'; |
305 | ::ApplyFeatureFlag(Bits&: All, Feature: F, FeatureTable: ProcFeatures); |
306 | } |
307 | return (FeatureBits & All) == Set; |
308 | } |
309 | |
310 | const MCSchedModel &MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const { |
311 | assert(llvm::is_sorted(ProcDesc) && |
312 | "Processor machine model table is not sorted" ); |
313 | |
314 | // Find entry |
315 | const SubtargetSubTypeKV *CPUEntry = Find(S: CPU, A: ProcDesc); |
316 | |
317 | if (!CPUEntry) { |
318 | if (CPU != "help" ) // Don't error if the user asked for help. |
319 | errs() << "'" << CPU |
320 | << "' is not a recognized processor for this target" |
321 | << " (ignoring processor)\n" ; |
322 | return MCSchedModel::Default; |
323 | } |
324 | assert(CPUEntry->SchedModel && "Missing processor SchedModel value" ); |
325 | return *CPUEntry->SchedModel; |
326 | } |
327 | |
328 | InstrItineraryData |
329 | MCSubtargetInfo::getInstrItineraryForCPU(StringRef CPU) const { |
330 | const MCSchedModel &SchedModel = getSchedModelForCPU(CPU); |
331 | return InstrItineraryData(SchedModel, Stages, OperandCycles, ForwardingPaths); |
332 | } |
333 | |
334 | void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const { |
335 | InstrItins = InstrItineraryData(getSchedModel(), Stages, OperandCycles, |
336 | ForwardingPaths); |
337 | } |
338 | |
339 | std::vector<SubtargetFeatureKV> |
340 | MCSubtargetInfo::getEnabledProcessorFeatures() const { |
341 | std::vector<SubtargetFeatureKV> EnabledFeatures; |
342 | auto IsEnabled = [&](const SubtargetFeatureKV &FeatureKV) { |
343 | return FeatureBits.test(I: FeatureKV.Value); |
344 | }; |
345 | llvm::copy_if(Range: ProcFeatures, Out: std::back_inserter(x&: EnabledFeatures), P: IsEnabled); |
346 | return EnabledFeatures; |
347 | } |
348 | |
349 | std::optional<unsigned> MCSubtargetInfo::getCacheSize(unsigned Level) const { |
350 | return std::nullopt; |
351 | } |
352 | |
353 | std::optional<unsigned> |
354 | MCSubtargetInfo::getCacheAssociativity(unsigned Level) const { |
355 | return std::nullopt; |
356 | } |
357 | |
358 | std::optional<unsigned> |
359 | MCSubtargetInfo::getCacheLineSize(unsigned Level) const { |
360 | return std::nullopt; |
361 | } |
362 | |
363 | unsigned MCSubtargetInfo::getPrefetchDistance() const { |
364 | return 0; |
365 | } |
366 | |
367 | unsigned MCSubtargetInfo::getMaxPrefetchIterationsAhead() const { |
368 | return UINT_MAX; |
369 | } |
370 | |
371 | bool MCSubtargetInfo::enableWritePrefetching() const { |
372 | return false; |
373 | } |
374 | |
375 | unsigned MCSubtargetInfo::getMinPrefetchStride(unsigned NumMemAccesses, |
376 | unsigned NumStridedMemAccesses, |
377 | unsigned NumPrefetches, |
378 | bool HasCall) const { |
379 | return 1; |
380 | } |
381 | |
382 | bool MCSubtargetInfo::shouldPrefetchAddressSpace(unsigned AS) const { |
383 | return !AS; |
384 | } |
385 | |