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