1e01718cdSDavid Spickett //===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===//
2e01718cdSDavid Spickett //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e01718cdSDavid Spickett //
7e01718cdSDavid Spickett //===----------------------------------------------------------------------===//
8e01718cdSDavid Spickett //
9e01718cdSDavid Spickett // This file implements a target parser to recognise ARM hardware features
10e01718cdSDavid Spickett // such as FPU/CPU/ARCH/extensions and specific support such as HWDIV.
11e01718cdSDavid Spickett //
12e01718cdSDavid Spickett //===----------------------------------------------------------------------===//
13e01718cdSDavid Spickett 
14e01718cdSDavid Spickett #include "llvm/Support/ARMTargetParser.h"
15e01718cdSDavid Spickett #include "llvm/ADT/StringSwitch.h"
16ffd9cfa7SSimon Pilgrim #include "llvm/ADT/Triple.h"
17cc3fa397SDavid Spickett #include <cctype>
18e01718cdSDavid Spickett 
19e01718cdSDavid Spickett using namespace llvm;
20e01718cdSDavid Spickett 
getHWDivSynonym(StringRef HWDiv)21e01718cdSDavid Spickett static StringRef getHWDivSynonym(StringRef HWDiv) {
22e01718cdSDavid Spickett   return StringSwitch<StringRef>(HWDiv)
23e01718cdSDavid Spickett       .Case("thumb,arm", "arm,thumb")
24e01718cdSDavid Spickett       .Default(HWDiv);
25e01718cdSDavid Spickett }
26e01718cdSDavid Spickett 
27e01718cdSDavid Spickett // Allows partial match, ex. "v7a" matches "armv7a".
parseArch(StringRef Arch)28e01718cdSDavid Spickett ARM::ArchKind ARM::parseArch(StringRef Arch) {
29e01718cdSDavid Spickett   Arch = getCanonicalArchName(Arch);
30e01718cdSDavid Spickett   StringRef Syn = getArchSynonym(Arch);
317982db5dSReid Kleckner   for (const auto &A : ARCHNames) {
32e01718cdSDavid Spickett     if (A.getName().endswith(Syn))
33e01718cdSDavid Spickett       return A.ID;
34e01718cdSDavid Spickett   }
35e01718cdSDavid Spickett   return ArchKind::INVALID;
36e01718cdSDavid Spickett }
37e01718cdSDavid Spickett 
38e01718cdSDavid Spickett // Version number (ex. v7 = 7).
parseArchVersion(StringRef Arch)39e01718cdSDavid Spickett unsigned ARM::parseArchVersion(StringRef Arch) {
40e01718cdSDavid Spickett   Arch = getCanonicalArchName(Arch);
41e01718cdSDavid Spickett   switch (parseArch(Arch)) {
42e01718cdSDavid Spickett   case ArchKind::ARMV2:
43e01718cdSDavid Spickett   case ArchKind::ARMV2A:
44e01718cdSDavid Spickett     return 2;
45e01718cdSDavid Spickett   case ArchKind::ARMV3:
46e01718cdSDavid Spickett   case ArchKind::ARMV3M:
47e01718cdSDavid Spickett     return 3;
48e01718cdSDavid Spickett   case ArchKind::ARMV4:
49e01718cdSDavid Spickett   case ArchKind::ARMV4T:
50e01718cdSDavid Spickett     return 4;
51e01718cdSDavid Spickett   case ArchKind::ARMV5T:
52e01718cdSDavid Spickett   case ArchKind::ARMV5TE:
53e01718cdSDavid Spickett   case ArchKind::IWMMXT:
54e01718cdSDavid Spickett   case ArchKind::IWMMXT2:
55e01718cdSDavid Spickett   case ArchKind::XSCALE:
56e01718cdSDavid Spickett   case ArchKind::ARMV5TEJ:
57e01718cdSDavid Spickett     return 5;
58e01718cdSDavid Spickett   case ArchKind::ARMV6:
59e01718cdSDavid Spickett   case ArchKind::ARMV6K:
60e01718cdSDavid Spickett   case ArchKind::ARMV6T2:
61e01718cdSDavid Spickett   case ArchKind::ARMV6KZ:
62e01718cdSDavid Spickett   case ArchKind::ARMV6M:
63e01718cdSDavid Spickett     return 6;
64e01718cdSDavid Spickett   case ArchKind::ARMV7A:
65e01718cdSDavid Spickett   case ArchKind::ARMV7VE:
66e01718cdSDavid Spickett   case ArchKind::ARMV7R:
67e01718cdSDavid Spickett   case ArchKind::ARMV7M:
68e01718cdSDavid Spickett   case ArchKind::ARMV7S:
69e01718cdSDavid Spickett   case ArchKind::ARMV7EM:
70e01718cdSDavid Spickett   case ArchKind::ARMV7K:
71e01718cdSDavid Spickett     return 7;
72e01718cdSDavid Spickett   case ArchKind::ARMV8A:
73e01718cdSDavid Spickett   case ArchKind::ARMV8_1A:
74e01718cdSDavid Spickett   case ArchKind::ARMV8_2A:
75e01718cdSDavid Spickett   case ArchKind::ARMV8_3A:
76e01718cdSDavid Spickett   case ArchKind::ARMV8_4A:
77e01718cdSDavid Spickett   case ArchKind::ARMV8_5A:
7871ae267dSTies Stuij   case ArchKind::ARMV8_6A:
79c5046ebdSLucas Prates   case ArchKind::ARMV8_7A:
80d50072f7SSimon Tatham   case ArchKind::ARMV8_8A:
81e01718cdSDavid Spickett   case ArchKind::ARMV8R:
82e01718cdSDavid Spickett   case ArchKind::ARMV8MBaseline:
83e01718cdSDavid Spickett   case ArchKind::ARMV8MMainline:
84930dee2cSSjoerd Meijer   case ArchKind::ARMV8_1MMainline:
85e01718cdSDavid Spickett     return 8;
863550e242SVictor Campos   case ArchKind::ARMV9A:
873550e242SVictor Campos   case ArchKind::ARMV9_1A:
883550e242SVictor Campos   case ArchKind::ARMV9_2A:
89*cd7f621aSLucas Prates   case ArchKind::ARMV9_3A:
903550e242SVictor Campos     return 9;
91e01718cdSDavid Spickett   case ArchKind::INVALID:
92e01718cdSDavid Spickett     return 0;
93e01718cdSDavid Spickett   }
94e01718cdSDavid Spickett   llvm_unreachable("Unhandled architecture");
95e01718cdSDavid Spickett }
96e01718cdSDavid Spickett 
97e01718cdSDavid Spickett // Profile A/R/M
parseArchProfile(StringRef Arch)98e01718cdSDavid Spickett ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
99e01718cdSDavid Spickett   Arch = getCanonicalArchName(Arch);
100e01718cdSDavid Spickett   switch (parseArch(Arch)) {
101e01718cdSDavid Spickett   case ArchKind::ARMV6M:
102e01718cdSDavid Spickett   case ArchKind::ARMV7M:
103e01718cdSDavid Spickett   case ArchKind::ARMV7EM:
104e01718cdSDavid Spickett   case ArchKind::ARMV8MMainline:
105e01718cdSDavid Spickett   case ArchKind::ARMV8MBaseline:
106930dee2cSSjoerd Meijer   case ArchKind::ARMV8_1MMainline:
107e01718cdSDavid Spickett     return ProfileKind::M;
108e01718cdSDavid Spickett   case ArchKind::ARMV7R:
109e01718cdSDavid Spickett   case ArchKind::ARMV8R:
110e01718cdSDavid Spickett     return ProfileKind::R;
111e01718cdSDavid Spickett   case ArchKind::ARMV7A:
112e01718cdSDavid Spickett   case ArchKind::ARMV7VE:
113e01718cdSDavid Spickett   case ArchKind::ARMV7K:
114e01718cdSDavid Spickett   case ArchKind::ARMV8A:
115e01718cdSDavid Spickett   case ArchKind::ARMV8_1A:
116e01718cdSDavid Spickett   case ArchKind::ARMV8_2A:
117e01718cdSDavid Spickett   case ArchKind::ARMV8_3A:
118e01718cdSDavid Spickett   case ArchKind::ARMV8_4A:
119e01718cdSDavid Spickett   case ArchKind::ARMV8_5A:
12071ae267dSTies Stuij   case ArchKind::ARMV8_6A:
121c5046ebdSLucas Prates   case ArchKind::ARMV8_7A:
122d50072f7SSimon Tatham   case ArchKind::ARMV8_8A:
1233550e242SVictor Campos   case ArchKind::ARMV9A:
1243550e242SVictor Campos   case ArchKind::ARMV9_1A:
1253550e242SVictor Campos   case ArchKind::ARMV9_2A:
126*cd7f621aSLucas Prates   case ArchKind::ARMV9_3A:
127e01718cdSDavid Spickett     return ProfileKind::A;
128e01718cdSDavid Spickett   case ArchKind::ARMV2:
129e01718cdSDavid Spickett   case ArchKind::ARMV2A:
130e01718cdSDavid Spickett   case ArchKind::ARMV3:
131e01718cdSDavid Spickett   case ArchKind::ARMV3M:
132e01718cdSDavid Spickett   case ArchKind::ARMV4:
133e01718cdSDavid Spickett   case ArchKind::ARMV4T:
134e01718cdSDavid Spickett   case ArchKind::ARMV5T:
135e01718cdSDavid Spickett   case ArchKind::ARMV5TE:
136e01718cdSDavid Spickett   case ArchKind::ARMV5TEJ:
137e01718cdSDavid Spickett   case ArchKind::ARMV6:
138e01718cdSDavid Spickett   case ArchKind::ARMV6K:
139e01718cdSDavid Spickett   case ArchKind::ARMV6T2:
140e01718cdSDavid Spickett   case ArchKind::ARMV6KZ:
141e01718cdSDavid Spickett   case ArchKind::ARMV7S:
142e01718cdSDavid Spickett   case ArchKind::IWMMXT:
143e01718cdSDavid Spickett   case ArchKind::IWMMXT2:
144e01718cdSDavid Spickett   case ArchKind::XSCALE:
145e01718cdSDavid Spickett   case ArchKind::INVALID:
146e01718cdSDavid Spickett     return ProfileKind::INVALID;
147e01718cdSDavid Spickett   }
148e01718cdSDavid Spickett   llvm_unreachable("Unhandled architecture");
149e01718cdSDavid Spickett }
150e01718cdSDavid Spickett 
getArchSynonym(StringRef Arch)151e01718cdSDavid Spickett StringRef ARM::getArchSynonym(StringRef Arch) {
152e01718cdSDavid Spickett   return StringSwitch<StringRef>(Arch)
153e01718cdSDavid Spickett       .Case("v5", "v5t")
154e01718cdSDavid Spickett       .Case("v5e", "v5te")
155e01718cdSDavid Spickett       .Case("v6j", "v6")
156e01718cdSDavid Spickett       .Case("v6hl", "v6k")
157e01718cdSDavid Spickett       .Cases("v6m", "v6sm", "v6s-m", "v6-m")
158e01718cdSDavid Spickett       .Cases("v6z", "v6zk", "v6kz")
159e01718cdSDavid Spickett       .Cases("v7", "v7a", "v7hl", "v7l", "v7-a")
160e01718cdSDavid Spickett       .Case("v7r", "v7-r")
161e01718cdSDavid Spickett       .Case("v7m", "v7-m")
162e01718cdSDavid Spickett       .Case("v7em", "v7e-m")
163e01718cdSDavid Spickett       .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a")
164e01718cdSDavid Spickett       .Case("v8.1a", "v8.1-a")
165e01718cdSDavid Spickett       .Case("v8.2a", "v8.2-a")
166e01718cdSDavid Spickett       .Case("v8.3a", "v8.3-a")
167e01718cdSDavid Spickett       .Case("v8.4a", "v8.4-a")
168e01718cdSDavid Spickett       .Case("v8.5a", "v8.5-a")
16971ae267dSTies Stuij       .Case("v8.6a", "v8.6-a")
170c4d851b0SLucas Prates       .Case("v8.7a", "v8.7-a")
171d50072f7SSimon Tatham       .Case("v8.8a", "v8.8-a")
172e01718cdSDavid Spickett       .Case("v8r", "v8-r")
1733550e242SVictor Campos       .Cases("v9", "v9a", "v9-a")
1743550e242SVictor Campos       .Case("v9.1a", "v9.1-a")
1753550e242SVictor Campos       .Case("v9.2a", "v9.2-a")
176*cd7f621aSLucas Prates       .Case("v9.3a", "v9.3-a")
177e01718cdSDavid Spickett       .Case("v8m.base", "v8-m.base")
178e01718cdSDavid Spickett       .Case("v8m.main", "v8-m.main")
179930dee2cSSjoerd Meijer       .Case("v8.1m.main", "v8.1-m.main")
180e01718cdSDavid Spickett       .Default(Arch);
181e01718cdSDavid Spickett }
182e01718cdSDavid Spickett 
getFPUFeatures(unsigned FPUKind,std::vector<StringRef> & Features)183e01718cdSDavid Spickett bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) {
184e01718cdSDavid Spickett 
185e01718cdSDavid Spickett   if (FPUKind >= FK_LAST || FPUKind == FK_INVALID)
186e01718cdSDavid Spickett     return false;
187e01718cdSDavid Spickett 
1885d66f2b0SSimon Tatham   static const struct FPUFeatureNameInfo {
1895d66f2b0SSimon Tatham     const char *PlusName, *MinusName;
1905d66f2b0SSimon Tatham     FPUVersion MinVersion;
1915d66f2b0SSimon Tatham     FPURestriction MaxRestriction;
1925d66f2b0SSimon Tatham   } FPUFeatureInfoList[] = {
1935d66f2b0SSimon Tatham     // We have to specify the + and - versions of the name in full so
1945d66f2b0SSimon Tatham     // that we can return them as static StringRefs.
1955d66f2b0SSimon Tatham     //
1965d66f2b0SSimon Tatham     // Also, the SubtargetFeatures ending in just "sp" are listed here
1975d66f2b0SSimon Tatham     // under FPURestriction::None, which is the only FPURestriction in
1985d66f2b0SSimon Tatham     // which they would be valid (since FPURestriction::SP doesn't
1995d66f2b0SSimon Tatham     // exist).
200ddf5e86cSEli Friedman     {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::D16},
201ddf5e86cSEli Friedman     {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::SP_D16},
2025d66f2b0SSimon Tatham     {"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None},
2035d66f2b0SSimon Tatham     {"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16},
2045d66f2b0SSimon Tatham     {"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16},
2055d66f2b0SSimon Tatham     {"+vfp3sp", "-vfp3sp", FPUVersion::VFPV3, FPURestriction::None},
2065d66f2b0SSimon Tatham     {"+fp16", "-fp16", FPUVersion::VFPV3_FP16, FPURestriction::SP_D16},
2075d66f2b0SSimon Tatham     {"+vfp4", "-vfp4", FPUVersion::VFPV4, FPURestriction::None},
2085d66f2b0SSimon Tatham     {"+vfp4d16", "-vfp4d16", FPUVersion::VFPV4, FPURestriction::D16},
2095d66f2b0SSimon Tatham     {"+vfp4d16sp", "-vfp4d16sp", FPUVersion::VFPV4, FPURestriction::SP_D16},
2105d66f2b0SSimon Tatham     {"+vfp4sp", "-vfp4sp", FPUVersion::VFPV4, FPURestriction::None},
2115d66f2b0SSimon Tatham     {"+fp-armv8", "-fp-armv8", FPUVersion::VFPV5, FPURestriction::None},
2125d66f2b0SSimon Tatham     {"+fp-armv8d16", "-fp-armv8d16", FPUVersion::VFPV5, FPURestriction::D16},
2135d66f2b0SSimon Tatham     {"+fp-armv8d16sp", "-fp-armv8d16sp", FPUVersion::VFPV5, FPURestriction::SP_D16},
2145d66f2b0SSimon Tatham     {"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None},
2155d66f2b0SSimon Tatham     {"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16},
2165d66f2b0SSimon Tatham     {"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16},
217ddf5e86cSEli Friedman     {"+d32", "-d32", FPUVersion::VFPV3, FPURestriction::None},
2185d66f2b0SSimon Tatham   };
2195d66f2b0SSimon Tatham 
2205d66f2b0SSimon Tatham   for (const auto &Info: FPUFeatureInfoList) {
2215d66f2b0SSimon Tatham     if (FPUNames[FPUKind].FPUVer >= Info.MinVersion &&
2225d66f2b0SSimon Tatham         FPUNames[FPUKind].Restriction <= Info.MaxRestriction)
2235d66f2b0SSimon Tatham       Features.push_back(Info.PlusName);
2245d66f2b0SSimon Tatham     else
2255d66f2b0SSimon Tatham       Features.push_back(Info.MinusName);
226e01718cdSDavid Spickett   }
227e01718cdSDavid Spickett 
2285d66f2b0SSimon Tatham   static const struct NeonFeatureNameInfo {
2295d66f2b0SSimon Tatham     const char *PlusName, *MinusName;
2305d66f2b0SSimon Tatham     NeonSupportLevel MinSupportLevel;
2315d66f2b0SSimon Tatham   } NeonFeatureInfoList[] = {
2325d66f2b0SSimon Tatham       {"+neon", "-neon", NeonSupportLevel::Neon},
233b8baa2a9SDavid Candler       {"+sha2", "-sha2", NeonSupportLevel::Crypto},
234b8baa2a9SDavid Candler       {"+aes", "-aes", NeonSupportLevel::Crypto},
2355d66f2b0SSimon Tatham   };
236760df47bSSimon Tatham 
2375d66f2b0SSimon Tatham   for (const auto &Info: NeonFeatureInfoList) {
2385d66f2b0SSimon Tatham     if (FPUNames[FPUKind].NeonSupport >= Info.MinSupportLevel)
2395d66f2b0SSimon Tatham       Features.push_back(Info.PlusName);
2405d66f2b0SSimon Tatham     else
2415d66f2b0SSimon Tatham       Features.push_back(Info.MinusName);
242e01718cdSDavid Spickett   }
243e01718cdSDavid Spickett 
244e01718cdSDavid Spickett   return true;
245e01718cdSDavid Spickett }
246e01718cdSDavid Spickett 
247e01718cdSDavid Spickett // Little/Big endian
parseArchEndian(StringRef Arch)248e01718cdSDavid Spickett ARM::EndianKind ARM::parseArchEndian(StringRef Arch) {
249e01718cdSDavid Spickett   if (Arch.startswith("armeb") || Arch.startswith("thumbeb") ||
250e01718cdSDavid Spickett       Arch.startswith("aarch64_be"))
251e01718cdSDavid Spickett     return EndianKind::BIG;
252e01718cdSDavid Spickett 
253e01718cdSDavid Spickett   if (Arch.startswith("arm") || Arch.startswith("thumb")) {
254e01718cdSDavid Spickett     if (Arch.endswith("eb"))
255e01718cdSDavid Spickett       return EndianKind::BIG;
256e01718cdSDavid Spickett     else
257e01718cdSDavid Spickett       return EndianKind::LITTLE;
258e01718cdSDavid Spickett   }
259e01718cdSDavid Spickett 
260ff6875acSTim Northover   if (Arch.startswith("aarch64") || Arch.startswith("aarch64_32"))
261e01718cdSDavid Spickett     return EndianKind::LITTLE;
262e01718cdSDavid Spickett 
263e01718cdSDavid Spickett   return EndianKind::INVALID;
264e01718cdSDavid Spickett }
265e01718cdSDavid Spickett 
266e01718cdSDavid Spickett // ARM, Thumb, AArch64
parseArchISA(StringRef Arch)267e01718cdSDavid Spickett ARM::ISAKind ARM::parseArchISA(StringRef Arch) {
268e01718cdSDavid Spickett   return StringSwitch<ISAKind>(Arch)
269e01718cdSDavid Spickett       .StartsWith("aarch64", ISAKind::AARCH64)
270e01718cdSDavid Spickett       .StartsWith("arm64", ISAKind::AARCH64)
271e01718cdSDavid Spickett       .StartsWith("thumb", ISAKind::THUMB)
272e01718cdSDavid Spickett       .StartsWith("arm", ISAKind::ARM)
273e01718cdSDavid Spickett       .Default(ISAKind::INVALID);
274e01718cdSDavid Spickett }
275e01718cdSDavid Spickett 
parseFPU(StringRef FPU)276e01718cdSDavid Spickett unsigned ARM::parseFPU(StringRef FPU) {
277e01718cdSDavid Spickett   StringRef Syn = getFPUSynonym(FPU);
278f16b2d83SSimon Pilgrim   for (const auto &F : FPUNames) {
279e01718cdSDavid Spickett     if (Syn == F.getName())
280e01718cdSDavid Spickett       return F.ID;
281e01718cdSDavid Spickett   }
282e01718cdSDavid Spickett   return FK_INVALID;
283e01718cdSDavid Spickett }
284e01718cdSDavid Spickett 
getFPUNeonSupportLevel(unsigned FPUKind)285e01718cdSDavid Spickett ARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(unsigned FPUKind) {
286e01718cdSDavid Spickett   if (FPUKind >= FK_LAST)
287e01718cdSDavid Spickett     return NeonSupportLevel::None;
288e01718cdSDavid Spickett   return FPUNames[FPUKind].NeonSupport;
289e01718cdSDavid Spickett }
290e01718cdSDavid Spickett 
291e01718cdSDavid Spickett // MArch is expected to be of the form (arm|thumb)?(eb)?(v.+)?(eb)?, but
292e01718cdSDavid Spickett // (iwmmxt|xscale)(eb)? is also permitted. If the former, return
293e01718cdSDavid Spickett // "v.+", if the latter, return unmodified string, minus 'eb'.
294e01718cdSDavid Spickett // If invalid, return empty string.
getCanonicalArchName(StringRef Arch)295e01718cdSDavid Spickett StringRef ARM::getCanonicalArchName(StringRef Arch) {
296e01718cdSDavid Spickett   size_t offset = StringRef::npos;
297e01718cdSDavid Spickett   StringRef A = Arch;
298e01718cdSDavid Spickett   StringRef Error = "";
299e01718cdSDavid Spickett 
300e01718cdSDavid Spickett   // Begins with "arm" / "thumb", move past it.
301ff6875acSTim Northover   if (A.startswith("arm64_32"))
302ff6875acSTim Northover     offset = 8;
303f77c948dSAhmed Bougacha   else if (A.startswith("arm64e"))
304f77c948dSAhmed Bougacha     offset = 6;
305ff6875acSTim Northover   else if (A.startswith("arm64"))
306e01718cdSDavid Spickett     offset = 5;
307ff6875acSTim Northover   else if (A.startswith("aarch64_32"))
308ff6875acSTim Northover     offset = 10;
309e01718cdSDavid Spickett   else if (A.startswith("arm"))
310e01718cdSDavid Spickett     offset = 3;
311e01718cdSDavid Spickett   else if (A.startswith("thumb"))
312e01718cdSDavid Spickett     offset = 5;
313e01718cdSDavid Spickett   else if (A.startswith("aarch64")) {
314e01718cdSDavid Spickett     offset = 7;
315e01718cdSDavid Spickett     // AArch64 uses "_be", not "eb" suffix.
316d14d7068SKazu Hirata     if (A.contains("eb"))
317e01718cdSDavid Spickett       return Error;
318e01718cdSDavid Spickett     if (A.substr(offset, 3) == "_be")
319e01718cdSDavid Spickett       offset += 3;
320e01718cdSDavid Spickett   }
321e01718cdSDavid Spickett 
322e01718cdSDavid Spickett   // Ex. "armebv7", move past the "eb".
323e01718cdSDavid Spickett   if (offset != StringRef::npos && A.substr(offset, 2) == "eb")
324e01718cdSDavid Spickett     offset += 2;
325e01718cdSDavid Spickett   // Or, if it ends with eb ("armv7eb"), chop it off.
326e01718cdSDavid Spickett   else if (A.endswith("eb"))
327e01718cdSDavid Spickett     A = A.substr(0, A.size() - 2);
328e01718cdSDavid Spickett   // Trim the head
329e01718cdSDavid Spickett   if (offset != StringRef::npos)
330e01718cdSDavid Spickett     A = A.substr(offset);
331e01718cdSDavid Spickett 
332e01718cdSDavid Spickett   // Empty string means offset reached the end, which means it's valid.
333e01718cdSDavid Spickett   if (A.empty())
334e01718cdSDavid Spickett     return Arch;
335e01718cdSDavid Spickett 
336e01718cdSDavid Spickett   // Only match non-marketing names
337e01718cdSDavid Spickett   if (offset != StringRef::npos) {
338e01718cdSDavid Spickett     // Must start with 'vN'.
339e01718cdSDavid Spickett     if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1])))
340e01718cdSDavid Spickett       return Error;
341e01718cdSDavid Spickett     // Can't have an extra 'eb'.
342d14d7068SKazu Hirata     if (A.contains("eb"))
343e01718cdSDavid Spickett       return Error;
344e01718cdSDavid Spickett   }
345e01718cdSDavid Spickett 
346e01718cdSDavid Spickett   // Arch will either be a 'v' name (v7a) or a marketing name (xscale).
347e01718cdSDavid Spickett   return A;
348e01718cdSDavid Spickett }
349e01718cdSDavid Spickett 
getFPUSynonym(StringRef FPU)350e01718cdSDavid Spickett StringRef ARM::getFPUSynonym(StringRef FPU) {
351e01718cdSDavid Spickett   return StringSwitch<StringRef>(FPU)
352e01718cdSDavid Spickett       .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported
353e01718cdSDavid Spickett       .Case("vfp2", "vfpv2")
354e01718cdSDavid Spickett       .Case("vfp3", "vfpv3")
355e01718cdSDavid Spickett       .Case("vfp4", "vfpv4")
356e01718cdSDavid Spickett       .Case("vfp3-d16", "vfpv3-d16")
357e01718cdSDavid Spickett       .Case("vfp4-d16", "vfpv4-d16")
358e01718cdSDavid Spickett       .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16")
359e01718cdSDavid Spickett       .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16")
360e01718cdSDavid Spickett       .Case("fp5-sp-d16", "fpv5-sp-d16")
361e01718cdSDavid Spickett       .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16")
362e01718cdSDavid Spickett       // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3.
363e01718cdSDavid Spickett       .Case("neon-vfpv3", "neon")
364e01718cdSDavid Spickett       .Default(FPU);
365e01718cdSDavid Spickett }
366e01718cdSDavid Spickett 
getFPUName(unsigned FPUKind)367e01718cdSDavid Spickett StringRef ARM::getFPUName(unsigned FPUKind) {
368e01718cdSDavid Spickett   if (FPUKind >= FK_LAST)
369e01718cdSDavid Spickett     return StringRef();
370e01718cdSDavid Spickett   return FPUNames[FPUKind].getName();
371e01718cdSDavid Spickett }
372e01718cdSDavid Spickett 
getFPUVersion(unsigned FPUKind)373e01718cdSDavid Spickett ARM::FPUVersion ARM::getFPUVersion(unsigned FPUKind) {
374e01718cdSDavid Spickett   if (FPUKind >= FK_LAST)
375e01718cdSDavid Spickett     return FPUVersion::NONE;
376e01718cdSDavid Spickett   return FPUNames[FPUKind].FPUVer;
377e01718cdSDavid Spickett }
378e01718cdSDavid Spickett 
getFPURestriction(unsigned FPUKind)379e01718cdSDavid Spickett ARM::FPURestriction ARM::getFPURestriction(unsigned FPUKind) {
380e01718cdSDavid Spickett   if (FPUKind >= FK_LAST)
381e01718cdSDavid Spickett     return FPURestriction::None;
382e01718cdSDavid Spickett   return FPUNames[FPUKind].Restriction;
383e01718cdSDavid Spickett }
384e01718cdSDavid Spickett 
getDefaultFPU(StringRef CPU,ARM::ArchKind AK)385e01718cdSDavid Spickett unsigned ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) {
386e01718cdSDavid Spickett   if (CPU == "generic")
387e01718cdSDavid Spickett     return ARM::ARCHNames[static_cast<unsigned>(AK)].DefaultFPU;
388e01718cdSDavid Spickett 
389e01718cdSDavid Spickett   return StringSwitch<unsigned>(CPU)
390e01718cdSDavid Spickett #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)           \
391e01718cdSDavid Spickett   .Case(NAME, DEFAULT_FPU)
392e01718cdSDavid Spickett #include "llvm/Support/ARMTargetParser.def"
393e01718cdSDavid Spickett    .Default(ARM::FK_INVALID);
394e01718cdSDavid Spickett }
395e01718cdSDavid Spickett 
getDefaultExtensions(StringRef CPU,ARM::ArchKind AK)3967128aaceSMikhail Maltsev uint64_t ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) {
397e01718cdSDavid Spickett   if (CPU == "generic")
398e01718cdSDavid Spickett     return ARM::ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions;
399e01718cdSDavid Spickett 
4007128aaceSMikhail Maltsev   return StringSwitch<uint64_t>(CPU)
401e01718cdSDavid Spickett #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)           \
402e01718cdSDavid Spickett   .Case(NAME,                                                                  \
403e01718cdSDavid Spickett         ARCHNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions |    \
404e01718cdSDavid Spickett             DEFAULT_EXT)
405e01718cdSDavid Spickett #include "llvm/Support/ARMTargetParser.def"
406e01718cdSDavid Spickett   .Default(ARM::AEK_INVALID);
407e01718cdSDavid Spickett }
408e01718cdSDavid Spickett 
getHWDivFeatures(uint64_t HWDivKind,std::vector<StringRef> & Features)4097128aaceSMikhail Maltsev bool ARM::getHWDivFeatures(uint64_t HWDivKind,
410e01718cdSDavid Spickett                            std::vector<StringRef> &Features) {
411e01718cdSDavid Spickett 
412e01718cdSDavid Spickett   if (HWDivKind == AEK_INVALID)
413e01718cdSDavid Spickett     return false;
414e01718cdSDavid Spickett 
415e01718cdSDavid Spickett   if (HWDivKind & AEK_HWDIVARM)
416e01718cdSDavid Spickett     Features.push_back("+hwdiv-arm");
417e01718cdSDavid Spickett   else
418e01718cdSDavid Spickett     Features.push_back("-hwdiv-arm");
419e01718cdSDavid Spickett 
420e01718cdSDavid Spickett   if (HWDivKind & AEK_HWDIVTHUMB)
421e01718cdSDavid Spickett     Features.push_back("+hwdiv");
422e01718cdSDavid Spickett   else
423e01718cdSDavid Spickett     Features.push_back("-hwdiv");
424e01718cdSDavid Spickett 
425e01718cdSDavid Spickett   return true;
426e01718cdSDavid Spickett }
427e01718cdSDavid Spickett 
getExtensionFeatures(uint64_t Extensions,std::vector<StringRef> & Features)4287128aaceSMikhail Maltsev bool ARM::getExtensionFeatures(uint64_t Extensions,
429e01718cdSDavid Spickett                                std::vector<StringRef> &Features) {
430e01718cdSDavid Spickett 
431e01718cdSDavid Spickett   if (Extensions == AEK_INVALID)
432e01718cdSDavid Spickett     return false;
433e01718cdSDavid Spickett 
434f16b2d83SSimon Pilgrim   for (const auto &AE : ARCHExtNames) {
43524cacf9cSAlexandros Lamprineas     if ((Extensions & AE.ID) == AE.ID && AE.Feature)
43624cacf9cSAlexandros Lamprineas       Features.push_back(AE.Feature);
43724cacf9cSAlexandros Lamprineas     else if (AE.NegFeature)
43824cacf9cSAlexandros Lamprineas       Features.push_back(AE.NegFeature);
43924cacf9cSAlexandros Lamprineas   }
440e01718cdSDavid Spickett 
441e01718cdSDavid Spickett   return getHWDivFeatures(Extensions, Features);
442e01718cdSDavid Spickett }
443e01718cdSDavid Spickett 
getArchName(ARM::ArchKind AK)444e01718cdSDavid Spickett StringRef ARM::getArchName(ARM::ArchKind AK) {
445e01718cdSDavid Spickett   return ARCHNames[static_cast<unsigned>(AK)].getName();
446e01718cdSDavid Spickett }
447e01718cdSDavid Spickett 
getCPUAttr(ARM::ArchKind AK)448e01718cdSDavid Spickett StringRef ARM::getCPUAttr(ARM::ArchKind AK) {
449e01718cdSDavid Spickett   return ARCHNames[static_cast<unsigned>(AK)].getCPUAttr();
450e01718cdSDavid Spickett }
451e01718cdSDavid Spickett 
getSubArch(ARM::ArchKind AK)452e01718cdSDavid Spickett StringRef ARM::getSubArch(ARM::ArchKind AK) {
453e01718cdSDavid Spickett   return ARCHNames[static_cast<unsigned>(AK)].getSubArch();
454e01718cdSDavid Spickett }
455e01718cdSDavid Spickett 
getArchAttr(ARM::ArchKind AK)456e01718cdSDavid Spickett unsigned ARM::getArchAttr(ARM::ArchKind AK) {
457e01718cdSDavid Spickett   return ARCHNames[static_cast<unsigned>(AK)].ArchAttr;
458e01718cdSDavid Spickett }
459e01718cdSDavid Spickett 
getArchExtName(uint64_t ArchExtKind)4607128aaceSMikhail Maltsev StringRef ARM::getArchExtName(uint64_t ArchExtKind) {
461f16b2d83SSimon Pilgrim   for (const auto &AE : ARCHExtNames) {
462e01718cdSDavid Spickett     if (ArchExtKind == AE.ID)
463e01718cdSDavid Spickett       return AE.getName();
464e01718cdSDavid Spickett   }
465e01718cdSDavid Spickett   return StringRef();
466e01718cdSDavid Spickett }
467e01718cdSDavid Spickett 
stripNegationPrefix(StringRef & Name)468a1bb4fb7SSjoerd Meijer static bool stripNegationPrefix(StringRef &Name) {
469a1bb4fb7SSjoerd Meijer   if (Name.startswith("no")) {
470a1bb4fb7SSjoerd Meijer     Name = Name.substr(2);
471a1bb4fb7SSjoerd Meijer     return true;
472a1bb4fb7SSjoerd Meijer   }
473a1bb4fb7SSjoerd Meijer   return false;
474a1bb4fb7SSjoerd Meijer }
475a1bb4fb7SSjoerd Meijer 
getArchExtFeature(StringRef ArchExt)476e01718cdSDavid Spickett StringRef ARM::getArchExtFeature(StringRef ArchExt) {
477a1bb4fb7SSjoerd Meijer   bool Negated = stripNegationPrefix(ArchExt);
478f16b2d83SSimon Pilgrim   for (const auto &AE : ARCHExtNames) {
479e01718cdSDavid Spickett     if (AE.Feature && ArchExt == AE.getName())
480a1bb4fb7SSjoerd Meijer       return StringRef(Negated ? AE.NegFeature : AE.Feature);
481e01718cdSDavid Spickett   }
482e01718cdSDavid Spickett 
483e01718cdSDavid Spickett   return StringRef();
484e01718cdSDavid Spickett }
485e01718cdSDavid Spickett 
findDoublePrecisionFPU(unsigned InputFPUKind)486a1bb4fb7SSjoerd Meijer static unsigned findDoublePrecisionFPU(unsigned InputFPUKind) {
487a1bb4fb7SSjoerd Meijer   const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];
488a1bb4fb7SSjoerd Meijer 
489a1bb4fb7SSjoerd Meijer   // If the input FPU already supports double-precision, then there
490a1bb4fb7SSjoerd Meijer   // isn't any different FPU we can return here.
491a1bb4fb7SSjoerd Meijer   //
492a1bb4fb7SSjoerd Meijer   // The current available FPURestriction values are None (no
493a1bb4fb7SSjoerd Meijer   // restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs
494a1bb4fb7SSjoerd Meijer   // and single precision only); there's no value representing
495a1bb4fb7SSjoerd Meijer   // SP restriction without D16. So this test just means 'is it
496a1bb4fb7SSjoerd Meijer   // SP only?'.
497a1bb4fb7SSjoerd Meijer   if (InputFPU.Restriction != ARM::FPURestriction::SP_D16)
498a1bb4fb7SSjoerd Meijer     return ARM::FK_INVALID;
499a1bb4fb7SSjoerd Meijer 
500a1bb4fb7SSjoerd Meijer   // Otherwise, look for an FPU entry with all the same fields, except
501a1bb4fb7SSjoerd Meijer   // that SP_D16 has been replaced with just D16, representing adding
502a1bb4fb7SSjoerd Meijer   // double precision and not changing anything else.
503a1bb4fb7SSjoerd Meijer   for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
504a1bb4fb7SSjoerd Meijer     if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
505a1bb4fb7SSjoerd Meijer         CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
506a1bb4fb7SSjoerd Meijer         CandidateFPU.Restriction == ARM::FPURestriction::D16) {
507a1bb4fb7SSjoerd Meijer       return CandidateFPU.ID;
508a1bb4fb7SSjoerd Meijer     }
509a1bb4fb7SSjoerd Meijer   }
510a1bb4fb7SSjoerd Meijer 
511a1bb4fb7SSjoerd Meijer   // nothing found
512a1bb4fb7SSjoerd Meijer   return ARM::FK_INVALID;
513a1bb4fb7SSjoerd Meijer }
514a1bb4fb7SSjoerd Meijer 
appendArchExtFeatures(StringRef CPU,ARM::ArchKind AK,StringRef ArchExt,std::vector<StringRef> & Features,unsigned & ArgFPUID)515d1a3396bSVictor Campos bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK,
516d1a3396bSVictor Campos                                 StringRef ArchExt,
517d1a3396bSVictor Campos                                 std::vector<StringRef> &Features,
518d1a3396bSVictor Campos                                 unsigned &ArgFPUID) {
519a1bb4fb7SSjoerd Meijer 
520951bb68cSAlexandros Lamprineas   size_t StartingNumFeatures = Features.size();
521a1bb4fb7SSjoerd Meijer   const bool Negated = stripNegationPrefix(ArchExt);
5227128aaceSMikhail Maltsev   uint64_t ID = parseArchExt(ArchExt);
523951bb68cSAlexandros Lamprineas 
524951bb68cSAlexandros Lamprineas   if (ID == AEK_INVALID)
525951bb68cSAlexandros Lamprineas     return false;
526951bb68cSAlexandros Lamprineas 
527f16b2d83SSimon Pilgrim   for (const auto &AE : ARCHExtNames) {
5283627c91eSMomchil Velikov     if (Negated) {
5293627c91eSMomchil Velikov       if ((AE.ID & ID) == ID && AE.NegFeature)
530951bb68cSAlexandros Lamprineas         Features.push_back(AE.NegFeature);
5313627c91eSMomchil Velikov     } else {
5323627c91eSMomchil Velikov       if ((AE.ID & ID) == AE.ID && AE.Feature)
533951bb68cSAlexandros Lamprineas         Features.push_back(AE.Feature);
534951bb68cSAlexandros Lamprineas     }
5353627c91eSMomchil Velikov   }
536a1bb4fb7SSjoerd Meijer 
537a1bb4fb7SSjoerd Meijer   if (CPU == "")
538a1bb4fb7SSjoerd Meijer     CPU = "generic";
539a1bb4fb7SSjoerd Meijer 
540a1bb4fb7SSjoerd Meijer   if (ArchExt == "fp" || ArchExt == "fp.dp") {
541a1bb4fb7SSjoerd Meijer     unsigned FPUKind;
542a1bb4fb7SSjoerd Meijer     if (ArchExt == "fp.dp") {
543a1bb4fb7SSjoerd Meijer       if (Negated) {
544a1bb4fb7SSjoerd Meijer         Features.push_back("-fp64");
545a1bb4fb7SSjoerd Meijer         return true;
546a1bb4fb7SSjoerd Meijer       }
547a1bb4fb7SSjoerd Meijer       FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK));
548a1bb4fb7SSjoerd Meijer     } else if (Negated) {
549a1bb4fb7SSjoerd Meijer       FPUKind = ARM::FK_NONE;
550a1bb4fb7SSjoerd Meijer     } else {
551a1bb4fb7SSjoerd Meijer       FPUKind = getDefaultFPU(CPU, AK);
552a1bb4fb7SSjoerd Meijer     }
553d1a3396bSVictor Campos     ArgFPUID = FPUKind;
554a1bb4fb7SSjoerd Meijer     return ARM::getFPUFeatures(FPUKind, Features);
555a1bb4fb7SSjoerd Meijer   }
556951bb68cSAlexandros Lamprineas   return StartingNumFeatures != Features.size();
557a1bb4fb7SSjoerd Meijer }
558a1bb4fb7SSjoerd Meijer 
getDefaultCPU(StringRef Arch)559e01718cdSDavid Spickett StringRef ARM::getDefaultCPU(StringRef Arch) {
560e01718cdSDavid Spickett   ArchKind AK = parseArch(Arch);
561e01718cdSDavid Spickett   if (AK == ArchKind::INVALID)
562e01718cdSDavid Spickett     return StringRef();
563e01718cdSDavid Spickett 
564e01718cdSDavid Spickett   // Look for multiple AKs to find the default for pair AK+Name.
565f16b2d83SSimon Pilgrim   for (const auto &CPU : CPUNames) {
566e01718cdSDavid Spickett     if (CPU.ArchID == AK && CPU.Default)
567e01718cdSDavid Spickett       return CPU.getName();
568e01718cdSDavid Spickett   }
569e01718cdSDavid Spickett 
570e01718cdSDavid Spickett   // If we can't find a default then target the architecture instead
571e01718cdSDavid Spickett   return "generic";
572e01718cdSDavid Spickett }
573e01718cdSDavid Spickett 
parseHWDiv(StringRef HWDiv)5747128aaceSMikhail Maltsev uint64_t ARM::parseHWDiv(StringRef HWDiv) {
575e01718cdSDavid Spickett   StringRef Syn = getHWDivSynonym(HWDiv);
576f16b2d83SSimon Pilgrim   for (const auto &D : HWDivNames) {
577e01718cdSDavid Spickett     if (Syn == D.getName())
578e01718cdSDavid Spickett       return D.ID;
579e01718cdSDavid Spickett   }
580e01718cdSDavid Spickett   return AEK_INVALID;
581e01718cdSDavid Spickett }
582e01718cdSDavid Spickett 
parseArchExt(StringRef ArchExt)5837128aaceSMikhail Maltsev uint64_t ARM::parseArchExt(StringRef ArchExt) {
584f16b2d83SSimon Pilgrim   for (const auto &A : ARCHExtNames) {
585e01718cdSDavid Spickett     if (ArchExt == A.getName())
586e01718cdSDavid Spickett       return A.ID;
587e01718cdSDavid Spickett   }
588e01718cdSDavid Spickett   return AEK_INVALID;
589e01718cdSDavid Spickett }
590e01718cdSDavid Spickett 
parseCPUArch(StringRef CPU)591e01718cdSDavid Spickett ARM::ArchKind ARM::parseCPUArch(StringRef CPU) {
592f16b2d83SSimon Pilgrim   for (const auto &C : CPUNames) {
593e01718cdSDavid Spickett     if (CPU == C.getName())
594e01718cdSDavid Spickett       return C.ArchID;
595e01718cdSDavid Spickett   }
596e01718cdSDavid Spickett   return ArchKind::INVALID;
597e01718cdSDavid Spickett }
598e01718cdSDavid Spickett 
fillValidCPUArchList(SmallVectorImpl<StringRef> & Values)599e01718cdSDavid Spickett void ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
600e01718cdSDavid Spickett   for (const CpuNames<ArchKind> &Arch : CPUNames) {
601e01718cdSDavid Spickett     if (Arch.ArchID != ArchKind::INVALID)
602e01718cdSDavid Spickett       Values.push_back(Arch.getName());
603e01718cdSDavid Spickett   }
604e01718cdSDavid Spickett }
605e01718cdSDavid Spickett 
computeDefaultTargetABI(const Triple & TT,StringRef CPU)606e01718cdSDavid Spickett StringRef ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) {
607e01718cdSDavid Spickett   StringRef ArchName =
608e01718cdSDavid Spickett       CPU.empty() ? TT.getArchName() : getArchName(parseCPUArch(CPU));
609e01718cdSDavid Spickett 
610e01718cdSDavid Spickett   if (TT.isOSBinFormatMachO()) {
611e01718cdSDavid Spickett     if (TT.getEnvironment() == Triple::EABI ||
612e01718cdSDavid Spickett         TT.getOS() == Triple::UnknownOS ||
613e01718cdSDavid Spickett         parseArchProfile(ArchName) == ProfileKind::M)
614e01718cdSDavid Spickett       return "aapcs";
615e01718cdSDavid Spickett     if (TT.isWatchABI())
616e01718cdSDavid Spickett       return "aapcs16";
617e01718cdSDavid Spickett     return "apcs-gnu";
618e01718cdSDavid Spickett   } else if (TT.isOSWindows())
619e01718cdSDavid Spickett     // FIXME: this is invalid for WindowsCE.
620e01718cdSDavid Spickett     return "aapcs";
621e01718cdSDavid Spickett 
622e01718cdSDavid Spickett   // Select the default based on the platform.
623e01718cdSDavid Spickett   switch (TT.getEnvironment()) {
624e01718cdSDavid Spickett   case Triple::Android:
625e01718cdSDavid Spickett   case Triple::GNUEABI:
626e01718cdSDavid Spickett   case Triple::GNUEABIHF:
627e01718cdSDavid Spickett   case Triple::MuslEABI:
628e01718cdSDavid Spickett   case Triple::MuslEABIHF:
629e01718cdSDavid Spickett     return "aapcs-linux";
630e01718cdSDavid Spickett   case Triple::EABIHF:
631e01718cdSDavid Spickett   case Triple::EABI:
632e01718cdSDavid Spickett     return "aapcs";
633e01718cdSDavid Spickett   default:
634e01718cdSDavid Spickett     if (TT.isOSNetBSD())
635e01718cdSDavid Spickett       return "apcs-gnu";
636e01718cdSDavid Spickett     if (TT.isOSOpenBSD())
637e01718cdSDavid Spickett       return "aapcs-linux";
638e01718cdSDavid Spickett     return "aapcs";
639e01718cdSDavid Spickett   }
640e01718cdSDavid Spickett }
641