| 1 | //===-- RISCVISAInfo.cpp - RISC-V 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/TargetParser/RISCVISAInfo.h" |
| 10 | #include "llvm/ADT/STLExtras.h" |
| 11 | #include "llvm/ADT/StringExtras.h" |
| 12 | #include "llvm/ADT/StringRef.h" |
| 13 | #include "llvm/Support/Errc.h" |
| 14 | #include "llvm/Support/Error.h" |
| 15 | #include "llvm/Support/raw_ostream.h" |
| 16 | |
| 17 | #include <array> |
| 18 | #include <atomic> |
| 19 | #include <optional> |
| 20 | #include <string> |
| 21 | #include <vector> |
| 22 | |
| 23 | using namespace llvm; |
| 24 | |
| 25 | namespace { |
| 26 | |
| 27 | struct RISCVSupportedExtension { |
| 28 | const char *Name; |
| 29 | /// Supported version. |
| 30 | RISCVISAUtils::ExtensionVersion Version; |
| 31 | |
| 32 | bool operator<(const RISCVSupportedExtension &RHS) const { |
| 33 | return StringRef(Name) < StringRef(RHS.Name); |
| 34 | } |
| 35 | }; |
| 36 | |
| 37 | struct RISCVProfile { |
| 38 | StringLiteral Name; |
| 39 | StringLiteral MArch; |
| 40 | |
| 41 | bool operator<(const RISCVProfile &RHS) const { |
| 42 | return StringRef(Name) < StringRef(RHS.Name); |
| 43 | } |
| 44 | }; |
| 45 | |
| 46 | } // end anonymous namespace |
| 47 | |
| 48 | static const char *RISCVGImplications[] = {"i" , "m" , "a" , "f" , "d" }; |
| 49 | static const char *RISCVGImplicationsZi[] = {"zicsr" , "zifencei" }; |
| 50 | |
| 51 | #define GET_SUPPORTED_EXTENSIONS |
| 52 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
| 53 | |
| 54 | #define GET_SUPPORTED_PROFILES |
| 55 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
| 56 | |
| 57 | static void verifyTables() { |
| 58 | #ifndef NDEBUG |
| 59 | static std::atomic<bool> TableChecked(false); |
| 60 | if (!TableChecked.load(std::memory_order_relaxed)) { |
| 61 | assert(llvm::is_sorted(SupportedExtensions) && |
| 62 | "Extensions are not sorted by name" ); |
| 63 | assert(llvm::is_sorted(SupportedExperimentalExtensions) && |
| 64 | "Experimental extensions are not sorted by name" ); |
| 65 | assert(llvm::is_sorted(SupportedProfiles) && |
| 66 | "Profiles are not sorted by name" ); |
| 67 | assert(llvm::is_sorted(SupportedExperimentalProfiles) && |
| 68 | "Experimental profiles are not sorted by name" ); |
| 69 | TableChecked.store(true, std::memory_order_relaxed); |
| 70 | } |
| 71 | #endif |
| 72 | } |
| 73 | |
| 74 | static void PrintExtension(StringRef Name, StringRef Version, |
| 75 | StringRef Description) { |
| 76 | outs().indent(NumSpaces: 4); |
| 77 | unsigned VersionWidth = Description.empty() ? 0 : 10; |
| 78 | outs() << left_justify(Str: Name, Width: 21) << left_justify(Str: Version, Width: VersionWidth) |
| 79 | << Description << "\n" ; |
| 80 | } |
| 81 | |
| 82 | void RISCVISAInfo::printSupportedExtensions(StringMap<StringRef> &DescMap) { |
| 83 | outs() << "All available -march extensions for RISC-V\n\n" ; |
| 84 | PrintExtension(Name: "Name" , Version: "Version" , Description: (DescMap.empty() ? "" : "Description" )); |
| 85 | |
| 86 | RISCVISAUtils::OrderedExtensionMap ExtMap; |
| 87 | for (const auto &E : SupportedExtensions) |
| 88 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
| 89 | for (const auto &E : ExtMap) { |
| 90 | std::string Version = |
| 91 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
| 92 | PrintExtension(Name: E.first, Version, Description: DescMap[E.first]); |
| 93 | } |
| 94 | |
| 95 | outs() << "\nExperimental extensions\n" ; |
| 96 | ExtMap.clear(); |
| 97 | for (const auto &E : SupportedExperimentalExtensions) |
| 98 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
| 99 | for (const auto &E : ExtMap) { |
| 100 | std::string Version = |
| 101 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
| 102 | PrintExtension(Name: E.first, Version, Description: DescMap["experimental-" + E.first]); |
| 103 | } |
| 104 | |
| 105 | outs() << "\nSupported Profiles\n" ; |
| 106 | for (const auto &P : SupportedProfiles) |
| 107 | outs().indent(NumSpaces: 4) << P.Name << "\n" ; |
| 108 | |
| 109 | outs() << "\nExperimental Profiles\n" ; |
| 110 | for (const auto &P : SupportedExperimentalProfiles) |
| 111 | outs().indent(NumSpaces: 4) << P.Name << "\n" ; |
| 112 | |
| 113 | outs() << "\nUse -march to specify the target's extension.\n" |
| 114 | "For example, clang -march=rv32i_v1p0\n" ; |
| 115 | } |
| 116 | |
| 117 | void RISCVISAInfo::printEnabledExtensions( |
| 118 | bool IsRV64, std::set<StringRef> &EnabledFeatureNames, |
| 119 | StringMap<StringRef> &DescMap) { |
| 120 | outs() << "Extensions enabled for the given RISC-V target\n\n" ; |
| 121 | PrintExtension(Name: "Name" , Version: "Version" , Description: (DescMap.empty() ? "" : "Description" )); |
| 122 | |
| 123 | RISCVISAUtils::OrderedExtensionMap FullExtMap; |
| 124 | RISCVISAUtils::OrderedExtensionMap ExtMap; |
| 125 | for (const auto &E : SupportedExtensions) |
| 126 | if (EnabledFeatureNames.count(x: E.Name) != 0) { |
| 127 | FullExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
| 128 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
| 129 | } |
| 130 | for (const auto &E : ExtMap) { |
| 131 | std::string Version = |
| 132 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
| 133 | PrintExtension(Name: E.first, Version, Description: DescMap[E.first]); |
| 134 | } |
| 135 | |
| 136 | outs() << "\nExperimental extensions\n" ; |
| 137 | ExtMap.clear(); |
| 138 | for (const auto &E : SupportedExperimentalExtensions) { |
| 139 | StringRef Name(E.Name); |
| 140 | if (EnabledFeatureNames.count(x: "experimental-" + Name.str()) != 0) { |
| 141 | FullExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
| 142 | ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor}; |
| 143 | } |
| 144 | } |
| 145 | for (const auto &E : ExtMap) { |
| 146 | std::string Version = |
| 147 | std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor); |
| 148 | PrintExtension(Name: E.first, Version, Description: DescMap["experimental-" + E.first]); |
| 149 | } |
| 150 | |
| 151 | unsigned XLen = IsRV64 ? 64 : 32; |
| 152 | if (auto ISAString = RISCVISAInfo::createFromExtMap(XLen, Exts: FullExtMap)) |
| 153 | outs() << "\nISA String: " << ISAString.get()->toString() << "\n" ; |
| 154 | } |
| 155 | |
| 156 | static bool stripExperimentalPrefix(StringRef &Ext) { |
| 157 | return Ext.consume_front(Prefix: "experimental-" ); |
| 158 | } |
| 159 | |
| 160 | // This function finds the last character that doesn't belong to a version |
| 161 | // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will |
| 162 | // consume [0-9]*p[0-9]* starting from the backward. An extension name will not |
| 163 | // end with a digit or the letter 'p', so this function will parse correctly. |
| 164 | // NOTE: This function is NOT able to take empty strings or strings that only |
| 165 | // have version numbers and no extension name. It assumes the extension name |
| 166 | // will be at least more than one character. |
| 167 | static size_t findLastNonVersionCharacter(StringRef Ext) { |
| 168 | assert(!Ext.empty() && |
| 169 | "Already guarded by if-statement in ::parseArchString" ); |
| 170 | |
| 171 | int Pos = Ext.size() - 1; |
| 172 | while (Pos > 0 && isDigit(C: Ext[Pos])) |
| 173 | Pos--; |
| 174 | if (Pos > 0 && Ext[Pos] == 'p' && isDigit(C: Ext[Pos - 1])) { |
| 175 | Pos--; |
| 176 | while (Pos > 0 && isDigit(C: Ext[Pos])) |
| 177 | Pos--; |
| 178 | } |
| 179 | return Pos; |
| 180 | } |
| 181 | |
| 182 | namespace { |
| 183 | struct LessExtName { |
| 184 | bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) { |
| 185 | return StringRef(LHS.Name) < RHS; |
| 186 | } |
| 187 | bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) { |
| 188 | return LHS < StringRef(RHS.Name); |
| 189 | } |
| 190 | }; |
| 191 | } // namespace |
| 192 | |
| 193 | static std::optional<RISCVISAUtils::ExtensionVersion> |
| 194 | findDefaultVersion(StringRef ExtName) { |
| 195 | // Find default version of an extension. |
| 196 | // TODO: We might set default version based on profile or ISA spec. |
| 197 | for (auto &ExtInfo : {ArrayRef(SupportedExtensions), |
| 198 | ArrayRef(SupportedExperimentalExtensions)}) { |
| 199 | auto I = llvm::lower_bound(Range: ExtInfo, Value&: ExtName, C: LessExtName()); |
| 200 | |
| 201 | if (I == ExtInfo.end() || I->Name != ExtName) |
| 202 | continue; |
| 203 | |
| 204 | return I->Version; |
| 205 | } |
| 206 | return std::nullopt; |
| 207 | } |
| 208 | |
| 209 | static StringRef getExtensionTypeDesc(StringRef Ext) { |
| 210 | if (Ext.starts_with(Prefix: 's')) |
| 211 | return "standard supervisor-level extension" ; |
| 212 | if (Ext.starts_with(Prefix: 'x')) |
| 213 | return "non-standard user-level extension" ; |
| 214 | if (Ext.starts_with(Prefix: 'z')) |
| 215 | return "standard user-level extension" ; |
| 216 | return StringRef(); |
| 217 | } |
| 218 | |
| 219 | static StringRef getExtensionType(StringRef Ext) { |
| 220 | if (Ext.starts_with(Prefix: 's')) |
| 221 | return "s" ; |
| 222 | if (Ext.starts_with(Prefix: 'x')) |
| 223 | return "x" ; |
| 224 | if (Ext.starts_with(Prefix: 'z')) |
| 225 | return "z" ; |
| 226 | return StringRef(); |
| 227 | } |
| 228 | |
| 229 | static std::optional<RISCVISAUtils::ExtensionVersion> |
| 230 | isExperimentalExtension(StringRef Ext) { |
| 231 | auto I = |
| 232 | llvm::lower_bound(Range: SupportedExperimentalExtensions, Value&: Ext, C: LessExtName()); |
| 233 | if (I == std::end(arr: SupportedExperimentalExtensions) || I->Name != Ext) |
| 234 | return std::nullopt; |
| 235 | |
| 236 | return I->Version; |
| 237 | } |
| 238 | |
| 239 | bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) { |
| 240 | bool IsExperimental = stripExperimentalPrefix(Ext); |
| 241 | |
| 242 | ArrayRef<RISCVSupportedExtension> ExtInfo = |
| 243 | IsExperimental ? ArrayRef(SupportedExperimentalExtensions) |
| 244 | : ArrayRef(SupportedExtensions); |
| 245 | |
| 246 | auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName()); |
| 247 | return I != ExtInfo.end() && I->Name == Ext; |
| 248 | } |
| 249 | |
| 250 | bool RISCVISAInfo::isSupportedExtension(StringRef Ext) { |
| 251 | verifyTables(); |
| 252 | |
| 253 | for (auto ExtInfo : {ArrayRef(SupportedExtensions), |
| 254 | ArrayRef(SupportedExperimentalExtensions)}) { |
| 255 | auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName()); |
| 256 | if (I != ExtInfo.end() && I->Name == Ext) |
| 257 | return true; |
| 258 | } |
| 259 | |
| 260 | return false; |
| 261 | } |
| 262 | |
| 263 | bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion, |
| 264 | unsigned MinorVersion) { |
| 265 | for (auto ExtInfo : {ArrayRef(SupportedExtensions), |
| 266 | ArrayRef(SupportedExperimentalExtensions)}) { |
| 267 | auto Range = |
| 268 | std::equal_range(first: ExtInfo.begin(), last: ExtInfo.end(), val: Ext, comp: LessExtName()); |
| 269 | for (auto I = Range.first, E = Range.second; I != E; ++I) |
| 270 | if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion) |
| 271 | return true; |
| 272 | } |
| 273 | |
| 274 | return false; |
| 275 | } |
| 276 | |
| 277 | bool RISCVISAInfo::hasExtension(StringRef Ext) const { |
| 278 | stripExperimentalPrefix(Ext); |
| 279 | |
| 280 | if (!isSupportedExtension(Ext)) |
| 281 | return false; |
| 282 | |
| 283 | return Exts.count(x: Ext.str()) != 0; |
| 284 | } |
| 285 | |
| 286 | std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions, |
| 287 | bool IgnoreUnknown) const { |
| 288 | std::vector<std::string> Features; |
| 289 | for (const auto &[ExtName, _] : Exts) { |
| 290 | // i is a base instruction set, not an extension (see |
| 291 | // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa) |
| 292 | // and is not recognized in clang -cc1 |
| 293 | if (ExtName == "i" ) |
| 294 | continue; |
| 295 | if (IgnoreUnknown && !isSupportedExtension(Ext: ExtName)) |
| 296 | continue; |
| 297 | |
| 298 | if (isExperimentalExtension(Ext: ExtName)) { |
| 299 | Features.push_back(x: (llvm::Twine("+experimental-" ) + ExtName).str()); |
| 300 | } else { |
| 301 | Features.push_back(x: (llvm::Twine("+" ) + ExtName).str()); |
| 302 | } |
| 303 | } |
| 304 | if (AddAllExtensions) { |
| 305 | for (const RISCVSupportedExtension &Ext : SupportedExtensions) { |
| 306 | if (Exts.count(x: Ext.Name)) |
| 307 | continue; |
| 308 | Features.push_back(x: (llvm::Twine("-" ) + Ext.Name).str()); |
| 309 | } |
| 310 | |
| 311 | for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) { |
| 312 | if (Exts.count(x: Ext.Name)) |
| 313 | continue; |
| 314 | Features.push_back(x: (llvm::Twine("-experimental-" ) + Ext.Name).str()); |
| 315 | } |
| 316 | } |
| 317 | return Features; |
| 318 | } |
| 319 | |
| 320 | static Error getError(const Twine &Message) { |
| 321 | return createStringError(EC: errc::invalid_argument, S: Message); |
| 322 | } |
| 323 | |
| 324 | static Error getErrorForInvalidExt(StringRef ExtName) { |
| 325 | if (ExtName.size() == 1) { |
| 326 | return getError(Message: "unsupported standard user-level extension '" + ExtName + |
| 327 | "'" ); |
| 328 | } |
| 329 | return getError(Message: "unsupported " + getExtensionTypeDesc(Ext: ExtName) + " '" + |
| 330 | ExtName + "'" ); |
| 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(F: isDigit); |
| 347 | In = In.substr(Start: MajorStr.size()); |
| 348 | |
| 349 | if (!MajorStr.empty() && In.consume_front(Prefix: "p" )) { |
| 350 | MinorStr = In.take_while(F: isDigit); |
| 351 | In = In.substr(Start: MajorStr.size() + MinorStr.size() - 1); |
| 352 | |
| 353 | // Expected 'p' to be followed by minor version number. |
| 354 | if (MinorStr.empty()) { |
| 355 | return getError(Message: "minor version number missing after 'p' for extension '" + |
| 356 | Ext + "'" ); |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | if (!MajorStr.empty() && MajorStr.getAsInteger(Radix: 10, Result&: Major)) |
| 361 | return getError(Message: "Failed to parse major version number for extension '" + |
| 362 | Ext + "'" ); |
| 363 | |
| 364 | if (!MinorStr.empty() && MinorStr.getAsInteger(Radix: 10, Result&: Minor)) |
| 365 | return getError(Message: "Failed to parse minor version number for extension '" + |
| 366 | Ext + "'" ); |
| 367 | |
| 368 | ConsumeLength = MajorStr.size(); |
| 369 | |
| 370 | if (!MinorStr.empty()) |
| 371 | ConsumeLength += MinorStr.size() + 1 /*'p'*/; |
| 372 | |
| 373 | // Expected multi-character extension with version number to have no |
| 374 | // subsequent characters (i.e. must either end string or be followed by |
| 375 | // an underscore). |
| 376 | if (Ext.size() > 1 && In.size()) |
| 377 | return getError( |
| 378 | Message: "multi-character extensions must be separated by underscores" ); |
| 379 | |
| 380 | // If experimental extension, require use of current version number |
| 381 | if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { |
| 382 | if (!EnableExperimentalExtension) |
| 383 | return getError(Message: "requires '-menable-experimental-extensions' " |
| 384 | "for experimental extension '" + |
| 385 | Ext + "'" ); |
| 386 | |
| 387 | if (ExperimentalExtensionVersionCheck && |
| 388 | (MajorStr.empty() && MinorStr.empty())) |
| 389 | return getError( |
| 390 | Message: "experimental extension requires explicit version number `" + Ext + |
| 391 | "`" ); |
| 392 | |
| 393 | auto SupportedVers = *ExperimentalExtension; |
| 394 | if (ExperimentalExtensionVersionCheck && |
| 395 | (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) { |
| 396 | std::string Error = "unsupported version number " + MajorStr.str(); |
| 397 | if (!MinorStr.empty()) |
| 398 | Error += "." + MinorStr.str(); |
| 399 | Error += " for experimental extension '" + Ext.str() + |
| 400 | "' (this compiler supports " + utostr(X: SupportedVers.Major) + |
| 401 | "." + utostr(X: SupportedVers.Minor) + ")" ; |
| 402 | return getError(Message: Error); |
| 403 | } |
| 404 | return Error::success(); |
| 405 | } |
| 406 | |
| 407 | // Exception rule for `g`, we don't have clear version scheme for that on |
| 408 | // ISA spec. |
| 409 | if (Ext == "g" ) |
| 410 | return Error::success(); |
| 411 | |
| 412 | if (MajorStr.empty() && MinorStr.empty()) { |
| 413 | if (auto DefaultVersion = findDefaultVersion(ExtName: Ext)) { |
| 414 | Major = DefaultVersion->Major; |
| 415 | Minor = DefaultVersion->Minor; |
| 416 | } |
| 417 | // No matter found or not, return success, assume other place will |
| 418 | // verify. |
| 419 | return Error::success(); |
| 420 | } |
| 421 | |
| 422 | if (RISCVISAInfo::isSupportedExtension(Ext, MajorVersion: Major, MinorVersion: Minor)) |
| 423 | return Error::success(); |
| 424 | |
| 425 | if (!RISCVISAInfo::isSupportedExtension(Ext)) |
| 426 | return getErrorForInvalidExt(ExtName: Ext); |
| 427 | |
| 428 | std::string Error = "unsupported version number " + MajorStr.str(); |
| 429 | if (!MinorStr.empty()) |
| 430 | Error += "." + MinorStr.str(); |
| 431 | Error += " for extension '" + Ext.str() + "'" ; |
| 432 | return getError(Message: Error); |
| 433 | } |
| 434 | |
| 435 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
| 436 | RISCVISAInfo::createFromExtMap(unsigned XLen, |
| 437 | const RISCVISAUtils::OrderedExtensionMap &Exts) { |
| 438 | assert(XLen == 32 || XLen == 64); |
| 439 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
| 440 | |
| 441 | ISAInfo->Exts = Exts; |
| 442 | |
| 443 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
| 444 | } |
| 445 | |
| 446 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
| 447 | RISCVISAInfo::parseFeatures(unsigned XLen, |
| 448 | const std::vector<std::string> &Features) { |
| 449 | assert(XLen == 32 || XLen == 64); |
| 450 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
| 451 | |
| 452 | for (StringRef ExtName : Features) { |
| 453 | assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); |
| 454 | bool Add = ExtName[0] == '+'; |
| 455 | ExtName = ExtName.drop_front(N: 1); // Drop '+' or '-' |
| 456 | bool Experimental = stripExperimentalPrefix(Ext&: ExtName); |
| 457 | auto ExtensionInfos = Experimental |
| 458 | ? ArrayRef(SupportedExperimentalExtensions) |
| 459 | : ArrayRef(SupportedExtensions); |
| 460 | auto ExtensionInfoIterator = |
| 461 | llvm::lower_bound(Range&: ExtensionInfos, Value&: ExtName, C: LessExtName()); |
| 462 | |
| 463 | // Not all features is related to ISA extension, like `relax` or |
| 464 | // `save-restore`, skip those feature. |
| 465 | if (ExtensionInfoIterator == ExtensionInfos.end() || |
| 466 | ExtensionInfoIterator->Name != ExtName) |
| 467 | continue; |
| 468 | |
| 469 | if (Add) |
| 470 | ISAInfo->Exts[ExtName.str()] = ExtensionInfoIterator->Version; |
| 471 | else |
| 472 | ISAInfo->Exts.erase(x: ExtName.str()); |
| 473 | } |
| 474 | |
| 475 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
| 476 | } |
| 477 | |
| 478 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
| 479 | RISCVISAInfo::parseNormalizedArchString(StringRef Arch) { |
| 480 | // RISC-V ISA strings must be [a-z0-9_] |
| 481 | if (!llvm::all_of( |
| 482 | Range&: Arch, P: [](char C) { return isDigit(C) || isLower(C) || C == '_'; })) |
| 483 | return getError(Message: "string may only contain [a-z0-9_]" ); |
| 484 | |
| 485 | // Must start with a valid base ISA name. |
| 486 | unsigned XLen = 0; |
| 487 | if (Arch.consume_front(Prefix: "rv32" )) |
| 488 | XLen = 32; |
| 489 | else if (Arch.consume_front(Prefix: "rv64" )) |
| 490 | XLen = 64; |
| 491 | |
| 492 | if (XLen == 0 || Arch.empty() || (Arch[0] != 'i' && Arch[0] != 'e')) |
| 493 | return getError(Message: "arch string must begin with valid base ISA" ); |
| 494 | |
| 495 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
| 496 | |
| 497 | // Each extension is of the form ${name}${major_version}p${minor_version} |
| 498 | // and separated by _. Split by _ and then extract the name and version |
| 499 | // information for each extension. |
| 500 | while (!Arch.empty()) { |
| 501 | if (Arch[0] == '_') { |
| 502 | if (Arch.size() == 1 || Arch[1] == '_') |
| 503 | return getError(Message: "extension name missing after separator '_'" ); |
| 504 | Arch = Arch.drop_front(); |
| 505 | } |
| 506 | |
| 507 | size_t Idx = Arch.find(C: '_'); |
| 508 | StringRef Ext = Arch.slice(Start: 0, End: Idx); |
| 509 | Arch = Arch.substr(Start: Idx); |
| 510 | |
| 511 | StringRef Prefix, MinorVersionStr; |
| 512 | std::tie(args&: Prefix, args&: MinorVersionStr) = Ext.rsplit(Separator: 'p'); |
| 513 | if (MinorVersionStr.empty()) |
| 514 | return getError(Message: "extension lacks version in expected format" ); |
| 515 | unsigned MajorVersion, MinorVersion; |
| 516 | if (MinorVersionStr.getAsInteger(Radix: 10, Result&: MinorVersion)) |
| 517 | return getError(Message: "failed to parse minor version number" ); |
| 518 | |
| 519 | // Split Prefix into the extension name and the major version number |
| 520 | // (the trailing digits of Prefix). |
| 521 | size_t VersionStart = Prefix.size(); |
| 522 | while (VersionStart != 0) { |
| 523 | if (!isDigit(C: Prefix[VersionStart - 1])) |
| 524 | break; |
| 525 | --VersionStart; |
| 526 | } |
| 527 | if (VersionStart == Prefix.size()) |
| 528 | return getError(Message: "extension lacks version in expected format" ); |
| 529 | |
| 530 | if (VersionStart == 0) |
| 531 | return getError(Message: "missing extension name" ); |
| 532 | |
| 533 | StringRef ExtName = Prefix.slice(Start: 0, End: VersionStart); |
| 534 | StringRef MajorVersionStr = Prefix.substr(Start: VersionStart); |
| 535 | if (MajorVersionStr.getAsInteger(Radix: 10, Result&: MajorVersion)) |
| 536 | return getError(Message: "failed to parse major version number" ); |
| 537 | |
| 538 | if ((ExtName[0] == 'z' || ExtName[0] == 's' || ExtName[0] == 'x') && |
| 539 | (ExtName.size() == 1 || isDigit(C: ExtName[1]))) |
| 540 | return getError(Message: "'" + Twine(ExtName[0]) + |
| 541 | "' must be followed by a letter" ); |
| 542 | |
| 543 | if (!ISAInfo->Exts |
| 544 | .emplace( |
| 545 | args: ExtName.str(), |
| 546 | args: RISCVISAUtils::ExtensionVersion{.Major: MajorVersion, .Minor: MinorVersion}) |
| 547 | .second) |
| 548 | return getError(Message: "duplicate extension '" + ExtName + "'" ); |
| 549 | } |
| 550 | ISAInfo->updateImpliedLengths(); |
| 551 | return std::move(ISAInfo); |
| 552 | } |
| 553 | |
| 554 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
| 555 | RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension, |
| 556 | bool ExperimentalExtensionVersionCheck) { |
| 557 | // RISC-V ISA strings must be [a-z0-9_] |
| 558 | if (!llvm::all_of( |
| 559 | Range&: Arch, P: [](char C) { return isDigit(C) || isLower(C) || C == '_'; })) |
| 560 | return getError(Message: "string may only contain [a-z0-9_]" ); |
| 561 | |
| 562 | // ISA string must begin with rv32, rv64, or a profile. |
| 563 | unsigned XLen = 0; |
| 564 | if (Arch.consume_front(Prefix: "rv32" )) { |
| 565 | XLen = 32; |
| 566 | } else if (Arch.consume_front(Prefix: "rv64" )) { |
| 567 | XLen = 64; |
| 568 | } else { |
| 569 | // Try parsing as a profile. |
| 570 | auto ProfileCmp = [](StringRef Arch, const RISCVProfile &Profile) { |
| 571 | return Arch < Profile.Name; |
| 572 | }; |
| 573 | auto I = llvm::upper_bound(Range: SupportedProfiles, Value&: Arch, C: ProfileCmp); |
| 574 | bool FoundProfile = I != std::begin(arr: SupportedProfiles) && |
| 575 | Arch.starts_with(Prefix: std::prev(x: I)->Name); |
| 576 | if (!FoundProfile) { |
| 577 | I = llvm::upper_bound(Range: SupportedExperimentalProfiles, Value&: Arch, C: ProfileCmp); |
| 578 | FoundProfile = (I != std::begin(arr: SupportedExperimentalProfiles) && |
| 579 | Arch.starts_with(Prefix: std::prev(x: I)->Name)); |
| 580 | if (FoundProfile && !EnableExperimentalExtension) { |
| 581 | return getError(Message: "requires '-menable-experimental-extensions' " |
| 582 | "for profile '" + |
| 583 | std::prev(x: I)->Name + "'" ); |
| 584 | } |
| 585 | } |
| 586 | if (FoundProfile) { |
| 587 | --I; |
| 588 | std::string NewArch = I->MArch.str(); |
| 589 | StringRef ArchWithoutProfile = Arch.drop_front(N: I->Name.size()); |
| 590 | if (!ArchWithoutProfile.empty()) { |
| 591 | if (ArchWithoutProfile.front() != '_') |
| 592 | return getError(Message: "additional extensions must be after separator '_'" ); |
| 593 | NewArch += ArchWithoutProfile.str(); |
| 594 | } |
| 595 | return parseArchString(Arch: NewArch, EnableExperimentalExtension, |
| 596 | ExperimentalExtensionVersionCheck); |
| 597 | } |
| 598 | } |
| 599 | |
| 600 | if (XLen == 0 || Arch.empty()) |
| 601 | return getError( |
| 602 | Message: "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported " |
| 603 | "profile name" ); |
| 604 | |
| 605 | std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen)); |
| 606 | |
| 607 | // The canonical order specified in ISA manual. |
| 608 | // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 |
| 609 | char Baseline = Arch.front(); |
| 610 | // Skip the baseline. |
| 611 | Arch = Arch.drop_front(); |
| 612 | |
| 613 | unsigned Major, Minor, ConsumeLength; |
| 614 | |
| 615 | // First letter should be 'e', 'i' or 'g'. |
| 616 | switch (Baseline) { |
| 617 | default: |
| 618 | return getError(Message: "first letter after \'rv" + Twine(XLen) + |
| 619 | "\' should be 'e', 'i' or 'g'" ); |
| 620 | case 'e': |
| 621 | case 'i': |
| 622 | // Baseline is `i` or `e` |
| 623 | if (auto E = getExtensionVersion( |
| 624 | Ext: StringRef(&Baseline, 1), In: Arch, Major, Minor, ConsumeLength, |
| 625 | EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) |
| 626 | return std::move(E); |
| 627 | |
| 628 | ISAInfo->Exts[std::string(1, Baseline)] = {.Major: Major, .Minor: Minor}; |
| 629 | break; |
| 630 | case 'g': |
| 631 | // g expands to extensions in RISCVGImplications. |
| 632 | if (!Arch.empty() && isDigit(C: Arch.front())) |
| 633 | return getError(Message: "version not supported for 'g'" ); |
| 634 | |
| 635 | // Versions for g are disallowed, and this was checked for previously. |
| 636 | ConsumeLength = 0; |
| 637 | |
| 638 | // No matter which version is given to `g`, we always set imafd to default |
| 639 | // version since the we don't have clear version scheme for that on |
| 640 | // ISA spec. |
| 641 | for (const char *Ext : RISCVGImplications) { |
| 642 | auto Version = findDefaultVersion(ExtName: Ext); |
| 643 | assert(Version && "Default extension version not found?" ); |
| 644 | ISAInfo->Exts[std::string(Ext)] = {.Major: Version->Major, .Minor: Version->Minor}; |
| 645 | } |
| 646 | break; |
| 647 | } |
| 648 | |
| 649 | // Consume the base ISA version number and any '_' between rvxxx and the |
| 650 | // first extension |
| 651 | Arch = Arch.drop_front(N: ConsumeLength); |
| 652 | |
| 653 | while (!Arch.empty()) { |
| 654 | if (Arch.front() == '_') { |
| 655 | if (Arch.size() == 1 || Arch[1] == '_') |
| 656 | return getError(Message: "extension name missing after separator '_'" ); |
| 657 | Arch = Arch.drop_front(); |
| 658 | } |
| 659 | |
| 660 | size_t Idx = Arch.find(C: '_'); |
| 661 | StringRef Ext = Arch.slice(Start: 0, End: Idx); |
| 662 | Arch = Arch.substr(Start: Idx); |
| 663 | |
| 664 | do { |
| 665 | StringRef Name, Vers, Desc; |
| 666 | if (RISCVISAUtils::AllStdExts.contains(C: Ext.front())) { |
| 667 | Name = Ext.take_front(N: 1); |
| 668 | Ext = Ext.drop_front(); |
| 669 | Vers = Ext; |
| 670 | Desc = "standard user-level extension" ; |
| 671 | } else if (Ext.front() == 'z' || Ext.front() == 's' || |
| 672 | Ext.front() == 'x') { |
| 673 | // Handle other types of extensions other than the standard |
| 674 | // general purpose and standard user-level extensions. |
| 675 | // Parse the ISA string containing non-standard user-level |
| 676 | // extensions, standard supervisor-level extensions and |
| 677 | // non-standard supervisor-level extensions. |
| 678 | // These extensions start with 'z', 's', 'x' prefixes, might have a |
| 679 | // version number (major, minor) and are separated by a single |
| 680 | // underscore '_'. We do not enforce a canonical order for them. |
| 681 | StringRef Type = getExtensionType(Ext); |
| 682 | Desc = getExtensionTypeDesc(Ext); |
| 683 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
| 684 | Name = Ext.substr(Start: 0, N: Pos); |
| 685 | Vers = Ext.substr(Start: Pos); |
| 686 | Ext = StringRef(); |
| 687 | |
| 688 | assert(!Type.empty() && "Empty type?" ); |
| 689 | if (Name.size() == Type.size()) |
| 690 | return getError(Message: Desc + " name missing after '" + Type + "'" ); |
| 691 | } else { |
| 692 | return getError(Message: "invalid standard user-level extension '" + |
| 693 | Twine(Ext.front()) + "'" ); |
| 694 | } |
| 695 | |
| 696 | unsigned Major, Minor, ConsumeLength; |
| 697 | if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength, |
| 698 | EnableExperimentalExtension, |
| 699 | ExperimentalExtensionVersionCheck)) |
| 700 | return E; |
| 701 | |
| 702 | if (Name.size() == 1) |
| 703 | Ext = Ext.substr(Start: ConsumeLength); |
| 704 | |
| 705 | if (!RISCVISAInfo::isSupportedExtension(Ext: Name)) |
| 706 | return getErrorForInvalidExt(ExtName: Name); |
| 707 | |
| 708 | // Insert and error for duplicates. |
| 709 | if (!ISAInfo->Exts |
| 710 | .emplace(args: Name.str(), |
| 711 | args: RISCVISAUtils::ExtensionVersion{.Major: Major, .Minor: Minor}) |
| 712 | .second) |
| 713 | return getError(Message: "duplicated " + Desc + " '" + Name + "'" ); |
| 714 | |
| 715 | } while (!Ext.empty()); |
| 716 | } |
| 717 | |
| 718 | // We add Zicsr/Zifenci as final to allow duplicated "zicsr"/"zifencei" like |
| 719 | // "rv64g_zicsr_zifencei". |
| 720 | if (Baseline == 'g') { |
| 721 | for (const char *Ext : RISCVGImplicationsZi) { |
| 722 | if (ISAInfo->Exts.count(x: Ext)) |
| 723 | continue; |
| 724 | |
| 725 | auto Version = findDefaultVersion(ExtName: Ext); |
| 726 | assert(Version && "Default extension version not found?" ); |
| 727 | ISAInfo->Exts[std::string(Ext)] = {.Major: Version->Major, .Minor: Version->Minor}; |
| 728 | } |
| 729 | } |
| 730 | |
| 731 | return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo)); |
| 732 | } |
| 733 | |
| 734 | static Error getIncompatibleError(StringRef Ext1, StringRef Ext2) { |
| 735 | return getError(Message: "'" + Ext1 + "' and '" + Ext2 + |
| 736 | "' extensions are incompatible" ); |
| 737 | } |
| 738 | |
| 739 | static Error getExtensionRequiresError(StringRef Ext, StringRef ReqExt) { |
| 740 | return getError(Message: "'" + Ext + "' requires '" + ReqExt + |
| 741 | "' extension to also be specified" ); |
| 742 | } |
| 743 | |
| 744 | Error RISCVISAInfo::checkDependency() { |
| 745 | bool HasE = Exts.count(x: "e" ) != 0; |
| 746 | bool HasI = Exts.count(x: "i" ) != 0; |
| 747 | bool HasC = Exts.count(x: "c" ) != 0; |
| 748 | bool HasF = Exts.count(x: "f" ) != 0; |
| 749 | bool HasD = Exts.count(x: "d" ) != 0; |
| 750 | bool HasZfinx = Exts.count(x: "zfinx" ) != 0; |
| 751 | bool HasVector = Exts.count(x: "zve32x" ) != 0; |
| 752 | bool HasZvl = MinVLen != 0; |
| 753 | bool HasZcmp = Exts.count(x: "zcmp" ) != 0; |
| 754 | bool HasXqccmp = Exts.count(x: "xqccmp" ) != 0; |
| 755 | |
| 756 | static constexpr StringLiteral XqciExts[] = { |
| 757 | {"xqcia" }, {"xqciac" }, {"xqcibi" }, {"xqcibm" }, {"xqcicli" }, |
| 758 | {"xqcicm" }, {"xqcics" }, {"xqcicsr" }, {"xqciint" }, {"xqciio" }, |
| 759 | {"xqcilb" }, {"xqcili" }, {"xqcilia" }, {"xqcilo" }, {"xqcilsm" }, |
| 760 | {"xqcisim" }, {"xqcisls" }, {"xqcisync" }}; |
| 761 | static constexpr StringLiteral ZcdOverlaps[] = { |
| 762 | {"zcmt" }, {"zcmp" }, {"xqccmp" }, {"xqciac" }, {"xqcicm" }}; |
| 763 | |
| 764 | if (HasI && HasE) |
| 765 | return getIncompatibleError(Ext1: "i" , Ext2: "e" ); |
| 766 | |
| 767 | if (HasF && HasZfinx) |
| 768 | return getIncompatibleError(Ext1: "f" , Ext2: "zfinx" ); |
| 769 | |
| 770 | if (HasZvl && !HasVector) |
| 771 | return getExtensionRequiresError(Ext: "zvl*b" , ReqExt: "v' or 'zve*" ); |
| 772 | |
| 773 | if (HasD && (HasC || Exts.count(x: "zcd" ))) |
| 774 | for (auto Ext : ZcdOverlaps) |
| 775 | if (Exts.count(x: Ext.str())) |
| 776 | return getError( |
| 777 | Message: Twine("'" ) + Ext + "' extension is incompatible with '" + |
| 778 | (HasC ? "c" : "zcd" ) + "' extension when 'd' extension is enabled" ); |
| 779 | |
| 780 | if (XLen != 32 && Exts.count(x: "zcf" )) |
| 781 | return getError(Message: "'zcf' is only supported for 'rv32'" ); |
| 782 | |
| 783 | if (Exts.count(x: "xwchc" ) != 0) { |
| 784 | if (XLen != 32) |
| 785 | return getError(Message: "'xwchc' is only supported for 'rv32'" ); |
| 786 | |
| 787 | if (HasD) |
| 788 | return getIncompatibleError(Ext1: "d" , Ext2: "xwchc" ); |
| 789 | |
| 790 | if (Exts.count(x: "zcb" ) != 0) |
| 791 | return getIncompatibleError(Ext1: "xwchc" , Ext2: "zcb" ); |
| 792 | } |
| 793 | |
| 794 | if (Exts.count(x: "zclsd" ) != 0) { |
| 795 | if (XLen != 32) |
| 796 | return getError(Message: "'zclsd' is only supported for 'rv32'" ); |
| 797 | |
| 798 | if (Exts.count(x: "zcf" ) != 0) |
| 799 | return getIncompatibleError(Ext1: "zclsd" , Ext2: "zcf" ); |
| 800 | } |
| 801 | |
| 802 | if (XLen != 32 && Exts.count(x: "zilsd" ) != 0) |
| 803 | return getError(Message: "'zilsd' is only supported for 'rv32'" ); |
| 804 | |
| 805 | for (auto Ext : XqciExts) |
| 806 | if (Exts.count(x: Ext.str()) && (XLen != 32)) |
| 807 | return getError(Message: "'" + Twine(Ext) + "'" + " is only supported for 'rv32'" ); |
| 808 | |
| 809 | if (HasZcmp && HasXqccmp) |
| 810 | return getIncompatibleError(Ext1: "zcmp" , Ext2: "xqccmp" ); |
| 811 | |
| 812 | return Error::success(); |
| 813 | } |
| 814 | |
| 815 | struct ImpliedExtsEntry { |
| 816 | StringLiteral Name; |
| 817 | const char *ImpliedExt; |
| 818 | |
| 819 | bool operator<(const ImpliedExtsEntry &Other) const { |
| 820 | return Name < Other.Name; |
| 821 | } |
| 822 | }; |
| 823 | |
| 824 | static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) { |
| 825 | return LHS.Name < RHS; |
| 826 | } |
| 827 | |
| 828 | static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) { |
| 829 | return LHS < RHS.Name; |
| 830 | } |
| 831 | |
| 832 | #define GET_IMPLIED_EXTENSIONS |
| 833 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
| 834 | |
| 835 | void RISCVISAInfo::updateImplication() { |
| 836 | bool HasE = Exts.count(x: "e" ) != 0; |
| 837 | bool HasI = Exts.count(x: "i" ) != 0; |
| 838 | |
| 839 | // If not in e extension and i extension does not exist, i extension is |
| 840 | // implied |
| 841 | if (!HasE && !HasI) { |
| 842 | auto Version = findDefaultVersion(ExtName: "i" ); |
| 843 | Exts["i" ] = *Version; |
| 844 | } |
| 845 | |
| 846 | if (HasE && HasI) |
| 847 | Exts.erase(x: "i" ); |
| 848 | |
| 849 | assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name" ); |
| 850 | |
| 851 | // This loop may execute over 1 iteration since implication can be layered |
| 852 | // Exits loop if no more implication is applied |
| 853 | SmallVector<StringRef, 16> WorkList; |
| 854 | for (auto const &Ext : Exts) |
| 855 | WorkList.push_back(Elt: Ext.first); |
| 856 | |
| 857 | while (!WorkList.empty()) { |
| 858 | StringRef ExtName = WorkList.pop_back_val(); |
| 859 | auto Range = std::equal_range(first: std::begin(arr: ImpliedExts), |
| 860 | last: std::end(arr: ImpliedExts), val: ExtName); |
| 861 | std::for_each(first: Range.first, last: Range.second, |
| 862 | f: [&](const ImpliedExtsEntry &Implied) { |
| 863 | const char *ImpliedExt = Implied.ImpliedExt; |
| 864 | auto [It, Inserted] = Exts.try_emplace(k: ImpliedExt); |
| 865 | if (!Inserted) |
| 866 | return; |
| 867 | auto Version = findDefaultVersion(ExtName: ImpliedExt); |
| 868 | It->second = *Version; |
| 869 | WorkList.push_back(Elt: ImpliedExt); |
| 870 | }); |
| 871 | } |
| 872 | |
| 873 | // Add Zcd if C and D are enabled. |
| 874 | if (Exts.count(x: "c" ) && Exts.count(x: "d" ) && !Exts.count(x: "zcd" )) { |
| 875 | auto Version = findDefaultVersion(ExtName: "zcd" ); |
| 876 | Exts["zcd" ] = *Version; |
| 877 | } |
| 878 | |
| 879 | // Add Zcf if C and F are enabled on RV32. |
| 880 | if (XLen == 32 && Exts.count(x: "c" ) && Exts.count(x: "f" ) && !Exts.count(x: "zcf" )) { |
| 881 | auto Version = findDefaultVersion(ExtName: "zcf" ); |
| 882 | Exts["zcf" ] = *Version; |
| 883 | } |
| 884 | |
| 885 | // Add Zcf if Zce and F are enabled on RV32. |
| 886 | if (XLen == 32 && Exts.count(x: "zce" ) && Exts.count(x: "f" ) && |
| 887 | !Exts.count(x: "zcf" )) { |
| 888 | auto Version = findDefaultVersion(ExtName: "zcf" ); |
| 889 | Exts["zcf" ] = *Version; |
| 890 | } |
| 891 | } |
| 892 | |
| 893 | static constexpr StringLiteral CombineIntoExts[] = { |
| 894 | {"b" }, {"zk" }, {"zkn" }, {"zks" }, {"zvkn" }, |
| 895 | {"zvknc" }, {"zvkng" }, {"zvks" }, {"zvksc" }, {"zvksg" }, |
| 896 | }; |
| 897 | |
| 898 | void RISCVISAInfo::updateCombination() { |
| 899 | bool MadeChange = false; |
| 900 | do { |
| 901 | MadeChange = false; |
| 902 | for (StringRef CombineExt : CombineIntoExts) { |
| 903 | if (Exts.count(x: CombineExt.str())) |
| 904 | continue; |
| 905 | |
| 906 | // Look up the extension in the ImpliesExt table to find everything it |
| 907 | // depends on. |
| 908 | auto Range = std::equal_range(first: std::begin(arr: ImpliedExts), |
| 909 | last: std::end(arr: ImpliedExts), val: CombineExt); |
| 910 | bool HasAllRequiredFeatures = std::all_of( |
| 911 | first: Range.first, last: Range.second, pred: [&](const ImpliedExtsEntry &Implied) { |
| 912 | return Exts.count(x: Implied.ImpliedExt); |
| 913 | }); |
| 914 | if (HasAllRequiredFeatures) { |
| 915 | auto Version = findDefaultVersion(ExtName: CombineExt); |
| 916 | Exts[CombineExt.str()] = *Version; |
| 917 | MadeChange = true; |
| 918 | } |
| 919 | } |
| 920 | } while (MadeChange); |
| 921 | } |
| 922 | |
| 923 | void RISCVISAInfo::updateImpliedLengths() { |
| 924 | assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 && |
| 925 | "Expected lengths to be initialied to zero" ); |
| 926 | |
| 927 | if (Exts.count(x: "q" )) |
| 928 | FLen = 128; |
| 929 | else if (Exts.count(x: "d" )) |
| 930 | FLen = 64; |
| 931 | else if (Exts.count(x: "f" )) |
| 932 | FLen = 32; |
| 933 | |
| 934 | if (Exts.count(x: "v" )) { |
| 935 | MaxELenFp = std::max(a: MaxELenFp, b: 64u); |
| 936 | MaxELen = std::max(a: MaxELen, b: 64u); |
| 937 | } |
| 938 | |
| 939 | for (auto const &Ext : Exts) { |
| 940 | StringRef ExtName = Ext.first; |
| 941 | // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d) |
| 942 | if (ExtName.consume_front(Prefix: "zve" )) { |
| 943 | unsigned ZveELen; |
| 944 | if (ExtName.consumeInteger(Radix: 10, Result&: ZveELen)) |
| 945 | continue; |
| 946 | |
| 947 | if (ExtName == "f" ) |
| 948 | MaxELenFp = std::max(a: MaxELenFp, b: 32u); |
| 949 | else if (ExtName == "d" ) |
| 950 | MaxELenFp = std::max(a: MaxELenFp, b: 64u); |
| 951 | else if (ExtName != "x" ) |
| 952 | continue; |
| 953 | |
| 954 | MaxELen = std::max(a: MaxELen, b: ZveELen); |
| 955 | continue; |
| 956 | } |
| 957 | |
| 958 | // Infer MinVLen from zvl*b. |
| 959 | if (ExtName.consume_front(Prefix: "zvl" )) { |
| 960 | unsigned ZvlLen; |
| 961 | if (ExtName.consumeInteger(Radix: 10, Result&: ZvlLen)) |
| 962 | continue; |
| 963 | |
| 964 | if (ExtName != "b" ) |
| 965 | continue; |
| 966 | |
| 967 | MinVLen = std::max(a: MinVLen, b: ZvlLen); |
| 968 | continue; |
| 969 | } |
| 970 | } |
| 971 | } |
| 972 | |
| 973 | std::string RISCVISAInfo::toString() const { |
| 974 | std::string Buffer; |
| 975 | raw_string_ostream Arch(Buffer); |
| 976 | |
| 977 | Arch << "rv" << XLen; |
| 978 | |
| 979 | ListSeparator LS("_" ); |
| 980 | for (auto const &Ext : Exts) { |
| 981 | StringRef ExtName = Ext.first; |
| 982 | auto ExtInfo = Ext.second; |
| 983 | Arch << LS << ExtName; |
| 984 | Arch << ExtInfo.Major << "p" << ExtInfo.Minor; |
| 985 | } |
| 986 | |
| 987 | return Arch.str(); |
| 988 | } |
| 989 | |
| 990 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
| 991 | RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) { |
| 992 | ISAInfo->updateImplication(); |
| 993 | ISAInfo->updateCombination(); |
| 994 | ISAInfo->updateImpliedLengths(); |
| 995 | |
| 996 | if (Error Result = ISAInfo->checkDependency()) |
| 997 | return std::move(Result); |
| 998 | return std::move(ISAInfo); |
| 999 | } |
| 1000 | |
| 1001 | StringRef RISCVISAInfo::computeDefaultABI() const { |
| 1002 | if (XLen == 32) { |
| 1003 | if (Exts.count(x: "e" )) |
| 1004 | return "ilp32e" ; |
| 1005 | if (Exts.count(x: "d" )) |
| 1006 | return "ilp32d" ; |
| 1007 | if (Exts.count(x: "f" )) |
| 1008 | return "ilp32f" ; |
| 1009 | return "ilp32" ; |
| 1010 | } else if (XLen == 64) { |
| 1011 | if (Exts.count(x: "e" )) |
| 1012 | return "lp64e" ; |
| 1013 | if (Exts.count(x: "d" )) |
| 1014 | return "lp64d" ; |
| 1015 | if (Exts.count(x: "f" )) |
| 1016 | return "lp64f" ; |
| 1017 | return "lp64" ; |
| 1018 | } |
| 1019 | llvm_unreachable("Invalid XLEN" ); |
| 1020 | } |
| 1021 | |
| 1022 | bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) { |
| 1023 | if (Ext.empty()) |
| 1024 | return false; |
| 1025 | |
| 1026 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
| 1027 | StringRef Name = Ext.substr(Start: 0, N: Pos); |
| 1028 | StringRef Vers = Ext.substr(Start: Pos); |
| 1029 | if (Vers.empty()) |
| 1030 | return false; |
| 1031 | |
| 1032 | unsigned Major, Minor, ConsumeLength; |
| 1033 | if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength, |
| 1034 | EnableExperimentalExtension: true, ExperimentalExtensionVersionCheck: true)) { |
| 1035 | consumeError(Err: std::move(E)); |
| 1036 | return false; |
| 1037 | } |
| 1038 | |
| 1039 | return true; |
| 1040 | } |
| 1041 | |
| 1042 | std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) { |
| 1043 | if (Ext.empty()) |
| 1044 | return std::string(); |
| 1045 | |
| 1046 | auto Pos = findLastNonVersionCharacter(Ext) + 1; |
| 1047 | StringRef Name = Ext.substr(Start: 0, N: Pos); |
| 1048 | |
| 1049 | if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext)) |
| 1050 | return std::string(); |
| 1051 | |
| 1052 | if (!isSupportedExtension(Ext: Name)) |
| 1053 | return std::string(); |
| 1054 | |
| 1055 | return isExperimentalExtension(Ext: Name) ? "experimental-" + Name.str() |
| 1056 | : Name.str(); |
| 1057 | } |
| 1058 | |
| 1059 | struct RISCVExtBit { |
| 1060 | const StringLiteral ext; |
| 1061 | uint8_t groupid; |
| 1062 | uint8_t bitpos; |
| 1063 | }; |
| 1064 | |
| 1065 | struct RISCVExtensionBitmask { |
| 1066 | const char *Name; |
| 1067 | unsigned GroupID; |
| 1068 | unsigned BitPosition; |
| 1069 | }; |
| 1070 | |
| 1071 | #define GET_RISCVExtensionBitmaskTable_IMPL |
| 1072 | #include "llvm/TargetParser/RISCVTargetParserDef.inc" |
| 1073 | |
| 1074 | std::pair<int, int> RISCVISAInfo::getRISCVFeaturesBitsInfo(StringRef Ext) { |
| 1075 | // Note that this code currently accepts mixed case extension names, but |
| 1076 | // does not handle extension versions at all. That's probably fine because |
| 1077 | // there's only one extension version in the __riscv_feature_bits vector. |
| 1078 | for (auto E : ExtensionBitmask) |
| 1079 | if (Ext.equals_insensitive(RHS: E.Name)) |
| 1080 | return std::make_pair(x&: E.GroupID, y&: E.BitPosition); |
| 1081 | return std::make_pair(x: -1, y: -1); |
| 1082 | } |
| 1083 | |