1 | //===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ------------*- 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 | #include "llvm/Support/RISCVISAInfo.h" |
10 | #include "llvm/ADT/MapVector.h" |
11 | #include "llvm/ADT/STLExtras.h" |
12 | #include "llvm/ADT/SetVector.h" |
13 | #include "llvm/ADT/StringExtras.h" |
14 | #include "llvm/ADT/StringRef.h" |
15 | #include "llvm/Support/Errc.h" |
16 | #include "llvm/Support/Error.h" |
17 | #include "llvm/Support/raw_ostream.h" |
18 | |
19 | #include <array> |
20 | #include <atomic> |
21 | #include <optional> |
22 | #include <string> |
23 | #include <vector> |
24 | |
25 | using namespace llvm; |
26 | |
27 | namespace { |
28 | |
29 | struct RISCVSupportedExtension { |
30 | const char *Name; |
31 | /// Supported version. |
32 | RISCVISAInfo::ExtensionVersion Version; |
33 | |
34 | bool operator<(const RISCVSupportedExtension &RHS) const { |
35 | return StringRef(Name) < StringRef(RHS.Name); |
36 | } |
37 | }; |
38 | |
39 | } // end anonymous namespace |
40 | |
41 | static constexpr StringLiteral AllStdExts = "mafdqlcbkjtpvnh" ; |
42 | |
43 | static const char *RISCVGImplications[] = { |
44 | "i" , "m" , "a" , "f" , "d" , "zicsr" , "zifencei" |
45 | }; |
46 | |
47 | // NOTE: This table should be sorted alphabetically by extension name. |
48 | static const RISCVSupportedExtension SupportedExtensions[] = { |
49 | {.Name: "a" , .Version: {.Major: 2, .Minor: 1}}, |
50 | {.Name: "c" , .Version: {.Major: 2, .Minor: 0}}, |
51 | {.Name: "d" , .Version: {.Major: 2, .Minor: 2}}, |
52 | {.Name: "e" , .Version: {.Major: 2, .Minor: 0}}, |
53 | {.Name: "f" , .Version: {.Major: 2, .Minor: 2}}, |
54 | {.Name: "h" , .Version: {.Major: 1, .Minor: 0}}, |
55 | {.Name: "i" , .Version: {.Major: 2, .Minor: 1}}, |
56 | {.Name: "m" , .Version: {.Major: 2, .Minor: 0}}, |
57 | |
58 | {.Name: "shcounterenw" , .Version: {.Major: 1, .Minor: 0}}, |
59 | {.Name: "shgatpa" , .Version: {.Major: 1, .Minor: 0}}, |
60 | {.Name: "shtvala" , .Version: {.Major: 1, .Minor: 0}}, |
61 | {.Name: "shvsatpa" , .Version: {.Major: 1, .Minor: 0}}, |
62 | {.Name: "shvstvala" , .Version: {.Major: 1, .Minor: 0}}, |
63 | {.Name: "shvstvecd" , .Version: {.Major: 1, .Minor: 0}}, |
64 | {.Name: "smaia" , .Version: {.Major: 1, .Minor: 0}}, |
65 | {.Name: "smepmp" , .Version: {.Major: 1, .Minor: 0}}, |
66 | {.Name: "ssaia" , .Version: {.Major: 1, .Minor: 0}}, |
67 | {.Name: "ssccptr" , .Version: {.Major: 1, .Minor: 0}}, |
68 | {.Name: "sscounterenw" , .Version: {.Major: 1, .Minor: 0}}, |
69 | {.Name: "ssstateen" , .Version: {.Major: 1, .Minor: 0}}, |
70 | {.Name: "ssstrict" , .Version: {.Major: 1, .Minor: 0}}, |
71 | {.Name: "sstc" , .Version: {.Major: 1, .Minor: 0}}, |
72 | {.Name: "sstvala" , .Version: {.Major: 1, .Minor: 0}}, |
73 | {.Name: "sstvecd" , .Version: {.Major: 1, .Minor: 0}}, |
74 | {.Name: "ssu64xl" , .Version: {.Major: 1, .Minor: 0}}, |
75 | {.Name: "svade" , .Version: {.Major: 1, .Minor: 0}}, |
76 | {.Name: "svadu" , .Version: {.Major: 1, .Minor: 0}}, |
77 | {.Name: "svbare" , .Version: {.Major: 1, .Minor: 0}}, |
78 | {.Name: "svinval" , .Version: {.Major: 1, .Minor: 0}}, |
79 | {.Name: "svnapot" , .Version: {.Major: 1, .Minor: 0}}, |
80 | {.Name: "svpbmt" , .Version: {.Major: 1, .Minor: 0}}, |
81 | |
82 | {.Name: "v" , .Version: {.Major: 1, .Minor: 0}}, |
83 | |
84 | // vendor-defined ('X') extensions |
85 | {.Name: "xcvalu" , .Version: {.Major: 1, .Minor: 0}}, |
86 | {.Name: "xcvbi" , .Version: {.Major: 1, .Minor: 0}}, |
87 | {.Name: "xcvbitmanip" , .Version: {.Major: 1, .Minor: 0}}, |
88 | {.Name: "xcvelw" , .Version: {.Major: 1, .Minor: 0}}, |
89 | {.Name: "xcvmac" , .Version: {.Major: 1, .Minor: 0}}, |
90 | {.Name: "xcvmem" , .Version: {.Major: 1, .Minor: 0}}, |
91 | {.Name: "xcvsimd" , .Version: {.Major: 1, .Minor: 0}}, |
92 | {.Name: "xsfvcp" , .Version: {.Major: 1, .Minor: 0}}, |
93 | {.Name: "xsfvfnrclipxfqf" , .Version: {.Major: 1, .Minor: 0}}, |
94 | {.Name: "xsfvfwmaccqqq" , .Version: {.Major: 1, .Minor: 0}}, |
95 | {.Name: "xsfvqmaccdod" , .Version: {.Major: 1, .Minor: 0}}, |
96 | {.Name: "xsfvqmaccqoq" , .Version: {.Major: 1, .Minor: 0}}, |
97 | {.Name: "xtheadba" , .Version: {.Major: 1, .Minor: 0}}, |
98 | {.Name: "xtheadbb" , .Version: {.Major: 1, .Minor: 0}}, |
99 | {.Name: "xtheadbs" , .Version: {.Major: 1, .Minor: 0}}, |
100 | {.Name: "xtheadcmo" , .Version: {.Major: 1, .Minor: 0}}, |
101 | {.Name: "xtheadcondmov" , .Version: {.Major: 1, .Minor: 0}}, |
102 | {.Name: "xtheadfmemidx" , .Version: {.Major: 1, .Minor: 0}}, |
103 | {.Name: "xtheadmac" , .Version: {.Major: 1, .Minor: 0}}, |
104 | {.Name: "xtheadmemidx" , .Version: {.Major: 1, .Minor: 0}}, |
105 | {.Name: "xtheadmempair" , .Version: {.Major: 1, .Minor: 0}}, |
106 | {.Name: "xtheadsync" , .Version: {.Major: 1, .Minor: 0}}, |
107 | {.Name: "xtheadvdot" , .Version: {.Major: 1, .Minor: 0}}, |
108 | {.Name: "xventanacondops" , .Version: {.Major: 1, .Minor: 0}}, |
109 | |
110 | {.Name: "za128rs" , .Version: {.Major: 1, .Minor: 0}}, |
111 | {.Name: "za64rs" , .Version: {.Major: 1, .Minor: 0}}, |
112 | {.Name: "zawrs" , .Version: {.Major: 1, .Minor: 0}}, |
113 | |
114 | {.Name: "zba" , .Version: {.Major: 1, .Minor: 0}}, |
115 | {.Name: "zbb" , .Version: {.Major: 1, .Minor: 0}}, |
116 | {.Name: "zbc" , .Version: {.Major: 1, .Minor: 0}}, |
117 | {.Name: "zbkb" , .Version: {.Major: 1, .Minor: 0}}, |
118 | {.Name: "zbkc" , .Version: {.Major: 1, .Minor: 0}}, |
119 | {.Name: "zbkx" , .Version: {.Major: 1, .Minor: 0}}, |
120 | {.Name: "zbs" , .Version: {.Major: 1, .Minor: 0}}, |
121 | |
122 | {.Name: "zca" , .Version: {.Major: 1, .Minor: 0}}, |
123 | {.Name: "zcb" , .Version: {.Major: 1, .Minor: 0}}, |
124 | {.Name: "zcd" , .Version: {.Major: 1, .Minor: 0}}, |
125 | {.Name: "zce" , .Version: {.Major: 1, .Minor: 0}}, |
126 | {.Name: "zcf" , .Version: {.Major: 1, .Minor: 0}}, |
127 | {.Name: "zcmp" , .Version: {.Major: 1, .Minor: 0}}, |
128 | {.Name: "zcmt" , .Version: {.Major: 1, .Minor: 0}}, |
129 | |
130 | {.Name: "zdinx" , .Version: {.Major: 1, .Minor: 0}}, |
131 | |
132 | {.Name: "zfa" , .Version: {.Major: 1, .Minor: 0}}, |
133 | {.Name: "zfh" , .Version: {.Major: 1, .Minor: 0}}, |
134 | {.Name: "zfhmin" , .Version: {.Major: 1, .Minor: 0}}, |
135 | {.Name: "zfinx" , .Version: {.Major: 1, .Minor: 0}}, |
136 | |
137 | {.Name: "zhinx" , .Version: {.Major: 1, .Minor: 0}}, |
138 | {.Name: "zhinxmin" , .Version: {.Major: 1, .Minor: 0}}, |
139 | |
140 | {.Name: "zic64b" , .Version: {.Major: 1, .Minor: 0}}, |
141 | {.Name: "zicbom" , .Version: {.Major: 1, .Minor: 0}}, |
142 | {.Name: "zicbop" , .Version: {.Major: 1, .Minor: 0}}, |
143 | {.Name: "zicboz" , .Version: {.Major: 1, .Minor: 0}}, |
144 | {.Name: "ziccamoa" , .Version: {.Major: 1, .Minor: 0}}, |
145 | {.Name: "ziccif" , .Version: {.Major: 1, .Minor: 0}}, |
146 | {.Name: "zicclsm" , .Version: {.Major: 1, .Minor: 0}}, |
147 | {.Name: "ziccrse" , .Version: {.Major: 1, .Minor: 0}}, |
148 | {.Name: "zicntr" , .Version: {.Major: 2, .Minor: 0}}, |
149 | {.Name: "zicond" , .Version: {.Major: 1, .Minor: 0}}, |
150 | {.Name: "zicsr" , .Version: {.Major: 2, .Minor: 0}}, |
151 | {.Name: "zifencei" , .Version: {.Major: 2, .Minor: 0}}, |
152 | {.Name: "zihintntl" , .Version: {.Major: 1, .Minor: 0}}, |
153 | {.Name: "zihintpause" , .Version: {.Major: 2, .Minor: 0}}, |
154 | {.Name: "zihpm" , .Version: {.Major: 2, .Minor: 0}}, |
155 | |
156 | {.Name: "zk" , .Version: {.Major: 1, .Minor: 0}}, |
157 | {.Name: "zkn" , .Version: {.Major: 1, .Minor: 0}}, |
158 | {.Name: "zknd" , .Version: {.Major: 1, .Minor: 0}}, |
159 | {.Name: "zkne" , .Version: {.Major: 1, .Minor: 0}}, |
160 | {.Name: "zknh" , .Version: {.Major: 1, .Minor: 0}}, |
161 | {.Name: "zkr" , .Version: {.Major: 1, .Minor: 0}}, |
162 | {.Name: "zks" , .Version: {.Major: 1, .Minor: 0}}, |
163 | {.Name: "zksed" , .Version: {.Major: 1, .Minor: 0}}, |
164 | {.Name: "zksh" , .Version: {.Major: 1, .Minor: 0}}, |
165 | {.Name: "zkt" , .Version: {.Major: 1, .Minor: 0}}, |
166 | |
167 | {.Name: "zmmul" , .Version: {.Major: 1, .Minor: 0}}, |
168 | |
169 | {.Name: "zvbb" , .Version: {.Major: 1, .Minor: 0}}, |
170 | {.Name: "zvbc" , .Version: {.Major: 1, .Minor: 0}}, |
171 | |
172 | {.Name: "zve32f" , .Version: {.Major: 1, .Minor: 0}}, |
173 | {.Name: "zve32x" , .Version: {.Major: 1, .Minor: 0}}, |
174 | {.Name: "zve64d" , .Version: {.Major: 1, .Minor: 0}}, |
175 | {.Name: "zve64f" , .Version: {.Major: 1, .Minor: 0}}, |
176 | {.Name: "zve64x" , .Version: {.Major: 1, .Minor: 0}}, |
177 | |
178 | {.Name: "zvfh" , .Version: {.Major: 1, .Minor: 0}}, |
179 | {.Name: "zvfhmin" , .Version: {.Major: 1, .Minor: 0}}, |
180 | |
181 | // vector crypto |
182 | {.Name: "zvkb" , .Version: {.Major: 1, .Minor: 0}}, |
183 | {.Name: "zvkg" , .Version: {.Major: 1, .Minor: 0}}, |
184 | {.Name: "zvkn" , .Version: {.Major: 1, .Minor: 0}}, |
185 | {.Name: "zvknc" , .Version: {.Major: 1, .Minor: 0}}, |
186 | {.Name: "zvkned" , .Version: {.Major: 1, .Minor: 0}}, |
187 | {.Name: "zvkng" , .Version: {.Major: 1, .Minor: 0}}, |
188 | {.Name: "zvknha" , .Version: {.Major: 1, .Minor: 0}}, |
189 | {.Name: "zvknhb" , .Version: {.Major: 1, .Minor: 0}}, |
190 | {.Name: "zvks" , .Version: {.Major: 1, .Minor: 0}}, |
191 | {.Name: "zvksc" , .Version: {.Major: 1, .Minor: 0}}, |
192 | {.Name: "zvksed" , .Version: {.Major: 1, .Minor: 0}}, |
193 | {.Name: "zvksg" , .Version: {.Major: 1, .Minor: 0}}, |
194 | {.Name: "zvksh" , .Version: {.Major: 1, .Minor: 0}}, |
195 | {.Name: "zvkt" , .Version: {.Major: 1, .Minor: 0}}, |
196 | |
197 | {.Name: "zvl1024b" , .Version: {.Major: 1, .Minor: 0}}, |
198 | {.Name: "zvl128b" , .Version: {.Major: 1, .Minor: 0}}, |
199 | {.Name: "zvl16384b" , .Version: {.Major: 1, .Minor: 0}}, |
200 | {.Name: "zvl2048b" , .Version: {.Major: 1, .Minor: 0}}, |
201 | {.Name: "zvl256b" , .Version: {.Major: 1, .Minor: 0}}, |
202 | {.Name: "zvl32768b" , .Version: {.Major: 1, .Minor: 0}}, |
203 | {.Name: "zvl32b" , .Version: {.Major: 1, .Minor: 0}}, |
204 | {.Name: "zvl4096b" , .Version: {.Major: 1, .Minor: 0}}, |
205 | {.Name: "zvl512b" , .Version: {.Major: 1, .Minor: 0}}, |
206 | {.Name: "zvl64b" , .Version: {.Major: 1, .Minor: 0}}, |
207 | {.Name: "zvl65536b" , .Version: {.Major: 1, .Minor: 0}}, |
208 | {.Name: "zvl8192b" , .Version: {.Major: 1, .Minor: 0}}, |
209 | }; |
210 | |
211 | // NOTE: This table should be sorted alphabetically by extension name. |
212 | // clang-format off |
213 | static const RISCVSupportedExtension SupportedExperimentalExtensions[] = { |
214 | {.Name: "smmpm" , .Version: {.Major: 0, .Minor: 8}}, |
215 | {.Name: "smnpm" , .Version: {.Major: 0, .Minor: 8}}, |
216 | {.Name: "ssnpm" , .Version: {.Major: 0, .Minor: 8}}, |
217 | {.Name: "sspm" , .Version: {.Major: 0, .Minor: 8}}, |
218 | {.Name: "ssqosid" , .Version: {.Major: 1, .Minor: 0}}, |
219 | {.Name: "supm" , .Version: {.Major: 0, .Minor: 8}}, |
220 | |
221 | {.Name: "zaamo" , .Version: {.Major: 0, .Minor: 2}}, |
222 | {.Name: "zabha" , .Version: {.Major: 1, .Minor: 0}}, |
223 | {.Name: "zacas" , .Version: {.Major: 1, .Minor: 0}}, |
224 | {.Name: "zalasr" , .Version: {.Major: 0, .Minor: 1}}, |
225 | {.Name: "zalrsc" , .Version: {.Major: 0, .Minor: 2}}, |
226 | |
227 | {.Name: "zcmop" , .Version: {.Major: 0, .Minor: 2}}, |
228 | |
229 | {.Name: "zfbfmin" , .Version: {.Major: 1, .Minor: 0}}, |
230 | |
231 | {.Name: "zicfilp" , .Version: {.Major: 0, .Minor: 4}}, |
232 | {.Name: "zicfiss" , .Version: {.Major: 0, .Minor: 4}}, |
233 | |
234 | {.Name: "zimop" , .Version: {.Major: 0, .Minor: 1}}, |
235 | |
236 | {.Name: "ztso" , .Version: {.Major: 0, .Minor: 1}}, |
237 | |
238 | {.Name: "zvfbfmin" , .Version: {.Major: 1, .Minor: 0}}, |
239 | {.Name: "zvfbfwma" , .Version: {.Major: 1, .Minor: 0}}, |
240 | }; |
241 | // clang-format on |
242 | |
243 | static void verifyTables() { |
244 | #ifndef NDEBUG |
245 | static std::atomic<bool> TableChecked(false); |
246 | if (!TableChecked.load(m: std::memory_order_relaxed)) { |
247 | assert(llvm::is_sorted(SupportedExtensions) && |
248 | "Extensions are not sorted by name" ); |
249 | assert(llvm::is_sorted(SupportedExperimentalExtensions) && |
250 | "Experimental extensions are not sorted by name" ); |
251 | TableChecked.store(i: true, m: std::memory_order_relaxed); |
252 | } |
253 | #endif |
254 | } |
255 | |
256 | static void PrintExtension(StringRef Name, StringRef Version, |
257 | StringRef Description) { |
258 | outs().indent(NumSpaces: 4); |
259 | unsigned VersionWidth = Description.empty() ? 0 : 10; |
260 | outs() << left_justify(Str: Name, Width: 20) << left_justify(Str: Version, Width: VersionWidth) |
261 | << Description << "\n" ; |
262 | } |
263 | |
264 | void llvm::riscvExtensionsHelp(StringMap<StringRef> DescMap) { |
265 | |
266 | outs() << "All available -march extensions for RISC-V\n\n" ; |
267 | PrintExtension(Name: "Name" , Version: "Version" , Description: (DescMap.empty() ? "" : "Description" )); |
268 | |
269 | RISCVISAInfo::OrderedExtensionMap ExtMap; |
270 | for (const auto &E : SupportedExtensions) |
271 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
272 | for (const auto &E : ExtMap) { |
273 | std::string Version = |
274 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
275 | PrintExtension(Name: E.first, Version, Description: DescMap[E.first]); |
276 | } |
277 | |
278 | outs() << "\nExperimental extensions\n" ; |
279 | ExtMap.clear(); |
280 | for (const auto &E : SupportedExperimentalExtensions) |
281 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
282 | for (const auto &E : ExtMap) { |
283 | std::string Version = |
284 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
285 | PrintExtension(Name: E.first, Version, Description: DescMap["experimental-" + E.first]); |
286 | } |
287 | |
288 | outs() << "\nUse -march to specify the target's extension.\n" |
289 | "For example, clang -march=rv32i_v1p0\n" ; |
290 | } |
291 | |
292 | static bool stripExperimentalPrefix(StringRef &Ext) { |
293 | return Ext.consume_front(Prefix: "experimental-" ); |
294 | } |
295 | |
296 | // This function finds the last character that doesn't belong to a version |
297 | // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will |
298 | // consume [0-9]*p[0-9]* starting from the backward. An extension name will not |
299 | // end with a digit or the letter 'p', so this function will parse correctly. |
300 | // NOTE: This function is NOT able to take empty strings or strings that only |
301 | // have version numbers and no extension name. It assumes the extension name |
302 | // will be at least more than one character. |
303 | static size_t findLastNonVersionCharacter(StringRef Ext) { |
304 | assert(!Ext.empty() && |
305 | "Already guarded by if-statement in ::parseArchString" ); |
306 | |
307 | int Pos = Ext.size() - 1; |
308 | while (Pos > 0 && isDigit(C: Ext[Pos])) |
309 | Pos--; |
310 | if (Pos > 0 && Ext[Pos] == 'p' && isDigit(C: Ext[Pos - 1])) { |
311 | Pos--; |
312 | while (Pos > 0 && isDigit(C: Ext[Pos])) |
313 | Pos--; |
314 | } |
315 | return Pos; |
316 | } |
317 | |
318 | namespace { |
319 | struct LessExtName { |
320 | bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) { |
321 | return StringRef(LHS.Name) < RHS; |
322 | } |
323 | bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) { |
324 | return LHS < StringRef(RHS.Name); |
325 | } |
326 | }; |
327 | } // namespace |
328 | |
329 | static std::optional<RISCVISAInfo::ExtensionVersion> |
330 | findDefaultVersion(StringRef ExtName) { |
331 | // Find default version of an extension. |
332 | // TODO: We might set default version based on profile or ISA spec. |
333 | for (auto &ExtInfo : {ArrayRef(SupportedExtensions), |
334 | ArrayRef(SupportedExperimentalExtensions)}) { |
335 | auto I = llvm::lower_bound(Range: ExtInfo, Value&: ExtName, C: LessExtName()); |
336 | |
337 | if (I == ExtInfo.end() || I->Name != ExtName) |
338 | continue; |
339 | |
340 | return I->Version; |
341 | } |
342 | return std::nullopt; |
343 | } |
344 | |
345 | void RISCVISAInfo::addExtension(StringRef ExtName, |
346 | RISCVISAInfo::ExtensionVersion Version) { |
347 | Exts[ExtName.str()] = Version; |
348 | } |
349 | |
350 | static StringRef getExtensionTypeDesc(StringRef Ext) { |
351 | if (Ext.starts_with(Prefix: "s" )) |
352 | return "standard supervisor-level extension" ; |
353 | if (Ext.starts_with(Prefix: "x" )) |
354 | return "non-standard user-level extension" ; |
355 | if (Ext.starts_with(Prefix: "z" )) |
356 | return "standard user-level extension" ; |
357 | return StringRef(); |
358 | } |
359 | |
360 | static StringRef getExtensionType(StringRef Ext) { |
361 | if (Ext.starts_with(Prefix: "s" )) |
362 | return "s" ; |
363 | if (Ext.starts_with(Prefix: "x" )) |
364 | return "x" ; |
365 | if (Ext.starts_with(Prefix: "z" )) |
366 | return "z" ; |
367 | return StringRef(); |
368 | } |
369 | |
370 | static std::optional<RISCVISAInfo::ExtensionVersion> |
371 | isExperimentalExtension(StringRef Ext) { |
372 | auto I = |
373 | llvm::lower_bound(Range: SupportedExperimentalExtensions, Value&: Ext, C: LessExtName()); |
374 | if (I == std::end(arr: SupportedExperimentalExtensions) || I->Name != Ext) |
375 | return std::nullopt; |
376 | |
377 | return I->Version; |
378 | } |
379 | |
380 | bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) { |
381 | bool IsExperimental = stripExperimentalPrefix(Ext); |
382 | |
383 | ArrayRef<RISCVSupportedExtension> ExtInfo = |
384 | IsExperimental ? ArrayRef(SupportedExperimentalExtensions) |
385 | : ArrayRef(SupportedExtensions); |
386 | |
387 | auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName()); |
388 | return I != ExtInfo.end() && I->Name == Ext; |
389 | } |
390 | |
391 | bool RISCVISAInfo::isSupportedExtension(StringRef Ext) { |
392 | verifyTables(); |
393 | |
394 | for (auto ExtInfo : {ArrayRef(SupportedExtensions), |
395 | ArrayRef(SupportedExperimentalExtensions)}) { |
396 | auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName()); |
397 | if (I != ExtInfo.end() && I->Name == Ext) |
398 | return true; |
399 | } |
400 | |
401 | return false; |
402 | } |
403 | |
404 | bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion, |
405 | unsigned MinorVersion) { |
406 | for (auto ExtInfo : {ArrayRef(SupportedExtensions), |
407 | ArrayRef(SupportedExperimentalExtensions)}) { |
408 | auto Range = |
409 | std::equal_range(first: ExtInfo.begin(), last: ExtInfo.end(), val: Ext, comp: LessExtName()); |
410 | for (auto I = Range.first, E = Range.second; I != E; ++I) |
411 | if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion) |
412 | return true; |
413 | } |
414 | |
415 | return false; |
416 | } |
417 | |
418 | bool RISCVISAInfo::hasExtension(StringRef Ext) const { |
419 | stripExperimentalPrefix(Ext); |
420 | |
421 | if (!isSupportedExtension(Ext)) |
422 | return false; |
423 | |
424 | return Exts.count(x: Ext.str()) != 0; |
425 | } |
426 | |
427 | // We rank extensions in the following order: |
428 | // -Single letter extensions in canonical order. |
429 | // -Unknown single letter extensions in alphabetical order. |
430 | // -Multi-letter extensions starting with 'z' sorted by canonical order of |
431 | // the second letter then sorted alphabetically. |
432 | // -Multi-letter extensions starting with 's' in alphabetical order. |
433 | // -(TODO) Multi-letter extensions starting with 'zxm' in alphabetical order. |
434 | // -X extensions in alphabetical order. |
435 | // These flags are used to indicate the category. The first 6 bits store the |
436 | // single letter extension rank for single letter and multi-letter extensions |
437 | // starting with 'z'. |
438 | enum RankFlags { |
439 | RF_Z_EXTENSION = 1 << 6, |
440 | RF_S_EXTENSION = 1 << 7, |
441 | RF_X_EXTENSION = 1 << 8, |
442 | }; |
443 | |
444 | // Get the rank for single-letter extension, lower value meaning higher |
445 | // priority. |
446 | static unsigned singleLetterExtensionRank(char Ext) { |
447 | assert(Ext >= 'a' && Ext <= 'z'); |
448 | switch (Ext) { |
449 | case 'i': |
450 | return 0; |
451 | case 'e': |
452 | return 1; |
453 | } |
454 | |
455 | size_t Pos = AllStdExts.find(C: Ext); |
456 | if (Pos != StringRef::npos) |
457 | return Pos + 2; // Skip 'e' and 'i' from above. |
458 | |
459 | // If we got an unknown extension letter, then give it an alphabetical |
460 | // order, but after all known standard extensions. |
461 | return 2 + AllStdExts.size() + (Ext - 'a'); |
462 | } |
463 | |
464 | // Get the rank for multi-letter extension, lower value meaning higher |
465 | // priority/order in canonical order. |
466 | static unsigned getExtensionRank(const std::string &ExtName) { |
467 | assert(ExtName.size() >= 1); |
468 | switch (ExtName[0]) { |
469 | case 's': |
470 | return RF_S_EXTENSION; |
471 | case 'z': |
472 | assert(ExtName.size() >= 2); |
473 | // `z` extension must be sorted by canonical order of second letter. |
474 | // e.g. zmx has higher rank than zax. |
475 | return RF_Z_EXTENSION | singleLetterExtensionRank(Ext: ExtName[1]); |
476 | case 'x': |
477 | return RF_X_EXTENSION; |
478 | default: |
479 | assert(ExtName.size() == 1); |
480 | return singleLetterExtensionRank(Ext: ExtName[0]); |
481 | } |
482 | } |
483 | |
484 | // Compare function for extension. |
485 | // Only compare the extension name, ignore version comparison. |
486 | bool RISCVISAInfo::compareExtension(const std::string &LHS, |
487 | const std::string &RHS) { |
488 | unsigned LHSRank = getExtensionRank(ExtName: LHS); |
489 | unsigned RHSRank = getExtensionRank(ExtName: RHS); |
490 | |
491 | // If the ranks differ, pick the lower rank. |
492 | if (LHSRank != RHSRank) |
493 | return LHSRank < RHSRank; |
494 | |
495 | // If the rank is same, it must be sorted by lexicographic order. |
496 | return LHS < RHS; |
497 | } |
498 | |
499 | std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions, |
500 | bool IgnoreUnknown) const { |
501 | std::vector<std::string> Features; |
502 | for (const auto &[ExtName, _] : Exts) { |
503 | // i is a base instruction set, not an extension (see |
504 | // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa) |
505 | // and is not recognized in clang -cc1 |
506 | if (ExtName == "i" ) |
507 | continue; |
508 | if (IgnoreUnknown && !isSupportedExtension(Ext: ExtName)) |
509 | continue; |
510 | |
511 | if (isExperimentalExtension(Ext: ExtName)) { |
512 | Features.push_back(x: (llvm::Twine("+experimental-" ) + ExtName).str()); |
513 | } else { |
514 | Features.push_back(x: (llvm::Twine("+" ) + ExtName).str()); |
515 | } |
516 | } |
517 | if (AddAllExtensions) { |
518 | for (const RISCVSupportedExtension &Ext : SupportedExtensions) { |
519 | if (Exts.count(x: Ext.Name)) |
520 | continue; |
521 | Features.push_back(x: (llvm::Twine("-" ) + Ext.Name).str()); |
522 | } |
523 | |
524 | for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) { |
525 | if (Exts.count(x: Ext.Name)) |
526 | continue; |
527 | Features.push_back(x: (llvm::Twine("-experimental-" ) + Ext.Name).str()); |
528 | } |
529 | } |
530 | return Features; |
531 | } |
532 | |
533 | // Extensions may have a version number, and may be separated by |
534 | // an underscore '_' e.g.: rv32i2_m2. |
535 | // Version number is divided into major and minor version numbers, |
536 | // separated by a 'p'. If the minor version is 0 then 'p0' can be |
537 | // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. |
538 | static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, |
539 | unsigned &Minor, unsigned &ConsumeLength, |
540 | bool EnableExperimentalExtension, |
541 | bool ExperimentalExtensionVersionCheck) { |
542 | StringRef MajorStr, MinorStr; |
543 | Major = 0; |
544 | Minor = 0; |
545 | ConsumeLength = 0; |
546 | MajorStr = In.take_while(F: isDigit); |
547 | In = In.substr(Start: MajorStr.size()); |
548 | |
549 | if (!MajorStr.empty() && In.consume_front(Prefix: "p" )) { |
550 | MinorStr = In.take_while(F: isDigit); |
551 | In = In.substr(Start: MajorStr.size() + MinorStr.size() - 1); |
552 | |
553 | // Expected 'p' to be followed by minor version number. |
554 | if (MinorStr.empty()) { |
555 | return createStringError( |
556 | EC: errc::invalid_argument, |
557 | S: "minor version number missing after 'p' for extension '" + Ext + "'" ); |
558 | } |
559 | } |
560 | |
561 | if (!MajorStr.empty() && MajorStr.getAsInteger(Radix: 10, Result&: Major)) |
562 | return createStringError( |
563 | EC: errc::invalid_argument, |
564 | S: "Failed to parse major version number for extension '" + Ext + "'" ); |
565 | |
566 | if (!MinorStr.empty() && MinorStr.getAsInteger(Radix: 10, Result&: Minor)) |
567 | return createStringError( |
568 | EC: errc::invalid_argument, |
569 | S: "Failed to parse minor version number for extension '" + Ext + "'" ); |
570 | |
571 | ConsumeLength = MajorStr.size(); |
572 | |
573 | if (!MinorStr.empty()) |
574 | ConsumeLength += MinorStr.size() + 1 /*'p'*/; |
575 | |
576 | // Expected multi-character extension with version number to have no |
577 | // subsequent characters (i.e. must either end string or be followed by |
578 | // an underscore). |
579 | if (Ext.size() > 1 && In.size()) |
580 | return createStringError( |
581 | EC: errc::invalid_argument, |
582 | Msg: "multi-character extensions must be separated by underscores" ); |
583 | |
584 | // If experimental extension, require use of current version number |
585 | if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { |
586 | if (!EnableExperimentalExtension) |
587 | return createStringError(EC: errc::invalid_argument, |
588 | S: "requires '-menable-experimental-extensions' " |
589 | "for experimental extension '" + |
590 | Ext + "'" ); |
591 | |
592 | if (ExperimentalExtensionVersionCheck && |
593 | (MajorStr.empty() && MinorStr.empty())) |
594 | return createStringError( |
595 | EC: errc::invalid_argument, |
596 | S: "experimental extension requires explicit version number `" + Ext + |
597 | "`" ); |
598 | |
599 | auto SupportedVers = *ExperimentalExtension; |
600 | if (ExperimentalExtensionVersionCheck && |
601 | (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) { |
602 | std::string Error = "unsupported version number " + MajorStr.str(); |
603 | if (!MinorStr.empty()) |
604 | Error += "." + MinorStr.str(); |
605 | Error += " for experimental extension '" + Ext.str() + |
606 | "' (this compiler supports " + utostr(X: SupportedVers.Major) + |
607 | "." + utostr(X: SupportedVers.Minor) + ")" ; |
608 | return createStringError(EC: errc::invalid_argument, S: Error); |
609 | } |
610 | return Error::success(); |
611 | } |
612 | |
613 | // Exception rule for `g`, we don't have clear version scheme for that on |
614 | // ISA spec. |
615 | if (Ext == "g" ) |
616 | return Error::success(); |
617 | |
618 | if (MajorStr.empty() && MinorStr.empty()) { |
619 | if (auto DefaultVersion = findDefaultVersion(ExtName: Ext)) { |
620 | Major = DefaultVersion->Major; |
621 | Minor = DefaultVersion->Minor; |
622 | } |
623 | // No matter found or not, return success, assume other place will |
624 | // verify. |
625 | return Error::success(); |
626 | } |
627 | |
628 | if (RISCVISAInfo::isSupportedExtension(Ext, MajorVersion: Major, MinorVersion: Minor)) |
629 | return Error::success(); |
630 | |
631 | std::string Error = "unsupported version number " + std::string(MajorStr); |
632 | if (!MinorStr.empty()) |
633 | Error += "." + MinorStr.str(); |
634 | Error += " for extension '" + Ext.str() + "'" ; |
635 | return createStringError(EC: errc::invalid_argument, S: Error); |
636 | } |
637 | |
638 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
639 | RISCVISAInfo::parseFeatures(unsigned XLen, |
640 | const std::vector<std::string> &Features) { |
641 | assert(XLen == 32 || XLen == 64); |
642 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
643 | |
644 | for (auto &Feature : Features) { |
645 | StringRef ExtName = Feature; |
646 | bool Experimental = false; |
647 | assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); |
648 | bool Add = ExtName[0] == '+'; |
649 | ExtName = ExtName.drop_front(N: 1); // Drop '+' or '-' |
650 | Experimental = stripExperimentalPrefix(Ext&: ExtName); |
651 | auto ExtensionInfos = Experimental |
652 | ? ArrayRef(SupportedExperimentalExtensions) |
653 | : ArrayRef(SupportedExtensions); |
654 | auto ExtensionInfoIterator = |
655 | llvm::lower_bound(Range&: ExtensionInfos, Value&: ExtName, C: LessExtName()); |
656 | |
657 | // Not all features is related to ISA extension, like `relax` or |
658 | // `save-restore`, skip those feature. |
659 | if (ExtensionInfoIterator == ExtensionInfos.end() || |
660 | ExtensionInfoIterator->Name != ExtName) |
661 | continue; |
662 | |
663 | if (Add) |
664 | ISAInfo->addExtension(ExtName, Version: ExtensionInfoIterator->Version); |
665 | else |
666 | ISAInfo->Exts.erase(x: ExtName.str()); |
667 | } |
668 | |
669 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
670 | } |
671 | |
672 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
673 | RISCVISAInfo::parseNormalizedArchString(StringRef Arch) { |
674 | if (llvm::any_of(Range&: Arch, P: isupper)) { |
675 | return createStringError(EC: errc::invalid_argument, |
676 | Msg: "string must be lowercase" ); |
677 | } |
678 | // Must start with a valid base ISA name. |
679 | unsigned XLen; |
680 | if (Arch.starts_with(Prefix: "rv32i" ) || Arch.starts_with(Prefix: "rv32e" )) |
681 | XLen = 32; |
682 | else if (Arch.starts_with(Prefix: "rv64i" ) || Arch.starts_with(Prefix: "rv64e" )) |
683 | XLen = 64; |
684 | else |
685 | return createStringError(EC: errc::invalid_argument, |
686 | Msg: "arch string must begin with valid base ISA" ); |
687 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
688 | // Discard rv32/rv64 prefix. |
689 | Arch = Arch.substr(Start: 4); |
690 | |
691 | // Each extension is of the form ${name}${major_version}p${minor_version} |
692 | // and separated by _. Split by _ and then extract the name and version |
693 | // information for each extension. |
694 | SmallVector<StringRef, 8> Split; |
695 | Arch.split(A&: Split, Separator: '_'); |
696 | for (StringRef Ext : Split) { |
697 | StringRef Prefix, MinorVersionStr; |
698 | std::tie(args&: Prefix, args&: MinorVersionStr) = Ext.rsplit(Separator: 'p'); |
699 | if (MinorVersionStr.empty()) |
700 | return createStringError(EC: errc::invalid_argument, |
701 | Msg: "extension lacks version in expected format" ); |
702 | unsigned MajorVersion, MinorVersion; |
703 | if (MinorVersionStr.getAsInteger(Radix: 10, Result&: MinorVersion)) |
704 | return createStringError(EC: errc::invalid_argument, |
705 | Msg: "failed to parse minor version number" ); |
706 | |
707 | // Split Prefix into the extension name and the major version number |
708 | // (the trailing digits of Prefix). |
709 | int TrailingDigits = 0; |
710 | StringRef ExtName = Prefix; |
711 | while (!ExtName.empty()) { |
712 | if (!isDigit(C: ExtName.back())) |
713 | break; |
714 | ExtName = ExtName.drop_back(N: 1); |
715 | TrailingDigits++; |
716 | } |
717 | if (!TrailingDigits) |
718 | return createStringError(EC: errc::invalid_argument, |
719 | Msg: "extension lacks version in expected format" ); |
720 | |
721 | StringRef MajorVersionStr = Prefix.take_back(N: TrailingDigits); |
722 | if (MajorVersionStr.getAsInteger(Radix: 10, Result&: MajorVersion)) |
723 | return createStringError(EC: errc::invalid_argument, |
724 | Msg: "failed to parse major version number" ); |
725 | ISAInfo->addExtension(ExtName, Version: {.Major: MajorVersion, .Minor: MinorVersion}); |
726 | } |
727 | ISAInfo->updateFLen(); |
728 | ISAInfo->updateMinVLen(); |
729 | ISAInfo->updateMaxELen(); |
730 | return std::move(ISAInfo); |
731 | } |
732 | |
733 | static Error splitExtsByUnderscore(StringRef Exts, |
734 | std::vector<std::string> &SplitExts) { |
735 | SmallVector<StringRef, 8> Split; |
736 | if (Exts.empty()) |
737 | return Error::success(); |
738 | |
739 | Exts.split(A&: Split, Separator: "_" ); |
740 | |
741 | for (auto Ext : Split) { |
742 | if (Ext.empty()) |
743 | return createStringError(EC: errc::invalid_argument, |
744 | Msg: "extension name missing after separator '_'" ); |
745 | |
746 | SplitExts.push_back(x: Ext.str()); |
747 | } |
748 | return Error::success(); |
749 | } |
750 | |
751 | static Error processMultiLetterExtension( |
752 | StringRef RawExt, |
753 | MapVector<std::string, RISCVISAInfo::ExtensionVersion, |
754 | std::map<std::string, unsigned>> &SeenExtMap, |
755 | bool IgnoreUnknown, bool EnableExperimentalExtension, |
756 | bool ExperimentalExtensionVersionCheck) { |
757 | StringRef Type = getExtensionType(Ext: RawExt); |
758 | StringRef Desc = getExtensionTypeDesc(Ext: RawExt); |
759 | auto Pos = findLastNonVersionCharacter(Ext: RawExt) + 1; |
760 | StringRef Name(RawExt.substr(Start: 0, N: Pos)); |
761 | StringRef Vers(RawExt.substr(Start: Pos)); |
762 | |
763 | if (Type.empty()) { |
764 | if (IgnoreUnknown) |
765 | return Error::success(); |
766 | return createStringError(EC: errc::invalid_argument, |
767 | S: "invalid extension prefix '" + RawExt + "'" ); |
768 | } |
769 | |
770 | if (!IgnoreUnknown && Name.size() == Type.size()) |
771 | return createStringError(EC: errc::invalid_argument, |
772 | S: Desc + " name missing after '" + Type + "'" ); |
773 | |
774 | unsigned Major, Minor, ConsumeLength; |
775 | if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength, |
776 | EnableExperimentalExtension, |
777 | ExperimentalExtensionVersionCheck)) { |
778 | if (IgnoreUnknown) { |
779 | consumeError(Err: std::move(E)); |
780 | return Error::success(); |
781 | } |
782 | return E; |
783 | } |
784 | |
785 | // Check if duplicated extension. |
786 | if (!IgnoreUnknown && SeenExtMap.contains(Key: Name.str())) |
787 | return createStringError(EC: errc::invalid_argument, |
788 | S: "duplicated " + Desc + " '" + Name + "'" ); |
789 | |
790 | if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Ext: Name)) |
791 | return Error::success(); |
792 | |
793 | SeenExtMap[Name.str()] = {.Major: Major, .Minor: Minor}; |
794 | return Error::success(); |
795 | } |
796 | |
797 | static Error processSingleLetterExtension( |
798 | StringRef &RawExt, |
799 | MapVector<std::string, RISCVISAInfo::ExtensionVersion, |
800 | std::map<std::string, unsigned>> &SeenExtMap, |
801 | bool IgnoreUnknown, bool EnableExperimentalExtension, |
802 | bool ExperimentalExtensionVersionCheck) { |
803 | unsigned Major, Minor, ConsumeLength; |
804 | StringRef Name = RawExt.take_front(N: 1); |
805 | RawExt.consume_front(Prefix: Name); |
806 | if (auto E = getExtensionVersion(Ext: Name, In: RawExt, Major, Minor, ConsumeLength, |
807 | EnableExperimentalExtension, |
808 | ExperimentalExtensionVersionCheck)) { |
809 | if (IgnoreUnknown) { |
810 | consumeError(Err: std::move(E)); |
811 | RawExt = RawExt.substr(Start: ConsumeLength); |
812 | return Error::success(); |
813 | } |
814 | return E; |
815 | } |
816 | |
817 | RawExt = RawExt.substr(Start: ConsumeLength); |
818 | |
819 | // Check if duplicated extension. |
820 | if (!IgnoreUnknown && SeenExtMap.contains(Key: Name.str())) |
821 | return createStringError(EC: errc::invalid_argument, |
822 | S: "duplicated standard user-level extension '" + |
823 | Name + "'" ); |
824 | |
825 | if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Ext: Name)) |
826 | return Error::success(); |
827 | |
828 | SeenExtMap[Name.str()] = {.Major: Major, .Minor: Minor}; |
829 | return Error::success(); |
830 | } |
831 | |
832 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
833 | RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, |
834 | bool ExperimentalExtensionVersionCheck, |
835 | bool IgnoreUnknown) { |
836 | // RISC-V ISA strings must be lowercase. |
837 | if (llvm::any_of(Range&: Arch, P: isupper)) { |
838 | return createStringError(EC: errc::invalid_argument, |
839 | Msg: "string must be lowercase" ); |
840 | } |
841 | |
842 | bool HasRV64 = Arch.starts_with(Prefix: "rv64" ); |
843 | // ISA string must begin with rv32 or rv64. |
844 | if (!(Arch.starts_with(Prefix: "rv32" ) || HasRV64) || (Arch.size() < 5)) { |
845 | return createStringError( |
846 | EC: errc::invalid_argument, |
847 | Msg: "string must begin with rv32{i,e,g} or rv64{i,e,g}" ); |
848 | } |
849 | |
850 | unsigned XLen = HasRV64 ? 64 : 32; |
851 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
852 | MapVector<std::string, RISCVISAInfo::ExtensionVersion, |
853 | std::map<std::string, unsigned>> |
854 | SeenExtMap; |
855 | |
856 | // The canonical order specified in ISA manual. |
857 | // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 |
858 | StringRef StdExts = AllStdExts; |
859 | char Baseline = Arch[4]; |
860 | |
861 | // First letter should be 'e', 'i' or 'g'. |
862 | switch (Baseline) { |
863 | default: |
864 | return createStringError(EC: errc::invalid_argument, |
865 | Msg: "first letter should be 'e', 'i' or 'g'" ); |
866 | case 'e': |
867 | case 'i': |
868 | break; |
869 | case 'g': |
870 | // g expands to extensions in RISCVGImplications. |
871 | if (Arch.size() > 5 && isDigit(C: Arch[5])) |
872 | return createStringError(EC: errc::invalid_argument, |
873 | Msg: "version not supported for 'g'" ); |
874 | StdExts = StdExts.drop_front(N: 4); |
875 | break; |
876 | } |
877 | |
878 | if (Arch.back() == '_') |
879 | return createStringError(EC: errc::invalid_argument, |
880 | Msg: "extension name missing after separator '_'" ); |
881 | |
882 | // Skip rvxxx |
883 | StringRef Exts = Arch.substr(Start: 5); |
884 | |
885 | unsigned Major, Minor, ConsumeLength; |
886 | if (Baseline == 'g') { |
887 | // Versions for g are disallowed, and this was checked for previously. |
888 | ConsumeLength = 0; |
889 | |
890 | // No matter which version is given to `g`, we always set imafd to default |
891 | // version since the we don't have clear version scheme for that on |
892 | // ISA spec. |
893 | for (const auto *Ext : RISCVGImplications) { |
894 | if (auto Version = findDefaultVersion(ExtName: Ext)) { |
895 | // Postpone AddExtension until end of this function |
896 | SeenExtMap[Ext] = {.Major: Version->Major, .Minor: Version->Minor}; |
897 | } else |
898 | llvm_unreachable("Default extension version not found?" ); |
899 | } |
900 | } else { |
901 | // Baseline is `i` or `e` |
902 | if (auto E = getExtensionVersion( |
903 | Ext: StringRef(&Baseline, 1), In: Exts, Major, Minor, ConsumeLength, |
904 | EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) { |
905 | if (!IgnoreUnknown) |
906 | return std::move(E); |
907 | // If IgnoreUnknown, then ignore an unrecognised version of the baseline |
908 | // ISA and just use the default supported version. |
909 | consumeError(Err: std::move(E)); |
910 | auto Version = findDefaultVersion(ExtName: StringRef(&Baseline, 1)); |
911 | Major = Version->Major; |
912 | Minor = Version->Minor; |
913 | } |
914 | |
915 | // Postpone AddExtension until end of this function |
916 | SeenExtMap[StringRef(&Baseline, 1).str()] = {.Major: Major, .Minor: Minor}; |
917 | } |
918 | |
919 | // Consume the base ISA version number and any '_' between rvxxx and the |
920 | // first extension |
921 | Exts = Exts.drop_front(N: ConsumeLength); |
922 | Exts.consume_front(Prefix: "_" ); |
923 | |
924 | std::vector<std::string> SplittedExts; |
925 | if (auto E = splitExtsByUnderscore(Exts, SplitExts&: SplittedExts)) |
926 | return std::move(E); |
927 | |
928 | for (auto &Ext : SplittedExts) { |
929 | StringRef CurrExt = Ext; |
930 | while (!CurrExt.empty()) { |
931 | if (AllStdExts.contains(C: CurrExt.front())) { |
932 | if (auto E = processSingleLetterExtension( |
933 | RawExt&: CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension, |
934 | ExperimentalExtensionVersionCheck)) |
935 | return std::move(E); |
936 | } else if (CurrExt.front() == 'z' || CurrExt.front() == 's' || |
937 | CurrExt.front() == 'x') { |
938 | // Handle other types of extensions other than the standard |
939 | // general purpose and standard user-level extensions. |
940 | // Parse the ISA string containing non-standard user-level |
941 | // extensions, standard supervisor-level extensions and |
942 | // non-standard supervisor-level extensions. |
943 | // These extensions start with 'z', 's', 'x' prefixes, might have a |
944 | // version number (major, minor) and are separated by a single |
945 | // underscore '_'. We do not enforce a canonical order for them. |
946 | if (auto E = processMultiLetterExtension( |
947 | RawExt: CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension, |
948 | ExperimentalExtensionVersionCheck)) |
949 | return std::move(E); |
950 | // Multi-letter extension must be seperate following extension with |
951 | // underscore |
952 | break; |
953 | } else { |
954 | // FIXME: Could it be ignored by IgnoreUnknown? |
955 | return createStringError(EC: errc::invalid_argument, |
956 | S: "invalid standard user-level extension '" + |
957 | Twine(CurrExt.front()) + "'" ); |
958 | } |
959 | } |
960 | } |
961 | |
962 | // Check all Extensions are supported. |
963 | for (auto &SeenExtAndVers : SeenExtMap) { |
964 | const std::string &ExtName = SeenExtAndVers.first; |
965 | RISCVISAInfo::ExtensionVersion ExtVers = SeenExtAndVers.second; |
966 | |
967 | if (!RISCVISAInfo::isSupportedExtension(Ext: ExtName)) { |
968 | if (ExtName.size() == 1) { |
969 | return createStringError(EC: errc::invalid_argument, |
970 | S: "unsupported standard user-level extension '" + |
971 | ExtName + "'" ); |
972 | } |
973 | return createStringError(EC: errc::invalid_argument, |
974 | S: "unsupported " + getExtensionTypeDesc(Ext: ExtName) + |
975 | " '" + ExtName + "'" ); |
976 | } |
977 | ISAInfo->addExtension(ExtName, Version: ExtVers); |
978 | } |
979 | |
980 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
981 | } |
982 | |
983 | Error RISCVISAInfo::checkDependency() { |
984 | bool HasC = Exts.count(x: "c" ) != 0; |
985 | bool HasF = Exts.count(x: "f" ) != 0; |
986 | bool HasZfinx = Exts.count(x: "zfinx" ) != 0; |
987 | bool HasVector = Exts.count(x: "zve32x" ) != 0; |
988 | bool HasZvl = MinVLen != 0; |
989 | bool HasZcmt = Exts.count(x: "zcmt" ) != 0; |
990 | |
991 | if (HasF && HasZfinx) |
992 | return createStringError(EC: errc::invalid_argument, |
993 | Msg: "'f' and 'zfinx' extensions are incompatible" ); |
994 | |
995 | if (HasZvl && !HasVector) |
996 | return createStringError( |
997 | EC: errc::invalid_argument, |
998 | Msg: "'zvl*b' requires 'v' or 'zve*' extension to also be specified" ); |
999 | |
1000 | if (Exts.count(x: "zvbb" ) && !HasVector) |
1001 | return createStringError( |
1002 | EC: errc::invalid_argument, |
1003 | Msg: "'zvbb' requires 'v' or 'zve*' extension to also be specified" ); |
1004 | |
1005 | if (Exts.count(x: "zvbc" ) && !Exts.count(x: "zve64x" )) |
1006 | return createStringError( |
1007 | EC: errc::invalid_argument, |
1008 | Msg: "'zvbc' requires 'v' or 'zve64*' extension to also be specified" ); |
1009 | |
1010 | if ((Exts.count(x: "zvkb" ) || Exts.count(x: "zvkg" ) || Exts.count(x: "zvkned" ) || |
1011 | Exts.count(x: "zvknha" ) || Exts.count(x: "zvksed" ) || Exts.count(x: "zvksh" )) && |
1012 | !HasVector) |
1013 | return createStringError( |
1014 | EC: errc::invalid_argument, |
1015 | Msg: "'zvk*' requires 'v' or 'zve*' extension to also be specified" ); |
1016 | |
1017 | if (Exts.count(x: "zvknhb" ) && !Exts.count(x: "zve64x" )) |
1018 | return createStringError( |
1019 | EC: errc::invalid_argument, |
1020 | Msg: "'zvknhb' requires 'v' or 'zve64*' extension to also be specified" ); |
1021 | |
1022 | if ((HasZcmt || Exts.count(x: "zcmp" )) && Exts.count(x: "d" ) && |
1023 | (HasC || Exts.count(x: "zcd" ))) |
1024 | return createStringError( |
1025 | EC: errc::invalid_argument, |
1026 | S: Twine("'" ) + (HasZcmt ? "zcmt" : "zcmp" ) + |
1027 | "' extension is incompatible with '" + (HasC ? "c" : "zcd" ) + |
1028 | "' extension when 'd' extension is enabled" ); |
1029 | |
1030 | if (XLen != 32 && Exts.count(x: "zcf" )) |
1031 | return createStringError(EC: errc::invalid_argument, |
1032 | Msg: "'zcf' is only supported for 'rv32'" ); |
1033 | |
1034 | return Error::success(); |
1035 | } |
1036 | |
1037 | static const char *ImpliedExtsD[] = {"f" }; |
1038 | static const char *ImpliedExtsF[] = {"zicsr" }; |
1039 | static const char *ImpliedExtsV[] = {"zvl128b" , "zve64d" }; |
1040 | static const char *ImpliedExtsXTHeadVdot[] = {"v" }; |
1041 | static const char *ImpliedExtsXSfvcp[] = {"zve32x" }; |
1042 | static const char *ImpliedExtsXSfvfnrclipxfqf[] = {"zve32f" }; |
1043 | static const char *ImpliedExtsXSfvfwmaccqqq[] = {"zvfbfmin" }; |
1044 | static const char *ImpliedExtsXSfvqmaccdod[] = {"zve32x" }; |
1045 | static const char *ImpliedExtsXSfvqmaccqoq[] = {"zve32x" }; |
1046 | static const char *ImpliedExtsZabha[] = {"a" }; |
1047 | static const char *ImpliedExtsZacas[] = {"a" }; |
1048 | static const char *ImpliedExtsZcb[] = {"zca" }; |
1049 | static const char *ImpliedExtsZcd[] = {"d" , "zca" }; |
1050 | static const char *ImpliedExtsZce[] = {"zcb" , "zcmp" , "zcmt" }; |
1051 | static const char *ImpliedExtsZcf[] = {"f" , "zca" }; |
1052 | static const char *ImpliedExtsZcmop[] = {"zca" }; |
1053 | static const char *ImpliedExtsZcmp[] = {"zca" }; |
1054 | static const char *ImpliedExtsZcmt[] = {"zca" , "zicsr" }; |
1055 | static const char *ImpliedExtsZdinx[] = {"zfinx" }; |
1056 | static const char *ImpliedExtsZfa[] = {"f" }; |
1057 | static const char *ImpliedExtsZfbfmin[] = {"f" }; |
1058 | static const char *ImpliedExtsZfh[] = {"zfhmin" }; |
1059 | static const char *ImpliedExtsZfhmin[] = {"f" }; |
1060 | static const char *ImpliedExtsZfinx[] = {"zicsr" }; |
1061 | static const char *ImpliedExtsZhinx[] = {"zhinxmin" }; |
1062 | static const char *ImpliedExtsZhinxmin[] = {"zfinx" }; |
1063 | static const char *ImpliedExtsZicntr[] = {"zicsr" }; |
1064 | static const char *ImpliedExtsZicfiss[] = {"zicsr" , "zimop" }; |
1065 | static const char *ImpliedExtsZihpm[] = {"zicsr" }; |
1066 | static const char *ImpliedExtsZk[] = {"zkn" , "zkt" , "zkr" }; |
1067 | static const char *ImpliedExtsZkn[] = {"zbkb" , "zbkc" , "zbkx" , |
1068 | "zkne" , "zknd" , "zknh" }; |
1069 | static const char *ImpliedExtsZks[] = {"zbkb" , "zbkc" , "zbkx" , "zksed" , "zksh" }; |
1070 | static const char *ImpliedExtsZvbb[] = {"zvkb" }; |
1071 | static const char *ImpliedExtsZve32f[] = {"zve32x" , "f" }; |
1072 | static const char *ImpliedExtsZve32x[] = {"zvl32b" , "zicsr" }; |
1073 | static const char *ImpliedExtsZve64d[] = {"zve64f" , "d" }; |
1074 | static const char *ImpliedExtsZve64f[] = {"zve64x" , "zve32f" }; |
1075 | static const char *ImpliedExtsZve64x[] = {"zve32x" , "zvl64b" }; |
1076 | static const char *ImpliedExtsZvfbfmin[] = {"zve32f" }; |
1077 | static const char *ImpliedExtsZvfbfwma[] = {"zvfbfmin" , "zfbfmin" }; |
1078 | static const char *ImpliedExtsZvfh[] = {"zvfhmin" , "zfhmin" }; |
1079 | static const char *ImpliedExtsZvfhmin[] = {"zve32f" }; |
1080 | static const char *ImpliedExtsZvkn[] = {"zvkb" , "zvkned" , "zvknhb" , "zvkt" }; |
1081 | static const char *ImpliedExtsZvknc[] = {"zvbc" , "zvkn" }; |
1082 | static const char *ImpliedExtsZvkng[] = {"zvkg" , "zvkn" }; |
1083 | static const char *ImpliedExtsZvknhb[] = {"zve64x" }; |
1084 | static const char *ImpliedExtsZvks[] = {"zvkb" , "zvksed" , "zvksh" , "zvkt" }; |
1085 | static const char *ImpliedExtsZvksc[] = {"zvbc" , "zvks" }; |
1086 | static const char *ImpliedExtsZvksg[] = {"zvkg" , "zvks" }; |
1087 | static const char *ImpliedExtsZvl1024b[] = {"zvl512b" }; |
1088 | static const char *ImpliedExtsZvl128b[] = {"zvl64b" }; |
1089 | static const char *ImpliedExtsZvl16384b[] = {"zvl8192b" }; |
1090 | static const char *ImpliedExtsZvl2048b[] = {"zvl1024b" }; |
1091 | static const char *ImpliedExtsZvl256b[] = {"zvl128b" }; |
1092 | static const char *ImpliedExtsZvl32768b[] = {"zvl16384b" }; |
1093 | static const char *ImpliedExtsZvl4096b[] = {"zvl2048b" }; |
1094 | static const char *ImpliedExtsZvl512b[] = {"zvl256b" }; |
1095 | static const char *ImpliedExtsZvl64b[] = {"zvl32b" }; |
1096 | static const char *ImpliedExtsZvl65536b[] = {"zvl32768b" }; |
1097 | static const char *ImpliedExtsZvl8192b[] = {"zvl4096b" }; |
1098 | |
1099 | struct ImpliedExtsEntry { |
1100 | StringLiteral Name; |
1101 | ArrayRef<const char *> Exts; |
1102 | |
1103 | bool operator<(const ImpliedExtsEntry &Other) const { |
1104 | return Name < Other.Name; |
1105 | } |
1106 | |
1107 | bool operator<(StringRef Other) const { return Name < Other; } |
1108 | }; |
1109 | |
1110 | // Note: The table needs to be sorted by name. |
1111 | static constexpr ImpliedExtsEntry ImpliedExts[] = { |
1112 | {.Name: {"d" }, .Exts: {ImpliedExtsD}}, |
1113 | {.Name: {"f" }, .Exts: {ImpliedExtsF}}, |
1114 | {.Name: {"v" }, .Exts: {ImpliedExtsV}}, |
1115 | {.Name: {"xsfvcp" }, .Exts: {ImpliedExtsXSfvcp}}, |
1116 | {.Name: {"xsfvfnrclipxfqf" }, .Exts: {ImpliedExtsXSfvfnrclipxfqf}}, |
1117 | {.Name: {"xsfvfwmaccqqq" }, .Exts: {ImpliedExtsXSfvfwmaccqqq}}, |
1118 | {.Name: {"xsfvqmaccdod" }, .Exts: {ImpliedExtsXSfvqmaccdod}}, |
1119 | {.Name: {"xsfvqmaccqoq" }, .Exts: {ImpliedExtsXSfvqmaccqoq}}, |
1120 | {.Name: {"xtheadvdot" }, .Exts: {ImpliedExtsXTHeadVdot}}, |
1121 | {.Name: {"zabha" }, .Exts: {ImpliedExtsZabha}}, |
1122 | {.Name: {"zacas" }, .Exts: {ImpliedExtsZacas}}, |
1123 | {.Name: {"zcb" }, .Exts: {ImpliedExtsZcb}}, |
1124 | {.Name: {"zcd" }, .Exts: {ImpliedExtsZcd}}, |
1125 | {.Name: {"zce" }, .Exts: {ImpliedExtsZce}}, |
1126 | {.Name: {"zcf" }, .Exts: {ImpliedExtsZcf}}, |
1127 | {.Name: {"zcmop" }, .Exts: {ImpliedExtsZcmop}}, |
1128 | {.Name: {"zcmp" }, .Exts: {ImpliedExtsZcmp}}, |
1129 | {.Name: {"zcmt" }, .Exts: {ImpliedExtsZcmt}}, |
1130 | {.Name: {"zdinx" }, .Exts: {ImpliedExtsZdinx}}, |
1131 | {.Name: {"zfa" }, .Exts: {ImpliedExtsZfa}}, |
1132 | {.Name: {"zfbfmin" }, .Exts: {ImpliedExtsZfbfmin}}, |
1133 | {.Name: {"zfh" }, .Exts: {ImpliedExtsZfh}}, |
1134 | {.Name: {"zfhmin" }, .Exts: {ImpliedExtsZfhmin}}, |
1135 | {.Name: {"zfinx" }, .Exts: {ImpliedExtsZfinx}}, |
1136 | {.Name: {"zhinx" }, .Exts: {ImpliedExtsZhinx}}, |
1137 | {.Name: {"zhinxmin" }, .Exts: {ImpliedExtsZhinxmin}}, |
1138 | {.Name: {"zicfiss" }, .Exts: {ImpliedExtsZicfiss}}, |
1139 | {.Name: {"zicntr" }, .Exts: {ImpliedExtsZicntr}}, |
1140 | {.Name: {"zihpm" }, .Exts: {ImpliedExtsZihpm}}, |
1141 | {.Name: {"zk" }, .Exts: {ImpliedExtsZk}}, |
1142 | {.Name: {"zkn" }, .Exts: {ImpliedExtsZkn}}, |
1143 | {.Name: {"zks" }, .Exts: {ImpliedExtsZks}}, |
1144 | {.Name: {"zvbb" }, .Exts: {ImpliedExtsZvbb}}, |
1145 | {.Name: {"zve32f" }, .Exts: {ImpliedExtsZve32f}}, |
1146 | {.Name: {"zve32x" }, .Exts: {ImpliedExtsZve32x}}, |
1147 | {.Name: {"zve64d" }, .Exts: {ImpliedExtsZve64d}}, |
1148 | {.Name: {"zve64f" }, .Exts: {ImpliedExtsZve64f}}, |
1149 | {.Name: {"zve64x" }, .Exts: {ImpliedExtsZve64x}}, |
1150 | {.Name: {"zvfbfmin" }, .Exts: {ImpliedExtsZvfbfmin}}, |
1151 | {.Name: {"zvfbfwma" }, .Exts: {ImpliedExtsZvfbfwma}}, |
1152 | {.Name: {"zvfh" }, .Exts: {ImpliedExtsZvfh}}, |
1153 | {.Name: {"zvfhmin" }, .Exts: {ImpliedExtsZvfhmin}}, |
1154 | {.Name: {"zvkn" }, .Exts: {ImpliedExtsZvkn}}, |
1155 | {.Name: {"zvknc" }, .Exts: {ImpliedExtsZvknc}}, |
1156 | {.Name: {"zvkng" }, .Exts: {ImpliedExtsZvkng}}, |
1157 | {.Name: {"zvknhb" }, .Exts: {ImpliedExtsZvknhb}}, |
1158 | {.Name: {"zvks" }, .Exts: {ImpliedExtsZvks}}, |
1159 | {.Name: {"zvksc" }, .Exts: {ImpliedExtsZvksc}}, |
1160 | {.Name: {"zvksg" }, .Exts: {ImpliedExtsZvksg}}, |
1161 | {.Name: {"zvl1024b" }, .Exts: {ImpliedExtsZvl1024b}}, |
1162 | {.Name: {"zvl128b" }, .Exts: {ImpliedExtsZvl128b}}, |
1163 | {.Name: {"zvl16384b" }, .Exts: {ImpliedExtsZvl16384b}}, |
1164 | {.Name: {"zvl2048b" }, .Exts: {ImpliedExtsZvl2048b}}, |
1165 | {.Name: {"zvl256b" }, .Exts: {ImpliedExtsZvl256b}}, |
1166 | {.Name: {"zvl32768b" }, .Exts: {ImpliedExtsZvl32768b}}, |
1167 | {.Name: {"zvl4096b" }, .Exts: {ImpliedExtsZvl4096b}}, |
1168 | {.Name: {"zvl512b" }, .Exts: {ImpliedExtsZvl512b}}, |
1169 | {.Name: {"zvl64b" }, .Exts: {ImpliedExtsZvl64b}}, |
1170 | {.Name: {"zvl65536b" }, .Exts: {ImpliedExtsZvl65536b}}, |
1171 | {.Name: {"zvl8192b" }, .Exts: {ImpliedExtsZvl8192b}}, |
1172 | }; |
1173 | |
1174 | void RISCVISAInfo::updateImplication() { |
1175 | bool HasE = Exts.count(x: "e" ) != 0; |
1176 | bool HasI = Exts.count(x: "i" ) != 0; |
1177 | |
1178 | // If not in e extension and i extension does not exist, i extension is |
1179 | // implied |
1180 | if (!HasE && !HasI) { |
1181 | auto Version = findDefaultVersion(ExtName: "i" ); |
1182 | addExtension(ExtName: "i" , Version: Version.value()); |
1183 | } |
1184 | |
1185 | assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name" ); |
1186 | |
1187 | // This loop may execute over 1 iteration since implication can be layered |
1188 | // Exits loop if no more implication is applied |
1189 | SmallSetVector<StringRef, 16> WorkList; |
1190 | for (auto const &Ext : Exts) |
1191 | WorkList.insert(X: Ext.first); |
1192 | |
1193 | while (!WorkList.empty()) { |
1194 | StringRef ExtName = WorkList.pop_back_val(); |
1195 | auto I = llvm::lower_bound(Range: ImpliedExts, Value&: ExtName); |
1196 | if (I != std::end(arr: ImpliedExts) && I->Name == ExtName) { |
1197 | for (const char *ImpliedExt : I->Exts) { |
1198 | if (WorkList.count(key: ImpliedExt)) |
1199 | continue; |
1200 | if (Exts.count(x: ImpliedExt)) |
1201 | continue; |
1202 | auto Version = findDefaultVersion(ExtName: ImpliedExt); |
1203 | addExtension(ExtName: ImpliedExt, Version: Version.value()); |
1204 | WorkList.insert(X: ImpliedExt); |
1205 | } |
1206 | } |
1207 | } |
1208 | |
1209 | // Add Zcf if Zce and F are enabled on RV32. |
1210 | if (XLen == 32 && Exts.count(x: "zce" ) && Exts.count(x: "f" ) && |
1211 | !Exts.count(x: "zcf" )) { |
1212 | auto Version = findDefaultVersion(ExtName: "zcf" ); |
1213 | addExtension(ExtName: "zcf" , Version: Version.value()); |
1214 | } |
1215 | } |
1216 | |
1217 | struct CombinedExtsEntry { |
1218 | StringLiteral CombineExt; |
1219 | ArrayRef<const char *> RequiredExts; |
1220 | }; |
1221 | |
1222 | static constexpr CombinedExtsEntry CombineIntoExts[] = { |
1223 | {.CombineExt: {"zk" }, .RequiredExts: {ImpliedExtsZk}}, |
1224 | {.CombineExt: {"zkn" }, .RequiredExts: {ImpliedExtsZkn}}, |
1225 | {.CombineExt: {"zks" }, .RequiredExts: {ImpliedExtsZks}}, |
1226 | {.CombineExt: {"zvkn" }, .RequiredExts: {ImpliedExtsZvkn}}, |
1227 | {.CombineExt: {"zvknc" }, .RequiredExts: {ImpliedExtsZvknc}}, |
1228 | {.CombineExt: {"zvkng" }, .RequiredExts: {ImpliedExtsZvkng}}, |
1229 | {.CombineExt: {"zvks" }, .RequiredExts: {ImpliedExtsZvks}}, |
1230 | {.CombineExt: {"zvksc" }, .RequiredExts: {ImpliedExtsZvksc}}, |
1231 | {.CombineExt: {"zvksg" }, .RequiredExts: {ImpliedExtsZvksg}}, |
1232 | }; |
1233 | |
1234 | void RISCVISAInfo::updateCombination() { |
1235 | bool IsNewCombine = false; |
1236 | do { |
1237 | IsNewCombine = false; |
1238 | for (CombinedExtsEntry CombineIntoExt : CombineIntoExts) { |
1239 | auto CombineExt = CombineIntoExt.CombineExt; |
1240 | auto RequiredExts = CombineIntoExt.RequiredExts; |
1241 | if (hasExtension(Ext: CombineExt)) |
1242 | continue; |
1243 | bool IsAllRequiredFeatureExist = true; |
1244 | for (const char *Ext : RequiredExts) |
1245 | IsAllRequiredFeatureExist &= hasExtension(Ext); |
1246 | if (IsAllRequiredFeatureExist) { |
1247 | auto Version = findDefaultVersion(ExtName: CombineExt); |
1248 | addExtension(ExtName: CombineExt, Version: Version.value()); |
1249 | IsNewCombine = true; |
1250 | } |
1251 | } |
1252 | } while (IsNewCombine); |
1253 | } |
1254 | |
1255 | void RISCVISAInfo::updateFLen() { |
1256 | FLen = 0; |
1257 | // TODO: Handle q extension. |
1258 | if (Exts.count(x: "d" )) |
1259 | FLen = 64; |
1260 | else if (Exts.count(x: "f" )) |
1261 | FLen = 32; |
1262 | } |
1263 | |
1264 | void RISCVISAInfo::updateMinVLen() { |
1265 | for (auto const &Ext : Exts) { |
1266 | StringRef ExtName = Ext.first; |
1267 | bool IsZvlExt = ExtName.consume_front(Prefix: "zvl" ) && ExtName.consume_back(Suffix: "b" ); |
1268 | if (IsZvlExt) { |
1269 | unsigned ZvlLen; |
1270 | if (!ExtName.getAsInteger(Radix: 10, Result&: ZvlLen)) |
1271 | MinVLen = std::max(a: MinVLen, b: ZvlLen); |
1272 | } |
1273 | } |
1274 | } |
1275 | |
1276 | void RISCVISAInfo::updateMaxELen() { |
1277 | // handles EEW restriction by sub-extension zve |
1278 | for (auto const &Ext : Exts) { |
1279 | StringRef ExtName = Ext.first; |
1280 | bool IsZveExt = ExtName.consume_front(Prefix: "zve" ); |
1281 | if (IsZveExt) { |
1282 | if (ExtName.back() == 'f') |
1283 | MaxELenFp = std::max(a: MaxELenFp, b: 32u); |
1284 | if (ExtName.back() == 'd') |
1285 | MaxELenFp = std::max(a: MaxELenFp, b: 64u); |
1286 | ExtName = ExtName.drop_back(); |
1287 | unsigned ZveELen; |
1288 | ExtName.getAsInteger(Radix: 10, Result&: ZveELen); |
1289 | MaxELen = std::max(a: MaxELen, b: ZveELen); |
1290 | } |
1291 | } |
1292 | } |
1293 | |
1294 | std::string RISCVISAInfo::toString() const { |
1295 | std::string Buffer; |
1296 | raw_string_ostream Arch(Buffer); |
1297 | |
1298 | Arch << "rv" << XLen; |
1299 | |
1300 | ListSeparator LS("_" ); |
1301 | for (auto const &Ext : Exts) { |
1302 | StringRef ExtName = Ext.first; |
1303 | auto ExtInfo = Ext.second; |
1304 | Arch << LS << ExtName; |
1305 | Arch << ExtInfo.Major << "p" << ExtInfo.Minor; |
1306 | } |
1307 | |
1308 | return Arch.str(); |
1309 | } |
1310 | |
1311 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
1312 | RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) { |
1313 | ISAInfo->updateImplication(); |
1314 | ISAInfo->updateCombination(); |
1315 | ISAInfo->updateFLen(); |
1316 | ISAInfo->updateMinVLen(); |
1317 | ISAInfo->updateMaxELen(); |
1318 | |
1319 | if (Error Result = ISAInfo->checkDependency()) |
1320 | return std::move(Result); |
1321 | return std::move(ISAInfo); |
1322 | } |
1323 | |
1324 | StringRef RISCVISAInfo::computeDefaultABI() const { |
1325 | if (XLen == 32) { |
1326 | if (hasExtension(Ext: "e" )) |
1327 | return "ilp32e" ; |
1328 | if (hasExtension(Ext: "d" )) |
1329 | return "ilp32d" ; |
1330 | if (hasExtension(Ext: "f" )) |
1331 | return "ilp32f" ; |
1332 | return "ilp32" ; |
1333 | } else if (XLen == 64) { |
1334 | if (hasExtension(Ext: "e" )) |
1335 | return "lp64e" ; |
1336 | if (hasExtension(Ext: "d" )) |
1337 | return "lp64d" ; |
1338 | if (hasExtension(Ext: "f" )) |
1339 | return "lp64f" ; |
1340 | return "lp64" ; |
1341 | } |
1342 | llvm_unreachable("Invalid XLEN" ); |
1343 | } |
1344 | |
1345 | bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) { |
1346 | if (Ext.empty()) |
1347 | return false; |
1348 | |
1349 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
1350 | StringRef Name = Ext.substr(Start: 0, N: Pos); |
1351 | StringRef Vers = Ext.substr(Start: Pos); |
1352 | if (Vers.empty()) |
1353 | return false; |
1354 | |
1355 | unsigned Major, Minor, ConsumeLength; |
1356 | if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength, |
1357 | EnableExperimentalExtension: true, ExperimentalExtensionVersionCheck: true)) { |
1358 | consumeError(Err: std::move(E)); |
1359 | return false; |
1360 | } |
1361 | |
1362 | return true; |
1363 | } |
1364 | |
1365 | std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) { |
1366 | if (Ext.empty()) |
1367 | return std::string(); |
1368 | |
1369 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
1370 | StringRef Name = Ext.substr(Start: 0, N: Pos); |
1371 | |
1372 | if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext)) |
1373 | return std::string(); |
1374 | |
1375 | if (!isSupportedExtension(Ext: Name)) |
1376 | return std::string(); |
1377 | |
1378 | return isExperimentalExtension(Ext: Name) ? "experimental-" + Name.str() |
1379 | : Name.str(); |
1380 | } |
1381 | |