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