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 | |
25 | using namespace llvm; |
26 | |
27 | namespace { |
28 | |
29 | struct 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 | |
39 | struct RISCVProfile { |
40 | StringLiteral Name; |
41 | StringLiteral MArch; |
42 | }; |
43 | |
44 | } // end anonymous namespace |
45 | |
46 | static const char *RISCVGImplications[] = { |
47 | "i" , "m" , "a" , "f" , "d" , "zicsr" , "zifencei" |
48 | }; |
49 | |
50 | // NOTE: This table should be sorted alphabetically by extension name. |
51 | static 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 |
224 | static 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 | |
249 | static 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 | |
285 | static 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 | |
298 | static 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 | |
306 | void 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 | |
334 | static 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. |
345 | static 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 | |
360 | namespace { |
361 | struct 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 | |
371 | static std::optional<RISCVISAUtils::ExtensionVersion> |
372 | findDefaultVersion(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 | |
387 | void RISCVISAInfo::addExtension(StringRef ExtName, |
388 | RISCVISAUtils::ExtensionVersion Version) { |
389 | Exts[ExtName.str()] = Version; |
390 | } |
391 | |
392 | static 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 | |
402 | static 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 | |
412 | static std::optional<RISCVISAUtils::ExtensionVersion> |
413 | isExperimentalExtension(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 | |
422 | bool 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 | |
433 | bool 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 | |
446 | bool 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 | |
460 | bool 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 | |
469 | std::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 | |
503 | static 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. |
519 | static 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 | |
622 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
623 | RISCVISAInfo::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 | |
656 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
657 | RISCVISAInfo::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 | |
717 | static 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 | |
735 | static 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 | |
781 | static 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 | |
816 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
817 | RISCVISAInfo::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 | |
980 | Error 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 | |
1044 | static const char *ImpliedExtsD[] = {"f" }; |
1045 | static const char *ImpliedExtsF[] = {"zicsr" }; |
1046 | static const char *ImpliedExtsV[] = {"zvl128b" , "zve64d" }; |
1047 | static const char *ImpliedExtsXSfvcp[] = {"zve32x" }; |
1048 | static const char *ImpliedExtsXSfvfnrclipxfqf[] = {"zve32f" }; |
1049 | static const char *ImpliedExtsXSfvfwmaccqqq[] = {"zvfbfmin" }; |
1050 | static const char *ImpliedExtsXSfvqmaccdod[] = {"zve32x" }; |
1051 | static const char *ImpliedExtsXSfvqmaccqoq[] = {"zve32x" }; |
1052 | static const char *ImpliedExtsXTHeadVdot[] = {"v" }; |
1053 | static const char *ImpliedExtsZcb[] = {"zca" }; |
1054 | static const char *ImpliedExtsZcd[] = {"d" , "zca" }; |
1055 | static const char *ImpliedExtsZce[] = {"zcb" , "zcmp" , "zcmt" }; |
1056 | static const char *ImpliedExtsZcf[] = {"f" , "zca" }; |
1057 | static const char *ImpliedExtsZcmop[] = {"zca" }; |
1058 | static const char *ImpliedExtsZcmp[] = {"zca" }; |
1059 | static const char *ImpliedExtsZcmt[] = {"zca" , "zicsr" }; |
1060 | static const char *ImpliedExtsZdinx[] = {"zfinx" }; |
1061 | static const char *ImpliedExtsZfa[] = {"f" }; |
1062 | static const char *ImpliedExtsZfbfmin[] = {"f" }; |
1063 | static const char *ImpliedExtsZfh[] = {"zfhmin" }; |
1064 | static const char *ImpliedExtsZfhmin[] = {"f" }; |
1065 | static const char *ImpliedExtsZfinx[] = {"zicsr" }; |
1066 | static const char *ImpliedExtsZhinx[] = {"zhinxmin" }; |
1067 | static const char *ImpliedExtsZhinxmin[] = {"zfinx" }; |
1068 | static const char *ImpliedExtsZicfiss[] = {"zicsr" , "zimop" }; |
1069 | static const char *ImpliedExtsZicntr[] = {"zicsr" }; |
1070 | static const char *ImpliedExtsZihpm[] = {"zicsr" }; |
1071 | static const char *ImpliedExtsZk[] = {"zkn" , "zkt" , "zkr" }; |
1072 | static const char *ImpliedExtsZkn[] = {"zbkb" , "zbkc" , "zbkx" , |
1073 | "zkne" , "zknd" , "zknh" }; |
1074 | static const char *ImpliedExtsZks[] = {"zbkb" , "zbkc" , "zbkx" , "zksed" , "zksh" }; |
1075 | static const char *ImpliedExtsZvbb[] = {"zvkb" }; |
1076 | static const char *ImpliedExtsZve32f[] = {"zve32x" , "f" }; |
1077 | static const char *ImpliedExtsZve32x[] = {"zvl32b" , "zicsr" }; |
1078 | static const char *ImpliedExtsZve64d[] = {"zve64f" , "d" }; |
1079 | static const char *ImpliedExtsZve64f[] = {"zve64x" , "zve32f" }; |
1080 | static const char *ImpliedExtsZve64x[] = {"zve32x" , "zvl64b" }; |
1081 | static const char *ImpliedExtsZvfbfmin[] = {"zve32f" }; |
1082 | static const char *ImpliedExtsZvfbfwma[] = {"zvfbfmin" , "zfbfmin" }; |
1083 | static const char *ImpliedExtsZvfh[] = {"zvfhmin" , "zfhmin" }; |
1084 | static const char *ImpliedExtsZvfhmin[] = {"zve32f" }; |
1085 | static const char *ImpliedExtsZvkn[] = {"zvkb" , "zvkned" , "zvknhb" , "zvkt" }; |
1086 | static const char *ImpliedExtsZvknc[] = {"zvbc" , "zvkn" }; |
1087 | static const char *ImpliedExtsZvkng[] = {"zvkg" , "zvkn" }; |
1088 | static const char *ImpliedExtsZvknhb[] = {"zve64x" }; |
1089 | static const char *ImpliedExtsZvks[] = {"zvkb" , "zvksed" , "zvksh" , "zvkt" }; |
1090 | static const char *ImpliedExtsZvksc[] = {"zvbc" , "zvks" }; |
1091 | static const char *ImpliedExtsZvksg[] = {"zvkg" , "zvks" }; |
1092 | static const char *ImpliedExtsZvl1024b[] = {"zvl512b" }; |
1093 | static const char *ImpliedExtsZvl128b[] = {"zvl64b" }; |
1094 | static const char *ImpliedExtsZvl16384b[] = {"zvl8192b" }; |
1095 | static const char *ImpliedExtsZvl2048b[] = {"zvl1024b" }; |
1096 | static const char *ImpliedExtsZvl256b[] = {"zvl128b" }; |
1097 | static const char *ImpliedExtsZvl32768b[] = {"zvl16384b" }; |
1098 | static const char *ImpliedExtsZvl4096b[] = {"zvl2048b" }; |
1099 | static const char *ImpliedExtsZvl512b[] = {"zvl256b" }; |
1100 | static const char *ImpliedExtsZvl64b[] = {"zvl32b" }; |
1101 | static const char *ImpliedExtsZvl65536b[] = {"zvl32768b" }; |
1102 | static const char *ImpliedExtsZvl8192b[] = {"zvl4096b" }; |
1103 | |
1104 | struct 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. |
1116 | static 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 | |
1177 | void 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 | |
1220 | struct CombinedExtsEntry { |
1221 | StringLiteral CombineExt; |
1222 | ArrayRef<const char *> RequiredExts; |
1223 | }; |
1224 | |
1225 | static 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 | |
1237 | void 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 | |
1258 | void 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 | |
1267 | void 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 | |
1279 | void 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 | |
1297 | std::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 | |
1314 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
1315 | RISCVISAInfo::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 | |
1327 | StringRef 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 | |
1348 | bool 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 | |
1368 | std::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 | |