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