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: "v8m.base" , Value: "v8-m.base" ) |
49 | .Case(S: "v8m.main" , Value: "v8-m.main" ) |
50 | .Case(S: "v8.1m.main" , Value: "v8.1-m.main" ) |
51 | .Default(Value: Arch); |
52 | } |
53 | |
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(Prefix: "arm64_32" )) |
61 | offset = 8; |
62 | else if (A.starts_with(Prefix: "arm64e" )) |
63 | offset = 6; |
64 | else if (A.starts_with(Prefix: "arm64" )) |
65 | offset = 5; |
66 | else if (A.starts_with(Prefix: "aarch64_32" )) |
67 | offset = 10; |
68 | else if (A.starts_with(Prefix: "arm" )) |
69 | offset = 3; |
70 | else if (A.starts_with(Prefix: "thumb" )) |
71 | offset = 5; |
72 | else if (A.starts_with(Prefix: "aarch64" )) { |
73 | offset = 7; |
74 | // AArch64 uses "_be", not "eb" suffix. |
75 | if (A.contains(Other: "eb" )) |
76 | return Error; |
77 | if (A.substr(Start: offset, N: 3) == "_be" ) |
78 | offset += 3; |
79 | } |
80 | |
81 | // Ex. "armebv7", move past the "eb". |
82 | if (offset != StringRef::npos && A.substr(Start: offset, N: 2) == "eb" ) |
83 | offset += 2; |
84 | // Or, if it ends with eb ("armv7eb"), chop it off. |
85 | else if (A.ends_with(Suffix: "eb" )) |
86 | A = A.substr(Start: 0, N: A.size() - 2); |
87 | // Trim the head |
88 | if (offset != StringRef::npos) |
89 | A = A.substr(Start: 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(Other: "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 | |
109 | ARM::ISAKind ARM::parseArchISA(StringRef Arch) { |
110 | return StringSwitch<ISAKind>(Arch) |
111 | .StartsWith(S: "aarch64" , Value: ISAKind::AARCH64) |
112 | .StartsWith(S: "arm64" , Value: ISAKind::AARCH64) |
113 | .StartsWith(S: "thumb" , Value: ISAKind::THUMB) |
114 | .StartsWith(S: "arm" , Value: ISAKind::ARM) |
115 | .Default(Value: ISAKind::INVALID); |
116 | } |
117 | |
118 | ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { |
119 | if (Arch.starts_with(Prefix: "armeb" ) || Arch.starts_with(Prefix: "thumbeb" ) || |
120 | Arch.starts_with(Prefix: "aarch64_be" )) |
121 | return EndianKind::BIG; |
122 | |
123 | if (Arch.starts_with(Prefix: "arm" ) || Arch.starts_with(Prefix: "thumb" )) { |
124 | if (Arch.ends_with(Suffix: "eb" )) |
125 | return EndianKind::BIG; |
126 | else |
127 | return EndianKind::LITTLE; |
128 | } |
129 | |
130 | if (Arch.starts_with(Prefix: "aarch64" ) || Arch.starts_with(Prefix: "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. |
141 | bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, |
142 | StringRef &Err, bool EnablePAuthLR) { |
143 | PBP = {.Scope: "none" , .Key: "a_key" , .BranchTargetEnforcement: false, .BranchProtectionPAuthLR: false, .GuardedControlStack: 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 | PBP.BranchProtectionPAuthLR = EnablePAuthLR; |
152 | return true; |
153 | } |
154 | |
155 | SmallVector<StringRef, 4> Opts; |
156 | Spec.split(A&: Opts, Separator: "+" ); |
157 | for (int I = 0, E = Opts.size(); I != E; ++I) { |
158 | StringRef Opt = Opts[I].trim(); |
159 | if (Opt == "bti" ) { |
160 | PBP.BranchTargetEnforcement = true; |
161 | continue; |
162 | } |
163 | if (Opt == "pac-ret" ) { |
164 | PBP.Scope = "non-leaf" ; |
165 | for (; I + 1 != E; ++I) { |
166 | StringRef PACOpt = Opts[I + 1].trim(); |
167 | if (PACOpt == "leaf" ) |
168 | PBP.Scope = "all" ; |
169 | else if (PACOpt == "b-key" ) |
170 | PBP.Key = "b_key" ; |
171 | else if (PACOpt == "pc" ) |
172 | PBP.BranchProtectionPAuthLR = true; |
173 | else |
174 | break; |
175 | } |
176 | continue; |
177 | } |
178 | if (Opt == "gcs" ) { |
179 | PBP.GuardedControlStack = true; |
180 | continue; |
181 | } |
182 | if (Opt == "" ) |
183 | Err = "<empty>" ; |
184 | else |
185 | Err = Opt; |
186 | return false; |
187 | } |
188 | |
189 | return true; |
190 | } |
191 | |