1343171Sdim//===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===//
2343171Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6343171Sdim//
7343171Sdim//===----------------------------------------------------------------------===//
8343171Sdim//
9343171Sdim// This file implements a target parser to recognise ARM hardware features
10343171Sdim// such as FPU/CPU/ARCH/extensions and specific support such as HWDIV.
11343171Sdim//
12343171Sdim//===----------------------------------------------------------------------===//
13343171Sdim
14343171Sdim#include "llvm/Support/ARMTargetParser.h"
15343171Sdim#include "llvm/ADT/StringSwitch.h"
16343171Sdim#include <cctype>
17343171Sdim
18343171Sdimusing namespace llvm;
19343171Sdim
20343171Sdimstatic StringRef getHWDivSynonym(StringRef HWDiv) {
21343171Sdim  return StringSwitch<StringRef>(HWDiv)
22343171Sdim      .Case("thumb,arm", "arm,thumb")
23343171Sdim      .Default(HWDiv);
24343171Sdim}
25343171Sdim
26343171Sdim// Allows partial match, ex. "v7a" matches "armv7a".
27343171SdimARM::ArchKind ARM::parseArch(StringRef Arch) {
28343171Sdim  Arch = getCanonicalArchName(Arch);
29343171Sdim  StringRef Syn = getArchSynonym(Arch);
30343171Sdim  for (const auto A : ARCHNames) {
31343171Sdim    if (A.getName().endswith(Syn))
32343171Sdim      return A.ID;
33343171Sdim  }
34343171Sdim  return ArchKind::INVALID;
35343171Sdim}
36343171Sdim
37343171Sdim// Version number (ex. v7 = 7).
38343171Sdimunsigned ARM::parseArchVersion(StringRef Arch) {
39343171Sdim  Arch = getCanonicalArchName(Arch);
40343171Sdim  switch (parseArch(Arch)) {
41343171Sdim  case ArchKind::ARMV2:
42343171Sdim  case ArchKind::ARMV2A:
43343171Sdim    return 2;
44343171Sdim  case ArchKind::ARMV3:
45343171Sdim  case ArchKind::ARMV3M:
46343171Sdim    return 3;
47343171Sdim  case ArchKind::ARMV4:
48343171Sdim  case ArchKind::ARMV4T:
49343171Sdim    return 4;
50343171Sdim  case ArchKind::ARMV5T:
51343171Sdim  case ArchKind::ARMV5TE:
52343171Sdim  case ArchKind::IWMMXT:
53343171Sdim  case ArchKind::IWMMXT2:
54343171Sdim  case ArchKind::XSCALE:
55343171Sdim  case ArchKind::ARMV5TEJ:
56343171Sdim    return 5;
57343171Sdim  case ArchKind::ARMV6:
58343171Sdim  case ArchKind::ARMV6K:
59343171Sdim  case ArchKind::ARMV6T2:
60343171Sdim  case ArchKind::ARMV6KZ:
61343171Sdim  case ArchKind::ARMV6M:
62343171Sdim    return 6;
63343171Sdim  case ArchKind::ARMV7A:
64343171Sdim  case ArchKind::ARMV7VE:
65343171Sdim  case ArchKind::ARMV7R:
66343171Sdim  case ArchKind::ARMV7M:
67343171Sdim  case ArchKind::ARMV7S:
68343171Sdim  case ArchKind::ARMV7EM:
69343171Sdim  case ArchKind::ARMV7K:
70343171Sdim    return 7;
71343171Sdim  case ArchKind::ARMV8A:
72343171Sdim  case ArchKind::ARMV8_1A:
73343171Sdim  case ArchKind::ARMV8_2A:
74343171Sdim  case ArchKind::ARMV8_3A:
75343171Sdim  case ArchKind::ARMV8_4A:
76343171Sdim  case ArchKind::ARMV8_5A:
77343171Sdim  case ArchKind::ARMV8R:
78343171Sdim  case ArchKind::ARMV8MBaseline:
79343171Sdim  case ArchKind::ARMV8MMainline:
80353358Sdim  case ArchKind::ARMV8_1MMainline:
81343171Sdim    return 8;
82343171Sdim  case ArchKind::INVALID:
83343171Sdim    return 0;
84343171Sdim  }
85343171Sdim  llvm_unreachable("Unhandled architecture");
86343171Sdim}
87343171Sdim
88343171Sdim// Profile A/R/M
89343171SdimARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
90343171Sdim  Arch = getCanonicalArchName(Arch);
91343171Sdim  switch (parseArch(Arch)) {
92343171Sdim  case ArchKind::ARMV6M:
93343171Sdim  case ArchKind::ARMV7M:
94343171Sdim  case ArchKind::ARMV7EM:
95343171Sdim  case ArchKind::ARMV8MMainline:
96343171Sdim  case ArchKind::ARMV8MBaseline:
97353358Sdim  case ArchKind::ARMV8_1MMainline:
98343171Sdim    return ProfileKind::M;
99343171Sdim  case ArchKind::ARMV7R:
100343171Sdim  case ArchKind::ARMV8R:
101343171Sdim    return ProfileKind::R;
102343171Sdim  case ArchKind::ARMV7A:
103343171Sdim  case ArchKind::ARMV7VE:
104343171Sdim  case ArchKind::ARMV7K:
105343171Sdim  case ArchKind::ARMV8A:
106343171Sdim  case ArchKind::ARMV8_1A:
107343171Sdim  case ArchKind::ARMV8_2A:
108343171Sdim  case ArchKind::ARMV8_3A:
109343171Sdim  case ArchKind::ARMV8_4A:
110343171Sdim  case ArchKind::ARMV8_5A:
111343171Sdim    return ProfileKind::A;
112343171Sdim  case ArchKind::ARMV2:
113343171Sdim  case ArchKind::ARMV2A:
114343171Sdim  case ArchKind::ARMV3:
115343171Sdim  case ArchKind::ARMV3M:
116343171Sdim  case ArchKind::ARMV4:
117343171Sdim  case ArchKind::ARMV4T:
118343171Sdim  case ArchKind::ARMV5T:
119343171Sdim  case ArchKind::ARMV5TE:
120343171Sdim  case ArchKind::ARMV5TEJ:
121343171Sdim  case ArchKind::ARMV6:
122343171Sdim  case ArchKind::ARMV6K:
123343171Sdim  case ArchKind::ARMV6T2:
124343171Sdim  case ArchKind::ARMV6KZ:
125343171Sdim  case ArchKind::ARMV7S:
126343171Sdim  case ArchKind::IWMMXT:
127343171Sdim  case ArchKind::IWMMXT2:
128343171Sdim  case ArchKind::XSCALE:
129343171Sdim  case ArchKind::INVALID:
130343171Sdim    return ProfileKind::INVALID;
131343171Sdim  }
132343171Sdim  llvm_unreachable("Unhandled architecture");
133343171Sdim}
134343171Sdim
135343171SdimStringRef ARM::getArchSynonym(StringRef Arch) {
136343171Sdim  return StringSwitch<StringRef>(Arch)
137343171Sdim      .Case("v5", "v5t")
138343171Sdim      .Case("v5e", "v5te")
139343171Sdim      .Case("v6j", "v6")
140343171Sdim      .Case("v6hl", "v6k")
141343171Sdim      .Cases("v6m", "v6sm", "v6s-m", "v6-m")
142343171Sdim      .Cases("v6z", "v6zk", "v6kz")
143343171Sdim      .Cases("v7", "v7a", "v7hl", "v7l", "v7-a")
144343171Sdim      .Case("v7r", "v7-r")
145343171Sdim      .Case("v7m", "v7-m")
146343171Sdim      .Case("v7em", "v7e-m")
147343171Sdim      .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a")
148343171Sdim      .Case("v8.1a", "v8.1-a")
149343171Sdim      .Case("v8.2a", "v8.2-a")
150343171Sdim      .Case("v8.3a", "v8.3-a")
151343171Sdim      .Case("v8.4a", "v8.4-a")
152343171Sdim      .Case("v8.5a", "v8.5-a")
153343171Sdim      .Case("v8r", "v8-r")
154343171Sdim      .Case("v8m.base", "v8-m.base")
155343171Sdim      .Case("v8m.main", "v8-m.main")
156353358Sdim      .Case("v8.1m.main", "v8.1-m.main")
157343171Sdim      .Default(Arch);
158343171Sdim}
159343171Sdim
160343171Sdimbool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) {
161343171Sdim
162343171Sdim  if (FPUKind >= FK_LAST || FPUKind == FK_INVALID)
163343171Sdim    return false;
164343171Sdim
165353358Sdim  static const struct FPUFeatureNameInfo {
166353358Sdim    const char *PlusName, *MinusName;
167353358Sdim    FPUVersion MinVersion;
168353358Sdim    FPURestriction MaxRestriction;
169353358Sdim  } FPUFeatureInfoList[] = {
170353358Sdim    // We have to specify the + and - versions of the name in full so
171353358Sdim    // that we can return them as static StringRefs.
172353358Sdim    //
173353358Sdim    // Also, the SubtargetFeatures ending in just "sp" are listed here
174353358Sdim    // under FPURestriction::None, which is the only FPURestriction in
175353358Sdim    // which they would be valid (since FPURestriction::SP doesn't
176353358Sdim    // exist).
177354097Sdim    {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::D16},
178354097Sdim    {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::SP_D16},
179353358Sdim    {"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None},
180353358Sdim    {"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16},
181353358Sdim    {"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16},
182353358Sdim    {"+vfp3sp", "-vfp3sp", FPUVersion::VFPV3, FPURestriction::None},
183353358Sdim    {"+fp16", "-fp16", FPUVersion::VFPV3_FP16, FPURestriction::SP_D16},
184353358Sdim    {"+vfp4", "-vfp4", FPUVersion::VFPV4, FPURestriction::None},
185353358Sdim    {"+vfp4d16", "-vfp4d16", FPUVersion::VFPV4, FPURestriction::D16},
186353358Sdim    {"+vfp4d16sp", "-vfp4d16sp", FPUVersion::VFPV4, FPURestriction::SP_D16},
187353358Sdim    {"+vfp4sp", "-vfp4sp", FPUVersion::VFPV4, FPURestriction::None},
188353358Sdim    {"+fp-armv8", "-fp-armv8", FPUVersion::VFPV5, FPURestriction::None},
189353358Sdim    {"+fp-armv8d16", "-fp-armv8d16", FPUVersion::VFPV5, FPURestriction::D16},
190353358Sdim    {"+fp-armv8d16sp", "-fp-armv8d16sp", FPUVersion::VFPV5, FPURestriction::SP_D16},
191353358Sdim    {"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None},
192353358Sdim    {"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16},
193353358Sdim    {"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16},
194354097Sdim    {"+d32", "-d32", FPUVersion::VFPV3, FPURestriction::None},
195353358Sdim  };
196353358Sdim
197353358Sdim  for (const auto &Info: FPUFeatureInfoList) {
198353358Sdim    if (FPUNames[FPUKind].FPUVer >= Info.MinVersion &&
199353358Sdim        FPUNames[FPUKind].Restriction <= Info.MaxRestriction)
200353358Sdim      Features.push_back(Info.PlusName);
201353358Sdim    else
202353358Sdim      Features.push_back(Info.MinusName);
203343171Sdim  }
204343171Sdim
205353358Sdim  static const struct NeonFeatureNameInfo {
206353358Sdim    const char *PlusName, *MinusName;
207353358Sdim    NeonSupportLevel MinSupportLevel;
208353358Sdim  } NeonFeatureInfoList[] = {
209353358Sdim    {"+neon", "-neon", NeonSupportLevel::Neon},
210353358Sdim    {"+crypto", "-crypto", NeonSupportLevel::Crypto},
211353358Sdim  };
212353358Sdim
213353358Sdim  for (const auto &Info: NeonFeatureInfoList) {
214353358Sdim    if (FPUNames[FPUKind].NeonSupport >= Info.MinSupportLevel)
215353358Sdim      Features.push_back(Info.PlusName);
216353358Sdim    else
217353358Sdim      Features.push_back(Info.MinusName);
218343171Sdim  }
219343171Sdim
220343171Sdim  return true;
221343171Sdim}
222343171Sdim
223343171Sdim// Little/Big endian
224343171SdimARM::EndianKind ARM::parseArchEndian(StringRef Arch) {
225343171Sdim  if (Arch.startswith("armeb") || Arch.startswith("thumbeb") ||
226343171Sdim      Arch.startswith("aarch64_be"))
227343171Sdim    return EndianKind::BIG;
228343171Sdim
229343171Sdim  if (Arch.startswith("arm") || Arch.startswith("thumb")) {
230343171Sdim    if (Arch.endswith("eb"))
231343171Sdim      return EndianKind::BIG;
232343171Sdim    else
233343171Sdim      return EndianKind::LITTLE;
234343171Sdim  }
235343171Sdim
236353358Sdim  if (Arch.startswith("aarch64") || Arch.startswith("aarch64_32"))
237343171Sdim    return EndianKind::LITTLE;
238343171Sdim
239343171Sdim  return EndianKind::INVALID;
240343171Sdim}
241343171Sdim
242343171Sdim// ARM, Thumb, AArch64
243343171SdimARM::ISAKind ARM::parseArchISA(StringRef Arch) {
244343171Sdim  return StringSwitch<ISAKind>(Arch)
245343171Sdim      .StartsWith("aarch64", ISAKind::AARCH64)
246343171Sdim      .StartsWith("arm64", ISAKind::AARCH64)
247343171Sdim      .StartsWith("thumb", ISAKind::THUMB)
248343171Sdim      .StartsWith("arm", ISAKind::ARM)
249343171Sdim      .Default(ISAKind::INVALID);
250343171Sdim}
251343171Sdim
252343171Sdimunsigned ARM::parseFPU(StringRef FPU) {
253343171Sdim  StringRef Syn = getFPUSynonym(FPU);
254343171Sdim  for (const auto F : FPUNames) {
255343171Sdim    if (Syn == F.getName())
256343171Sdim      return F.ID;
257343171Sdim  }
258343171Sdim  return FK_INVALID;
259343171Sdim}
260343171Sdim
261343171SdimARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(unsigned FPUKind) {
262343171Sdim  if (FPUKind >= FK_LAST)
263343171Sdim    return NeonSupportLevel::None;
264343171Sdim  return FPUNames[FPUKind].NeonSupport;
265343171Sdim}
266343171Sdim
267343171Sdim// MArch is expected to be of the form (arm|thumb)?(eb)?(v.+)?(eb)?, but
268343171Sdim// (iwmmxt|xscale)(eb)? is also permitted. If the former, return
269343171Sdim// "v.+", if the latter, return unmodified string, minus 'eb'.
270343171Sdim// If invalid, return empty string.
271343171SdimStringRef ARM::getCanonicalArchName(StringRef Arch) {
272343171Sdim  size_t offset = StringRef::npos;
273343171Sdim  StringRef A = Arch;
274343171Sdim  StringRef Error = "";
275343171Sdim
276343171Sdim  // Begins with "arm" / "thumb", move past it.
277353358Sdim  if (A.startswith("arm64_32"))
278353358Sdim    offset = 8;
279353358Sdim  else if (A.startswith("arm64"))
280343171Sdim    offset = 5;
281353358Sdim  else if (A.startswith("aarch64_32"))
282353358Sdim    offset = 10;
283343171Sdim  else if (A.startswith("arm"))
284343171Sdim    offset = 3;
285343171Sdim  else if (A.startswith("thumb"))
286343171Sdim    offset = 5;
287343171Sdim  else if (A.startswith("aarch64")) {
288343171Sdim    offset = 7;
289343171Sdim    // AArch64 uses "_be", not "eb" suffix.
290343171Sdim    if (A.find("eb") != StringRef::npos)
291343171Sdim      return Error;
292343171Sdim    if (A.substr(offset, 3) == "_be")
293343171Sdim      offset += 3;
294343171Sdim  }
295343171Sdim
296343171Sdim  // Ex. "armebv7", move past the "eb".
297343171Sdim  if (offset != StringRef::npos && A.substr(offset, 2) == "eb")
298343171Sdim    offset += 2;
299343171Sdim  // Or, if it ends with eb ("armv7eb"), chop it off.
300343171Sdim  else if (A.endswith("eb"))
301343171Sdim    A = A.substr(0, A.size() - 2);
302343171Sdim  // Trim the head
303343171Sdim  if (offset != StringRef::npos)
304343171Sdim    A = A.substr(offset);
305343171Sdim
306343171Sdim  // Empty string means offset reached the end, which means it's valid.
307343171Sdim  if (A.empty())
308343171Sdim    return Arch;
309343171Sdim
310343171Sdim  // Only match non-marketing names
311343171Sdim  if (offset != StringRef::npos) {
312343171Sdim    // Must start with 'vN'.
313343171Sdim    if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1])))
314343171Sdim      return Error;
315343171Sdim    // Can't have an extra 'eb'.
316343171Sdim    if (A.find("eb") != StringRef::npos)
317343171Sdim      return Error;
318343171Sdim  }
319343171Sdim
320343171Sdim  // Arch will either be a 'v' name (v7a) or a marketing name (xscale).
321343171Sdim  return A;
322343171Sdim}
323343171Sdim
324343171SdimStringRef ARM::getFPUSynonym(StringRef FPU) {
325343171Sdim  return StringSwitch<StringRef>(FPU)
326343171Sdim      .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported
327343171Sdim      .Case("vfp2", "vfpv2")
328343171Sdim      .Case("vfp3", "vfpv3")
329343171Sdim      .Case("vfp4", "vfpv4")
330343171Sdim      .Case("vfp3-d16", "vfpv3-d16")
331343171Sdim      .Case("vfp4-d16", "vfpv4-d16")
332343171Sdim      .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16")
333343171Sdim      .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16")
334343171Sdim      .Case("fp5-sp-d16", "fpv5-sp-d16")
335343171Sdim      .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16")
336343171Sdim      // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3.
337343171Sdim      .Case("neon-vfpv3", "neon")
338343171Sdim      .Default(FPU);
339343171Sdim}
340343171Sdim
341343171SdimStringRef ARM::getFPUName(unsigned FPUKind) {
342343171Sdim  if (FPUKind >= FK_LAST)
343343171Sdim    return StringRef();
344343171Sdim  return FPUNames[FPUKind].getName();
345343171Sdim}
346343171Sdim
347343171SdimARM::FPUVersion ARM::getFPUVersion(unsigned FPUKind) {
348343171Sdim  if (FPUKind >= FK_LAST)
349343171Sdim    return FPUVersion::NONE;
350343171Sdim  return FPUNames[FPUKind].FPUVer;
351343171Sdim}
352343171Sdim
353343171SdimARM::FPURestriction ARM::getFPURestriction(unsigned FPUKind) {
354343171Sdim  if (FPUKind >= FK_LAST)
355343171Sdim    return FPURestriction::None;
356343171Sdim  return FPUNames[FPUKind].Restriction;
357343171Sdim}
358343171Sdim
359343171Sdimunsigned ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) {
360343171Sdim  if (CPU == "generic")
361343171Sdim    return ARM::ARCHNames[static_cast<unsigned>(AK)].DefaultFPU;
362343171Sdim
363343171Sdim  return StringSwitch<unsigned>(CPU)
364343171Sdim#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)           \
365343171Sdim  .Case(NAME, DEFAULT_FPU)
366343171Sdim#include "llvm/Support/ARMTargetParser.def"
367343171Sdim   .Default(ARM::FK_INVALID);
368343171Sdim}
369343171Sdim
370343171Sdimunsigned ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) {
371343171Sdim  if (CPU == "generic")
372343171Sdim    return ARM::ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions;
373343171Sdim
374343171Sdim  return StringSwitch<unsigned>(CPU)
375343171Sdim#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)           \
376343171Sdim  .Case(NAME,                                                                  \
377343171Sdim        ARCHNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions |    \
378343171Sdim            DEFAULT_EXT)
379343171Sdim#include "llvm/Support/ARMTargetParser.def"
380343171Sdim  .Default(ARM::AEK_INVALID);
381343171Sdim}
382343171Sdim
383343171Sdimbool ARM::getHWDivFeatures(unsigned HWDivKind,
384343171Sdim                           std::vector<StringRef> &Features) {
385343171Sdim
386343171Sdim  if (HWDivKind == AEK_INVALID)
387343171Sdim    return false;
388343171Sdim
389343171Sdim  if (HWDivKind & AEK_HWDIVARM)
390343171Sdim    Features.push_back("+hwdiv-arm");
391343171Sdim  else
392343171Sdim    Features.push_back("-hwdiv-arm");
393343171Sdim
394343171Sdim  if (HWDivKind & AEK_HWDIVTHUMB)
395343171Sdim    Features.push_back("+hwdiv");
396343171Sdim  else
397343171Sdim    Features.push_back("-hwdiv");
398343171Sdim
399343171Sdim  return true;
400343171Sdim}
401343171Sdim
402343171Sdimbool ARM::getExtensionFeatures(unsigned Extensions,
403343171Sdim                               std::vector<StringRef> &Features) {
404343171Sdim
405343171Sdim  if (Extensions == AEK_INVALID)
406343171Sdim    return false;
407343171Sdim
408353358Sdim  for (const auto AE : ARCHExtNames) {
409353358Sdim    if ((Extensions & AE.ID) == AE.ID && AE.Feature)
410353358Sdim      Features.push_back(AE.Feature);
411353358Sdim    else if (AE.NegFeature)
412353358Sdim      Features.push_back(AE.NegFeature);
413353358Sdim  }
414343171Sdim
415343171Sdim  return getHWDivFeatures(Extensions, Features);
416343171Sdim}
417343171Sdim
418343171SdimStringRef ARM::getArchName(ARM::ArchKind AK) {
419343171Sdim  return ARCHNames[static_cast<unsigned>(AK)].getName();
420343171Sdim}
421343171Sdim
422343171SdimStringRef ARM::getCPUAttr(ARM::ArchKind AK) {
423343171Sdim  return ARCHNames[static_cast<unsigned>(AK)].getCPUAttr();
424343171Sdim}
425343171Sdim
426343171SdimStringRef ARM::getSubArch(ARM::ArchKind AK) {
427343171Sdim  return ARCHNames[static_cast<unsigned>(AK)].getSubArch();
428343171Sdim}
429343171Sdim
430343171Sdimunsigned ARM::getArchAttr(ARM::ArchKind AK) {
431343171Sdim  return ARCHNames[static_cast<unsigned>(AK)].ArchAttr;
432343171Sdim}
433343171Sdim
434343171SdimStringRef ARM::getArchExtName(unsigned ArchExtKind) {
435343171Sdim  for (const auto AE : ARCHExtNames) {
436343171Sdim    if (ArchExtKind == AE.ID)
437343171Sdim      return AE.getName();
438343171Sdim  }
439343171Sdim  return StringRef();
440343171Sdim}
441343171Sdim
442353358Sdimstatic bool stripNegationPrefix(StringRef &Name) {
443353358Sdim  if (Name.startswith("no")) {
444353358Sdim    Name = Name.substr(2);
445353358Sdim    return true;
446353358Sdim  }
447353358Sdim  return false;
448353358Sdim}
449353358Sdim
450343171SdimStringRef ARM::getArchExtFeature(StringRef ArchExt) {
451353358Sdim  bool Negated = stripNegationPrefix(ArchExt);
452343171Sdim  for (const auto AE : ARCHExtNames) {
453343171Sdim    if (AE.Feature && ArchExt == AE.getName())
454353358Sdim      return StringRef(Negated ? AE.NegFeature : AE.Feature);
455343171Sdim  }
456343171Sdim
457343171Sdim  return StringRef();
458343171Sdim}
459343171Sdim
460353358Sdimstatic unsigned findDoublePrecisionFPU(unsigned InputFPUKind) {
461353358Sdim  const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];
462353358Sdim
463353358Sdim  // If the input FPU already supports double-precision, then there
464353358Sdim  // isn't any different FPU we can return here.
465353358Sdim  //
466353358Sdim  // The current available FPURestriction values are None (no
467353358Sdim  // restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs
468353358Sdim  // and single precision only); there's no value representing
469353358Sdim  // SP restriction without D16. So this test just means 'is it
470353358Sdim  // SP only?'.
471353358Sdim  if (InputFPU.Restriction != ARM::FPURestriction::SP_D16)
472353358Sdim    return ARM::FK_INVALID;
473353358Sdim
474353358Sdim  // Otherwise, look for an FPU entry with all the same fields, except
475353358Sdim  // that SP_D16 has been replaced with just D16, representing adding
476353358Sdim  // double precision and not changing anything else.
477353358Sdim  for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
478353358Sdim    if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
479353358Sdim        CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
480353358Sdim        CandidateFPU.Restriction == ARM::FPURestriction::D16) {
481353358Sdim      return CandidateFPU.ID;
482353358Sdim    }
483353358Sdim  }
484353358Sdim
485353358Sdim  // nothing found
486353358Sdim  return ARM::FK_INVALID;
487353358Sdim}
488353358Sdim
489353358Sdimstatic unsigned getAEKID(StringRef ArchExtName) {
490353358Sdim  for (const auto AE : ARM::ARCHExtNames)
491353358Sdim    if (AE.getName() == ArchExtName)
492353358Sdim      return AE.ID;
493353358Sdim  return ARM::AEK_INVALID;
494353358Sdim}
495353358Sdim
496353358Sdimbool ARM::appendArchExtFeatures(
497353358Sdim  StringRef CPU, ARM::ArchKind AK, StringRef ArchExt,
498353358Sdim  std::vector<StringRef> &Features) {
499353358Sdim
500353358Sdim  size_t StartingNumFeatures = Features.size();
501353358Sdim  const bool Negated = stripNegationPrefix(ArchExt);
502353358Sdim  unsigned ID = getAEKID(ArchExt);
503353358Sdim
504353358Sdim  if (ID == AEK_INVALID)
505353358Sdim    return false;
506353358Sdim
507353358Sdim  for (const auto AE : ARCHExtNames) {
508353358Sdim    if (Negated && (AE.ID & ID) == ID && AE.NegFeature)
509353358Sdim      Features.push_back(AE.NegFeature);
510353358Sdim    else if (AE.ID == ID && AE.Feature)
511353358Sdim      Features.push_back(AE.Feature);
512353358Sdim  }
513353358Sdim
514353358Sdim  if (CPU == "")
515353358Sdim    CPU = "generic";
516353358Sdim
517353358Sdim  if (ArchExt == "fp" || ArchExt == "fp.dp") {
518353358Sdim    unsigned FPUKind;
519353358Sdim    if (ArchExt == "fp.dp") {
520353358Sdim      if (Negated) {
521353358Sdim        Features.push_back("-fp64");
522353358Sdim        return true;
523353358Sdim      }
524353358Sdim      FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK));
525353358Sdim    } else if (Negated) {
526353358Sdim      FPUKind = ARM::FK_NONE;
527353358Sdim    } else {
528353358Sdim      FPUKind = getDefaultFPU(CPU, AK);
529353358Sdim    }
530353358Sdim    return ARM::getFPUFeatures(FPUKind, Features);
531353358Sdim  }
532353358Sdim  return StartingNumFeatures != Features.size();
533353358Sdim}
534353358Sdim
535343171SdimStringRef ARM::getHWDivName(unsigned HWDivKind) {
536343171Sdim  for (const auto D : HWDivNames) {
537343171Sdim    if (HWDivKind == D.ID)
538343171Sdim      return D.getName();
539343171Sdim  }
540343171Sdim  return StringRef();
541343171Sdim}
542343171Sdim
543343171SdimStringRef ARM::getDefaultCPU(StringRef Arch) {
544343171Sdim  ArchKind AK = parseArch(Arch);
545343171Sdim  if (AK == ArchKind::INVALID)
546343171Sdim    return StringRef();
547343171Sdim
548343171Sdim  // Look for multiple AKs to find the default for pair AK+Name.
549343171Sdim  for (const auto CPU : CPUNames) {
550343171Sdim    if (CPU.ArchID == AK && CPU.Default)
551343171Sdim      return CPU.getName();
552343171Sdim  }
553343171Sdim
554343171Sdim  // If we can't find a default then target the architecture instead
555343171Sdim  return "generic";
556343171Sdim}
557343171Sdim
558343171Sdimunsigned ARM::parseHWDiv(StringRef HWDiv) {
559343171Sdim  StringRef Syn = getHWDivSynonym(HWDiv);
560343171Sdim  for (const auto D : HWDivNames) {
561343171Sdim    if (Syn == D.getName())
562343171Sdim      return D.ID;
563343171Sdim  }
564343171Sdim  return AEK_INVALID;
565343171Sdim}
566343171Sdim
567343171Sdimunsigned ARM::parseArchExt(StringRef ArchExt) {
568343171Sdim  for (const auto A : ARCHExtNames) {
569343171Sdim    if (ArchExt == A.getName())
570343171Sdim      return A.ID;
571343171Sdim  }
572343171Sdim  return AEK_INVALID;
573343171Sdim}
574343171Sdim
575343171SdimARM::ArchKind ARM::parseCPUArch(StringRef CPU) {
576343171Sdim  for (const auto C : CPUNames) {
577343171Sdim    if (CPU == C.getName())
578343171Sdim      return C.ArchID;
579343171Sdim  }
580343171Sdim  return ArchKind::INVALID;
581343171Sdim}
582343171Sdim
583343171Sdimvoid ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
584343171Sdim  for (const CpuNames<ArchKind> &Arch : CPUNames) {
585343171Sdim    if (Arch.ArchID != ArchKind::INVALID)
586343171Sdim      Values.push_back(Arch.getName());
587343171Sdim  }
588343171Sdim}
589343171Sdim
590343171SdimStringRef ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) {
591343171Sdim  StringRef ArchName =
592343171Sdim      CPU.empty() ? TT.getArchName() : getArchName(parseCPUArch(CPU));
593343171Sdim
594343171Sdim  if (TT.isOSBinFormatMachO()) {
595343171Sdim    if (TT.getEnvironment() == Triple::EABI ||
596343171Sdim        TT.getOS() == Triple::UnknownOS ||
597343171Sdim        parseArchProfile(ArchName) == ProfileKind::M)
598343171Sdim      return "aapcs";
599343171Sdim    if (TT.isWatchABI())
600343171Sdim      return "aapcs16";
601343171Sdim    return "apcs-gnu";
602343171Sdim  } else if (TT.isOSWindows())
603343171Sdim    // FIXME: this is invalid for WindowsCE.
604343171Sdim    return "aapcs";
605343171Sdim
606343171Sdim  // Select the default based on the platform.
607343171Sdim  switch (TT.getEnvironment()) {
608343171Sdim  case Triple::Android:
609343171Sdim  case Triple::GNUEABI:
610343171Sdim  case Triple::GNUEABIHF:
611343171Sdim  case Triple::MuslEABI:
612343171Sdim  case Triple::MuslEABIHF:
613343171Sdim    return "aapcs-linux";
614343171Sdim  case Triple::EABIHF:
615343171Sdim  case Triple::EABI:
616343171Sdim    return "aapcs";
617343171Sdim  default:
618343171Sdim    if (TT.isOSNetBSD())
619343171Sdim      return "apcs-gnu";
620343171Sdim    if (TT.isOSOpenBSD())
621343171Sdim      return "aapcs-linux";
622343171Sdim    return "aapcs";
623343171Sdim  }
624343171Sdim}
625