forked from OSchip/llvm-project
719 lines
23 KiB
C++
719 lines
23 KiB
C++
//===-- RISCVISAInfo.cpp - RISCV Arch String Parser --------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/RISCVISAInfo.h"
|
|
#include "llvm/ADT/None.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Errc.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <array>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
/// Represents the major and version number components of a RISC-V extension
|
|
struct RISCVExtensionVersion {
|
|
unsigned Major;
|
|
unsigned Minor;
|
|
};
|
|
|
|
struct RISCVSupportedExtension {
|
|
const char *Name;
|
|
/// Supported version.
|
|
RISCVExtensionVersion Version;
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
static constexpr StringLiteral AllStdExts = "mafdqlcbjtpvn";
|
|
|
|
static const RISCVSupportedExtension SupportedExtensions[] = {
|
|
{"i", RISCVExtensionVersion{2, 0}},
|
|
{"e", RISCVExtensionVersion{1, 9}},
|
|
{"m", RISCVExtensionVersion{2, 0}},
|
|
{"a", RISCVExtensionVersion{2, 0}},
|
|
{"f", RISCVExtensionVersion{2, 0}},
|
|
{"d", RISCVExtensionVersion{2, 0}},
|
|
{"c", RISCVExtensionVersion{2, 0}},
|
|
};
|
|
|
|
static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
|
|
{"v", RISCVExtensionVersion{0, 10}},
|
|
{"zba", RISCVExtensionVersion{1, 0}},
|
|
{"zbb", RISCVExtensionVersion{1, 0}},
|
|
{"zbc", RISCVExtensionVersion{1, 0}},
|
|
{"zbe", RISCVExtensionVersion{0, 93}},
|
|
{"zbf", RISCVExtensionVersion{0, 93}},
|
|
{"zbm", RISCVExtensionVersion{0, 93}},
|
|
{"zbp", RISCVExtensionVersion{0, 93}},
|
|
{"zbr", RISCVExtensionVersion{0, 93}},
|
|
{"zbs", RISCVExtensionVersion{1, 0}},
|
|
{"zbt", RISCVExtensionVersion{0, 93}},
|
|
|
|
{"zvamo", RISCVExtensionVersion{0, 10}},
|
|
{"zvlsseg", RISCVExtensionVersion{0, 10}},
|
|
|
|
{"zfhmin", RISCVExtensionVersion{0, 1}},
|
|
{"zfh", RISCVExtensionVersion{0, 1}},
|
|
};
|
|
|
|
static bool stripExperimentalPrefix(StringRef &Ext) {
|
|
return Ext.consume_front("experimental-");
|
|
}
|
|
|
|
struct FindByName {
|
|
FindByName(StringRef Ext) : Ext(Ext){};
|
|
StringRef Ext;
|
|
bool operator()(const RISCVSupportedExtension &ExtInfo) {
|
|
return ExtInfo.Name == Ext;
|
|
}
|
|
};
|
|
|
|
static Optional<RISCVExtensionVersion> findDefaultVersion(StringRef ExtName) {
|
|
// Find default version of an extension.
|
|
// TODO: We might set default version based on profile or ISA spec.
|
|
for (auto &ExtInfo : {makeArrayRef(SupportedExtensions),
|
|
makeArrayRef(SupportedExperimentalExtensions)}) {
|
|
auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
|
|
|
|
if (ExtensionInfoIterator == ExtInfo.end()) {
|
|
continue;
|
|
}
|
|
return ExtensionInfoIterator->Version;
|
|
}
|
|
return None;
|
|
}
|
|
|
|
void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion,
|
|
unsigned MinorVersion) {
|
|
RISCVExtensionInfo Ext;
|
|
Ext.ExtName = ExtName.str();
|
|
Ext.MajorVersion = MajorVersion;
|
|
Ext.MinorVersion = MinorVersion;
|
|
Exts[ExtName.str()] = Ext;
|
|
}
|
|
|
|
static StringRef getExtensionTypeDesc(StringRef Ext) {
|
|
if (Ext.startswith("sx"))
|
|
return "non-standard supervisor-level extension";
|
|
if (Ext.startswith("s"))
|
|
return "standard supervisor-level extension";
|
|
if (Ext.startswith("x"))
|
|
return "non-standard user-level extension";
|
|
if (Ext.startswith("z"))
|
|
return "standard user-level extension";
|
|
return StringRef();
|
|
}
|
|
|
|
static StringRef getExtensionType(StringRef Ext) {
|
|
if (Ext.startswith("sx"))
|
|
return "sx";
|
|
if (Ext.startswith("s"))
|
|
return "s";
|
|
if (Ext.startswith("x"))
|
|
return "x";
|
|
if (Ext.startswith("z"))
|
|
return "z";
|
|
return StringRef();
|
|
}
|
|
|
|
static Optional<RISCVExtensionVersion> isExperimentalExtension(StringRef Ext) {
|
|
auto ExtIterator =
|
|
llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext));
|
|
if (ExtIterator == std::end(SupportedExperimentalExtensions))
|
|
return None;
|
|
|
|
return ExtIterator->Version;
|
|
}
|
|
|
|
bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
|
|
bool IsExperimental = stripExperimentalPrefix(Ext);
|
|
|
|
if (IsExperimental)
|
|
return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
|
|
else
|
|
return llvm::any_of(SupportedExtensions, FindByName(Ext));
|
|
}
|
|
|
|
bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
|
|
return llvm::any_of(SupportedExtensions, FindByName(Ext)) ||
|
|
llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
|
|
}
|
|
|
|
bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
|
|
unsigned MinorVersion) {
|
|
auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) {
|
|
return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) &&
|
|
(MinorVersion == ExtInfo.Version.Minor);
|
|
};
|
|
return llvm::any_of(SupportedExtensions, FindByNameAndVersion) ||
|
|
llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion);
|
|
}
|
|
|
|
bool RISCVISAInfo::hasExtension(StringRef Ext) const {
|
|
stripExperimentalPrefix(Ext);
|
|
|
|
if (!isSupportedExtension(Ext))
|
|
return false;
|
|
|
|
return Exts.count(Ext.str()) != 0;
|
|
}
|
|
|
|
// Get the rank for single-letter extension, lower value meaning higher
|
|
// priority.
|
|
static int singleLetterExtensionRank(char Ext) {
|
|
switch (Ext) {
|
|
case 'i':
|
|
return -2;
|
|
case 'e':
|
|
return -1;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
size_t Pos = AllStdExts.find(Ext);
|
|
int Rank;
|
|
if (Pos == StringRef::npos)
|
|
// If we got an unknown extension letter, then give it an alphabetical
|
|
// order, but after all known standard extensions.
|
|
Rank = AllStdExts.size() + (Ext - 'a');
|
|
else
|
|
Rank = Pos;
|
|
|
|
return Rank;
|
|
}
|
|
|
|
// Get the rank for multi-letter extension, lower value meaning higher
|
|
// priority/order in canonical order.
|
|
static int multiLetterExtensionRank(const std::string &ExtName) {
|
|
assert(ExtName.length() >= 2);
|
|
int HighOrder;
|
|
int LowOrder = 0;
|
|
// The order between multi-char extensions: s -> h -> z -> x.
|
|
char ExtClass = ExtName[0];
|
|
switch (ExtClass) {
|
|
case 's':
|
|
HighOrder = 0;
|
|
break;
|
|
case 'h':
|
|
HighOrder = 1;
|
|
break;
|
|
case 'z':
|
|
HighOrder = 2;
|
|
// `z` extension must be sorted by canonical order of second letter.
|
|
// e.g. zmx has higher rank than zax.
|
|
LowOrder = singleLetterExtensionRank(ExtName[1]);
|
|
break;
|
|
case 'x':
|
|
HighOrder = 3;
|
|
break;
|
|
default:
|
|
llvm_unreachable("Unknown prefix for multi-char extension");
|
|
return -1;
|
|
}
|
|
|
|
return (HighOrder << 8) + LowOrder;
|
|
}
|
|
|
|
// Compare function for extension.
|
|
// Only compare the extension name, ignore version comparison.
|
|
bool RISCVISAInfo::compareExtension(const std::string &LHS,
|
|
const std::string &RHS) {
|
|
size_t LHSLen = LHS.length();
|
|
size_t RHSLen = RHS.length();
|
|
if (LHSLen == 1 && RHSLen != 1)
|
|
return true;
|
|
|
|
if (LHSLen != 1 && RHSLen == 1)
|
|
return false;
|
|
|
|
if (LHSLen == 1 && RHSLen == 1)
|
|
return singleLetterExtensionRank(LHS[0]) <
|
|
singleLetterExtensionRank(RHS[0]);
|
|
|
|
// Both are multi-char ext here.
|
|
int LHSRank = multiLetterExtensionRank(LHS);
|
|
int RHSRank = multiLetterExtensionRank(RHS);
|
|
if (LHSRank != RHSRank)
|
|
return LHSRank < RHSRank;
|
|
|
|
// If the rank is same, it must be sorted by lexicographic order.
|
|
return LHS < RHS;
|
|
}
|
|
|
|
void RISCVISAInfo::toFeatures(
|
|
std::vector<StringRef> &Features,
|
|
std::function<StringRef(const Twine &)> StrAlloc) const {
|
|
for (auto &Ext : Exts) {
|
|
StringRef ExtName = Ext.first;
|
|
|
|
if (ExtName == "i")
|
|
continue;
|
|
|
|
if (ExtName == "zvlsseg") {
|
|
Features.push_back("+experimental-v");
|
|
Features.push_back("+experimental-zvlsseg");
|
|
} else if (ExtName == "zvamo") {
|
|
Features.push_back("+experimental-v");
|
|
Features.push_back("+experimental-zvlsseg");
|
|
Features.push_back("+experimental-zvamo");
|
|
} else if (isExperimentalExtension(ExtName)) {
|
|
Features.push_back(StrAlloc("+experimental-" + ExtName));
|
|
} else {
|
|
Features.push_back(StrAlloc("+" + ExtName));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extensions may have a version number, and may be separated by
|
|
// an underscore '_' e.g.: rv32i2_m2.
|
|
// Version number is divided into major and minor version numbers,
|
|
// separated by a 'p'. If the minor version is 0 then 'p0' can be
|
|
// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
|
|
static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
|
|
unsigned &Minor, unsigned &ConsumeLength,
|
|
bool EnableExperimentalExtension,
|
|
bool ExperimentalExtensionVersionCheck) {
|
|
StringRef MajorStr, MinorStr;
|
|
Major = 0;
|
|
Minor = 0;
|
|
ConsumeLength = 0;
|
|
MajorStr = In.take_while(isDigit);
|
|
In = In.substr(MajorStr.size());
|
|
|
|
if (!MajorStr.empty() && In.consume_front("p")) {
|
|
MinorStr = In.take_while(isDigit);
|
|
In = In.substr(MajorStr.size() + 1);
|
|
|
|
// Expected 'p' to be followed by minor version number.
|
|
if (MinorStr.empty()) {
|
|
return createStringError(
|
|
errc::invalid_argument,
|
|
"minor version number missing after 'p' for extension '" + Ext + "'");
|
|
}
|
|
}
|
|
|
|
if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
|
|
return createStringError(
|
|
errc::invalid_argument,
|
|
"Failed to parse major version number for extension '" + Ext + "'");
|
|
|
|
if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
|
|
return createStringError(
|
|
errc::invalid_argument,
|
|
"Failed to parse minor version number for extension '" + Ext + "'");
|
|
|
|
ConsumeLength = MajorStr.size();
|
|
|
|
if (!MinorStr.empty())
|
|
ConsumeLength += MinorStr.size() + 1 /*'p'*/;
|
|
|
|
// Expected multi-character extension with version number to have no
|
|
// subsequent characters (i.e. must either end string or be followed by
|
|
// an underscore).
|
|
if (Ext.size() > 1 && In.size()) {
|
|
std::string Error =
|
|
"multi-character extensions must be separated by underscores";
|
|
return createStringError(errc::invalid_argument, Error);
|
|
}
|
|
|
|
// If experimental extension, require use of current version number number
|
|
if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
|
|
if (!EnableExperimentalExtension) {
|
|
std::string Error = "requires '-menable-experimental-extensions' for "
|
|
"experimental extension '" +
|
|
Ext.str() + "'";
|
|
return createStringError(errc::invalid_argument, Error);
|
|
}
|
|
|
|
if (ExperimentalExtensionVersionCheck &&
|
|
(MajorStr.empty() && MinorStr.empty())) {
|
|
std::string Error =
|
|
"experimental extension requires explicit version number `" +
|
|
Ext.str() + "`";
|
|
return createStringError(errc::invalid_argument, Error);
|
|
}
|
|
|
|
auto SupportedVers = *ExperimentalExtension;
|
|
if (ExperimentalExtensionVersionCheck &&
|
|
(Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
|
|
std::string Error = "unsupported version number " + MajorStr.str();
|
|
if (!MinorStr.empty())
|
|
Error += "." + MinorStr.str();
|
|
Error += " for experimental extension '" + Ext.str() +
|
|
"'(this compiler supports " + utostr(SupportedVers.Major) + "." +
|
|
utostr(SupportedVers.Minor) + ")";
|
|
return createStringError(errc::invalid_argument, Error);
|
|
}
|
|
return Error::success();
|
|
}
|
|
|
|
// Exception rule for `g`, we don't have clear version scheme for that on
|
|
// ISA spec.
|
|
if (Ext == "g")
|
|
return Error::success();
|
|
|
|
if (MajorStr.empty() && MinorStr.empty()) {
|
|
if (auto DefaultVersion = findDefaultVersion(Ext)) {
|
|
Major = DefaultVersion->Major;
|
|
Minor = DefaultVersion->Minor;
|
|
}
|
|
// No matter found or not, return success, assume other place will
|
|
// verify.
|
|
return Error::success();
|
|
}
|
|
|
|
if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
|
|
return Error::success();
|
|
|
|
std::string Error = "unsupported version number " + std::string(MajorStr);
|
|
if (!MinorStr.empty())
|
|
Error += "." + MinorStr.str();
|
|
Error += " for extension '" + Ext.str() + "'";
|
|
return createStringError(errc::invalid_argument, Error);
|
|
}
|
|
|
|
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
|
|
RISCVISAInfo::parseFeatures(unsigned XLen,
|
|
const std::vector<std::string> &Features) {
|
|
assert(XLen == 32 || XLen == 64);
|
|
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
|
|
|
|
bool HasE = false;
|
|
for (auto &Feature : Features) {
|
|
StringRef ExtName = Feature;
|
|
bool Experimental = false;
|
|
assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
|
|
bool Add = ExtName[0] == '+';
|
|
ExtName = ExtName.drop_front(1); // Drop '+' or '-'
|
|
Experimental = stripExperimentalPrefix(ExtName);
|
|
auto ExtensionInfos = Experimental
|
|
? makeArrayRef(SupportedExperimentalExtensions)
|
|
: makeArrayRef(SupportedExtensions);
|
|
auto ExtensionInfoIterator =
|
|
llvm::find_if(ExtensionInfos, FindByName(ExtName));
|
|
|
|
// Not all features is related to ISA extension, like `relax` or
|
|
// `save-restore`, skip those feature.
|
|
if (ExtensionInfoIterator == ExtensionInfos.end())
|
|
continue;
|
|
|
|
if (Add) {
|
|
if (ExtName == "e") {
|
|
if (XLen != 32)
|
|
return createStringError(
|
|
errc::invalid_argument,
|
|
"standard user-level extension 'e' requires 'rv32'");
|
|
HasE = true;
|
|
}
|
|
|
|
ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
|
|
ExtensionInfoIterator->Version.Minor);
|
|
} else
|
|
ISAInfo->Exts.erase(ExtName.str());
|
|
}
|
|
if (!HasE) {
|
|
if (auto Version = findDefaultVersion("i"))
|
|
ISAInfo->addExtension("i", Version->Major, Version->Minor);
|
|
else
|
|
llvm_unreachable("Default extension version for 'i' not found?");
|
|
}
|
|
|
|
ISAInfo->updateFLen();
|
|
|
|
return std::move(ISAInfo);
|
|
}
|
|
|
|
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
|
|
RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
|
|
bool ExperimentalExtensionVersionCheck) {
|
|
// RISC-V ISA strings must be lowercase.
|
|
if (llvm::any_of(Arch, isupper)) {
|
|
return createStringError(errc::invalid_argument,
|
|
"string must be lowercase");
|
|
}
|
|
|
|
bool HasRV64 = Arch.startswith("rv64");
|
|
// ISA string must begin with rv32 or rv64.
|
|
if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
|
|
return createStringError(errc::invalid_argument,
|
|
"string must begin with rv32{i,e,g} or rv64{i,g}");
|
|
}
|
|
|
|
unsigned XLen = HasRV64 ? 64 : 32;
|
|
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
|
|
|
|
// The canonical order specified in ISA manual.
|
|
// Ref: Table 22.1 in RISC-V User-Level ISA V2.2
|
|
StringRef StdExts = AllStdExts;
|
|
bool HasF = false, HasD = false;
|
|
char Baseline = Arch[4];
|
|
|
|
// First letter should be 'e', 'i' or 'g'.
|
|
switch (Baseline) {
|
|
default:
|
|
return createStringError(errc::invalid_argument,
|
|
"first letter should be 'e', 'i' or 'g'");
|
|
case 'e': {
|
|
// Extension 'e' is not allowed in rv64.
|
|
if (HasRV64)
|
|
return createStringError(
|
|
errc::invalid_argument,
|
|
"standard user-level extension 'e' requires 'rv32'");
|
|
break;
|
|
}
|
|
case 'i':
|
|
break;
|
|
case 'g':
|
|
// g = imafd
|
|
StdExts = StdExts.drop_front(4);
|
|
HasF = true;
|
|
HasD = true;
|
|
break;
|
|
}
|
|
|
|
// Skip rvxxx
|
|
StringRef Exts = Arch.substr(5);
|
|
|
|
// Remove multi-letter standard extensions, non-standard extensions and
|
|
// supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
|
|
// Parse them at the end.
|
|
// Find the very first occurrence of 's', 'x' or 'z'.
|
|
StringRef OtherExts;
|
|
size_t Pos = Exts.find_first_of("zsx");
|
|
if (Pos != StringRef::npos) {
|
|
OtherExts = Exts.substr(Pos);
|
|
Exts = Exts.substr(0, Pos);
|
|
}
|
|
|
|
unsigned Major, Minor, ConsumeLength;
|
|
if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
|
|
ConsumeLength, EnableExperimentalExtension,
|
|
ExperimentalExtensionVersionCheck))
|
|
return std::move(E);
|
|
|
|
if (Baseline == 'g') {
|
|
// No matter which version is given to `g`, we always set imafd to default
|
|
// version since the we don't have clear version scheme for that on
|
|
// ISA spec.
|
|
for (auto Ext : {"i", "m", "a", "f", "d"})
|
|
if (auto Version = findDefaultVersion(Ext))
|
|
ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
|
|
else
|
|
llvm_unreachable("Default extension version not found?");
|
|
} else
|
|
// Baseline is `i` or `e`
|
|
ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
|
|
|
|
// Consume the base ISA version number and any '_' between rvxxx and the
|
|
// first extension
|
|
Exts = Exts.drop_front(ConsumeLength);
|
|
Exts.consume_front("_");
|
|
|
|
// TODO: Use version number when setting target features
|
|
|
|
auto StdExtsItr = StdExts.begin();
|
|
auto StdExtsEnd = StdExts.end();
|
|
for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
|
|
char C = *I;
|
|
|
|
// Check ISA extensions are specified in the canonical order.
|
|
while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
|
|
++StdExtsItr;
|
|
|
|
if (StdExtsItr == StdExtsEnd) {
|
|
// Either c contains a valid extension but it was not given in
|
|
// canonical order or it is an invalid extension.
|
|
if (StdExts.contains(C)) {
|
|
return createStringError(
|
|
errc::invalid_argument,
|
|
"standard user-level extension not given in canonical order '%c'",
|
|
C);
|
|
}
|
|
|
|
return createStringError(errc::invalid_argument,
|
|
"invalid standard user-level extension '%c'", C);
|
|
}
|
|
|
|
// Move to next char to prevent repeated letter.
|
|
++StdExtsItr;
|
|
|
|
std::string Next;
|
|
unsigned Major, Minor, ConsumeLength;
|
|
if (std::next(I) != E)
|
|
Next = std::string(std::next(I), E);
|
|
if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
|
|
ConsumeLength, EnableExperimentalExtension,
|
|
ExperimentalExtensionVersionCheck))
|
|
return std::move(E);
|
|
|
|
// The order is OK, then push it into features.
|
|
// TODO: Use version number when setting target features
|
|
switch (C) {
|
|
default:
|
|
// Currently LLVM supports only "mafdcbv".
|
|
return createStringError(errc::invalid_argument,
|
|
"unsupported standard user-level extension '%c'",
|
|
C);
|
|
case 'm':
|
|
ISAInfo->addExtension("m", Major, Minor);
|
|
break;
|
|
case 'a':
|
|
ISAInfo->addExtension("a", Major, Minor);
|
|
break;
|
|
case 'f':
|
|
ISAInfo->addExtension("f", Major, Minor);
|
|
HasF = true;
|
|
break;
|
|
case 'd':
|
|
ISAInfo->addExtension("d", Major, Minor);
|
|
HasD = true;
|
|
break;
|
|
case 'c':
|
|
ISAInfo->addExtension("c", Major, Minor);
|
|
break;
|
|
case 'v':
|
|
ISAInfo->addExtension("v", Major, Minor);
|
|
ISAInfo->addExtension("zvlsseg", Major, Minor);
|
|
break;
|
|
}
|
|
// Consume full extension name and version, including any optional '_'
|
|
// between this extension and the next
|
|
++I;
|
|
I += ConsumeLength;
|
|
if (*I == '_')
|
|
++I;
|
|
}
|
|
// Dependency check.
|
|
// It's illegal to specify the 'd' (double-precision floating point)
|
|
// extension without also specifying the 'f' (single precision
|
|
// floating-point) extension.
|
|
// TODO: This has been removed in later specs, which specify that D implies F
|
|
if (HasD && !HasF)
|
|
return createStringError(errc::invalid_argument,
|
|
"d requires f extension to also be specified");
|
|
|
|
// Additional dependency checks.
|
|
// TODO: The 'q' extension requires rv64.
|
|
// TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
|
|
|
|
if (OtherExts.empty())
|
|
return std::move(ISAInfo);
|
|
|
|
// Handle other types of extensions other than the standard
|
|
// general purpose and standard user-level extensions.
|
|
// Parse the ISA string containing non-standard user-level
|
|
// extensions, standard supervisor-level extensions and
|
|
// non-standard supervisor-level extensions.
|
|
// These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
|
|
// canonical order, might have a version number (major, minor)
|
|
// and are separated by a single underscore '_'.
|
|
// Set the hardware features for the extensions that are supported.
|
|
|
|
// Multi-letter extensions are seperated by a single underscore
|
|
// as described in RISC-V User-Level ISA V2.2.
|
|
SmallVector<StringRef, 8> Split;
|
|
OtherExts.split(Split, '_');
|
|
|
|
SmallVector<StringRef, 8> AllExts;
|
|
std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
|
|
auto I = Prefix.begin();
|
|
auto E = Prefix.end();
|
|
|
|
for (StringRef Ext : Split) {
|
|
if (Ext.empty())
|
|
return createStringError(errc::invalid_argument,
|
|
"extension name missing after separator '_'");
|
|
|
|
StringRef Type = getExtensionType(Ext);
|
|
StringRef Desc = getExtensionTypeDesc(Ext);
|
|
auto Pos = Ext.find_if(isDigit);
|
|
StringRef Name(Ext.substr(0, Pos));
|
|
StringRef Vers(Ext.substr(Pos));
|
|
|
|
if (Type.empty())
|
|
return createStringError(errc::invalid_argument,
|
|
"invalid extension prefix '" + Ext + "'");
|
|
|
|
// Check ISA extensions are specified in the canonical order.
|
|
while (I != E && *I != Type)
|
|
++I;
|
|
|
|
if (I == E)
|
|
return createStringError(errc::invalid_argument,
|
|
"%s not given in canonical order '%s'",
|
|
Desc.str().c_str(), Ext.str().c_str());
|
|
|
|
if (Name.size() == Type.size()) {
|
|
return createStringError(errc::invalid_argument,
|
|
"%s name missing after '%s'", Desc.str().c_str(),
|
|
Type.str().c_str());
|
|
}
|
|
|
|
unsigned Major, Minor, ConsumeLength;
|
|
if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
|
|
EnableExperimentalExtension,
|
|
ExperimentalExtensionVersionCheck))
|
|
return std::move(E);
|
|
|
|
// Check if duplicated extension.
|
|
if (llvm::is_contained(AllExts, Name))
|
|
return createStringError(errc::invalid_argument, "duplicated %s '%s'",
|
|
Desc.str().c_str(), Name.str().c_str());
|
|
|
|
ISAInfo->addExtension(Name, Major, Minor);
|
|
// Extension format is correct, keep parsing the extensions.
|
|
// TODO: Save Type, Name, Major, Minor to avoid parsing them later.
|
|
AllExts.push_back(Name);
|
|
}
|
|
|
|
for (auto Ext : AllExts) {
|
|
if (!isSupportedExtension(Ext)) {
|
|
StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
|
|
return createStringError(errc::invalid_argument, "unsupported %s '%s'",
|
|
Desc.str().c_str(), Ext.str().c_str());
|
|
}
|
|
}
|
|
|
|
ISAInfo->updateFLen();
|
|
|
|
return std::move(ISAInfo);
|
|
}
|
|
|
|
void RISCVISAInfo::updateFLen() {
|
|
FLen = 0;
|
|
// TODO: Handle q extension.
|
|
if (Exts.count("d"))
|
|
FLen = 64;
|
|
else if (Exts.count("f"))
|
|
FLen = 32;
|
|
}
|
|
|
|
std::string RISCVISAInfo::toString() const {
|
|
std::string Buffer;
|
|
raw_string_ostream Arch(Buffer);
|
|
|
|
Arch << "rv" << XLen;
|
|
|
|
ListSeparator LS("_");
|
|
for (auto &Ext : Exts) {
|
|
StringRef ExtName = Ext.first;
|
|
auto ExtInfo = Ext.second;
|
|
Arch << LS << ExtName;
|
|
Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
|
|
}
|
|
|
|
return Arch.str();
|
|
}
|