llvm-project

Форк
0
/
AArch64TargetParser.cpp 
343 строки · 10.1 Кб
1
//===-- AArch64TargetParser - Parser for AArch64 features -------*- 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 file implements a target parser to recognise AArch64 hardware features
10
// such as FPU/CPU/ARCH and extension names.
11
//
12
//===----------------------------------------------------------------------===//
13

14
#include "llvm/TargetParser/AArch64TargetParser.h"
15
#include "llvm/Support/Debug.h"
16
#include "llvm/Support/Format.h"
17
#include "llvm/Support/raw_ostream.h"
18
#include "llvm/TargetParser/ARMTargetParserCommon.h"
19
#include "llvm/TargetParser/Triple.h"
20
#include <cctype>
21
#include <vector>
22

23
#define DEBUG_TYPE "target-parser"
24

25
using namespace llvm;
26

27
#define EMIT_FMV_INFO
28
#include "llvm/TargetParser/AArch64TargetParserDef.inc"
29

30
static unsigned checkArchVersion(llvm::StringRef Arch) {
31
  if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1]))
32
    return (Arch[1] - 48);
33
  return 0;
34
}
35

36
const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) {
37
  // Note: this now takes cpu aliases into account
38
  std::optional<CpuInfo> Cpu = parseCpu(CPU);
39
  if (!Cpu)
40
    return nullptr;
41
  return &Cpu->Arch;
42
}
43

44
std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubArch) {
45
  for (const auto *A : AArch64::ArchInfos)
46
    if (A->getSubArch() == SubArch)
47
      return *A;
48
  return {};
49
}
50

51
uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
52
  uint64_t FeaturesMask = 0;
53
  for (const StringRef &FeatureStr : FeatureStrs) {
54
    if (auto Ext = parseFMVExtension(FeatureStr))
55
      FeaturesMask |= (1ULL << Ext->Bit);
56
  }
57
  return FeaturesMask;
58
}
59

60
bool AArch64::getExtensionFeatures(
61
    const AArch64::ExtensionBitset &InputExts,
62
    std::vector<StringRef> &Features) {
63
  for (const auto &E : Extensions)
64
    /* INVALID and NONE have no feature name. */
65
    if (InputExts.test(E.ID) && !E.PosTargetFeature.empty())
66
      Features.push_back(E.PosTargetFeature);
67

68
  return true;
69
}
70

71
StringRef AArch64::resolveCPUAlias(StringRef Name) {
72
  for (const auto &A : CpuAliases)
73
    if (A.AltName == Name)
74
      return A.Name;
75
  return Name;
76
}
77

78
StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
79
  bool IsNegated = ArchExt.starts_with("no");
80
  StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt;
81

82
  if (auto AE = parseArchExtension(ArchExtBase)) {
83
    assert(!(AE.has_value() && AE->NegTargetFeature.empty()));
84
    return IsNegated ? AE->NegTargetFeature : AE->PosTargetFeature;
85
  }
86

87
  return StringRef();
88
}
89

90
void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
91
  for (const auto &C : CpuInfos)
92
    Values.push_back(C.Name);
93

94
  for (const auto &Alias : CpuAliases)
95
    // The apple-latest alias is backend only, do not expose it to clang's -mcpu.
96
    if (Alias.AltName != "apple-latest")
97
      Values.push_back(Alias.AltName);
98

99
  llvm::sort(Values);
100
}
101

102
bool AArch64::isX18ReservedByDefault(const Triple &TT) {
103
  return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() ||
104
         TT.isOSWindows() || TT.isOHOSFamily();
105
}
106

107
// Allows partial match, ex. "v8a" matches "armv8a".
108
const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) {
109
  Arch = llvm::ARM::getCanonicalArchName(Arch);
110
  if (checkArchVersion(Arch) < 8)
111
    return {};
112

113
  StringRef Syn = llvm::ARM::getArchSynonym(Arch);
114
  for (const auto *A : ArchInfos) {
115
    if (A->Name.ends_with(Syn))
116
      return A;
117
  }
118
  return {};
119
}
120

121
std::optional<AArch64::ExtensionInfo>
122
AArch64::parseArchExtension(StringRef ArchExt) {
123
  if (ArchExt.empty())
124
    return {};
125
  for (const auto &A : Extensions) {
126
    if (ArchExt == A.UserVisibleName || ArchExt == A.Alias)
127
      return A;
128
  }
129
  return {};
130
}
131

132
std::optional<AArch64::FMVInfo> AArch64::parseFMVExtension(StringRef FMVExt) {
133
  // FIXME introduce general alias functionality, or remove this exception.
134
  if (FMVExt == "rdma")
135
    FMVExt = "rdm";
136

137
  for (const auto &I : getFMVInfo()) {
138
    if (FMVExt == I.Name)
139
      return I;
140
  }
141
  return {};
142
}
143

144
std::optional<AArch64::ExtensionInfo>
145
AArch64::targetFeatureToExtension(StringRef TargetFeature) {
146
  for (const auto &E : Extensions)
147
    if (TargetFeature == E.PosTargetFeature)
148
      return E;
149
  return {};
150
}
151

152
std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) {
153
  // Resolve aliases first.
154
  Name = resolveCPUAlias(Name);
155

156
  // Then find the CPU name.
157
  for (const auto &C : CpuInfos)
158
    if (Name == C.Name)
159
      return C;
160

161
  return {};
162
}
163

164
void AArch64::PrintSupportedExtensions() {
165
  outs() << "All available -march extensions for AArch64\n\n"
166
         << "    " << left_justify("Name", 20)
167
         << left_justify("Architecture Feature(s)", 55)
168
         << "Description\n";
169
  for (const auto &Ext : Extensions) {
170
    // Extensions without a feature cannot be used with -march.
171
    if (!Ext.UserVisibleName.empty() && !Ext.PosTargetFeature.empty()) {
172
      outs() << "    "
173
             << format(Ext.Description.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n",
174
                       Ext.UserVisibleName.str().c_str(),
175
                       Ext.ArchFeatureName.str().c_str(),
176
                       Ext.Description.str().c_str());
177
    }
178
  }
179
}
180

181
void
182
AArch64::printEnabledExtensions(const std::set<StringRef> &EnabledFeatureNames) {
183
  outs() << "Extensions enabled for the given AArch64 target\n\n"
184
         << "    " << left_justify("Architecture Feature(s)", 55)
185
         << "Description\n";
186
  std::vector<ExtensionInfo> EnabledExtensionsInfo;
187
  for (const auto &FeatureName : EnabledFeatureNames) {
188
    std::string PosFeatureName = '+' + FeatureName.str();
189
    if (auto ExtInfo = targetFeatureToExtension(PosFeatureName))
190
      EnabledExtensionsInfo.push_back(*ExtInfo);
191
  }
192

193
  std::sort(EnabledExtensionsInfo.begin(), EnabledExtensionsInfo.end(),
194
            [](const ExtensionInfo &Lhs, const ExtensionInfo &Rhs) {
195
              return Lhs.ArchFeatureName < Rhs.ArchFeatureName;
196
            });
197

198
  for (const auto &Ext : EnabledExtensionsInfo) {
199
    outs() << "    "
200
           << format("%-55s%s\n",
201
                     Ext.ArchFeatureName.str().c_str(),
202
                     Ext.Description.str().c_str());
203
  }
204
}
205

206
const llvm::AArch64::ExtensionInfo &
207
lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) {
208
  for (const auto &E : llvm::AArch64::Extensions)
209
    if (E.ID == ExtID)
210
      return E;
211
  llvm_unreachable("Invalid extension ID");
212
}
213

214
void AArch64::ExtensionSet::enable(ArchExtKind E) {
215
  if (Enabled.test(E))
216
    return;
217

218
  LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).UserVisibleName << "\n");
219

220
  Touched.set(E);
221
  Enabled.set(E);
222

223
  // Recursively enable all features that this one depends on. This handles all
224
  // of the simple cases, where the behaviour doesn't depend on the base
225
  // architecture version.
226
  for (auto Dep : ExtensionDependencies)
227
    if (E == Dep.Later)
228
      enable(Dep.Earlier);
229

230
  // Special cases for dependencies which vary depending on the base
231
  // architecture version.
232
  if (BaseArch) {
233
    // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+
234
    if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) &&
235
        !BaseArch->is_superset(ARMV9A))
236
      enable(AEK_FP16FML);
237

238
    // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4.
239
    if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) {
240
      enable(AEK_SHA3);
241
      enable(AEK_SM4);
242
    }
243
  }
244
}
245

246
void AArch64::ExtensionSet::disable(ArchExtKind E) {
247
  // -crypto always disables aes, sha2, sha3 and sm4, even for architectures
248
  // where the latter two would not be enabled by +crypto.
249
  if (E == AEK_CRYPTO) {
250
    disable(AEK_AES);
251
    disable(AEK_SHA2);
252
    disable(AEK_SHA3);
253
    disable(AEK_SM4);
254
  }
255

256
  if (!Enabled.test(E))
257
    return;
258

259
  LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).UserVisibleName << "\n");
260

261
  Touched.set(E);
262
  Enabled.reset(E);
263

264
  // Recursively disable all features that depends on this one.
265
  for (auto Dep : ExtensionDependencies)
266
    if (E == Dep.Earlier)
267
      disable(Dep.Later);
268
}
269

270
void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) {
271
  LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n");
272
  BaseArch = &CPU.Arch;
273

274
  AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions();
275
  for (const auto &E : Extensions)
276
    if (CPUExtensions.test(E.ID))
277
      enable(E.ID);
278
}
279

280
void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) {
281
  LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n");
282
  BaseArch = &Arch;
283

284
  for (const auto &E : Extensions)
285
    if (Arch.DefaultExts.test(E.ID))
286
      enable(E.ID);
287
}
288

289
bool AArch64::ExtensionSet::parseModifier(StringRef Modifier,
290
                                          const bool AllowNoDashForm) {
291
  LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n");
292

293
  size_t NChars = 0;
294
  // The "no-feat" form is allowed in the target attribute but nowhere else.
295
  if (AllowNoDashForm && Modifier.starts_with("no-"))
296
    NChars = 3;
297
  else if (Modifier.starts_with("no"))
298
    NChars = 2;
299
  bool IsNegated = NChars != 0;
300
  StringRef ArchExt = Modifier.drop_front(NChars);
301

302
  if (auto AE = parseArchExtension(ArchExt)) {
303
    if (AE->PosTargetFeature.empty() || AE->NegTargetFeature.empty())
304
      return false;
305
    if (IsNegated)
306
      disable(AE->ID);
307
    else
308
      enable(AE->ID);
309
    return true;
310
  }
311
  return false;
312
}
313

314
void AArch64::ExtensionSet::reconstructFromParsedFeatures(
315
    const std::vector<std::string> &Features,
316
    std::vector<std::string> &NonExtensions) {
317
  assert(Touched.none() && "Bitset already initialized");
318
  for (auto &F : Features) {
319
    bool IsNegated = F[0] == '-';
320
    if (auto AE = targetFeatureToExtension(F)) {
321
      Touched.set(AE->ID);
322
      if (IsNegated)
323
        Enabled.reset(AE->ID);
324
      else
325
        Enabled.set(AE->ID);
326
      continue;
327
    }
328
    NonExtensions.push_back(F);
329
  }
330
}
331

332
void AArch64::ExtensionSet::dump() const {
333
  std::vector<StringRef> Features;
334
  toLLVMFeatureList(Features);
335
  for (StringRef F : Features)
336
    llvm::outs() << F << " ";
337
  llvm::outs() << "\n";
338
}
339

340
const AArch64::ExtensionInfo &
341
AArch64::getExtensionByID(AArch64::ArchExtKind ExtID) {
342
  return lookupExtensionByID(ExtID);
343
}
344

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.