#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.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 {
struct RISCVExtensionVersion {
unsigned Major;
unsigned Minor;
};
struct RISCVSupportedExtension {
const char *Name;
RISCVExtensionVersion Version;
};
}
static constexpr StringLiteral AllStdExts = "mafdqlcbkjtpvn";
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}},
{"zihintpause", RISCVExtensionVersion{2, 0}},
{"zfhmin", RISCVExtensionVersion{1, 0}},
{"zfh", RISCVExtensionVersion{1, 0}},
{"zfinx", RISCVExtensionVersion{1, 0}},
{"zdinx", RISCVExtensionVersion{1, 0}},
{"zhinxmin", RISCVExtensionVersion{1, 0}},
{"zhinx", RISCVExtensionVersion{1, 0}},
{"zba", RISCVExtensionVersion{1, 0}},
{"zbb", RISCVExtensionVersion{1, 0}},
{"zbc", RISCVExtensionVersion{1, 0}},
{"zbs", RISCVExtensionVersion{1, 0}},
{"zbkb", RISCVExtensionVersion{1, 0}},
{"zbkc", RISCVExtensionVersion{1, 0}},
{"zbkx", RISCVExtensionVersion{1, 0}},
{"zknd", RISCVExtensionVersion{1, 0}},
{"zkne", RISCVExtensionVersion{1, 0}},
{"zknh", RISCVExtensionVersion{1, 0}},
{"zksed", RISCVExtensionVersion{1, 0}},
{"zksh", RISCVExtensionVersion{1, 0}},
{"zkr", RISCVExtensionVersion{1, 0}},
{"zkn", RISCVExtensionVersion{1, 0}},
{"zks", RISCVExtensionVersion{1, 0}},
{"zkt", RISCVExtensionVersion{1, 0}},
{"zk", RISCVExtensionVersion{1, 0}},
{"zmmul", RISCVExtensionVersion{1, 0}},
{"v", RISCVExtensionVersion{1, 0}},
{"zvl32b", RISCVExtensionVersion{1, 0}},
{"zvl64b", RISCVExtensionVersion{1, 0}},
{"zvl128b", RISCVExtensionVersion{1, 0}},
{"zvl256b", RISCVExtensionVersion{1, 0}},
{"zvl512b", RISCVExtensionVersion{1, 0}},
{"zvl1024b", RISCVExtensionVersion{1, 0}},
{"zvl2048b", RISCVExtensionVersion{1, 0}},
{"zvl4096b", RISCVExtensionVersion{1, 0}},
{"zvl8192b", RISCVExtensionVersion{1, 0}},
{"zvl16384b", RISCVExtensionVersion{1, 0}},
{"zvl32768b", RISCVExtensionVersion{1, 0}},
{"zvl65536b", RISCVExtensionVersion{1, 0}},
{"zve32x", RISCVExtensionVersion{1, 0}},
{"zve32f", RISCVExtensionVersion{1, 0}},
{"zve64x", RISCVExtensionVersion{1, 0}},
{"zve64f", RISCVExtensionVersion{1, 0}},
{"zve64d", RISCVExtensionVersion{1, 0}},
{"zicbom", RISCVExtensionVersion{1, 0}},
{"zicboz", RISCVExtensionVersion{1, 0}},
{"zicbop", RISCVExtensionVersion{1, 0}},
};
static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
{"zbe", RISCVExtensionVersion{0, 93}},
{"zbf", RISCVExtensionVersion{0, 93}},
{"zbm", RISCVExtensionVersion{0, 93}},
{"zbp", RISCVExtensionVersion{0, 93}},
{"zbr", RISCVExtensionVersion{0, 93}},
{"zbt", RISCVExtensionVersion{0, 93}},
{"zvfh", RISCVExtensionVersion{0, 1}},
};
static bool stripExperimentalPrefix(StringRef &Ext) {
return Ext.consume_front("experimental-");
}
static size_t findFirstNonVersionCharacter(StringRef Ext) {
assert(!Ext.empty() &&
"Already guarded by if-statement in ::parseArchString");
int Pos = Ext.size() - 1;
while (Pos > 0 && isDigit(Ext[Pos]))
Pos--;
if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
Pos--;
while (Pos > 0 && isDigit(Ext[Pos]))
Pos--;
}
return Pos;
}
struct FindByName {
FindByName(StringRef Ext) : Ext(Ext){};
StringRef Ext;
bool operator()(const RISCVSupportedExtension &ExtInfo) {
return ExtInfo.Name == Ext;
}
};
static Optional<RISCVExtensionVersion> findDefaultVersion(StringRef ExtName) {
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;
}
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)
Rank = AllStdExts.size() + (Ext - 'a');
else
Rank = Pos;
return Rank;
}
static int multiLetterExtensionRank(const std::string &ExtName) {
assert(ExtName.length() >= 2);
int HighOrder;
int LowOrder = 0;
char ExtClass = ExtName[0];
switch (ExtClass) {
case 's':
HighOrder = 0;
break;
case 'h':
HighOrder = 1;
break;
case 'z':
HighOrder = 2;
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;
}
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]);
int LHSRank = multiLetterExtensionRank(LHS);
int RHSRank = multiLetterExtensionRank(RHS);
if (LHSRank != RHSRank)
return LHSRank < RHSRank;
return LHS < RHS;
}
void RISCVISAInfo::toFeatures(
std::vector<StringRef> &Features,
std::function<StringRef(const Twine &)> StrAlloc) const {
for (auto const &Ext : Exts) {
StringRef ExtName = Ext.first;
if (ExtName == "i")
continue;
if (isExperimentalExtension(ExtName)) {
Features.push_back(StrAlloc("+experimental-" + ExtName));
} else {
Features.push_back(StrAlloc("+" + ExtName));
}
}
}
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() + MinorStr.size() - 1);
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 ;
if (Ext.size() > 1 && In.size()) {
std::string Error =
"multi-character extensions must be separated by underscores";
return createStringError(errc::invalid_argument, Error);
}
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();
}
if (Ext == "g")
return Error::success();
if (MajorStr.empty() && MinorStr.empty()) {
if (auto DefaultVersion = findDefaultVersion(Ext)) {
Major = DefaultVersion->Major;
Minor = DefaultVersion->Minor;
}
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));
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); Experimental = stripExperimentalPrefix(ExtName);
auto ExtensionInfos = Experimental
? makeArrayRef(SupportedExperimentalExtensions)
: makeArrayRef(SupportedExtensions);
auto ExtensionInfoIterator =
llvm::find_if(ExtensionInfos, FindByName(ExtName));
if (ExtensionInfoIterator == ExtensionInfos.end())
continue;
if (Add)
ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
ExtensionInfoIterator->Version.Minor);
else
ISAInfo->Exts.erase(ExtName.str());
}
return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
}
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
bool ExperimentalExtensionVersionCheck) {
if (llvm::any_of(Arch, isupper)) {
return createStringError(errc::invalid_argument,
"string must be lowercase");
}
bool HasRV64 = Arch.startswith("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));
StringRef StdExts = AllStdExts;
char Baseline = Arch[4];
switch (Baseline) {
default:
return createStringError(errc::invalid_argument,
"first letter should be 'e', 'i' or 'g'");
case 'e': {
if (HasRV64)
return createStringError(
errc::invalid_argument,
"standard user-level extension 'e' requires 'rv32'");
break;
}
case 'i':
break;
case 'g':
StdExts = StdExts.drop_front(4);
break;
}
StringRef Exts = Arch.substr(5);
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') {
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
ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
Exts = Exts.drop_front(ConsumeLength);
Exts.consume_front("_");
auto StdExtsItr = StdExts.begin();
auto StdExtsEnd = StdExts.end();
for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
char C = *I;
while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
++StdExtsItr;
if (StdExtsItr == StdExtsEnd) {
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);
}
++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);
StringRef SupportedStandardExtension = "mafdcbv";
if (!SupportedStandardExtension.contains(C))
return createStringError(errc::invalid_argument,
"unsupported standard user-level extension '%c'",
C);
ISAInfo->addExtension(std::string(1, C), Major, Minor);
++I;
I += ConsumeLength;
if (*I == '_')
++I;
}
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();
if (Split.size() > 1 || Split[0] != "") {
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 = findFirstNonVersionCharacter(Ext) + 1;
StringRef Name(Ext.substr(0, Pos));
StringRef Vers(Ext.substr(Pos));
if (Type.empty())
return createStringError(errc::invalid_argument,
"invalid extension prefix '" + Ext + "'");
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);
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);
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());
}
}
return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
}
Error RISCVISAInfo::checkDependency() {
bool IsRv32 = XLen == 32;
bool HasE = Exts.count("e") != 0;
bool HasD = Exts.count("d") != 0;
bool HasF = Exts.count("f") != 0;
bool HasZfinx = Exts.count("zfinx") != 0;
bool HasZdinx = Exts.count("zdinx") != 0;
bool HasVector = Exts.count("zve32x") != 0;
bool HasZve32f = Exts.count("zve32f") != 0;
bool HasZve64d = Exts.count("zve64d") != 0;
bool HasZvl = MinVLen != 0;
if (HasE && !IsRv32)
return createStringError(
errc::invalid_argument,
"standard user-level extension 'e' requires 'rv32'");
if (HasD && !HasF)
return createStringError(errc::invalid_argument,
"d requires f extension to also be specified");
if (HasZve32f && !HasF && !HasZfinx)
return createStringError(
errc::invalid_argument,
"zve32f requires f or zfinx extension to also be specified");
if (HasZve64d && !HasD && !HasZdinx)
return createStringError(
errc::invalid_argument,
"zve64d requires d or zdinx extension to also be specified");
if (Exts.count("zvfh") && !Exts.count("zfh") && !Exts.count("zfhmin") &&
!Exts.count("zhinx") && !Exts.count("zhinxmin"))
return createStringError(
errc::invalid_argument,
"zvfh requires zfh, zfhmin, zhinx or zhinxmin extension to also be "
"specified");
if (HasZvl && !HasVector)
return createStringError(
errc::invalid_argument,
"zvl*b requires v or zve* extension to also be specified");
return Error::success();
}
static const char *ImpliedExtsV[] = {"zvl128b", "zve64d", "f", "d"};
static const char *ImpliedExtsZfhmin[] = {"f"};
static const char *ImpliedExtsZfh[] = {"f"};
static const char *ImpliedExtsZdinx[] = {"zfinx"};
static const char *ImpliedExtsZhinxmin[] = {"zfinx"};
static const char *ImpliedExtsZhinx[] = {"zfinx"};
static const char *ImpliedExtsZve64d[] = {"zve64f"};
static const char *ImpliedExtsZve64f[] = {"zve64x", "zve32f"};
static const char *ImpliedExtsZve64x[] = {"zve32x", "zvl64b"};
static const char *ImpliedExtsZve32f[] = {"zve32x"};
static const char *ImpliedExtsZve32x[] = {"zvl32b"};
static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
static const char *ImpliedExtsZk[] = {"zkn", "zkt", "zkr"};
static const char *ImpliedExtsZkn[] = {"zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"};
static const char *ImpliedExtsZks[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
static const char *ImpliedExtsZvfh[] = {"zve32f"};
struct ImpliedExtsEntry {
StringLiteral Name;
ArrayRef<const char *> Exts;
bool operator<(const ImpliedExtsEntry &Other) const {
return Name < Other.Name;
}
bool operator<(StringRef Other) const { return Name < Other; }
};
static constexpr ImpliedExtsEntry ImpliedExts[] = {
{{"v"}, {ImpliedExtsV}},
{{"zdinx"}, {ImpliedExtsZdinx}},
{{"zfh"}, {ImpliedExtsZfh}},
{{"zfhmin"}, {ImpliedExtsZfhmin}},
{{"zhinx"}, {ImpliedExtsZhinx}},
{{"zhinxmin"}, {ImpliedExtsZhinxmin}},
{{"zk"}, {ImpliedExtsZk}},
{{"zkn"}, {ImpliedExtsZkn}},
{{"zks"}, {ImpliedExtsZks}},
{{"zve32f"}, {ImpliedExtsZve32f}},
{{"zve32x"}, {ImpliedExtsZve32x}},
{{"zve64d"}, {ImpliedExtsZve64d}},
{{"zve64f"}, {ImpliedExtsZve64f}},
{{"zve64x"}, {ImpliedExtsZve64x}},
{{"zvfh"}, {ImpliedExtsZvfh}},
{{"zvl1024b"}, {ImpliedExtsZvl1024b}},
{{"zvl128b"}, {ImpliedExtsZvl128b}},
{{"zvl16384b"}, {ImpliedExtsZvl16384b}},
{{"zvl2048b"}, {ImpliedExtsZvl2048b}},
{{"zvl256b"}, {ImpliedExtsZvl256b}},
{{"zvl32768b"}, {ImpliedExtsZvl32768b}},
{{"zvl4096b"}, {ImpliedExtsZvl4096b}},
{{"zvl512b"}, {ImpliedExtsZvl512b}},
{{"zvl64b"}, {ImpliedExtsZvl64b}},
{{"zvl65536b"}, {ImpliedExtsZvl65536b}},
{{"zvl8192b"}, {ImpliedExtsZvl8192b}},
};
void RISCVISAInfo::updateImplication() {
bool HasE = Exts.count("e") != 0;
bool HasI = Exts.count("i") != 0;
if (!HasE && !HasI) {
auto Version = findDefaultVersion("i");
addExtension("i", Version->Major, Version->Minor);
}
assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
SmallSetVector<StringRef, 16> WorkList;
for (auto const &Ext : Exts)
WorkList.insert(Ext.first);
while (!WorkList.empty()) {
StringRef ExtName = WorkList.pop_back_val();
auto I = llvm::lower_bound(ImpliedExts, ExtName);
if (I != std::end(ImpliedExts) && I->Name == ExtName) {
for (const char *ImpliedExt : I->Exts) {
if (WorkList.count(ImpliedExt))
continue;
if (Exts.count(ImpliedExt))
continue;
auto Version = findDefaultVersion(ImpliedExt);
addExtension(ImpliedExt, Version->Major, Version->Minor);
WorkList.insert(ImpliedExt);
}
}
}
}
struct CombinedExtsEntry {
StringLiteral CombineExt;
ArrayRef<const char *> RequiredExts;
};
static constexpr CombinedExtsEntry CombineIntoExts[] = {
{{"zk"}, {ImpliedExtsZk}},
{{"zkn"}, {ImpliedExtsZkn}},
{{"zks"}, {ImpliedExtsZks}},
};
void RISCVISAInfo::updateCombination() {
bool IsNewCombine = false;
do {
IsNewCombine = false;
for (CombinedExtsEntry CombineIntoExt : CombineIntoExts) {
auto CombineExt = CombineIntoExt.CombineExt;
auto RequiredExts = CombineIntoExt.RequiredExts;
if (hasExtension(CombineExt))
continue;
bool IsAllRequiredFeatureExist = true;
for (const char *Ext : RequiredExts)
IsAllRequiredFeatureExist &= hasExtension(Ext);
if (IsAllRequiredFeatureExist) {
auto Version = findDefaultVersion(CombineExt);
addExtension(CombineExt, Version->Major, Version->Minor);
IsNewCombine = true;
}
}
} while (IsNewCombine);
}
void RISCVISAInfo::updateFLen() {
FLen = 0;
if (Exts.count("d"))
FLen = 64;
else if (Exts.count("f"))
FLen = 32;
}
void RISCVISAInfo::updateMinVLen() {
for (auto const &Ext : Exts) {
StringRef ExtName = Ext.first;
bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
if (IsZvlExt) {
unsigned ZvlLen;
if (!ExtName.getAsInteger(10, ZvlLen))
MinVLen = std::max(MinVLen, ZvlLen);
}
}
}
void RISCVISAInfo::updateMaxELen() {
for (auto const &Ext : Exts) {
StringRef ExtName = Ext.first;
bool IsZveExt = ExtName.consume_front("zve");
if (IsZveExt) {
if (ExtName.back() == 'f')
MaxELenFp = std::max(MaxELenFp, 32u);
if (ExtName.back() == 'd')
MaxELenFp = std::max(MaxELenFp, 64u);
ExtName = ExtName.drop_back();
unsigned ZveELen;
ExtName.getAsInteger(10, ZveELen);
MaxELen = std::max(MaxELen, ZveELen);
}
}
}
std::string RISCVISAInfo::toString() const {
std::string Buffer;
raw_string_ostream Arch(Buffer);
Arch << "rv" << XLen;
ListSeparator LS("_");
for (auto const &Ext : Exts) {
StringRef ExtName = Ext.first;
auto ExtInfo = Ext.second;
Arch << LS << ExtName;
Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
}
return Arch.str();
}
std::vector<std::string> RISCVISAInfo::toFeatureVector() const {
std::vector<std::string> FeatureVector;
for (auto const &Ext : Exts) {
std::string ExtName = Ext.first;
if (ExtName == "i") continue;
std::string Feature = isExperimentalExtension(ExtName)
? "+experimental-" + ExtName
: "+" + ExtName;
FeatureVector.push_back(Feature);
}
return FeatureVector;
}
llvm::Expected<std::unique_ptr<RISCVISAInfo>>
RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
ISAInfo->updateImplication();
ISAInfo->updateCombination();
ISAInfo->updateFLen();
ISAInfo->updateMinVLen();
ISAInfo->updateMaxELen();
if (Error Result = ISAInfo->checkDependency())
return std::move(Result);
return std::move(ISAInfo);
}
StringRef RISCVISAInfo::computeDefaultABI() const {
if (XLen == 32) {
if (hasExtension("d"))
return "ilp32d";
if (hasExtension("e"))
return "ilp32e";
return "ilp32";
} else if (XLen == 64) {
if (hasExtension("d"))
return "lp64d";
return "lp64";
}
llvm_unreachable("Invalid XLEN");
}