1 //===-- RISCVISAInfo.cpp - RISCV 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/Support/RISCVISAInfo.h" 10 #include "llvm/ADT/None.h" 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/ADT/StringExtras.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/Support/Errc.h" 15 #include "llvm/Support/Error.h" 16 #include "llvm/Support/raw_ostream.h" 17 18 #include <array> 19 #include <string> 20 #include <vector> 21 22 using namespace llvm; 23 24 namespace { 25 /// Represents the major and version number components of a RISC-V extension 26 struct RISCVExtensionVersion { 27 unsigned Major; 28 unsigned Minor; 29 }; 30 31 struct RISCVSupportedExtension { 32 const char *Name; 33 /// Supported version. 34 RISCVExtensionVersion Version; 35 }; 36 37 } // end anonymous namespace 38 39 static constexpr StringLiteral AllStdExts = "mafdqlcbjtpvn"; 40 41 static const RISCVSupportedExtension SupportedExtensions[] = { 42 {"i", RISCVExtensionVersion{2, 0}}, 43 {"e", RISCVExtensionVersion{1, 9}}, 44 {"m", RISCVExtensionVersion{2, 0}}, 45 {"a", RISCVExtensionVersion{2, 0}}, 46 {"f", RISCVExtensionVersion{2, 0}}, 47 {"d", RISCVExtensionVersion{2, 0}}, 48 {"c", RISCVExtensionVersion{2, 0}}, 49 50 {"zba", RISCVExtensionVersion{1, 0}}, 51 {"zbb", RISCVExtensionVersion{1, 0}}, 52 {"zbc", RISCVExtensionVersion{1, 0}}, 53 {"zbs", RISCVExtensionVersion{1, 0}}, 54 }; 55 56 static const RISCVSupportedExtension SupportedExperimentalExtensions[] = { 57 {"v", RISCVExtensionVersion{0, 10}}, 58 {"zbe", RISCVExtensionVersion{0, 93}}, 59 {"zbf", RISCVExtensionVersion{0, 93}}, 60 {"zbm", RISCVExtensionVersion{0, 93}}, 61 {"zbp", RISCVExtensionVersion{0, 93}}, 62 {"zbr", RISCVExtensionVersion{0, 93}}, 63 {"zbt", RISCVExtensionVersion{0, 93}}, 64 65 {"zvlsseg", RISCVExtensionVersion{0, 10}}, 66 67 {"zfhmin", RISCVExtensionVersion{0, 1}}, 68 {"zfh", RISCVExtensionVersion{0, 1}}, 69 }; 70 71 static bool stripExperimentalPrefix(StringRef &Ext) { 72 return Ext.consume_front("experimental-"); 73 } 74 75 // This function finds the first character that doesn't belong to a version 76 // (e.g. zbe0p93 is extension 'zbe' of version '0p93'). So the function will 77 // consume [0-9]*p[0-9]* starting from the backward. An extension name will not 78 // end with a digit or the letter 'p', so this function will parse correctly. 79 // NOTE: This function is NOT able to take empty strings or strings that only 80 // have version numbers and no extension name. It assumes the extension name 81 // will be at least more than one character. 82 static size_t findFirstNonVersionCharacter(const StringRef &Ext) { 83 if (Ext.size() == 0) 84 llvm_unreachable("Already guarded by if-statement in ::parseArchString"); 85 86 int Pos = Ext.size() - 1; 87 while (Pos > 0 && isDigit(Ext[Pos])) 88 Pos--; 89 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) { 90 Pos--; 91 while (Pos > 0 && isDigit(Ext[Pos])) 92 Pos--; 93 } 94 return Pos; 95 } 96 97 struct FindByName { 98 FindByName(StringRef Ext) : Ext(Ext){}; 99 StringRef Ext; 100 bool operator()(const RISCVSupportedExtension &ExtInfo) { 101 return ExtInfo.Name == Ext; 102 } 103 }; 104 105 static Optional<RISCVExtensionVersion> findDefaultVersion(StringRef ExtName) { 106 // Find default version of an extension. 107 // TODO: We might set default version based on profile or ISA spec. 108 for (auto &ExtInfo : {makeArrayRef(SupportedExtensions), 109 makeArrayRef(SupportedExperimentalExtensions)}) { 110 auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName)); 111 112 if (ExtensionInfoIterator == ExtInfo.end()) { 113 continue; 114 } 115 return ExtensionInfoIterator->Version; 116 } 117 return None; 118 } 119 120 void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion, 121 unsigned MinorVersion) { 122 RISCVExtensionInfo Ext; 123 Ext.ExtName = ExtName.str(); 124 Ext.MajorVersion = MajorVersion; 125 Ext.MinorVersion = MinorVersion; 126 Exts[ExtName.str()] = Ext; 127 } 128 129 static StringRef getExtensionTypeDesc(StringRef Ext) { 130 if (Ext.startswith("sx")) 131 return "non-standard supervisor-level extension"; 132 if (Ext.startswith("s")) 133 return "standard supervisor-level extension"; 134 if (Ext.startswith("x")) 135 return "non-standard user-level extension"; 136 if (Ext.startswith("z")) 137 return "standard user-level extension"; 138 return StringRef(); 139 } 140 141 static StringRef getExtensionType(StringRef Ext) { 142 if (Ext.startswith("sx")) 143 return "sx"; 144 if (Ext.startswith("s")) 145 return "s"; 146 if (Ext.startswith("x")) 147 return "x"; 148 if (Ext.startswith("z")) 149 return "z"; 150 return StringRef(); 151 } 152 153 static Optional<RISCVExtensionVersion> isExperimentalExtension(StringRef Ext) { 154 auto ExtIterator = 155 llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext)); 156 if (ExtIterator == std::end(SupportedExperimentalExtensions)) 157 return None; 158 159 return ExtIterator->Version; 160 } 161 162 bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) { 163 bool IsExperimental = stripExperimentalPrefix(Ext); 164 165 if (IsExperimental) 166 return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext)); 167 else 168 return llvm::any_of(SupportedExtensions, FindByName(Ext)); 169 } 170 171 bool RISCVISAInfo::isSupportedExtension(StringRef Ext) { 172 return llvm::any_of(SupportedExtensions, FindByName(Ext)) || 173 llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext)); 174 } 175 176 bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion, 177 unsigned MinorVersion) { 178 auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) { 179 return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) && 180 (MinorVersion == ExtInfo.Version.Minor); 181 }; 182 return llvm::any_of(SupportedExtensions, FindByNameAndVersion) || 183 llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion); 184 } 185 186 bool RISCVISAInfo::hasExtension(StringRef Ext) const { 187 stripExperimentalPrefix(Ext); 188 189 if (!isSupportedExtension(Ext)) 190 return false; 191 192 return Exts.count(Ext.str()) != 0; 193 } 194 195 // Get the rank for single-letter extension, lower value meaning higher 196 // priority. 197 static int singleLetterExtensionRank(char Ext) { 198 switch (Ext) { 199 case 'i': 200 return -2; 201 case 'e': 202 return -1; 203 default: 204 break; 205 } 206 207 size_t Pos = AllStdExts.find(Ext); 208 int Rank; 209 if (Pos == StringRef::npos) 210 // If we got an unknown extension letter, then give it an alphabetical 211 // order, but after all known standard extensions. 212 Rank = AllStdExts.size() + (Ext - 'a'); 213 else 214 Rank = Pos; 215 216 return Rank; 217 } 218 219 // Get the rank for multi-letter extension, lower value meaning higher 220 // priority/order in canonical order. 221 static int multiLetterExtensionRank(const std::string &ExtName) { 222 assert(ExtName.length() >= 2); 223 int HighOrder; 224 int LowOrder = 0; 225 // The order between multi-char extensions: s -> h -> z -> x. 226 char ExtClass = ExtName[0]; 227 switch (ExtClass) { 228 case 's': 229 HighOrder = 0; 230 break; 231 case 'h': 232 HighOrder = 1; 233 break; 234 case 'z': 235 HighOrder = 2; 236 // `z` extension must be sorted by canonical order of second letter. 237 // e.g. zmx has higher rank than zax. 238 LowOrder = singleLetterExtensionRank(ExtName[1]); 239 break; 240 case 'x': 241 HighOrder = 3; 242 break; 243 default: 244 llvm_unreachable("Unknown prefix for multi-char extension"); 245 return -1; 246 } 247 248 return (HighOrder << 8) + LowOrder; 249 } 250 251 // Compare function for extension. 252 // Only compare the extension name, ignore version comparison. 253 bool RISCVISAInfo::compareExtension(const std::string &LHS, 254 const std::string &RHS) { 255 size_t LHSLen = LHS.length(); 256 size_t RHSLen = RHS.length(); 257 if (LHSLen == 1 && RHSLen != 1) 258 return true; 259 260 if (LHSLen != 1 && RHSLen == 1) 261 return false; 262 263 if (LHSLen == 1 && RHSLen == 1) 264 return singleLetterExtensionRank(LHS[0]) < 265 singleLetterExtensionRank(RHS[0]); 266 267 // Both are multi-char ext here. 268 int LHSRank = multiLetterExtensionRank(LHS); 269 int RHSRank = multiLetterExtensionRank(RHS); 270 if (LHSRank != RHSRank) 271 return LHSRank < RHSRank; 272 273 // If the rank is same, it must be sorted by lexicographic order. 274 return LHS < RHS; 275 } 276 277 void RISCVISAInfo::toFeatures( 278 std::vector<StringRef> &Features, 279 std::function<StringRef(const Twine &)> StrAlloc) const { 280 for (auto &Ext : Exts) { 281 StringRef ExtName = Ext.first; 282 283 if (ExtName == "i") 284 continue; 285 286 if (ExtName == "zvlsseg") { 287 Features.push_back("+experimental-v"); 288 Features.push_back("+experimental-zvlsseg"); 289 } else if (isExperimentalExtension(ExtName)) { 290 Features.push_back(StrAlloc("+experimental-" + ExtName)); 291 } else { 292 Features.push_back(StrAlloc("+" + ExtName)); 293 } 294 } 295 } 296 297 // Extensions may have a version number, and may be separated by 298 // an underscore '_' e.g.: rv32i2_m2. 299 // Version number is divided into major and minor version numbers, 300 // separated by a 'p'. If the minor version is 0 then 'p0' can be 301 // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. 302 static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, 303 unsigned &Minor, unsigned &ConsumeLength, 304 bool EnableExperimentalExtension, 305 bool ExperimentalExtensionVersionCheck) { 306 StringRef MajorStr, MinorStr; 307 Major = 0; 308 Minor = 0; 309 ConsumeLength = 0; 310 MajorStr = In.take_while(isDigit); 311 In = In.substr(MajorStr.size()); 312 313 if (!MajorStr.empty() && In.consume_front("p")) { 314 MinorStr = In.take_while(isDigit); 315 In = In.substr(MajorStr.size() + 1); 316 317 // Expected 'p' to be followed by minor version number. 318 if (MinorStr.empty()) { 319 return createStringError( 320 errc::invalid_argument, 321 "minor version number missing after 'p' for extension '" + Ext + "'"); 322 } 323 } 324 325 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major)) 326 return createStringError( 327 errc::invalid_argument, 328 "Failed to parse major version number for extension '" + Ext + "'"); 329 330 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor)) 331 return createStringError( 332 errc::invalid_argument, 333 "Failed to parse minor version number for extension '" + Ext + "'"); 334 335 ConsumeLength = MajorStr.size(); 336 337 if (!MinorStr.empty()) 338 ConsumeLength += MinorStr.size() + 1 /*'p'*/; 339 340 // Expected multi-character extension with version number to have no 341 // subsequent characters (i.e. must either end string or be followed by 342 // an underscore). 343 if (Ext.size() > 1 && In.size()) { 344 std::string Error = 345 "multi-character extensions must be separated by underscores"; 346 return createStringError(errc::invalid_argument, Error); 347 } 348 349 // If experimental extension, require use of current version number number 350 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { 351 if (!EnableExperimentalExtension) { 352 std::string Error = "requires '-menable-experimental-extensions' for " 353 "experimental extension '" + 354 Ext.str() + "'"; 355 return createStringError(errc::invalid_argument, Error); 356 } 357 358 if (ExperimentalExtensionVersionCheck && 359 (MajorStr.empty() && MinorStr.empty())) { 360 std::string Error = 361 "experimental extension requires explicit version number `" + 362 Ext.str() + "`"; 363 return createStringError(errc::invalid_argument, Error); 364 } 365 366 auto SupportedVers = *ExperimentalExtension; 367 if (ExperimentalExtensionVersionCheck && 368 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) { 369 std::string Error = "unsupported version number " + MajorStr.str(); 370 if (!MinorStr.empty()) 371 Error += "." + MinorStr.str(); 372 Error += " for experimental extension '" + Ext.str() + 373 "'(this compiler supports " + utostr(SupportedVers.Major) + "." + 374 utostr(SupportedVers.Minor) + ")"; 375 return createStringError(errc::invalid_argument, Error); 376 } 377 return Error::success(); 378 } 379 380 // Exception rule for `g`, we don't have clear version scheme for that on 381 // ISA spec. 382 if (Ext == "g") 383 return Error::success(); 384 385 if (MajorStr.empty() && MinorStr.empty()) { 386 if (auto DefaultVersion = findDefaultVersion(Ext)) { 387 Major = DefaultVersion->Major; 388 Minor = DefaultVersion->Minor; 389 } 390 // No matter found or not, return success, assume other place will 391 // verify. 392 return Error::success(); 393 } 394 395 if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor)) 396 return Error::success(); 397 398 std::string Error = "unsupported version number " + std::string(MajorStr); 399 if (!MinorStr.empty()) 400 Error += "." + MinorStr.str(); 401 Error += " for extension '" + Ext.str() + "'"; 402 return createStringError(errc::invalid_argument, Error); 403 } 404 405 llvm::Expected<std::unique_ptr<RISCVISAInfo>> 406 RISCVISAInfo::parseFeatures(unsigned XLen, 407 const std::vector<std::string> &Features) { 408 assert(XLen == 32 || XLen == 64); 409 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 410 411 for (auto &Feature : Features) { 412 StringRef ExtName = Feature; 413 bool Experimental = false; 414 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); 415 bool Add = ExtName[0] == '+'; 416 ExtName = ExtName.drop_front(1); // Drop '+' or '-' 417 Experimental = stripExperimentalPrefix(ExtName); 418 auto ExtensionInfos = Experimental 419 ? makeArrayRef(SupportedExperimentalExtensions) 420 : makeArrayRef(SupportedExtensions); 421 auto ExtensionInfoIterator = 422 llvm::find_if(ExtensionInfos, FindByName(ExtName)); 423 424 // Not all features is related to ISA extension, like `relax` or 425 // `save-restore`, skip those feature. 426 if (ExtensionInfoIterator == ExtensionInfos.end()) 427 continue; 428 429 if (Add) 430 ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major, 431 ExtensionInfoIterator->Version.Minor); 432 else 433 ISAInfo->Exts.erase(ExtName.str()); 434 } 435 436 ISAInfo->updateImplication(); 437 ISAInfo->updateFLen(); 438 439 if (Error Result = ISAInfo->checkDependency()) 440 return std::move(Result); 441 442 return std::move(ISAInfo); 443 } 444 445 llvm::Expected<std::unique_ptr<RISCVISAInfo>> 446 RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, 447 bool ExperimentalExtensionVersionCheck) { 448 // RISC-V ISA strings must be lowercase. 449 if (llvm::any_of(Arch, isupper)) { 450 return createStringError(errc::invalid_argument, 451 "string must be lowercase"); 452 } 453 454 bool HasRV64 = Arch.startswith("rv64"); 455 // ISA string must begin with rv32 or rv64. 456 if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) { 457 return createStringError(errc::invalid_argument, 458 "string must begin with rv32{i,e,g} or rv64{i,g}"); 459 } 460 461 unsigned XLen = HasRV64 ? 64 : 32; 462 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 463 464 // The canonical order specified in ISA manual. 465 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 466 StringRef StdExts = AllStdExts; 467 char Baseline = Arch[4]; 468 469 // First letter should be 'e', 'i' or 'g'. 470 switch (Baseline) { 471 default: 472 return createStringError(errc::invalid_argument, 473 "first letter should be 'e', 'i' or 'g'"); 474 case 'e': { 475 // Extension 'e' is not allowed in rv64. 476 if (HasRV64) 477 return createStringError( 478 errc::invalid_argument, 479 "standard user-level extension 'e' requires 'rv32'"); 480 break; 481 } 482 case 'i': 483 break; 484 case 'g': 485 // g = imafd 486 StdExts = StdExts.drop_front(4); 487 break; 488 } 489 490 // Skip rvxxx 491 StringRef Exts = Arch.substr(5); 492 493 // Remove multi-letter standard extensions, non-standard extensions and 494 // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes. 495 // Parse them at the end. 496 // Find the very first occurrence of 's', 'x' or 'z'. 497 StringRef OtherExts; 498 size_t Pos = Exts.find_first_of("zsx"); 499 if (Pos != StringRef::npos) { 500 OtherExts = Exts.substr(Pos); 501 Exts = Exts.substr(0, Pos); 502 } 503 504 unsigned Major, Minor, ConsumeLength; 505 if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor, 506 ConsumeLength, EnableExperimentalExtension, 507 ExperimentalExtensionVersionCheck)) 508 return std::move(E); 509 510 if (Baseline == 'g') { 511 // No matter which version is given to `g`, we always set imafd to default 512 // version since the we don't have clear version scheme for that on 513 // ISA spec. 514 for (auto Ext : {"i", "m", "a", "f", "d"}) 515 if (auto Version = findDefaultVersion(Ext)) 516 ISAInfo->addExtension(Ext, Version->Major, Version->Minor); 517 else 518 llvm_unreachable("Default extension version not found?"); 519 } else 520 // Baseline is `i` or `e` 521 ISAInfo->addExtension(std::string(1, Baseline), Major, Minor); 522 523 // Consume the base ISA version number and any '_' between rvxxx and the 524 // first extension 525 Exts = Exts.drop_front(ConsumeLength); 526 Exts.consume_front("_"); 527 528 // TODO: Use version number when setting target features 529 530 auto StdExtsItr = StdExts.begin(); 531 auto StdExtsEnd = StdExts.end(); 532 for (auto I = Exts.begin(), E = Exts.end(); I != E;) { 533 char C = *I; 534 535 // Check ISA extensions are specified in the canonical order. 536 while (StdExtsItr != StdExtsEnd && *StdExtsItr != C) 537 ++StdExtsItr; 538 539 if (StdExtsItr == StdExtsEnd) { 540 // Either c contains a valid extension but it was not given in 541 // canonical order or it is an invalid extension. 542 if (StdExts.contains(C)) { 543 return createStringError( 544 errc::invalid_argument, 545 "standard user-level extension not given in canonical order '%c'", 546 C); 547 } 548 549 return createStringError(errc::invalid_argument, 550 "invalid standard user-level extension '%c'", C); 551 } 552 553 // Move to next char to prevent repeated letter. 554 ++StdExtsItr; 555 556 std::string Next; 557 unsigned Major, Minor, ConsumeLength; 558 if (std::next(I) != E) 559 Next = std::string(std::next(I), E); 560 if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor, 561 ConsumeLength, EnableExperimentalExtension, 562 ExperimentalExtensionVersionCheck)) 563 return std::move(E); 564 565 // The order is OK, then push it into features. 566 // TODO: Use version number when setting target features 567 // Currently LLVM supports only "mafdcbv". 568 StringRef SupportedStandardExtension = "mafdcbv"; 569 if (!SupportedStandardExtension.contains(C)) 570 return createStringError(errc::invalid_argument, 571 "unsupported standard user-level extension '%c'", 572 C); 573 ISAInfo->addExtension(std::string(1, C), Major, Minor); 574 575 // Consume full extension name and version, including any optional '_' 576 // between this extension and the next 577 ++I; 578 I += ConsumeLength; 579 if (*I == '_') 580 ++I; 581 } 582 583 // Handle other types of extensions other than the standard 584 // general purpose and standard user-level extensions. 585 // Parse the ISA string containing non-standard user-level 586 // extensions, standard supervisor-level extensions and 587 // non-standard supervisor-level extensions. 588 // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a 589 // canonical order, might have a version number (major, minor) 590 // and are separated by a single underscore '_'. 591 // Set the hardware features for the extensions that are supported. 592 593 // Multi-letter extensions are seperated by a single underscore 594 // as described in RISC-V User-Level ISA V2.2. 595 SmallVector<StringRef, 8> Split; 596 OtherExts.split(Split, '_'); 597 598 SmallVector<StringRef, 8> AllExts; 599 std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"}; 600 auto I = Prefix.begin(); 601 auto E = Prefix.end(); 602 if (Split.size() > 1 || Split[0] != "") { 603 for (StringRef Ext : Split) { 604 if (Ext.empty()) 605 return createStringError(errc::invalid_argument, 606 "extension name missing after separator '_'"); 607 608 StringRef Type = getExtensionType(Ext); 609 StringRef Desc = getExtensionTypeDesc(Ext); 610 auto Pos = findFirstNonVersionCharacter(Ext) + 1; 611 StringRef Name(Ext.substr(0, Pos)); 612 StringRef Vers(Ext.substr(Pos)); 613 614 if (Type.empty()) 615 return createStringError(errc::invalid_argument, 616 "invalid extension prefix '" + Ext + "'"); 617 618 // Check ISA extensions are specified in the canonical order. 619 while (I != E && *I != Type) 620 ++I; 621 622 if (I == E) 623 return createStringError(errc::invalid_argument, 624 "%s not given in canonical order '%s'", 625 Desc.str().c_str(), Ext.str().c_str()); 626 627 if (Name.size() == Type.size()) { 628 return createStringError(errc::invalid_argument, 629 "%s name missing after '%s'", 630 Desc.str().c_str(), Type.str().c_str()); 631 } 632 633 unsigned Major, Minor, ConsumeLength; 634 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, 635 EnableExperimentalExtension, 636 ExperimentalExtensionVersionCheck)) 637 return std::move(E); 638 639 // Check if duplicated extension. 640 if (llvm::is_contained(AllExts, Name)) 641 return createStringError(errc::invalid_argument, "duplicated %s '%s'", 642 Desc.str().c_str(), Name.str().c_str()); 643 644 ISAInfo->addExtension(Name, Major, Minor); 645 // Extension format is correct, keep parsing the extensions. 646 // TODO: Save Type, Name, Major, Minor to avoid parsing them later. 647 AllExts.push_back(Name); 648 } 649 } 650 651 for (auto Ext : AllExts) { 652 if (!isSupportedExtension(Ext)) { 653 StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); 654 return createStringError(errc::invalid_argument, "unsupported %s '%s'", 655 Desc.str().c_str(), Ext.str().c_str()); 656 } 657 } 658 659 ISAInfo->updateImplication(); 660 ISAInfo->updateFLen(); 661 662 if (Error Result = ISAInfo->checkDependency()) 663 return std::move(Result); 664 665 return std::move(ISAInfo); 666 } 667 668 Error RISCVISAInfo::checkDependency() { 669 bool IsRv32 = XLen == 32; 670 bool HasE = Exts.count("e") == 1; 671 bool HasD = Exts.count("d") == 1; 672 bool HasF = Exts.count("f") == 1; 673 674 if (HasE && !IsRv32) 675 return createStringError( 676 errc::invalid_argument, 677 "standard user-level extension 'e' requires 'rv32'"); 678 679 // It's illegal to specify the 'd' (double-precision floating point) 680 // extension without also specifying the 'f' (single precision 681 // floating-point) extension. 682 // TODO: This has been removed in later specs, which specify that D implies F 683 if (HasD && !HasF) 684 return createStringError(errc::invalid_argument, 685 "d requires f extension to also be specified"); 686 687 // Additional dependency checks. 688 // TODO: The 'q' extension requires rv64. 689 // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. 690 691 return Error::success(); 692 } 693 694 static const char *ImpliedExtsV[] = {"zvlsseg"}; 695 static const char *ImpliedExtsZfh[] = {"zfhmin"}; 696 697 struct ImpliedExtsEntry { 698 StringLiteral Name; 699 ArrayRef<const char *> Exts; 700 701 bool operator<(const ImpliedExtsEntry &Other) const { 702 return Name < Other.Name; 703 } 704 705 bool operator<(StringRef Other) const { return Name < Other; } 706 }; 707 708 static constexpr ImpliedExtsEntry ImpliedExts[] = { 709 {{"v"}, {ImpliedExtsV}}, 710 {{"zfh"}, {ImpliedExtsZfh}}, 711 }; 712 713 void RISCVISAInfo::updateImplication() { 714 bool HasE = Exts.count("e") == 1; 715 bool HasI = Exts.count("i") == 1; 716 717 // If not in e extension and i extension does not exist, i extension is 718 // implied 719 if (!HasE && !HasI) { 720 auto Version = findDefaultVersion("i"); 721 addExtension("i", Version->Major, Version->Minor); 722 } 723 724 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name"); 725 for (auto &Ext : Exts) { 726 auto I = llvm::lower_bound(ImpliedExts, Ext.first); 727 if (I != std::end(ImpliedExts) && I->Name == Ext.first) { 728 for (auto &ImpliedExt : I->Exts) { 729 auto Version = findDefaultVersion(ImpliedExt); 730 addExtension(ImpliedExt, Version->Major, Version->Minor); 731 } 732 } 733 } 734 } 735 736 void RISCVISAInfo::updateFLen() { 737 FLen = 0; 738 // TODO: Handle q extension. 739 if (Exts.count("d")) 740 FLen = 64; 741 else if (Exts.count("f")) 742 FLen = 32; 743 } 744 745 std::string RISCVISAInfo::toString() const { 746 std::string Buffer; 747 raw_string_ostream Arch(Buffer); 748 749 Arch << "rv" << XLen; 750 751 ListSeparator LS("_"); 752 for (auto &Ext : Exts) { 753 StringRef ExtName = Ext.first; 754 auto ExtInfo = Ext.second; 755 Arch << LS << ExtName; 756 Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion; 757 } 758 759 return Arch.str(); 760 } 761