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