TargetParser.cpp revision 284734
1283625Sdim//===-- TargetParser - Parser for target features ---------------*- C++ -*-===//
2283625Sdim//
3283625Sdim//                     The LLVM Compiler Infrastructure
4283625Sdim//
5283625Sdim// This file is distributed under the University of Illinois Open Source
6283625Sdim// License. See LICENSE.TXT for details.
7283625Sdim//
8283625Sdim//===----------------------------------------------------------------------===//
9283625Sdim//
10283625Sdim// This file implements a target parser to recognise hardware features such as
11283625Sdim// FPU/CPU/ARCH names as well as specific support such as HDIV, etc.
12283625Sdim//
13283625Sdim//===----------------------------------------------------------------------===//
14283625Sdim
15283625Sdim#include "llvm/Support/ARMBuildAttributes.h"
16283625Sdim#include "llvm/Support/TargetParser.h"
17283625Sdim#include "llvm/ADT/StringExtras.h"
18283625Sdim#include "llvm/ADT/StringSwitch.h"
19283625Sdim#include <cctype>
20283625Sdim
21283625Sdimusing namespace llvm;
22283625Sdim
23283625Sdimnamespace {
24283625Sdim
25284236Sdim// List of canonical FPU names (use getFPUSynonym) and which architectural
26284236Sdim// features they correspond to (use getFPUFeatures).
27283625Sdim// FIXME: TableGen this.
28283625Sdimstruct {
29283625Sdim  const char * Name;
30283625Sdim  ARM::FPUKind ID;
31284236Sdim  unsigned FPUVersion; ///< Corresponds directly to the FP arch version number.
32284236Sdim  ARM::NeonSupportLevel NeonSupport;
33284236Sdim  ARM::FPURestriction Restriction;
34283625Sdim} FPUNames[] = {
35284236Sdim  { "invalid",       ARM::FK_INVALID,       0, ARM::NS_None,   ARM::FR_None},
36284236Sdim  { "none",          ARM::FK_NONE,          0, ARM::NS_None,   ARM::FR_None},
37284236Sdim  { "vfp",           ARM::FK_VFP,           2, ARM::NS_None,   ARM::FR_None},
38284236Sdim  { "vfpv2",         ARM::FK_VFPV2,         2, ARM::NS_None,   ARM::FR_None},
39284236Sdim  { "vfpv3",         ARM::FK_VFPV3,         3, ARM::NS_None,   ARM::FR_None},
40284236Sdim  { "vfpv3-d16",     ARM::FK_VFPV3_D16,     3, ARM::NS_None,   ARM::FR_D16},
41284236Sdim  { "vfpv4",         ARM::FK_VFPV4,         4, ARM::NS_None,   ARM::FR_None},
42284236Sdim  { "vfpv4-d16",     ARM::FK_VFPV4_D16,     4, ARM::NS_None,   ARM::FR_D16},
43284236Sdim  { "fpv4-sp-d16",   ARM::FK_FPV4_SP_D16,   4, ARM::NS_None,   ARM::FR_SP_D16},
44284236Sdim  { "fpv5-d16",      ARM::FK_FPV5_D16,      5, ARM::NS_None,   ARM::FR_D16},
45284236Sdim  { "fpv5-sp-d16",   ARM::FK_FPV5_SP_D16,   5, ARM::NS_None,   ARM::FR_SP_D16},
46284236Sdim  { "fp-armv8",      ARM::FK_FP_ARMV8,      5, ARM::NS_None,   ARM::FR_None},
47284236Sdim  { "neon",          ARM::FK_NEON,          3, ARM::NS_Neon,   ARM::FR_None},
48284236Sdim  { "neon-vfpv4",    ARM::FK_NEON_VFPV4,    4, ARM::NS_Neon,   ARM::FR_None},
49284236Sdim  { "neon-fp-armv8", ARM::FK_NEON_FP_ARMV8, 5, ARM::NS_Neon,   ARM::FR_None},
50284236Sdim  { "crypto-neon-fp-armv8",
51284236Sdim              ARM::FK_CRYPTO_NEON_FP_ARMV8, 5, ARM::NS_Crypto, ARM::FR_None},
52284236Sdim  { "softvfp",       ARM::FK_SOFTVFP,       0, ARM::NS_None,   ARM::FR_None},
53283625Sdim};
54284236Sdim
55284236Sdim// List of canonical arch names (use getArchSynonym).
56284236Sdim// This table also provides the build attribute fields for CPU arch
57284236Sdim// and Arch ID, according to the Addenda to the ARM ABI, chapters
58284236Sdim// 2.4 and 2.3.5.2 respectively.
59284236Sdim// FIXME: SubArch values were simplified to fit into the expectations
60284236Sdim// of the triples and are not conforming with their official names.
61284236Sdim// Check to see if the expectation should be changed.
62283625Sdim// FIXME: TableGen this.
63283625Sdimstruct {
64283625Sdim  const char *Name;
65283625Sdim  ARM::ArchKind ID;
66284236Sdim  const char *CPUAttr; // CPU class in build attributes.
67284236Sdim  const char *SubArch; // Sub-Arch name.
68284236Sdim  ARMBuildAttrs::CPUArch ArchAttr; // Arch ID in build attributes.
69283625Sdim} ARCHNames[] = {
70284236Sdim  { "invalid",   ARM::AK_INVALID,  nullptr,   nullptr, ARMBuildAttrs::CPUArch::Pre_v4 },
71284236Sdim  { "armv2",     ARM::AK_ARMV2,    "2",       "v2",    ARMBuildAttrs::CPUArch::Pre_v4 },
72284236Sdim  { "armv2a",    ARM::AK_ARMV2A,   "2A",      "v2a",   ARMBuildAttrs::CPUArch::Pre_v4 },
73284236Sdim  { "armv3",     ARM::AK_ARMV3,    "3",       "v3",    ARMBuildAttrs::CPUArch::Pre_v4 },
74284236Sdim  { "armv3m",    ARM::AK_ARMV3M,   "3M",      "v3m",   ARMBuildAttrs::CPUArch::Pre_v4 },
75284236Sdim  { "armv4",     ARM::AK_ARMV4,    "4",       "v4",    ARMBuildAttrs::CPUArch::v4 },
76284236Sdim  { "armv4t",    ARM::AK_ARMV4T,   "4T",      "v4t",   ARMBuildAttrs::CPUArch::v4T },
77284236Sdim  { "armv5t",    ARM::AK_ARMV5T,   "5T",      "v5",    ARMBuildAttrs::CPUArch::v5T },
78284236Sdim  { "armv5te",   ARM::AK_ARMV5TE,  "5TE",     "v5e",   ARMBuildAttrs::CPUArch::v5TE },
79284236Sdim  { "armv5tej",  ARM::AK_ARMV5TEJ, "5TEJ",    "v5e",   ARMBuildAttrs::CPUArch::v5TEJ },
80284236Sdim  { "armv6",     ARM::AK_ARMV6,    "6",       "v6",    ARMBuildAttrs::CPUArch::v6 },
81284236Sdim  { "armv6k",    ARM::AK_ARMV6K,   "6K",      "v6k",   ARMBuildAttrs::CPUArch::v6K },
82284236Sdim  { "armv6t2",   ARM::AK_ARMV6T2,  "6T2",     "v6t2",  ARMBuildAttrs::CPUArch::v6T2 },
83284236Sdim  { "armv6z",    ARM::AK_ARMV6Z,   "6Z",      "v6z",   ARMBuildAttrs::CPUArch::v6KZ },
84284236Sdim  { "armv6zk",   ARM::AK_ARMV6ZK,  "6ZK",     "v6zk",  ARMBuildAttrs::CPUArch::v6KZ },
85284236Sdim  { "armv6-m",   ARM::AK_ARMV6M,   "6-M",     "v6m",   ARMBuildAttrs::CPUArch::v6_M },
86284236Sdim  { "armv6s-m",  ARM::AK_ARMV6SM,  "6S-M",    "v6sm",  ARMBuildAttrs::CPUArch::v6S_M },
87284236Sdim  { "armv7-a",   ARM::AK_ARMV7A,   "7-A",     "v7",    ARMBuildAttrs::CPUArch::v7 },
88284236Sdim  { "armv7-r",   ARM::AK_ARMV7R,   "7-R",     "v7r",   ARMBuildAttrs::CPUArch::v7 },
89284236Sdim  { "armv7-m",   ARM::AK_ARMV7M,   "7-M",     "v7m",   ARMBuildAttrs::CPUArch::v7 },
90284236Sdim  { "armv7e-m",  ARM::AK_ARMV7EM,  "7E-M",    "v7em",  ARMBuildAttrs::CPUArch::v7E_M },
91284236Sdim  { "armv8-a",   ARM::AK_ARMV8A,   "8-A",     "v8",    ARMBuildAttrs::CPUArch::v8 },
92284236Sdim  { "armv8.1-a", ARM::AK_ARMV8_1A, "8.1-A",   "v8.1a", ARMBuildAttrs::CPUArch::v8 },
93283625Sdim  // Non-standard Arch names.
94284236Sdim  { "iwmmxt",    ARM::AK_IWMMXT,   "iwmmxt",  "",      ARMBuildAttrs::CPUArch::v5TE },
95284236Sdim  { "iwmmxt2",   ARM::AK_IWMMXT2,  "iwmmxt2", "",      ARMBuildAttrs::CPUArch::v5TE },
96284236Sdim  { "xscale",    ARM::AK_XSCALE,   "xscale",  "",      ARMBuildAttrs::CPUArch::v5TE },
97284236Sdim  { "armv5",     ARM::AK_ARMV5,    "5T",      "v5",    ARMBuildAttrs::CPUArch::v5T },
98284236Sdim  { "armv5e",    ARM::AK_ARMV5E,   "5TE",     "v5e",   ARMBuildAttrs::CPUArch::v5TE },
99284236Sdim  { "armv6j",    ARM::AK_ARMV6J,   "6J",      "v6",    ARMBuildAttrs::CPUArch::v6 },
100284236Sdim  { "armv6hl",   ARM::AK_ARMV6HL,  "6-M",     "v6hl",  ARMBuildAttrs::CPUArch::v6_M },
101284236Sdim  { "armv7",     ARM::AK_ARMV7,    "7",       "v7",    ARMBuildAttrs::CPUArch::v7 },
102284236Sdim  { "armv7l",    ARM::AK_ARMV7L,   "7-L",     "v7l",   ARMBuildAttrs::CPUArch::v7 },
103284236Sdim  { "armv7hl",   ARM::AK_ARMV7HL,  "7-L",     "v7hl",  ARMBuildAttrs::CPUArch::v7 },
104284236Sdim  { "armv7s",    ARM::AK_ARMV7S,   "7-S",     "v7s",   ARMBuildAttrs::CPUArch::v7 }
105283625Sdim};
106284236Sdim// List of Arch Extension names.
107283625Sdim// FIXME: TableGen this.
108283625Sdimstruct {
109283625Sdim  const char *Name;
110283625Sdim  ARM::ArchExtKind ID;
111283625Sdim} ARCHExtNames[] = {
112283625Sdim  { "invalid",  ARM::AEK_INVALID },
113283625Sdim  { "crc",      ARM::AEK_CRC },
114283625Sdim  { "crypto",   ARM::AEK_CRYPTO },
115283625Sdim  { "fp",       ARM::AEK_FP },
116283625Sdim  { "idiv",     ARM::AEK_HWDIV },
117283625Sdim  { "mp",       ARM::AEK_MP },
118284236Sdim  { "simd",     ARM::AEK_SIMD },
119283625Sdim  { "sec",      ARM::AEK_SEC },
120284236Sdim  { "virt",     ARM::AEK_VIRT },
121284236Sdim  { "os",       ARM::AEK_OS },
122284236Sdim  { "iwmmxt",   ARM::AEK_IWMMXT },
123284236Sdim  { "iwmmxt2",  ARM::AEK_IWMMXT2 },
124284236Sdim  { "maverick", ARM::AEK_MAVERICK },
125284236Sdim  { "xscale",   ARM::AEK_XSCALE }
126283625Sdim};
127283625Sdim// List of CPU names and their arches.
128283625Sdim// The same CPU can have multiple arches and can be default on multiple arches.
129283625Sdim// When finding the Arch for a CPU, first-found prevails. Sort them accordingly.
130284236Sdim// When this becomes table-generated, we'd probably need two tables.
131283625Sdim// FIXME: TableGen this.
132283625Sdimstruct {
133283625Sdim  const char *Name;
134283625Sdim  ARM::ArchKind ArchID;
135283625Sdim  bool Default;
136283625Sdim} CPUNames[] = {
137283625Sdim  { "arm2",          ARM::AK_ARMV2,    true },
138284236Sdim  { "arm3",          ARM::AK_ARMV2A,   true },
139283625Sdim  { "arm6",          ARM::AK_ARMV3,    true },
140283625Sdim  { "arm7m",         ARM::AK_ARMV3M,   true },
141284236Sdim  { "arm8",          ARM::AK_ARMV4,    false },
142284236Sdim  { "arm810",        ARM::AK_ARMV4,    false },
143283625Sdim  { "strongarm",     ARM::AK_ARMV4,    true },
144284236Sdim  { "strongarm110",  ARM::AK_ARMV4,    false },
145284236Sdim  { "strongarm1100", ARM::AK_ARMV4,    false },
146284236Sdim  { "strongarm1110", ARM::AK_ARMV4,    false },
147283625Sdim  { "arm7tdmi",      ARM::AK_ARMV4T,   true },
148283625Sdim  { "arm7tdmi-s",    ARM::AK_ARMV4T,   false },
149283625Sdim  { "arm710t",       ARM::AK_ARMV4T,   false },
150283625Sdim  { "arm720t",       ARM::AK_ARMV4T,   false },
151283625Sdim  { "arm9",          ARM::AK_ARMV4T,   false },
152283625Sdim  { "arm9tdmi",      ARM::AK_ARMV4T,   false },
153283625Sdim  { "arm920",        ARM::AK_ARMV4T,   false },
154283625Sdim  { "arm920t",       ARM::AK_ARMV4T,   false },
155283625Sdim  { "arm922t",       ARM::AK_ARMV4T,   false },
156283625Sdim  { "arm9312",       ARM::AK_ARMV4T,   false },
157283625Sdim  { "arm940t",       ARM::AK_ARMV4T,   false },
158283625Sdim  { "ep9312",        ARM::AK_ARMV4T,   false },
159283625Sdim  { "arm10tdmi",     ARM::AK_ARMV5T,   true },
160283625Sdim  { "arm1020t",      ARM::AK_ARMV5T,   false },
161283625Sdim  { "arm9e",         ARM::AK_ARMV5TE,  false },
162284236Sdim  { "arm946e-s",     ARM::AK_ARMV5TE,  false },
163283625Sdim  { "arm966e-s",     ARM::AK_ARMV5TE,  false },
164283625Sdim  { "arm968e-s",     ARM::AK_ARMV5TE,  false },
165284236Sdim  { "arm10e",        ARM::AK_ARMV5TE,  false },
166283625Sdim  { "arm1020e",      ARM::AK_ARMV5TE,  false },
167283625Sdim  { "arm1022e",      ARM::AK_ARMV5TE,  true },
168283625Sdim  { "iwmmxt",        ARM::AK_ARMV5TE,  false },
169284236Sdim  { "xscale",        ARM::AK_ARMV5TE,  false },
170284236Sdim  { "arm926ej-s",    ARM::AK_ARMV5TEJ, true },
171283625Sdim  { "arm1136jf-s",   ARM::AK_ARMV6,    true },
172283625Sdim  { "arm1176j-s",    ARM::AK_ARMV6K,   false },
173284236Sdim  { "arm1176jz-s",   ARM::AK_ARMV6K,   false },
174283625Sdim  { "mpcore",        ARM::AK_ARMV6K,   false },
175283625Sdim  { "mpcorenovfp",   ARM::AK_ARMV6K,   false },
176283625Sdim  { "arm1176jzf-s",  ARM::AK_ARMV6K,   true },
177283625Sdim  { "arm1176jzf-s",  ARM::AK_ARMV6Z,   true },
178283625Sdim  { "arm1176jzf-s",  ARM::AK_ARMV6ZK,  true },
179283625Sdim  { "arm1156t2-s",   ARM::AK_ARMV6T2,  true },
180283625Sdim  { "arm1156t2f-s",  ARM::AK_ARMV6T2,  false },
181283625Sdim  { "cortex-m0",     ARM::AK_ARMV6M,   true },
182283625Sdim  { "cortex-m0plus", ARM::AK_ARMV6M,   false },
183283625Sdim  { "cortex-m1",     ARM::AK_ARMV6M,   false },
184283625Sdim  { "sc000",         ARM::AK_ARMV6M,   false },
185283625Sdim  { "cortex-a5",     ARM::AK_ARMV7A,   false },
186283625Sdim  { "cortex-a7",     ARM::AK_ARMV7A,   false },
187283625Sdim  { "cortex-a8",     ARM::AK_ARMV7A,   true },
188283625Sdim  { "cortex-a9",     ARM::AK_ARMV7A,   false },
189283625Sdim  { "cortex-a12",    ARM::AK_ARMV7A,   false },
190283625Sdim  { "cortex-a15",    ARM::AK_ARMV7A,   false },
191283625Sdim  { "cortex-a17",    ARM::AK_ARMV7A,   false },
192283625Sdim  { "krait",         ARM::AK_ARMV7A,   false },
193283625Sdim  { "cortex-r4",     ARM::AK_ARMV7R,   true },
194283625Sdim  { "cortex-r4f",    ARM::AK_ARMV7R,   false },
195283625Sdim  { "cortex-r5",     ARM::AK_ARMV7R,   false },
196283625Sdim  { "cortex-r7",     ARM::AK_ARMV7R,   false },
197283625Sdim  { "sc300",         ARM::AK_ARMV7M,   false },
198283625Sdim  { "cortex-m3",     ARM::AK_ARMV7M,   true },
199284236Sdim  { "cortex-m4",     ARM::AK_ARMV7EM,  true },
200284236Sdim  { "cortex-m7",     ARM::AK_ARMV7EM,  false },
201283625Sdim  { "cortex-a53",    ARM::AK_ARMV8A,   true },
202283625Sdim  { "cortex-a57",    ARM::AK_ARMV8A,   false },
203283625Sdim  { "cortex-a72",    ARM::AK_ARMV8A,   false },
204283625Sdim  { "cyclone",       ARM::AK_ARMV8A,   false },
205283625Sdim  { "generic",       ARM::AK_ARMV8_1A, true },
206283625Sdim  // Non-standard Arch names.
207284236Sdim  { "iwmmxt",        ARM::AK_IWMMXT,   true },
208284236Sdim  { "xscale",        ARM::AK_XSCALE,   true },
209284236Sdim  { "arm10tdmi",     ARM::AK_ARMV5,    true },
210283625Sdim  { "arm1022e",      ARM::AK_ARMV5E,   true },
211284236Sdim  { "arm1136j-s",    ARM::AK_ARMV6J,   true },
212284236Sdim  { "arm1136jz-s",   ARM::AK_ARMV6J,   false },
213283625Sdim  { "cortex-m0",     ARM::AK_ARMV6SM,  true },
214283625Sdim  { "arm1176jzf-s",  ARM::AK_ARMV6HL,  true },
215284236Sdim  { "cortex-a8",     ARM::AK_ARMV7,    true },
216283625Sdim  { "cortex-a8",     ARM::AK_ARMV7L,   true },
217283625Sdim  { "cortex-a8",     ARM::AK_ARMV7HL,  true },
218283625Sdim  { "cortex-m4",     ARM::AK_ARMV7EM,  true },
219283625Sdim  { "swift",         ARM::AK_ARMV7S,   true },
220283625Sdim  // Invalid CPU
221283625Sdim  { "invalid",       ARM::AK_INVALID,  true }
222283625Sdim};
223283625Sdim
224283625Sdim} // namespace
225283625Sdim
226283625Sdim// ======================================================= //
227283625Sdim// Information by ID
228283625Sdim// ======================================================= //
229283625Sdim
230283625Sdimconst char *ARMTargetParser::getFPUName(unsigned FPUKind) {
231283625Sdim  if (FPUKind >= ARM::FK_LAST)
232283625Sdim    return nullptr;
233283625Sdim  return FPUNames[FPUKind].Name;
234283625Sdim}
235283625Sdim
236284236Sdimunsigned ARMTargetParser::getFPUVersion(unsigned FPUKind) {
237284236Sdim  if (FPUKind >= ARM::FK_LAST)
238284236Sdim    return 0;
239284236Sdim  return FPUNames[FPUKind].FPUVersion;
240284236Sdim}
241284236Sdim
242284236Sdimunsigned ARMTargetParser::getFPUNeonSupportLevel(unsigned FPUKind) {
243284236Sdim  if (FPUKind >= ARM::FK_LAST)
244284236Sdim    return 0;
245284236Sdim  return FPUNames[FPUKind].NeonSupport;
246284236Sdim}
247284236Sdim
248284236Sdimunsigned ARMTargetParser::getFPURestriction(unsigned FPUKind) {
249284236Sdim  if (FPUKind >= ARM::FK_LAST)
250284236Sdim    return 0;
251284236Sdim  return FPUNames[FPUKind].Restriction;
252284236Sdim}
253284236Sdim
254284236Sdimbool ARMTargetParser::getFPUFeatures(unsigned FPUKind,
255284236Sdim                                     std::vector<const char *> &Features) {
256284236Sdim
257284236Sdim  if (FPUKind >= ARM::FK_LAST || FPUKind == ARM::FK_INVALID)
258284236Sdim    return false;
259284236Sdim
260284236Sdim  // fp-only-sp and d16 subtarget features are independent of each other, so we
261284236Sdim  // must enable/disable both.
262284236Sdim  switch (FPUNames[FPUKind].Restriction) {
263284236Sdim  case ARM::FR_SP_D16:
264284236Sdim    Features.push_back("+fp-only-sp");
265284236Sdim    Features.push_back("+d16");
266284236Sdim    break;
267284236Sdim  case ARM::FR_D16:
268284236Sdim    Features.push_back("-fp-only-sp");
269284236Sdim    Features.push_back("+d16");
270284236Sdim    break;
271284236Sdim  case ARM::FR_None:
272284236Sdim    Features.push_back("-fp-only-sp");
273284236Sdim    Features.push_back("-d16");
274284236Sdim    break;
275284236Sdim  }
276284236Sdim
277284236Sdim  // FPU version subtarget features are inclusive of lower-numbered ones, so
278284236Sdim  // enable the one corresponding to this version and disable all that are
279284734Sdim  // higher. We also have to make sure to disable fp16 when vfp4 is disabled,
280284734Sdim  // as +vfp4 implies +fp16 but -vfp4 does not imply -fp16.
281284236Sdim  switch (FPUNames[FPUKind].FPUVersion) {
282284236Sdim  case 5:
283284236Sdim    Features.push_back("+fp-armv8");
284284236Sdim    break;
285284236Sdim  case 4:
286284236Sdim    Features.push_back("+vfp4");
287284236Sdim    Features.push_back("-fp-armv8");
288284236Sdim    break;
289284236Sdim  case 3:
290284236Sdim    Features.push_back("+vfp3");
291284734Sdim    Features.push_back("-fp16");
292284236Sdim    Features.push_back("-vfp4");
293284236Sdim    Features.push_back("-fp-armv8");
294284236Sdim    break;
295284236Sdim  case 2:
296284236Sdim    Features.push_back("+vfp2");
297284236Sdim    Features.push_back("-vfp3");
298284734Sdim    Features.push_back("-fp16");
299284236Sdim    Features.push_back("-vfp4");
300284236Sdim    Features.push_back("-fp-armv8");
301284236Sdim    break;
302284236Sdim  case 0:
303284236Sdim    Features.push_back("-vfp2");
304284236Sdim    Features.push_back("-vfp3");
305284734Sdim    Features.push_back("-fp16");
306284236Sdim    Features.push_back("-vfp4");
307284236Sdim    Features.push_back("-fp-armv8");
308284236Sdim    break;
309284236Sdim  }
310284236Sdim
311284236Sdim  // crypto includes neon, so we handle this similarly to FPU version.
312284236Sdim  switch (FPUNames[FPUKind].NeonSupport) {
313284236Sdim  case ARM::NS_Crypto:
314284236Sdim    Features.push_back("+crypto");
315284236Sdim    break;
316284236Sdim  case ARM::NS_Neon:
317284236Sdim    Features.push_back("+neon");
318284236Sdim    Features.push_back("-crypto");
319284236Sdim    break;
320284236Sdim  case ARM::NS_None:
321284236Sdim    Features.push_back("-neon");
322284236Sdim    Features.push_back("-crypto");
323284236Sdim    break;
324284236Sdim  }
325284236Sdim
326284236Sdim  return true;
327284236Sdim}
328284236Sdim
329283625Sdimconst char *ARMTargetParser::getArchName(unsigned ArchKind) {
330283625Sdim  if (ArchKind >= ARM::AK_LAST)
331283625Sdim    return nullptr;
332283625Sdim  return ARCHNames[ArchKind].Name;
333283625Sdim}
334283625Sdim
335284236Sdimconst char *ARMTargetParser::getCPUAttr(unsigned ArchKind) {
336283625Sdim  if (ArchKind >= ARM::AK_LAST)
337283625Sdim    return nullptr;
338284236Sdim  return ARCHNames[ArchKind].CPUAttr;
339283625Sdim}
340283625Sdim
341284236Sdimconst char *ARMTargetParser::getSubArch(unsigned ArchKind) {
342283625Sdim  if (ArchKind >= ARM::AK_LAST)
343284236Sdim    return nullptr;
344284236Sdim  return ARCHNames[ArchKind].SubArch;
345284236Sdim}
346284236Sdim
347284236Sdimunsigned ARMTargetParser::getArchAttr(unsigned ArchKind) {
348284236Sdim  if (ArchKind >= ARM::AK_LAST)
349283625Sdim    return ARMBuildAttrs::CPUArch::Pre_v4;
350284236Sdim  return ARCHNames[ArchKind].ArchAttr;
351283625Sdim}
352283625Sdim
353283625Sdimconst char *ARMTargetParser::getArchExtName(unsigned ArchExtKind) {
354283625Sdim  if (ArchExtKind >= ARM::AEK_LAST)
355283625Sdim    return nullptr;
356283625Sdim  return ARCHExtNames[ArchExtKind].Name;
357283625Sdim}
358283625Sdim
359283625Sdimconst char *ARMTargetParser::getDefaultCPU(StringRef Arch) {
360283625Sdim  unsigned AK = parseArch(Arch);
361283625Sdim  if (AK == ARM::AK_INVALID)
362283625Sdim    return nullptr;
363283625Sdim
364283625Sdim  // Look for multiple AKs to find the default for pair AK+Name.
365283625Sdim  for (const auto CPU : CPUNames) {
366283625Sdim    if (CPU.ArchID == AK && CPU.Default)
367283625Sdim      return CPU.Name;
368283625Sdim  }
369283625Sdim  return nullptr;
370283625Sdim}
371283625Sdim
372283625Sdim// ======================================================= //
373283625Sdim// Parsers
374283625Sdim// ======================================================= //
375283625Sdim
376283625SdimStringRef ARMTargetParser::getFPUSynonym(StringRef FPU) {
377283625Sdim  return StringSwitch<StringRef>(FPU)
378283625Sdim    .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported
379283625Sdim    .Case("vfp2", "vfpv2")
380283625Sdim    .Case("vfp3", "vfpv3")
381283625Sdim    .Case("vfp4", "vfpv4")
382283625Sdim    .Case("vfp3-d16", "vfpv3-d16")
383283625Sdim    .Case("vfp4-d16", "vfpv4-d16")
384284236Sdim    .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16")
385283625Sdim    .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16")
386284236Sdim    .Case("fp5-sp-d16", "fpv5-sp-d16")
387283625Sdim    .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16")
388283625Sdim    // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3.
389283625Sdim    .Case("neon-vfpv3", "neon")
390283625Sdim    .Default(FPU);
391283625Sdim}
392283625Sdim
393283625SdimStringRef ARMTargetParser::getArchSynonym(StringRef Arch) {
394283625Sdim  return StringSwitch<StringRef>(Arch)
395284236Sdim    .Case("v6sm", "v6s-m")
396284236Sdim    .Case("v6m", "v6-m")
397284236Sdim    .Case("v7a", "v7-a")
398284236Sdim    .Case("v7r", "v7-r")
399284236Sdim    .Case("v7m", "v7-m")
400284236Sdim    .Case("v7em", "v7e-m")
401284236Sdim    .Cases("v8", "v8a", "aarch64", "arm64", "v8-a")
402284236Sdim    .Case("v8.1a", "v8.1-a")
403283625Sdim    .Default(Arch);
404283625Sdim}
405283625Sdim
406283625Sdim// MArch is expected to be of the form (arm|thumb)?(eb)?(v.+)?(eb)?, but
407283625Sdim// (iwmmxt|xscale)(eb)? is also permitted. If the former, return
408283625Sdim// "v.+", if the latter, return unmodified string, minus 'eb'.
409283625Sdim// If invalid, return empty string.
410283625SdimStringRef ARMTargetParser::getCanonicalArchName(StringRef Arch) {
411283625Sdim  size_t offset = StringRef::npos;
412283625Sdim  StringRef A = Arch;
413283625Sdim  StringRef Error = "";
414283625Sdim
415283625Sdim  // Begins with "arm" / "thumb", move past it.
416283625Sdim  if (A.startswith("arm64"))
417283625Sdim    offset = 5;
418283625Sdim  else if (A.startswith("arm"))
419283625Sdim    offset = 3;
420283625Sdim  else if (A.startswith("thumb"))
421283625Sdim    offset = 5;
422283625Sdim  else if (A.startswith("aarch64")) {
423283625Sdim    offset = 7;
424283625Sdim    // AArch64 uses "_be", not "eb" suffix.
425283625Sdim    if (A.find("eb") != StringRef::npos)
426283625Sdim      return Error;
427283625Sdim    if (A.substr(offset,3) == "_be")
428283625Sdim      offset += 3;
429283625Sdim  }
430283625Sdim
431283625Sdim  // Ex. "armebv7", move past the "eb".
432283625Sdim  if (offset != StringRef::npos && A.substr(offset, 2) == "eb")
433283625Sdim    offset += 2;
434283625Sdim  // Or, if it ends with eb ("armv7eb"), chop it off.
435283625Sdim  else if (A.endswith("eb"))
436283625Sdim    A = A.substr(0, A.size() - 2);
437283625Sdim  // Trim the head
438283625Sdim  if (offset != StringRef::npos)
439283625Sdim    A = A.substr(offset);
440283625Sdim
441283625Sdim  // Empty string means offset reached the end, which means it's valid.
442283625Sdim  if (A.empty())
443283625Sdim    return Arch;
444283625Sdim
445283625Sdim  // Only match non-marketing names
446283625Sdim  if (offset != StringRef::npos) {
447283625Sdim  // Must start with 'vN'.
448283625Sdim    if (A[0] != 'v' || !std::isdigit(A[1]))
449283625Sdim      return Error;
450283625Sdim    // Can't have an extra 'eb'.
451283625Sdim    if (A.find("eb") != StringRef::npos)
452283625Sdim      return Error;
453283625Sdim  }
454283625Sdim
455283625Sdim  // Arch will either be a 'v' name (v7a) or a marketing name (xscale).
456283625Sdim  return A;
457283625Sdim}
458283625Sdim
459283625Sdimunsigned ARMTargetParser::parseFPU(StringRef FPU) {
460283625Sdim  StringRef Syn = getFPUSynonym(FPU);
461283625Sdim  for (const auto F : FPUNames) {
462283625Sdim    if (Syn == F.Name)
463283625Sdim      return F.ID;
464283625Sdim  }
465283625Sdim  return ARM::FK_INVALID;
466283625Sdim}
467283625Sdim
468283625Sdim// Allows partial match, ex. "v7a" matches "armv7a".
469283625Sdimunsigned ARMTargetParser::parseArch(StringRef Arch) {
470284236Sdim  Arch = getCanonicalArchName(Arch);
471283625Sdim  StringRef Syn = getArchSynonym(Arch);
472283625Sdim  for (const auto A : ARCHNames) {
473283625Sdim    if (StringRef(A.Name).endswith(Syn))
474283625Sdim      return A.ID;
475283625Sdim  }
476283625Sdim  return ARM::AK_INVALID;
477283625Sdim}
478283625Sdim
479283625Sdimunsigned ARMTargetParser::parseArchExt(StringRef ArchExt) {
480283625Sdim  for (const auto A : ARCHExtNames) {
481283625Sdim    if (ArchExt == A.Name)
482283625Sdim      return A.ID;
483283625Sdim  }
484283625Sdim  return ARM::AEK_INVALID;
485283625Sdim}
486283625Sdim
487283625Sdimunsigned ARMTargetParser::parseCPUArch(StringRef CPU) {
488283625Sdim  for (const auto C : CPUNames) {
489283625Sdim    if (CPU == C.Name)
490283625Sdim      return C.ArchID;
491283625Sdim  }
492283625Sdim  return ARM::AK_INVALID;
493283625Sdim}
494283625Sdim
495283625Sdim// ARM, Thumb, AArch64
496283625Sdimunsigned ARMTargetParser::parseArchISA(StringRef Arch) {
497283625Sdim  return StringSwitch<unsigned>(Arch)
498283625Sdim      .StartsWith("aarch64", ARM::IK_AARCH64)
499283625Sdim      .StartsWith("arm64",   ARM::IK_AARCH64)
500283625Sdim      .StartsWith("thumb",   ARM::IK_THUMB)
501283625Sdim      .StartsWith("arm",     ARM::IK_ARM)
502283625Sdim      .Default(ARM::EK_INVALID);
503283625Sdim}
504283625Sdim
505283625Sdim// Little/Big endian
506283625Sdimunsigned ARMTargetParser::parseArchEndian(StringRef Arch) {
507283625Sdim  if (Arch.startswith("armeb") ||
508283625Sdim      Arch.startswith("thumbeb") ||
509283625Sdim      Arch.startswith("aarch64_be"))
510283625Sdim    return ARM::EK_BIG;
511283625Sdim
512283625Sdim  if (Arch.startswith("arm") || Arch.startswith("thumb")) {
513283625Sdim    if (Arch.endswith("eb"))
514283625Sdim      return ARM::EK_BIG;
515283625Sdim    else
516283625Sdim      return ARM::EK_LITTLE;
517283625Sdim  }
518283625Sdim
519283625Sdim  if (Arch.startswith("aarch64"))
520283625Sdim    return ARM::EK_LITTLE;
521283625Sdim
522283625Sdim  return ARM::EK_INVALID;
523283625Sdim}
524283625Sdim
525283625Sdim// Profile A/R/M
526283625Sdimunsigned ARMTargetParser::parseArchProfile(StringRef Arch) {
527283625Sdim  Arch = getCanonicalArchName(Arch);
528283625Sdim  switch(parseArch(Arch)) {
529283625Sdim  case ARM::AK_ARMV6M:
530283625Sdim  case ARM::AK_ARMV7M:
531283625Sdim  case ARM::AK_ARMV6SM:
532283625Sdim  case ARM::AK_ARMV7EM:
533283625Sdim    return ARM::PK_M;
534283625Sdim  case ARM::AK_ARMV7R:
535283625Sdim    return ARM::PK_R;
536283625Sdim  case ARM::AK_ARMV7:
537283625Sdim  case ARM::AK_ARMV7A:
538283625Sdim  case ARM::AK_ARMV8A:
539283625Sdim  case ARM::AK_ARMV8_1A:
540283625Sdim    return ARM::PK_A;
541283625Sdim  }
542283625Sdim  return ARM::PK_INVALID;
543283625Sdim}
544283625Sdim
545283625Sdim// Version number (ex. v7 = 7).
546283625Sdimunsigned ARMTargetParser::parseArchVersion(StringRef Arch) {
547283625Sdim  Arch = getCanonicalArchName(Arch);
548283625Sdim  switch(parseArch(Arch)) {
549283625Sdim  case ARM::AK_ARMV2:
550283625Sdim  case ARM::AK_ARMV2A:
551283625Sdim    return 2;
552283625Sdim  case ARM::AK_ARMV3:
553283625Sdim  case ARM::AK_ARMV3M:
554283625Sdim    return 3;
555283625Sdim  case ARM::AK_ARMV4:
556283625Sdim  case ARM::AK_ARMV4T:
557283625Sdim    return 4;
558283625Sdim  case ARM::AK_ARMV5:
559283625Sdim  case ARM::AK_ARMV5T:
560283625Sdim  case ARM::AK_ARMV5TE:
561283625Sdim  case ARM::AK_IWMMXT:
562283625Sdim  case ARM::AK_IWMMXT2:
563283625Sdim  case ARM::AK_XSCALE:
564283625Sdim  case ARM::AK_ARMV5E:
565283625Sdim  case ARM::AK_ARMV5TEJ:
566283625Sdim    return 5;
567283625Sdim  case ARM::AK_ARMV6:
568283625Sdim  case ARM::AK_ARMV6J:
569283625Sdim  case ARM::AK_ARMV6K:
570283625Sdim  case ARM::AK_ARMV6T2:
571283625Sdim  case ARM::AK_ARMV6Z:
572283625Sdim  case ARM::AK_ARMV6ZK:
573283625Sdim  case ARM::AK_ARMV6M:
574283625Sdim  case ARM::AK_ARMV6SM:
575283625Sdim  case ARM::AK_ARMV6HL:
576283625Sdim    return 6;
577283625Sdim  case ARM::AK_ARMV7:
578283625Sdim  case ARM::AK_ARMV7A:
579283625Sdim  case ARM::AK_ARMV7R:
580283625Sdim  case ARM::AK_ARMV7M:
581283625Sdim  case ARM::AK_ARMV7L:
582283625Sdim  case ARM::AK_ARMV7HL:
583283625Sdim  case ARM::AK_ARMV7S:
584283625Sdim  case ARM::AK_ARMV7EM:
585283625Sdim    return 7;
586283625Sdim  case ARM::AK_ARMV8A:
587283625Sdim  case ARM::AK_ARMV8_1A:
588283625Sdim    return 8;
589283625Sdim  }
590283625Sdim  return 0;
591283625Sdim}
592