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