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

source code of llvm/lib/TargetParser/RISCVISAInfo.cpp