1 | //===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "RISCV.h" |
10 | #include "clang/Basic/CharInfo.h" |
11 | #include "clang/Driver/Driver.h" |
12 | #include "clang/Driver/DriverDiagnostic.h" |
13 | #include "clang/Driver/Options.h" |
14 | #include "llvm/Option/ArgList.h" |
15 | #include "llvm/ADT/Optional.h" |
16 | #include "llvm/Support/TargetParser.h" |
17 | #include "llvm/Support/raw_ostream.h" |
18 | #include "ToolChains/CommonArgs.h" |
19 | |
20 | using namespace clang::driver; |
21 | using namespace clang::driver::tools; |
22 | using namespace clang; |
23 | using namespace llvm::opt; |
24 | |
25 | namespace { |
26 | // Represents the major and version number components of a RISC-V extension |
27 | struct RISCVExtensionVersion { |
28 | StringRef Major; |
29 | StringRef Minor; |
30 | }; |
31 | } // end anonymous namespace |
32 | |
33 | static StringRef getExtensionTypeDesc(StringRef Ext) { |
34 | if (Ext.startswith("sx" )) |
35 | return "non-standard supervisor-level extension" ; |
36 | if (Ext.startswith("s" )) |
37 | return "standard supervisor-level extension" ; |
38 | if (Ext.startswith("x" )) |
39 | return "non-standard user-level extension" ; |
40 | if (Ext.startswith("z" )) |
41 | return "standard user-level extension" ; |
42 | return StringRef(); |
43 | } |
44 | |
45 | static StringRef getExtensionType(StringRef Ext) { |
46 | if (Ext.startswith("sx" )) |
47 | return "sx" ; |
48 | if (Ext.startswith("s" )) |
49 | return "s" ; |
50 | if (Ext.startswith("x" )) |
51 | return "x" ; |
52 | if (Ext.startswith("z" )) |
53 | return "z" ; |
54 | return StringRef(); |
55 | } |
56 | |
57 | // If the extension is supported as experimental, return the version of that |
58 | // extension that the compiler currently supports. |
59 | static Optional<RISCVExtensionVersion> |
60 | isExperimentalExtension(StringRef Ext) { |
61 | if (Ext == "b" || Ext == "zba" || Ext == "zbb" || Ext == "zbc" || |
62 | Ext == "zbe" || Ext == "zbf" || Ext == "zbm" || Ext == "zbp" || |
63 | Ext == "zbr" || Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc" ) |
64 | return RISCVExtensionVersion{"0" , "93" }; |
65 | if (Ext == "v" || Ext == "zvamo" || Ext == "zvlsseg" ) |
66 | return RISCVExtensionVersion{"0" , "10" }; |
67 | if (Ext == "zfh" ) |
68 | return RISCVExtensionVersion{"0" , "1" }; |
69 | return None; |
70 | } |
71 | |
72 | static bool isSupportedExtension(StringRef Ext) { |
73 | // LLVM supports "z" extensions which are marked as experimental. |
74 | if (isExperimentalExtension(Ext)) |
75 | return true; |
76 | |
77 | // LLVM does not support "sx", "s" nor "x" extensions. |
78 | return false; |
79 | } |
80 | |
81 | // Extensions may have a version number, and may be separated by |
82 | // an underscore '_' e.g.: rv32i2_m2. |
83 | // Version number is divided into major and minor version numbers, |
84 | // separated by a 'p'. If the minor version is 0 then 'p0' can be |
85 | // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. |
86 | static bool getExtensionVersion(const Driver &D, const ArgList &Args, |
87 | StringRef MArch, StringRef Ext, StringRef In, |
88 | std::string &Major, std::string &Minor) { |
89 | Major = std::string(In.take_while(isDigit)); |
90 | In = In.substr(Major.size()); |
91 | |
92 | if (Major.size() && In.consume_front("p" )) { |
93 | Minor = std::string(In.take_while(isDigit)); |
94 | In = In.substr(Major.size() + 1); |
95 | |
96 | // Expected 'p' to be followed by minor version number. |
97 | if (Minor.empty()) { |
98 | std::string Error = |
99 | "minor version number missing after 'p' for extension" ; |
100 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
101 | << MArch << Error << Ext; |
102 | return false; |
103 | } |
104 | } |
105 | |
106 | // Expected multi-character extension with version number to have no |
107 | // subsequent characters (i.e. must either end string or be followed by |
108 | // an underscore). |
109 | if (Ext.size() > 1 && In.size()) { |
110 | std::string Error = |
111 | "multi-character extensions must be separated by underscores" ; |
112 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << In; |
113 | return false; |
114 | } |
115 | |
116 | // If experimental extension, require use of current version number number |
117 | if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { |
118 | if (!Args.hasArg(options::OPT_menable_experimental_extensions)) { |
119 | std::string Error = |
120 | "requires '-menable-experimental-extensions' for experimental extension" ; |
121 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
122 | << MArch << Error << Ext; |
123 | return false; |
124 | } else if (Major.empty() && Minor.empty()) { |
125 | std::string Error = |
126 | "experimental extension requires explicit version number" ; |
127 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
128 | << MArch << Error << Ext; |
129 | return false; |
130 | } |
131 | auto SupportedVers = *ExperimentalExtension; |
132 | if (Major != SupportedVers.Major || Minor != SupportedVers.Minor) { |
133 | std::string Error = |
134 | "unsupported version number " + Major; |
135 | if (!Minor.empty()) |
136 | Error += "." + Minor; |
137 | Error += " for experimental extension (this compiler supports " |
138 | + SupportedVers.Major.str() + "." |
139 | + SupportedVers.Minor.str() + ")" ; |
140 | |
141 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
142 | << MArch << Error << Ext; |
143 | return false; |
144 | } |
145 | return true; |
146 | } |
147 | |
148 | // Allow extensions to declare no version number |
149 | if (Major.empty() && Minor.empty()) |
150 | return true; |
151 | |
152 | // TODO: Handle supported extensions with version number. |
153 | std::string Error = "unsupported version number " + Major; |
154 | if (!Minor.empty()) |
155 | Error += "." + Minor; |
156 | Error += " for extension" ; |
157 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext; |
158 | |
159 | return false; |
160 | } |
161 | |
162 | // Handle other types of extensions other than the standard |
163 | // general purpose and standard user-level extensions. |
164 | // Parse the ISA string containing non-standard user-level |
165 | // extensions, standard supervisor-level extensions and |
166 | // non-standard supervisor-level extensions. |
167 | // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a |
168 | // canonical order, might have a version number (major, minor) |
169 | // and are separated by a single underscore '_'. |
170 | // Set the hardware features for the extensions that are supported. |
171 | static void getExtensionFeatures(const Driver &D, |
172 | const ArgList &Args, |
173 | std::vector<StringRef> &Features, |
174 | StringRef &MArch, StringRef &Exts) { |
175 | if (Exts.empty()) |
176 | return; |
177 | |
178 | // Multi-letter extensions are seperated by a single underscore |
179 | // as described in RISC-V User-Level ISA V2.2. |
180 | SmallVector<StringRef, 8> Split; |
181 | Exts.split(Split, StringRef("_" )); |
182 | |
183 | SmallVector<StringRef, 4> Prefix{"z" , "x" , "s" , "sx" }; |
184 | auto I = Prefix.begin(); |
185 | auto E = Prefix.end(); |
186 | |
187 | SmallVector<StringRef, 8> AllExts; |
188 | |
189 | for (StringRef Ext : Split) { |
190 | if (Ext.empty()) { |
191 | D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch |
192 | << "extension name missing after separator '_'" ; |
193 | return; |
194 | } |
195 | |
196 | StringRef Type = getExtensionType(Ext); |
197 | StringRef Desc = getExtensionTypeDesc(Ext); |
198 | auto Pos = Ext.find_if(isDigit); |
199 | StringRef Name(Ext.substr(0, Pos)); |
200 | StringRef Vers(Ext.substr(Pos)); |
201 | |
202 | if (Type.empty()) { |
203 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
204 | << MArch << "invalid extension prefix" << Ext; |
205 | return; |
206 | } |
207 | |
208 | // Check ISA extensions are specified in the canonical order. |
209 | while (I != E && *I != Type) |
210 | ++I; |
211 | |
212 | if (I == E) { |
213 | std::string Error = std::string(Desc); |
214 | Error += " not given in canonical order" ; |
215 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
216 | << MArch << Error << Ext; |
217 | return; |
218 | } |
219 | |
220 | // The order is OK, do not advance I to the next prefix |
221 | // to allow repeated extension type, e.g.: rv32ixabc_xdef. |
222 | |
223 | if (Name.size() == Type.size()) { |
224 | std::string Error = std::string(Desc); |
225 | Error += " name missing after" ; |
226 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
227 | << MArch << Error << Type; |
228 | return; |
229 | } |
230 | |
231 | std::string Major, Minor; |
232 | if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor)) |
233 | return; |
234 | |
235 | // Check if duplicated extension. |
236 | if (llvm::is_contained(AllExts, Name)) { |
237 | std::string Error = "duplicated " ; |
238 | Error += Desc; |
239 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
240 | << MArch << Error << Name; |
241 | return; |
242 | } |
243 | |
244 | // Extension format is correct, keep parsing the extensions. |
245 | // TODO: Save Type, Name, Major, Minor to avoid parsing them later. |
246 | AllExts.push_back(Name); |
247 | } |
248 | |
249 | // Set target features. |
250 | // TODO: Hardware features to be handled in Support/TargetParser.cpp. |
251 | // TODO: Use version number when setting target features. |
252 | for (auto Ext : AllExts) { |
253 | if (!isSupportedExtension(Ext)) { |
254 | StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); |
255 | std::string Error = "unsupported " ; |
256 | Error += Desc; |
257 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
258 | << MArch << Error << Ext; |
259 | return; |
260 | } |
261 | if (Ext == "zvamo" || Ext == "zvlsseg" ) { |
262 | Features.push_back("+experimental-v" ); |
263 | Features.push_back("+experimental-zvamo" ); |
264 | Features.push_back("+experimental-zvlsseg" ); |
265 | } else if (isExperimentalExtension(Ext)) |
266 | Features.push_back(Args.MakeArgString("+experimental-" + Ext)); |
267 | else |
268 | Features.push_back(Args.MakeArgString("+" + Ext)); |
269 | } |
270 | } |
271 | |
272 | // Returns false if an error is diagnosed. |
273 | static bool getArchFeatures(const Driver &D, StringRef MArch, |
274 | std::vector<StringRef> &Features, |
275 | const ArgList &Args) { |
276 | // RISC-V ISA strings must be lowercase. |
277 | if (llvm::any_of(MArch, [](char c) { return isupper(c); })) { |
278 | D.Diag(diag::err_drv_invalid_riscv_arch_name) |
279 | << MArch << "string must be lowercase" ; |
280 | return false; |
281 | } |
282 | |
283 | // ISA string must begin with rv32 or rv64. |
284 | if (!(MArch.startswith("rv32" ) || MArch.startswith("rv64" )) || |
285 | (MArch.size() < 5)) { |
286 | D.Diag(diag::err_drv_invalid_riscv_arch_name) |
287 | << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}" ; |
288 | return false; |
289 | } |
290 | |
291 | bool HasRV64 = MArch.startswith("rv64" ); |
292 | |
293 | // The canonical order specified in ISA manual. |
294 | // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 |
295 | StringRef StdExts = "mafdqlcbjtpvn" ; |
296 | bool HasF = false, HasD = false; |
297 | char Baseline = MArch[4]; |
298 | |
299 | // First letter should be 'e', 'i' or 'g'. |
300 | switch (Baseline) { |
301 | default: |
302 | D.Diag(diag::err_drv_invalid_riscv_arch_name) |
303 | << MArch << "first letter should be 'e', 'i' or 'g'" ; |
304 | return false; |
305 | case 'e': { |
306 | StringRef Error; |
307 | // Currently LLVM does not support 'e'. |
308 | // Extension 'e' is not allowed in rv64. |
309 | if (HasRV64) |
310 | Error = "standard user-level extension 'e' requires 'rv32'" ; |
311 | else |
312 | Error = "unsupported standard user-level extension 'e'" ; |
313 | D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error; |
314 | return false; |
315 | } |
316 | case 'i': |
317 | break; |
318 | case 'g': |
319 | // g = imafd |
320 | StdExts = StdExts.drop_front(4); |
321 | Features.push_back("+m" ); |
322 | Features.push_back("+a" ); |
323 | Features.push_back("+f" ); |
324 | Features.push_back("+d" ); |
325 | HasF = true; |
326 | HasD = true; |
327 | break; |
328 | } |
329 | |
330 | // Skip rvxxx |
331 | StringRef Exts = MArch.substr(5); |
332 | |
333 | // Remove multi-letter standard extensions, non-standard extensions and |
334 | // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes. |
335 | // Parse them at the end. |
336 | // Find the very first occurrence of 's', 'x' or 'z'. |
337 | StringRef OtherExts; |
338 | size_t Pos = Exts.find_first_of("zsx" ); |
339 | if (Pos != StringRef::npos) { |
340 | OtherExts = Exts.substr(Pos); |
341 | Exts = Exts.substr(0, Pos); |
342 | } |
343 | |
344 | std::string Major, Minor; |
345 | if (!getExtensionVersion(D, Args, MArch, std::string(1, Baseline), Exts, |
346 | Major, Minor)) |
347 | return false; |
348 | |
349 | // Consume the base ISA version number and any '_' between rvxxx and the |
350 | // first extension |
351 | Exts = Exts.drop_front(Major.size()); |
352 | if (!Minor.empty()) |
353 | Exts = Exts.drop_front(Minor.size() + 1 /*'p'*/); |
354 | Exts.consume_front("_" ); |
355 | |
356 | // TODO: Use version number when setting target features |
357 | |
358 | auto StdExtsItr = StdExts.begin(); |
359 | auto StdExtsEnd = StdExts.end(); |
360 | |
361 | for (auto I = Exts.begin(), E = Exts.end(); I != E; ) { |
362 | char c = *I; |
363 | |
364 | // Check ISA extensions are specified in the canonical order. |
365 | while (StdExtsItr != StdExtsEnd && *StdExtsItr != c) |
366 | ++StdExtsItr; |
367 | |
368 | if (StdExtsItr == StdExtsEnd) { |
369 | // Either c contains a valid extension but it was not given in |
370 | // canonical order or it is an invalid extension. |
371 | StringRef Error; |
372 | if (StdExts.contains(c)) |
373 | Error = "standard user-level extension not given in canonical order" ; |
374 | else |
375 | Error = "invalid standard user-level extension" ; |
376 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
377 | << MArch << Error << std::string(1, c); |
378 | return false; |
379 | } |
380 | |
381 | // Move to next char to prevent repeated letter. |
382 | ++StdExtsItr; |
383 | |
384 | std::string Next, Major, Minor; |
385 | if (std::next(I) != E) |
386 | Next = std::string(std::next(I), E); |
387 | if (!getExtensionVersion(D, Args, MArch, std::string(1, c), Next, Major, |
388 | Minor)) |
389 | return false; |
390 | |
391 | // The order is OK, then push it into features. |
392 | // TODO: Use version number when setting target features |
393 | switch (c) { |
394 | default: |
395 | // Currently LLVM supports only "mafdc". |
396 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
397 | << MArch << "unsupported standard user-level extension" |
398 | << std::string(1, c); |
399 | return false; |
400 | case 'm': |
401 | Features.push_back("+m" ); |
402 | break; |
403 | case 'a': |
404 | Features.push_back("+a" ); |
405 | break; |
406 | case 'f': |
407 | Features.push_back("+f" ); |
408 | HasF = true; |
409 | break; |
410 | case 'd': |
411 | Features.push_back("+d" ); |
412 | HasD = true; |
413 | break; |
414 | case 'c': |
415 | Features.push_back("+c" ); |
416 | break; |
417 | case 'b': |
418 | Features.push_back("+experimental-b" ); |
419 | Features.push_back("+experimental-zba" ); |
420 | Features.push_back("+experimental-zbb" ); |
421 | Features.push_back("+experimental-zbc" ); |
422 | Features.push_back("+experimental-zbe" ); |
423 | Features.push_back("+experimental-zbf" ); |
424 | Features.push_back("+experimental-zbm" ); |
425 | Features.push_back("+experimental-zbp" ); |
426 | Features.push_back("+experimental-zbr" ); |
427 | Features.push_back("+experimental-zbs" ); |
428 | Features.push_back("+experimental-zbt" ); |
429 | break; |
430 | case 'v': |
431 | Features.push_back("+experimental-v" ); |
432 | Features.push_back("+experimental-zvamo" ); |
433 | Features.push_back("+experimental-zvlsseg" ); |
434 | break; |
435 | } |
436 | |
437 | // Consume full extension name and version, including any optional '_' |
438 | // between this extension and the next |
439 | ++I; |
440 | I += Major.size(); |
441 | if (Minor.size()) |
442 | I += Minor.size() + 1 /*'p'*/; |
443 | if (*I == '_') |
444 | ++I; |
445 | } |
446 | |
447 | // Dependency check. |
448 | // It's illegal to specify the 'd' (double-precision floating point) |
449 | // extension without also specifying the 'f' (single precision |
450 | // floating-point) extension. |
451 | if (HasD && !HasF) { |
452 | D.Diag(diag::err_drv_invalid_riscv_arch_name) |
453 | << MArch << "d requires f extension to also be specified" ; |
454 | return false; |
455 | } |
456 | |
457 | // Additional dependency checks. |
458 | // TODO: The 'q' extension requires rv64. |
459 | // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. |
460 | |
461 | // Handle all other types of extensions. |
462 | getExtensionFeatures(D, Args, Features, MArch, OtherExts); |
463 | |
464 | return true; |
465 | } |
466 | |
467 | // Get features except standard extension feature |
468 | static void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple, |
469 | const llvm::opt::ArgList &Args, |
470 | const llvm::opt::Arg *A, StringRef Mcpu, |
471 | std::vector<StringRef> &Features) { |
472 | bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64); |
473 | llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu); |
474 | if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) || |
475 | !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) { |
476 | D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); |
477 | } |
478 | } |
479 | |
480 | void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, |
481 | const ArgList &Args, |
482 | std::vector<StringRef> &Features) { |
483 | StringRef MArch = getRISCVArch(Args, Triple); |
484 | |
485 | if (!getArchFeatures(D, MArch, Features, Args)) |
486 | return; |
487 | |
488 | // If users give march and mcpu, get std extension feature from MArch |
489 | // and other features (ex. mirco architecture feature) from mcpu |
490 | if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) |
491 | getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features); |
492 | |
493 | // Handle features corresponding to "-ffixed-X" options |
494 | if (Args.hasArg(options::OPT_ffixed_x1)) |
495 | Features.push_back("+reserve-x1" ); |
496 | if (Args.hasArg(options::OPT_ffixed_x2)) |
497 | Features.push_back("+reserve-x2" ); |
498 | if (Args.hasArg(options::OPT_ffixed_x3)) |
499 | Features.push_back("+reserve-x3" ); |
500 | if (Args.hasArg(options::OPT_ffixed_x4)) |
501 | Features.push_back("+reserve-x4" ); |
502 | if (Args.hasArg(options::OPT_ffixed_x5)) |
503 | Features.push_back("+reserve-x5" ); |
504 | if (Args.hasArg(options::OPT_ffixed_x6)) |
505 | Features.push_back("+reserve-x6" ); |
506 | if (Args.hasArg(options::OPT_ffixed_x7)) |
507 | Features.push_back("+reserve-x7" ); |
508 | if (Args.hasArg(options::OPT_ffixed_x8)) |
509 | Features.push_back("+reserve-x8" ); |
510 | if (Args.hasArg(options::OPT_ffixed_x9)) |
511 | Features.push_back("+reserve-x9" ); |
512 | if (Args.hasArg(options::OPT_ffixed_x10)) |
513 | Features.push_back("+reserve-x10" ); |
514 | if (Args.hasArg(options::OPT_ffixed_x11)) |
515 | Features.push_back("+reserve-x11" ); |
516 | if (Args.hasArg(options::OPT_ffixed_x12)) |
517 | Features.push_back("+reserve-x12" ); |
518 | if (Args.hasArg(options::OPT_ffixed_x13)) |
519 | Features.push_back("+reserve-x13" ); |
520 | if (Args.hasArg(options::OPT_ffixed_x14)) |
521 | Features.push_back("+reserve-x14" ); |
522 | if (Args.hasArg(options::OPT_ffixed_x15)) |
523 | Features.push_back("+reserve-x15" ); |
524 | if (Args.hasArg(options::OPT_ffixed_x16)) |
525 | Features.push_back("+reserve-x16" ); |
526 | if (Args.hasArg(options::OPT_ffixed_x17)) |
527 | Features.push_back("+reserve-x17" ); |
528 | if (Args.hasArg(options::OPT_ffixed_x18)) |
529 | Features.push_back("+reserve-x18" ); |
530 | if (Args.hasArg(options::OPT_ffixed_x19)) |
531 | Features.push_back("+reserve-x19" ); |
532 | if (Args.hasArg(options::OPT_ffixed_x20)) |
533 | Features.push_back("+reserve-x20" ); |
534 | if (Args.hasArg(options::OPT_ffixed_x21)) |
535 | Features.push_back("+reserve-x21" ); |
536 | if (Args.hasArg(options::OPT_ffixed_x22)) |
537 | Features.push_back("+reserve-x22" ); |
538 | if (Args.hasArg(options::OPT_ffixed_x23)) |
539 | Features.push_back("+reserve-x23" ); |
540 | if (Args.hasArg(options::OPT_ffixed_x24)) |
541 | Features.push_back("+reserve-x24" ); |
542 | if (Args.hasArg(options::OPT_ffixed_x25)) |
543 | Features.push_back("+reserve-x25" ); |
544 | if (Args.hasArg(options::OPT_ffixed_x26)) |
545 | Features.push_back("+reserve-x26" ); |
546 | if (Args.hasArg(options::OPT_ffixed_x27)) |
547 | Features.push_back("+reserve-x27" ); |
548 | if (Args.hasArg(options::OPT_ffixed_x28)) |
549 | Features.push_back("+reserve-x28" ); |
550 | if (Args.hasArg(options::OPT_ffixed_x29)) |
551 | Features.push_back("+reserve-x29" ); |
552 | if (Args.hasArg(options::OPT_ffixed_x30)) |
553 | Features.push_back("+reserve-x30" ); |
554 | if (Args.hasArg(options::OPT_ffixed_x31)) |
555 | Features.push_back("+reserve-x31" ); |
556 | |
557 | // -mrelax is default, unless -mno-relax is specified. |
558 | if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) |
559 | Features.push_back("+relax" ); |
560 | else |
561 | Features.push_back("-relax" ); |
562 | |
563 | // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is |
564 | // specified. |
565 | if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) |
566 | Features.push_back("+save-restore" ); |
567 | else |
568 | Features.push_back("-save-restore" ); |
569 | |
570 | // Now add any that the user explicitly requested on the command line, |
571 | // which may override the defaults. |
572 | handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); |
573 | } |
574 | |
575 | StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { |
576 | assert((Triple.getArch() == llvm::Triple::riscv32 || |
577 | Triple.getArch() == llvm::Triple::riscv64) && |
578 | "Unexpected triple" ); |
579 | |
580 | // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not |
581 | // configured using `--with-abi=`, then the logic for the default choice is |
582 | // defined in config.gcc. This function is based on the logic in GCC 9.2.0. |
583 | // |
584 | // The logic used in GCC 9.2.0 is the following, in order: |
585 | // 1. Explicit choices using `--with-abi=` |
586 | // 2. A default based on `--with-arch=`, if provided |
587 | // 3. A default based on the target triple's arch |
588 | // |
589 | // The logic in config.gcc is a little circular but it is not inconsistent. |
590 | // |
591 | // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` |
592 | // and `-mabi=` respectively instead. |
593 | // |
594 | // In order to make chosing logic more clear, Clang uses the following logic, |
595 | // in order: |
596 | // 1. Explicit choices using `-mabi=` |
597 | // 2. A default based on the architecture as determined by getRISCVArch |
598 | // 3. Choose a default based on the triple |
599 | |
600 | // 1. If `-mabi=` is specified, use it. |
601 | if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) |
602 | return A->getValue(); |
603 | |
604 | // 2. Choose a default based on the target architecture. |
605 | // |
606 | // rv32g | rv32*d -> ilp32d |
607 | // rv32e -> ilp32e |
608 | // rv32* -> ilp32 |
609 | // rv64g | rv64*d -> lp64d |
610 | // rv64* -> lp64 |
611 | StringRef MArch = getRISCVArch(Args, Triple); |
612 | |
613 | if (MArch.startswith_lower("rv32" )) { |
614 | // FIXME: parse `March` to find `D` extension properly |
615 | if (MArch.substr(4).contains_lower("d" ) || MArch.startswith_lower("rv32g" )) |
616 | return "ilp32d" ; |
617 | else if (MArch.startswith_lower("rv32e" )) |
618 | return "ilp32e" ; |
619 | else |
620 | return "ilp32" ; |
621 | } else if (MArch.startswith_lower("rv64" )) { |
622 | // FIXME: parse `March` to find `D` extension properly |
623 | if (MArch.substr(4).contains_lower("d" ) || MArch.startswith_lower("rv64g" )) |
624 | return "lp64d" ; |
625 | else |
626 | return "lp64" ; |
627 | } |
628 | |
629 | // 3. Choose a default based on the triple |
630 | // |
631 | // We deviate from GCC's defaults here: |
632 | // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only. |
633 | // - On all other OSs we use the double floating point calling convention. |
634 | if (Triple.getArch() == llvm::Triple::riscv32) { |
635 | if (Triple.getOS() == llvm::Triple::UnknownOS) |
636 | return "ilp32" ; |
637 | else |
638 | return "ilp32d" ; |
639 | } else { |
640 | if (Triple.getOS() == llvm::Triple::UnknownOS) |
641 | return "lp64" ; |
642 | else |
643 | return "lp64d" ; |
644 | } |
645 | } |
646 | |
647 | StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, |
648 | const llvm::Triple &Triple) { |
649 | assert((Triple.getArch() == llvm::Triple::riscv32 || |
650 | Triple.getArch() == llvm::Triple::riscv64) && |
651 | "Unexpected triple" ); |
652 | |
653 | // GCC's logic around choosing a default `-march=` is complex. If GCC is not |
654 | // configured using `--with-arch=`, then the logic for the default choice is |
655 | // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We |
656 | // deviate from GCC's default on additional `-mcpu` option (GCC does not |
657 | // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march` |
658 | // nor `-mabi` is specified. |
659 | // |
660 | // The logic used in GCC 9.2.0 is the following, in order: |
661 | // 1. Explicit choices using `--with-arch=` |
662 | // 2. A default based on `--with-abi=`, if provided |
663 | // 3. A default based on the target triple's arch |
664 | // |
665 | // The logic in config.gcc is a little circular but it is not inconsistent. |
666 | // |
667 | // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` |
668 | // and `-mabi=` respectively instead. |
669 | // |
670 | // Clang uses the following logic, in order: |
671 | // 1. Explicit choices using `-march=` |
672 | // 2. Based on `-mcpu` if the target CPU has a default ISA string |
673 | // 3. A default based on `-mabi`, if provided |
674 | // 4. A default based on the target triple's arch |
675 | // |
676 | // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc` |
677 | // instead of `rv{XLEN}gc` though they are (currently) equivalent. |
678 | |
679 | // 1. If `-march=` is specified, use it. |
680 | if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) |
681 | return A->getValue(); |
682 | |
683 | // 2. Get march (isa string) based on `-mcpu=` |
684 | if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { |
685 | StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue()); |
686 | // Bypass if target cpu's default march is empty. |
687 | if (MArch != "" ) |
688 | return MArch; |
689 | } |
690 | |
691 | // 3. Choose a default based on `-mabi=` |
692 | // |
693 | // ilp32e -> rv32e |
694 | // ilp32 | ilp32f | ilp32d -> rv32imafdc |
695 | // lp64 | lp64f | lp64d -> rv64imafdc |
696 | if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { |
697 | StringRef MABI = A->getValue(); |
698 | |
699 | if (MABI.equals_lower("ilp32e" )) |
700 | return "rv32e" ; |
701 | else if (MABI.startswith_lower("ilp32" )) |
702 | return "rv32imafdc" ; |
703 | else if (MABI.startswith_lower("lp64" )) |
704 | return "rv64imafdc" ; |
705 | } |
706 | |
707 | // 4. Choose a default based on the triple |
708 | // |
709 | // We deviate from GCC's defaults here: |
710 | // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac` |
711 | // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`) |
712 | if (Triple.getArch() == llvm::Triple::riscv32) { |
713 | if (Triple.getOS() == llvm::Triple::UnknownOS) |
714 | return "rv32imac" ; |
715 | else |
716 | return "rv32imafdc" ; |
717 | } else { |
718 | if (Triple.getOS() == llvm::Triple::UnknownOS) |
719 | return "rv64imac" ; |
720 | else |
721 | return "rv64imafdc" ; |
722 | } |
723 | } |
724 | |