1 //===---------------- ARMTargetParserCommon ---------------------*- 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 // Code that is common to ARMTargetParser and AArch64TargetParser.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/TargetParser/ARMTargetParserCommon.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/StringSwitch.h"
16 
17 using namespace llvm;
18 
getArchSynonym(StringRef Arch)19 StringRef ARM::getArchSynonym(StringRef Arch) {
20   return StringSwitch<StringRef>(Arch)
21       .Case("v5", "v5t")
22       .Case("v5e", "v5te")
23       .Case("v6j", "v6")
24       .Case("v6hl", "v6k")
25       .Cases("v6m", "v6sm", "v6s-m", "v6-m")
26       .Cases("v6z", "v6zk", "v6kz")
27       .Cases("v7", "v7a", "v7hl", "v7l", "v7-a")
28       .Case("v7r", "v7-r")
29       .Case("v7m", "v7-m")
30       .Case("v7em", "v7e-m")
31       .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a")
32       .Case("v8.1a", "v8.1-a")
33       .Case("v8.2a", "v8.2-a")
34       .Case("v8.3a", "v8.3-a")
35       .Case("v8.4a", "v8.4-a")
36       .Case("v8.5a", "v8.5-a")
37       .Case("v8.6a", "v8.6-a")
38       .Case("v8.7a", "v8.7-a")
39       .Case("v8.8a", "v8.8-a")
40       .Case("v8.9a", "v8.9-a")
41       .Case("v8r", "v8-r")
42       .Cases("v9", "v9a", "v9-a")
43       .Case("v9.1a", "v9.1-a")
44       .Case("v9.2a", "v9.2-a")
45       .Case("v9.3a", "v9.3-a")
46       .Case("v9.4a", "v9.4-a")
47       .Case("v9.5a", "v9.5-a")
48       .Case("v8m.base", "v8-m.base")
49       .Case("v8m.main", "v8-m.main")
50       .Case("v8.1m.main", "v8.1-m.main")
51       .Default(Arch);
52 }
53 
getCanonicalArchName(StringRef Arch)54 StringRef ARM::getCanonicalArchName(StringRef Arch) {
55   size_t offset = StringRef::npos;
56   StringRef A = Arch;
57   StringRef Error = "";
58 
59   // Begins with "arm" / "thumb", move past it.
60   if (A.starts_with("arm64_32"))
61     offset = 8;
62   else if (A.starts_with("arm64e"))
63     offset = 6;
64   else if (A.starts_with("arm64"))
65     offset = 5;
66   else if (A.starts_with("aarch64_32"))
67     offset = 10;
68   else if (A.starts_with("arm"))
69     offset = 3;
70   else if (A.starts_with("thumb"))
71     offset = 5;
72   else if (A.starts_with("aarch64")) {
73     offset = 7;
74     // AArch64 uses "_be", not "eb" suffix.
75     if (A.contains("eb"))
76       return Error;
77     if (A.substr(offset, 3) == "_be")
78       offset += 3;
79   }
80 
81   // Ex. "armebv7", move past the "eb".
82   if (offset != StringRef::npos && A.substr(offset, 2) == "eb")
83     offset += 2;
84   // Or, if it ends with eb ("armv7eb"), chop it off.
85   else if (A.ends_with("eb"))
86     A = A.substr(0, A.size() - 2);
87   // Trim the head
88   if (offset != StringRef::npos)
89     A = A.substr(offset);
90 
91   // Empty string means offset reached the end, which means it's valid.
92   if (A.empty())
93     return Arch;
94 
95   // Only match non-marketing names
96   if (offset != StringRef::npos) {
97     // Must start with 'vN'.
98     if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1])))
99       return Error;
100     // Can't have an extra 'eb'.
101     if (A.contains("eb"))
102       return Error;
103   }
104 
105   // Arch will either be a 'v' name (v7a) or a marketing name (xscale).
106   return A;
107 }
108 
parseArchISA(StringRef Arch)109 ARM::ISAKind ARM::parseArchISA(StringRef Arch) {
110   return StringSwitch<ISAKind>(Arch)
111       .StartsWith("aarch64", ISAKind::AARCH64)
112       .StartsWith("arm64", ISAKind::AARCH64)
113       .StartsWith("thumb", ISAKind::THUMB)
114       .StartsWith("arm", ISAKind::ARM)
115       .Default(ISAKind::INVALID);
116 }
117 
parseArchEndian(StringRef Arch)118 ARM::EndianKind ARM::parseArchEndian(StringRef Arch) {
119   if (Arch.starts_with("armeb") || Arch.starts_with("thumbeb") ||
120       Arch.starts_with("aarch64_be"))
121     return EndianKind::BIG;
122 
123   if (Arch.starts_with("arm") || Arch.starts_with("thumb")) {
124     if (Arch.ends_with("eb"))
125       return EndianKind::BIG;
126     else
127       return EndianKind::LITTLE;
128   }
129 
130   if (Arch.starts_with("aarch64") || Arch.starts_with("aarch64_32"))
131     return EndianKind::LITTLE;
132 
133   return EndianKind::INVALID;
134 }
135 
136 // Parse a branch protection specification, which has the form
137 //   standard | none | [bti,pac-ret[+b-key,+leaf,+pc]*]
138 // Returns true on success, with individual elements of the specification
139 // returned in `PBP`. Returns false in error, with `Err` containing
140 // an erroneous part of the spec.
parseBranchProtection(StringRef Spec,ParsedBranchProtection & PBP,StringRef & Err)141 bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP,
142                                 StringRef &Err) {
143   PBP = {"none", "a_key", false, false, false};
144   if (Spec == "none")
145     return true; // defaults are ok
146 
147   if (Spec == "standard") {
148     PBP.Scope = "non-leaf";
149     PBP.BranchTargetEnforcement = true;
150     PBP.GuardedControlStack = true;
151     return true;
152   }
153 
154   SmallVector<StringRef, 4> Opts;
155   Spec.split(Opts, "+");
156   for (int I = 0, E = Opts.size(); I != E; ++I) {
157     StringRef Opt = Opts[I].trim();
158     if (Opt == "bti") {
159       PBP.BranchTargetEnforcement = true;
160       continue;
161     }
162     if (Opt == "pac-ret") {
163       PBP.Scope = "non-leaf";
164       for (; I + 1 != E; ++I) {
165         StringRef PACOpt = Opts[I + 1].trim();
166         if (PACOpt == "leaf")
167           PBP.Scope = "all";
168         else if (PACOpt == "b-key")
169           PBP.Key = "b_key";
170         else if (PACOpt == "pc")
171           PBP.BranchProtectionPAuthLR = true;
172         else
173           break;
174       }
175       continue;
176     }
177     if (Opt == "gcs") {
178       PBP.GuardedControlStack = true;
179       continue;
180     }
181     if (Opt == "")
182       Err = "<empty>";
183     else
184       Err = Opt;
185     return false;
186   }
187 
188   return true;
189 }
190