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