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