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