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 51 static const RISCVSupportedExtension SupportedExperimentalExtensions[] = { 52 {"v", RISCVExtensionVersion{0, 10}}, 53 {"zba", RISCVExtensionVersion{1, 0}}, 54 {"zbb", RISCVExtensionVersion{1, 0}}, 55 {"zbc", RISCVExtensionVersion{1, 0}}, 56 {"zbe", RISCVExtensionVersion{0, 93}}, 57 {"zbf", RISCVExtensionVersion{0, 93}}, 58 {"zbm", RISCVExtensionVersion{0, 93}}, 59 {"zbp", RISCVExtensionVersion{0, 93}}, 60 {"zbr", RISCVExtensionVersion{0, 93}}, 61 {"zbs", RISCVExtensionVersion{1, 0}}, 62 {"zbt", RISCVExtensionVersion{0, 93}}, 63 64 {"zvamo", RISCVExtensionVersion{0, 10}}, 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 (ExtName == "zvamo") { 290 Features.push_back("+experimental-v"); 291 Features.push_back("+experimental-zvlsseg"); 292 Features.push_back("+experimental-zvamo"); 293 } else if (isExperimentalExtension(ExtName)) { 294 Features.push_back(StrAlloc("+experimental-" + ExtName)); 295 } else { 296 Features.push_back(StrAlloc("+" + ExtName)); 297 } 298 } 299 } 300 301 // Extensions may have a version number, and may be separated by 302 // an underscore '_' e.g.: rv32i2_m2. 303 // Version number is divided into major and minor version numbers, 304 // separated by a 'p'. If the minor version is 0 then 'p0' can be 305 // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. 306 static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, 307 unsigned &Minor, unsigned &ConsumeLength, 308 bool EnableExperimentalExtension, 309 bool ExperimentalExtensionVersionCheck) { 310 StringRef MajorStr, MinorStr; 311 Major = 0; 312 Minor = 0; 313 ConsumeLength = 0; 314 MajorStr = In.take_while(isDigit); 315 In = In.substr(MajorStr.size()); 316 317 if (!MajorStr.empty() && In.consume_front("p")) { 318 MinorStr = In.take_while(isDigit); 319 In = In.substr(MajorStr.size() + 1); 320 321 // Expected 'p' to be followed by minor version number. 322 if (MinorStr.empty()) { 323 return createStringError( 324 errc::invalid_argument, 325 "minor version number missing after 'p' for extension '" + Ext + "'"); 326 } 327 } 328 329 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major)) 330 return createStringError( 331 errc::invalid_argument, 332 "Failed to parse major version number for extension '" + Ext + "'"); 333 334 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor)) 335 return createStringError( 336 errc::invalid_argument, 337 "Failed to parse minor version number for extension '" + Ext + "'"); 338 339 ConsumeLength = MajorStr.size(); 340 341 if (!MinorStr.empty()) 342 ConsumeLength += MinorStr.size() + 1 /*'p'*/; 343 344 // Expected multi-character extension with version number to have no 345 // subsequent characters (i.e. must either end string or be followed by 346 // an underscore). 347 if (Ext.size() > 1 && In.size()) { 348 std::string Error = 349 "multi-character extensions must be separated by underscores"; 350 return createStringError(errc::invalid_argument, Error); 351 } 352 353 // If experimental extension, require use of current version number number 354 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { 355 if (!EnableExperimentalExtension) { 356 std::string Error = "requires '-menable-experimental-extensions' for " 357 "experimental extension '" + 358 Ext.str() + "'"; 359 return createStringError(errc::invalid_argument, Error); 360 } 361 362 if (ExperimentalExtensionVersionCheck && 363 (MajorStr.empty() && MinorStr.empty())) { 364 std::string Error = 365 "experimental extension requires explicit version number `" + 366 Ext.str() + "`"; 367 return createStringError(errc::invalid_argument, Error); 368 } 369 370 auto SupportedVers = *ExperimentalExtension; 371 if (ExperimentalExtensionVersionCheck && 372 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) { 373 std::string Error = "unsupported version number " + MajorStr.str(); 374 if (!MinorStr.empty()) 375 Error += "." + MinorStr.str(); 376 Error += " for experimental extension '" + Ext.str() + 377 "'(this compiler supports " + utostr(SupportedVers.Major) + "." + 378 utostr(SupportedVers.Minor) + ")"; 379 return createStringError(errc::invalid_argument, Error); 380 } 381 return Error::success(); 382 } 383 384 // Exception rule for `g`, we don't have clear version scheme for that on 385 // ISA spec. 386 if (Ext == "g") 387 return Error::success(); 388 389 if (MajorStr.empty() && MinorStr.empty()) { 390 if (auto DefaultVersion = findDefaultVersion(Ext)) { 391 Major = DefaultVersion->Major; 392 Minor = DefaultVersion->Minor; 393 } 394 // No matter found or not, return success, assume other place will 395 // verify. 396 return Error::success(); 397 } 398 399 if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor)) 400 return Error::success(); 401 402 std::string Error = "unsupported version number " + std::string(MajorStr); 403 if (!MinorStr.empty()) 404 Error += "." + MinorStr.str(); 405 Error += " for extension '" + Ext.str() + "'"; 406 return createStringError(errc::invalid_argument, Error); 407 } 408 409 llvm::Expected<std::unique_ptr<RISCVISAInfo>> 410 RISCVISAInfo::parseFeatures(unsigned XLen, 411 const std::vector<std::string> &Features) { 412 assert(XLen == 32 || XLen == 64); 413 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 414 415 for (auto &Feature : Features) { 416 StringRef ExtName = Feature; 417 bool Experimental = false; 418 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); 419 bool Add = ExtName[0] == '+'; 420 ExtName = ExtName.drop_front(1); // Drop '+' or '-' 421 Experimental = stripExperimentalPrefix(ExtName); 422 auto ExtensionInfos = Experimental 423 ? makeArrayRef(SupportedExperimentalExtensions) 424 : makeArrayRef(SupportedExtensions); 425 auto ExtensionInfoIterator = 426 llvm::find_if(ExtensionInfos, FindByName(ExtName)); 427 428 // Not all features is related to ISA extension, like `relax` or 429 // `save-restore`, skip those feature. 430 if (ExtensionInfoIterator == ExtensionInfos.end()) 431 continue; 432 433 if (Add) 434 ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major, 435 ExtensionInfoIterator->Version.Minor); 436 else 437 ISAInfo->Exts.erase(ExtName.str()); 438 } 439 440 ISAInfo->updateImplication(); 441 ISAInfo->updateFLen(); 442 443 if (Error Result = ISAInfo->checkDependency()) 444 return std::move(Result); 445 446 return std::move(ISAInfo); 447 } 448 449 llvm::Expected<std::unique_ptr<RISCVISAInfo>> 450 RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, 451 bool ExperimentalExtensionVersionCheck) { 452 // RISC-V ISA strings must be lowercase. 453 if (llvm::any_of(Arch, isupper)) { 454 return createStringError(errc::invalid_argument, 455 "string must be lowercase"); 456 } 457 458 bool HasRV64 = Arch.startswith("rv64"); 459 // ISA string must begin with rv32 or rv64. 460 if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) { 461 return createStringError(errc::invalid_argument, 462 "string must begin with rv32{i,e,g} or rv64{i,g}"); 463 } 464 465 unsigned XLen = HasRV64 ? 64 : 32; 466 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); 467 468 // The canonical order specified in ISA manual. 469 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 470 StringRef StdExts = AllStdExts; 471 char Baseline = Arch[4]; 472 473 // First letter should be 'e', 'i' or 'g'. 474 switch (Baseline) { 475 default: 476 return createStringError(errc::invalid_argument, 477 "first letter should be 'e', 'i' or 'g'"); 478 case 'e': { 479 // Extension 'e' is not allowed in rv64. 480 if (HasRV64) 481 return createStringError( 482 errc::invalid_argument, 483 "standard user-level extension 'e' requires 'rv32'"); 484 break; 485 } 486 case 'i': 487 break; 488 case 'g': 489 // g = imafd 490 StdExts = StdExts.drop_front(4); 491 break; 492 } 493 494 // Skip rvxxx 495 StringRef Exts = Arch.substr(5); 496 497 // Remove multi-letter standard extensions, non-standard extensions and 498 // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes. 499 // Parse them at the end. 500 // Find the very first occurrence of 's', 'x' or 'z'. 501 StringRef OtherExts; 502 size_t Pos = Exts.find_first_of("zsx"); 503 if (Pos != StringRef::npos) { 504 OtherExts = Exts.substr(Pos); 505 Exts = Exts.substr(0, Pos); 506 } 507 508 unsigned Major, Minor, ConsumeLength; 509 if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor, 510 ConsumeLength, EnableExperimentalExtension, 511 ExperimentalExtensionVersionCheck)) 512 return std::move(E); 513 514 if (Baseline == 'g') { 515 // No matter which version is given to `g`, we always set imafd to default 516 // version since the we don't have clear version scheme for that on 517 // ISA spec. 518 for (auto Ext : {"i", "m", "a", "f", "d"}) 519 if (auto Version = findDefaultVersion(Ext)) 520 ISAInfo->addExtension(Ext, Version->Major, Version->Minor); 521 else 522 llvm_unreachable("Default extension version not found?"); 523 } else 524 // Baseline is `i` or `e` 525 ISAInfo->addExtension(std::string(1, Baseline), Major, Minor); 526 527 // Consume the base ISA version number and any '_' between rvxxx and the 528 // first extension 529 Exts = Exts.drop_front(ConsumeLength); 530 Exts.consume_front("_"); 531 532 // TODO: Use version number when setting target features 533 534 auto StdExtsItr = StdExts.begin(); 535 auto StdExtsEnd = StdExts.end(); 536 for (auto I = Exts.begin(), E = Exts.end(); I != E;) { 537 char C = *I; 538 539 // Check ISA extensions are specified in the canonical order. 540 while (StdExtsItr != StdExtsEnd && *StdExtsItr != C) 541 ++StdExtsItr; 542 543 if (StdExtsItr == StdExtsEnd) { 544 // Either c contains a valid extension but it was not given in 545 // canonical order or it is an invalid extension. 546 if (StdExts.contains(C)) { 547 return createStringError( 548 errc::invalid_argument, 549 "standard user-level extension not given in canonical order '%c'", 550 C); 551 } 552 553 return createStringError(errc::invalid_argument, 554 "invalid standard user-level extension '%c'", C); 555 } 556 557 // Move to next char to prevent repeated letter. 558 ++StdExtsItr; 559 560 std::string Next; 561 unsigned Major, Minor, ConsumeLength; 562 if (std::next(I) != E) 563 Next = std::string(std::next(I), E); 564 if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor, 565 ConsumeLength, EnableExperimentalExtension, 566 ExperimentalExtensionVersionCheck)) 567 return std::move(E); 568 569 // The order is OK, then push it into features. 570 // TODO: Use version number when setting target features 571 // Currently LLVM supports only "mafdcbv". 572 StringRef SupportedStandardExtension = "mafdcbv"; 573 if (SupportedStandardExtension.find(C) == StringRef::npos) 574 return createStringError(errc::invalid_argument, 575 "unsupported standard user-level extension '%c'", 576 C); 577 ISAInfo->addExtension(std::string(1, C), Major, Minor); 578 579 // Consume full extension name and version, including any optional '_' 580 // between this extension and the next 581 ++I; 582 I += ConsumeLength; 583 if (*I == '_') 584 ++I; 585 } 586 587 // Handle other types of extensions other than the standard 588 // general purpose and standard user-level extensions. 589 // Parse the ISA string containing non-standard user-level 590 // extensions, standard supervisor-level extensions and 591 // non-standard supervisor-level extensions. 592 // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a 593 // canonical order, might have a version number (major, minor) 594 // and are separated by a single underscore '_'. 595 // Set the hardware features for the extensions that are supported. 596 597 // Multi-letter extensions are seperated by a single underscore 598 // as described in RISC-V User-Level ISA V2.2. 599 SmallVector<StringRef, 8> Split; 600 OtherExts.split(Split, '_'); 601 602 SmallVector<StringRef, 8> AllExts; 603 std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"}; 604 auto I = Prefix.begin(); 605 auto E = Prefix.end(); 606 if (Split.size() > 1 || Split[0] != "") { 607 for (StringRef Ext : Split) { 608 if (Ext.empty()) 609 return createStringError(errc::invalid_argument, 610 "extension name missing after separator '_'"); 611 612 StringRef Type = getExtensionType(Ext); 613 StringRef Desc = getExtensionTypeDesc(Ext); 614 auto Pos = findFirstNonVersionCharacter(Ext) + 1; 615 StringRef Name(Ext.substr(0, Pos)); 616 StringRef Vers(Ext.substr(Pos)); 617 618 if (Type.empty()) 619 return createStringError(errc::invalid_argument, 620 "invalid extension prefix '" + Ext + "'"); 621 622 // Check ISA extensions are specified in the canonical order. 623 while (I != E && *I != Type) 624 ++I; 625 626 if (I == E) 627 return createStringError(errc::invalid_argument, 628 "%s not given in canonical order '%s'", 629 Desc.str().c_str(), Ext.str().c_str()); 630 631 if (Name.size() == Type.size()) { 632 return createStringError(errc::invalid_argument, 633 "%s name missing after '%s'", 634 Desc.str().c_str(), Type.str().c_str()); 635 } 636 637 unsigned Major, Minor, ConsumeLength; 638 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength, 639 EnableExperimentalExtension, 640 ExperimentalExtensionVersionCheck)) 641 return std::move(E); 642 643 // Check if duplicated extension. 644 if (llvm::is_contained(AllExts, Name)) 645 return createStringError(errc::invalid_argument, "duplicated %s '%s'", 646 Desc.str().c_str(), Name.str().c_str()); 647 648 ISAInfo->addExtension(Name, Major, Minor); 649 // Extension format is correct, keep parsing the extensions. 650 // TODO: Save Type, Name, Major, Minor to avoid parsing them later. 651 AllExts.push_back(Name); 652 } 653 } 654 655 for (auto Ext : AllExts) { 656 if (!isSupportedExtension(Ext)) { 657 StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); 658 return createStringError(errc::invalid_argument, "unsupported %s '%s'", 659 Desc.str().c_str(), Ext.str().c_str()); 660 } 661 } 662 663 ISAInfo->updateImplication(); 664 ISAInfo->updateFLen(); 665 666 if (Error Result = ISAInfo->checkDependency()) 667 return std::move(Result); 668 669 return std::move(ISAInfo); 670 } 671 672 Error RISCVISAInfo::checkDependency() { 673 bool IsRv32 = XLen == 32; 674 bool HasE = Exts.count("e") == 1; 675 bool HasD = Exts.count("d") == 1; 676 bool HasF = Exts.count("f") == 1; 677 678 if (HasE && !IsRv32) 679 return createStringError( 680 errc::invalid_argument, 681 "standard user-level extension 'e' requires 'rv32'"); 682 683 // It's illegal to specify the 'd' (double-precision floating point) 684 // extension without also specifying the 'f' (single precision 685 // floating-point) extension. 686 // TODO: This has been removed in later specs, which specify that D implies F 687 if (HasD && !HasF) 688 return createStringError(errc::invalid_argument, 689 "d requires f extension to also be specified"); 690 691 // Additional dependency checks. 692 // TODO: The 'q' extension requires rv64. 693 // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. 694 695 return Error::success(); 696 } 697 698 static const char *ImpliedExtsV[] = {"zvlsseg"}; 699 static const char *ImpliedExtsZfh[] = {"zfhmin"}; 700 701 struct ImpliedExtsEntry { 702 StringLiteral Name; 703 ArrayRef<const char *> Exts; 704 705 bool operator<(const ImpliedExtsEntry &Other) const { 706 return Name < Other.Name; 707 } 708 709 bool operator<(StringRef Other) const { return Name < Other; } 710 }; 711 712 static constexpr ImpliedExtsEntry ImpliedExts[] = { 713 {"v", ImpliedExtsV}, 714 {"zfh", ImpliedExtsZfh}, 715 }; 716 717 void RISCVISAInfo::updateImplication() { 718 bool HasE = Exts.count("e") == 1; 719 bool HasI = Exts.count("i") == 1; 720 721 // If not in e extension and i extension does not exist, i extension is 722 // implied 723 if (!HasE && !HasI) { 724 auto Version = findDefaultVersion("i"); 725 addExtension("i", Version->Major, Version->Minor); 726 } 727 728 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name"); 729 for (auto &Ext : Exts) { 730 auto I = llvm::lower_bound(ImpliedExts, Ext.first); 731 if (I != std::end(ImpliedExts) && I->Name == Ext.first) { 732 for (auto &ImpliedExt : I->Exts) { 733 auto Version = findDefaultVersion(ImpliedExt); 734 addExtension(ImpliedExt, Version->Major, Version->Minor); 735 } 736 } 737 } 738 } 739 740 void RISCVISAInfo::updateFLen() { 741 FLen = 0; 742 // TODO: Handle q extension. 743 if (Exts.count("d")) 744 FLen = 64; 745 else if (Exts.count("f")) 746 FLen = 32; 747 } 748 749 std::string RISCVISAInfo::toString() const { 750 std::string Buffer; 751 raw_string_ostream Arch(Buffer); 752 753 Arch << "rv" << XLen; 754 755 ListSeparator LS("_"); 756 for (auto &Ext : Exts) { 757 StringRef ExtName = Ext.first; 758 auto ExtInfo = Ext.second; 759 Arch << LS << ExtName; 760 Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion; 761 } 762 763 return Arch.str(); 764 } 765