1 //===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a target parser to recognise ARM hardware features
10 // such as FPU/CPU/ARCH/extensions and specific support such as HWDIV.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/TargetParser/ARMTargetParser.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/TargetParser/ARMTargetParserCommon.h"
17 #include "llvm/TargetParser/Triple.h"
18 #include <cctype>
19 
20 using namespace llvm;
21 
getHWDivSynonym(StringRef HWDiv)22 static StringRef getHWDivSynonym(StringRef HWDiv) {
23   return StringSwitch<StringRef>(HWDiv)
24       .Case("thumb,arm", "arm,thumb")
25       .Default(HWDiv);
26 }
27 
28 // Allows partial match, ex. "v7a" matches "armv7a".
parseArch(StringRef Arch)29 ARM::ArchKind ARM::parseArch(StringRef Arch) {
30   Arch = getCanonicalArchName(Arch);
31   StringRef Syn = getArchSynonym(Arch);
32   for (const auto &A : ARMArchNames) {
33     if (A.Name.endswith(Syn))
34       return A.ID;
35   }
36   return ArchKind::INVALID;
37 }
38 
39 // Version number (ex. v7 = 7).
parseArchVersion(StringRef Arch)40 unsigned ARM::parseArchVersion(StringRef Arch) {
41   Arch = getCanonicalArchName(Arch);
42   switch (parseArch(Arch)) {
43   case ArchKind::ARMV4:
44   case ArchKind::ARMV4T:
45     return 4;
46   case ArchKind::ARMV5T:
47   case ArchKind::ARMV5TE:
48   case ArchKind::IWMMXT:
49   case ArchKind::IWMMXT2:
50   case ArchKind::XSCALE:
51   case ArchKind::ARMV5TEJ:
52     return 5;
53   case ArchKind::ARMV6:
54   case ArchKind::ARMV6K:
55   case ArchKind::ARMV6T2:
56   case ArchKind::ARMV6KZ:
57   case ArchKind::ARMV6M:
58     return 6;
59   case ArchKind::ARMV7A:
60   case ArchKind::ARMV7VE:
61   case ArchKind::ARMV7R:
62   case ArchKind::ARMV7M:
63   case ArchKind::ARMV7S:
64   case ArchKind::ARMV7EM:
65   case ArchKind::ARMV7K:
66     return 7;
67   case ArchKind::ARMV8A:
68   case ArchKind::ARMV8_1A:
69   case ArchKind::ARMV8_2A:
70   case ArchKind::ARMV8_3A:
71   case ArchKind::ARMV8_4A:
72   case ArchKind::ARMV8_5A:
73   case ArchKind::ARMV8_6A:
74   case ArchKind::ARMV8_7A:
75   case ArchKind::ARMV8_8A:
76   case ArchKind::ARMV8_9A:
77   case ArchKind::ARMV8R:
78   case ArchKind::ARMV8MBaseline:
79   case ArchKind::ARMV8MMainline:
80   case ArchKind::ARMV8_1MMainline:
81     return 8;
82   case ArchKind::ARMV9A:
83   case ArchKind::ARMV9_1A:
84   case ArchKind::ARMV9_2A:
85   case ArchKind::ARMV9_3A:
86   case ArchKind::ARMV9_4A:
87     return 9;
88   case ArchKind::INVALID:
89     return 0;
90   }
91   llvm_unreachable("Unhandled architecture");
92 }
93 
getProfileKind(ARM::ArchKind AK)94 static ARM::ProfileKind getProfileKind(ARM::ArchKind AK) {
95   switch (AK) {
96   case ARM::ArchKind::ARMV6M:
97   case ARM::ArchKind::ARMV7M:
98   case ARM::ArchKind::ARMV7EM:
99   case ARM::ArchKind::ARMV8MMainline:
100   case ARM::ArchKind::ARMV8MBaseline:
101   case ARM::ArchKind::ARMV8_1MMainline:
102     return ARM::ProfileKind::M;
103   case ARM::ArchKind::ARMV7R:
104   case ARM::ArchKind::ARMV8R:
105     return ARM::ProfileKind::R;
106   case ARM::ArchKind::ARMV7A:
107   case ARM::ArchKind::ARMV7VE:
108   case ARM::ArchKind::ARMV7K:
109   case ARM::ArchKind::ARMV8A:
110   case ARM::ArchKind::ARMV8_1A:
111   case ARM::ArchKind::ARMV8_2A:
112   case ARM::ArchKind::ARMV8_3A:
113   case ARM::ArchKind::ARMV8_4A:
114   case ARM::ArchKind::ARMV8_5A:
115   case ARM::ArchKind::ARMV8_6A:
116   case ARM::ArchKind::ARMV8_7A:
117   case ARM::ArchKind::ARMV8_8A:
118   case ARM::ArchKind::ARMV8_9A:
119   case ARM::ArchKind::ARMV9A:
120   case ARM::ArchKind::ARMV9_1A:
121   case ARM::ArchKind::ARMV9_2A:
122   case ARM::ArchKind::ARMV9_3A:
123   case ARM::ArchKind::ARMV9_4A:
124     return ARM::ProfileKind::A;
125   case ARM::ArchKind::ARMV4:
126   case ARM::ArchKind::ARMV4T:
127   case ARM::ArchKind::ARMV5T:
128   case ARM::ArchKind::ARMV5TE:
129   case ARM::ArchKind::ARMV5TEJ:
130   case ARM::ArchKind::ARMV6:
131   case ARM::ArchKind::ARMV6K:
132   case ARM::ArchKind::ARMV6T2:
133   case ARM::ArchKind::ARMV6KZ:
134   case ARM::ArchKind::ARMV7S:
135   case ARM::ArchKind::IWMMXT:
136   case ARM::ArchKind::IWMMXT2:
137   case ARM::ArchKind::XSCALE:
138   case ARM::ArchKind::INVALID:
139     return ARM::ProfileKind::INVALID;
140   }
141   llvm_unreachable("Unhandled architecture");
142 }
143 
144 // Profile A/R/M
parseArchProfile(StringRef Arch)145 ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
146   Arch = getCanonicalArchName(Arch);
147   return getProfileKind(parseArch(Arch));
148 }
149 
getFPUFeatures(unsigned FPUKind,std::vector<StringRef> & Features)150 bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) {
151 
152   if (FPUKind >= FK_LAST || FPUKind == FK_INVALID)
153     return false;
154 
155   static const struct FPUFeatureNameInfo {
156     const char *PlusName, *MinusName;
157     FPUVersion MinVersion;
158     FPURestriction MaxRestriction;
159   } FPUFeatureInfoList[] = {
160     // We have to specify the + and - versions of the name in full so
161     // that we can return them as static StringRefs.
162     //
163     // Also, the SubtargetFeatures ending in just "sp" are listed here
164     // under FPURestriction::None, which is the only FPURestriction in
165     // which they would be valid (since FPURestriction::SP doesn't
166     // exist).
167     {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::D16},
168     {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::SP_D16},
169     {"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None},
170     {"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16},
171     {"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16},
172     {"+vfp3sp", "-vfp3sp", FPUVersion::VFPV3, FPURestriction::None},
173     {"+fp16", "-fp16", FPUVersion::VFPV3_FP16, FPURestriction::SP_D16},
174     {"+vfp4", "-vfp4", FPUVersion::VFPV4, FPURestriction::None},
175     {"+vfp4d16", "-vfp4d16", FPUVersion::VFPV4, FPURestriction::D16},
176     {"+vfp4d16sp", "-vfp4d16sp", FPUVersion::VFPV4, FPURestriction::SP_D16},
177     {"+vfp4sp", "-vfp4sp", FPUVersion::VFPV4, FPURestriction::None},
178     {"+fp-armv8", "-fp-armv8", FPUVersion::VFPV5, FPURestriction::None},
179     {"+fp-armv8d16", "-fp-armv8d16", FPUVersion::VFPV5, FPURestriction::D16},
180     {"+fp-armv8d16sp", "-fp-armv8d16sp", FPUVersion::VFPV5, FPURestriction::SP_D16},
181     {"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None},
182     {"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16},
183     {"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16},
184     {"+d32", "-d32", FPUVersion::VFPV3, FPURestriction::None},
185   };
186 
187   for (const auto &Info: FPUFeatureInfoList) {
188     if (FPUNames[FPUKind].FPUVer >= Info.MinVersion &&
189         FPUNames[FPUKind].Restriction <= Info.MaxRestriction)
190       Features.push_back(Info.PlusName);
191     else
192       Features.push_back(Info.MinusName);
193   }
194 
195   static const struct NeonFeatureNameInfo {
196     const char *PlusName, *MinusName;
197     NeonSupportLevel MinSupportLevel;
198   } NeonFeatureInfoList[] = {
199       {"+neon", "-neon", NeonSupportLevel::Neon},
200       {"+sha2", "-sha2", NeonSupportLevel::Crypto},
201       {"+aes", "-aes", NeonSupportLevel::Crypto},
202   };
203 
204   for (const auto &Info: NeonFeatureInfoList) {
205     if (FPUNames[FPUKind].NeonSupport >= Info.MinSupportLevel)
206       Features.push_back(Info.PlusName);
207     else
208       Features.push_back(Info.MinusName);
209   }
210 
211   return true;
212 }
213 
parseFPU(StringRef FPU)214 unsigned ARM::parseFPU(StringRef FPU) {
215   StringRef Syn = getFPUSynonym(FPU);
216   for (const auto &F : FPUNames) {
217     if (Syn == F.Name)
218       return F.ID;
219   }
220   return FK_INVALID;
221 }
222 
getFPUNeonSupportLevel(unsigned FPUKind)223 ARM::NeonSupportLevel ARM::getFPUNeonSupportLevel(unsigned FPUKind) {
224   if (FPUKind >= FK_LAST)
225     return NeonSupportLevel::None;
226   return FPUNames[FPUKind].NeonSupport;
227 }
228 
getFPUSynonym(StringRef FPU)229 StringRef ARM::getFPUSynonym(StringRef FPU) {
230   return StringSwitch<StringRef>(FPU)
231       .Cases("fpa", "fpe2", "fpe3", "maverick", "invalid") // Unsupported
232       .Case("vfp2", "vfpv2")
233       .Case("vfp3", "vfpv3")
234       .Case("vfp4", "vfpv4")
235       .Case("vfp3-d16", "vfpv3-d16")
236       .Case("vfp4-d16", "vfpv4-d16")
237       .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16")
238       .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16")
239       .Case("fp5-sp-d16", "fpv5-sp-d16")
240       .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16")
241       // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3.
242       .Case("neon-vfpv3", "neon")
243       .Default(FPU);
244 }
245 
getFPUName(unsigned FPUKind)246 StringRef ARM::getFPUName(unsigned FPUKind) {
247   if (FPUKind >= FK_LAST)
248     return StringRef();
249   return FPUNames[FPUKind].Name;
250 }
251 
getFPUVersion(unsigned FPUKind)252 ARM::FPUVersion ARM::getFPUVersion(unsigned FPUKind) {
253   if (FPUKind >= FK_LAST)
254     return FPUVersion::NONE;
255   return FPUNames[FPUKind].FPUVer;
256 }
257 
getFPURestriction(unsigned FPUKind)258 ARM::FPURestriction ARM::getFPURestriction(unsigned FPUKind) {
259   if (FPUKind >= FK_LAST)
260     return FPURestriction::None;
261   return FPUNames[FPUKind].Restriction;
262 }
263 
getDefaultFPU(StringRef CPU,ARM::ArchKind AK)264 unsigned ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) {
265   if (CPU == "generic")
266     return ARM::ARMArchNames[static_cast<unsigned>(AK)].DefaultFPU;
267 
268   return StringSwitch<unsigned>(CPU)
269 #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)           \
270   .Case(NAME, DEFAULT_FPU)
271 #include "llvm/TargetParser/ARMTargetParser.def"
272    .Default(ARM::FK_INVALID);
273 }
274 
getDefaultExtensions(StringRef CPU,ARM::ArchKind AK)275 uint64_t ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) {
276   if (CPU == "generic")
277     return ARM::ARMArchNames[static_cast<unsigned>(AK)].ArchBaseExtensions;
278 
279   return StringSwitch<uint64_t>(CPU)
280 #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)           \
281   .Case(NAME,                                                                  \
282         ARMArchNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions | \
283             DEFAULT_EXT)
284 #include "llvm/TargetParser/ARMTargetParser.def"
285   .Default(ARM::AEK_INVALID);
286 }
287 
getHWDivFeatures(uint64_t HWDivKind,std::vector<StringRef> & Features)288 bool ARM::getHWDivFeatures(uint64_t HWDivKind,
289                            std::vector<StringRef> &Features) {
290 
291   if (HWDivKind == AEK_INVALID)
292     return false;
293 
294   if (HWDivKind & AEK_HWDIVARM)
295     Features.push_back("+hwdiv-arm");
296   else
297     Features.push_back("-hwdiv-arm");
298 
299   if (HWDivKind & AEK_HWDIVTHUMB)
300     Features.push_back("+hwdiv");
301   else
302     Features.push_back("-hwdiv");
303 
304   return true;
305 }
306 
getExtensionFeatures(uint64_t Extensions,std::vector<StringRef> & Features)307 bool ARM::getExtensionFeatures(uint64_t Extensions,
308                                std::vector<StringRef> &Features) {
309 
310   if (Extensions == AEK_INVALID)
311     return false;
312 
313   for (const auto &AE : ARCHExtNames) {
314     if ((Extensions & AE.ID) == AE.ID && !AE.Feature.empty())
315       Features.push_back(AE.Feature);
316     else if (!AE.NegFeature.empty())
317       Features.push_back(AE.NegFeature);
318   }
319 
320   return getHWDivFeatures(Extensions, Features);
321 }
322 
getArchName(ARM::ArchKind AK)323 StringRef ARM::getArchName(ARM::ArchKind AK) {
324   return ARMArchNames[static_cast<unsigned>(AK)].Name;
325 }
326 
getCPUAttr(ARM::ArchKind AK)327 StringRef ARM::getCPUAttr(ARM::ArchKind AK) {
328   return ARMArchNames[static_cast<unsigned>(AK)].CPUAttr;
329 }
330 
getSubArch(ARM::ArchKind AK)331 StringRef ARM::getSubArch(ARM::ArchKind AK) {
332   return ARMArchNames[static_cast<unsigned>(AK)].getSubArch();
333 }
334 
getArchAttr(ARM::ArchKind AK)335 unsigned ARM::getArchAttr(ARM::ArchKind AK) {
336   return ARMArchNames[static_cast<unsigned>(AK)].ArchAttr;
337 }
338 
getArchExtName(uint64_t ArchExtKind)339 StringRef ARM::getArchExtName(uint64_t ArchExtKind) {
340   for (const auto &AE : ARCHExtNames) {
341     if (ArchExtKind == AE.ID)
342       return AE.Name;
343   }
344   return StringRef();
345 }
346 
stripNegationPrefix(StringRef & Name)347 static bool stripNegationPrefix(StringRef &Name) {
348   if (Name.startswith("no")) {
349     Name = Name.substr(2);
350     return true;
351   }
352   return false;
353 }
354 
getArchExtFeature(StringRef ArchExt)355 StringRef ARM::getArchExtFeature(StringRef ArchExt) {
356   bool Negated = stripNegationPrefix(ArchExt);
357   for (const auto &AE : ARCHExtNames) {
358     if (!AE.Feature.empty() && ArchExt == AE.Name)
359       return StringRef(Negated ? AE.NegFeature : AE.Feature);
360   }
361 
362   return StringRef();
363 }
364 
findDoublePrecisionFPU(unsigned InputFPUKind)365 static unsigned findDoublePrecisionFPU(unsigned InputFPUKind) {
366   const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];
367 
368   // If the input FPU already supports double-precision, then there
369   // isn't any different FPU we can return here.
370   //
371   // The current available FPURestriction values are None (no
372   // restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs
373   // and single precision only); there's no value representing
374   // SP restriction without D16. So this test just means 'is it
375   // SP only?'.
376   if (InputFPU.Restriction != ARM::FPURestriction::SP_D16)
377     return ARM::FK_INVALID;
378 
379   // Otherwise, look for an FPU entry with all the same fields, except
380   // that SP_D16 has been replaced with just D16, representing adding
381   // double precision and not changing anything else.
382   for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
383     if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
384         CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
385         CandidateFPU.Restriction == ARM::FPURestriction::D16) {
386       return CandidateFPU.ID;
387     }
388   }
389 
390   // nothing found
391   return ARM::FK_INVALID;
392 }
393 
appendArchExtFeatures(StringRef CPU,ARM::ArchKind AK,StringRef ArchExt,std::vector<StringRef> & Features,unsigned & ArgFPUID)394 bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK,
395                                 StringRef ArchExt,
396                                 std::vector<StringRef> &Features,
397                                 unsigned &ArgFPUID) {
398 
399   size_t StartingNumFeatures = Features.size();
400   const bool Negated = stripNegationPrefix(ArchExt);
401   uint64_t ID = parseArchExt(ArchExt);
402 
403   if (ID == AEK_INVALID)
404     return false;
405 
406   for (const auto &AE : ARCHExtNames) {
407     if (Negated) {
408       if ((AE.ID & ID) == ID && !AE.NegFeature.empty())
409         Features.push_back(AE.NegFeature);
410     } else {
411       if ((AE.ID & ID) == AE.ID && !AE.Feature.empty())
412         Features.push_back(AE.Feature);
413     }
414   }
415 
416   if (CPU == "")
417     CPU = "generic";
418 
419   if (ArchExt == "fp" || ArchExt == "fp.dp") {
420     unsigned FPUKind;
421     if (ArchExt == "fp.dp") {
422       if (Negated) {
423         Features.push_back("-fp64");
424         return true;
425       }
426       FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK));
427     } else if (Negated) {
428       FPUKind = ARM::FK_NONE;
429     } else {
430       FPUKind = getDefaultFPU(CPU, AK);
431     }
432     ArgFPUID = FPUKind;
433     return ARM::getFPUFeatures(FPUKind, Features);
434   }
435   return StartingNumFeatures != Features.size();
436 }
437 
convertV9toV8(ARM::ArchKind AK)438 ARM::ArchKind ARM::convertV9toV8(ARM::ArchKind AK) {
439   if (getProfileKind(AK) != ProfileKind::A)
440     return ARM::ArchKind::INVALID;
441   if (AK < ARM::ArchKind::ARMV9A || AK > ARM::ArchKind::ARMV9_3A)
442     return ARM::ArchKind::INVALID;
443   unsigned AK_v8 = static_cast<unsigned>(ARM::ArchKind::ARMV8_5A);
444   AK_v8 += static_cast<unsigned>(AK) -
445            static_cast<unsigned>(ARM::ArchKind::ARMV9A);
446   return static_cast<ARM::ArchKind>(AK_v8);
447 }
448 
getDefaultCPU(StringRef Arch)449 StringRef ARM::getDefaultCPU(StringRef Arch) {
450   ArchKind AK = parseArch(Arch);
451   if (AK == ArchKind::INVALID)
452     return StringRef();
453 
454   // Look for multiple AKs to find the default for pair AK+Name.
455   for (const auto &CPU : CPUNames) {
456     if (CPU.ArchID == AK && CPU.Default)
457       return CPU.Name;
458   }
459 
460   // If we can't find a default then target the architecture instead
461   return "generic";
462 }
463 
parseHWDiv(StringRef HWDiv)464 uint64_t ARM::parseHWDiv(StringRef HWDiv) {
465   StringRef Syn = getHWDivSynonym(HWDiv);
466   for (const auto &D : HWDivNames) {
467     if (Syn == D.Name)
468       return D.ID;
469   }
470   return AEK_INVALID;
471 }
472 
parseArchExt(StringRef ArchExt)473 uint64_t ARM::parseArchExt(StringRef ArchExt) {
474   for (const auto &A : ARCHExtNames) {
475     if (ArchExt == A.Name)
476       return A.ID;
477   }
478   return AEK_INVALID;
479 }
480 
parseCPUArch(StringRef CPU)481 ARM::ArchKind ARM::parseCPUArch(StringRef CPU) {
482   for (const auto &C : CPUNames) {
483     if (CPU == C.Name)
484       return C.ArchID;
485   }
486   return ArchKind::INVALID;
487 }
488 
fillValidCPUArchList(SmallVectorImpl<StringRef> & Values)489 void ARM::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
490   for (const auto &Arch : CPUNames) {
491     if (Arch.ArchID != ArchKind::INVALID)
492       Values.push_back(Arch.Name);
493   }
494 }
495 
computeDefaultTargetABI(const Triple & TT,StringRef CPU)496 StringRef ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) {
497   StringRef ArchName =
498       CPU.empty() ? TT.getArchName() : getArchName(parseCPUArch(CPU));
499 
500   if (TT.isOSBinFormatMachO()) {
501     if (TT.getEnvironment() == Triple::EABI ||
502         TT.getOS() == Triple::UnknownOS ||
503         parseArchProfile(ArchName) == ProfileKind::M)
504       return "aapcs";
505     if (TT.isWatchABI())
506       return "aapcs16";
507     return "apcs-gnu";
508   } else if (TT.isOSWindows())
509     // FIXME: this is invalid for WindowsCE.
510     return "aapcs";
511 
512   // Select the default based on the platform.
513   switch (TT.getEnvironment()) {
514   case Triple::Android:
515   case Triple::GNUEABI:
516   case Triple::GNUEABIHF:
517   case Triple::MuslEABI:
518   case Triple::MuslEABIHF:
519     return "aapcs-linux";
520   case Triple::EABIHF:
521   case Triple::EABI:
522     return "aapcs";
523   default:
524     if (TT.isOSNetBSD())
525       return "apcs-gnu";
526     if (TT.isOSFreeBSD() || TT.isOSOpenBSD())
527       return "aapcs-linux";
528     return "aapcs";
529   }
530 }
531 
getARMCPUForArch(const llvm::Triple & Triple,StringRef MArch)532 StringRef ARM::getARMCPUForArch(const llvm::Triple &Triple, StringRef MArch) {
533   if (MArch.empty())
534     MArch = Triple.getArchName();
535   MArch = llvm::ARM::getCanonicalArchName(MArch);
536 
537   // Some defaults are forced.
538   switch (Triple.getOS()) {
539   case llvm::Triple::FreeBSD:
540   case llvm::Triple::NetBSD:
541   case llvm::Triple::OpenBSD:
542     if (!MArch.empty() && MArch == "v6")
543       return "arm1176jzf-s";
544     if (!MArch.empty() && MArch == "v7")
545       return "cortex-a8";
546     break;
547   case llvm::Triple::Win32:
548     // FIXME: this is invalid for WindowsCE
549     if (llvm::ARM::parseArchVersion(MArch) <= 7)
550       return "cortex-a9";
551     break;
552   case llvm::Triple::IOS:
553   case llvm::Triple::MacOSX:
554   case llvm::Triple::TvOS:
555   case llvm::Triple::WatchOS:
556   case llvm::Triple::DriverKit:
557     if (MArch == "v7k")
558       return "cortex-a7";
559     break;
560   default:
561     break;
562   }
563 
564   if (MArch.empty())
565     return StringRef();
566 
567   StringRef CPU = llvm::ARM::getDefaultCPU(MArch);
568   if (!CPU.empty() && !CPU.equals("invalid"))
569     return CPU;
570 
571   // If no specific architecture version is requested, return the minimum CPU
572   // required by the OS and environment.
573   switch (Triple.getOS()) {
574   case llvm::Triple::NetBSD:
575     switch (Triple.getEnvironment()) {
576     case llvm::Triple::EABI:
577     case llvm::Triple::EABIHF:
578     case llvm::Triple::GNUEABI:
579     case llvm::Triple::GNUEABIHF:
580       return "arm926ej-s";
581     default:
582       return "strongarm";
583     }
584   case llvm::Triple::NaCl:
585   case llvm::Triple::OpenBSD:
586     return "cortex-a8";
587   default:
588     switch (Triple.getEnvironment()) {
589     case llvm::Triple::EABIHF:
590     case llvm::Triple::GNUEABIHF:
591     case llvm::Triple::MuslEABIHF:
592       return "arm1176jzf-s";
593     default:
594       return "arm7tdmi";
595     }
596   }
597 
598   llvm_unreachable("invalid arch name");
599 }
600