summaryrefslogtreecommitdiff
path: root/llvm/lib/Support/RISCVISAInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/RISCVISAInfo.cpp')
-rw-r--r--llvm/lib/Support/RISCVISAInfo.cpp247
1 files changed, 144 insertions, 103 deletions
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index 8e984002f90d..e2e4340f44e9 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -61,7 +61,6 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
{"zbs", RISCVExtensionVersion{1, 0}},
{"zbt", RISCVExtensionVersion{0, 93}},
- {"zvamo", RISCVExtensionVersion{0, 10}},
{"zvlsseg", RISCVExtensionVersion{0, 10}},
{"zfhmin", RISCVExtensionVersion{0, 1}},
@@ -72,6 +71,28 @@ static bool stripExperimentalPrefix(StringRef &Ext) {
return Ext.consume_front("experimental-");
}
+// This function finds the first character that doesn't belong to a version
+// (e.g. zbe0p93 is extension 'zbe' of version '0p93'). So the function will
+// consume [0-9]*p[0-9]* starting from the backward. An extension name will not
+// end with a digit or the letter 'p', so this function will parse correctly.
+// NOTE: This function is NOT able to take empty strings or strings that only
+// have version numbers and no extension name. It assumes the extension name
+// will be at least more than one character.
+static size_t findFirstNonVersionCharacter(const StringRef &Ext) {
+ if (Ext.size() == 0)
+ llvm_unreachable("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;
@@ -264,10 +285,6 @@ void RISCVISAInfo::toFeatures(
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 {
@@ -390,7 +407,6 @@ RISCVISAInfo::parseFeatures(unsigned XLen,
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;
@@ -409,29 +425,19 @@ RISCVISAInfo::parseFeatures(unsigned XLen,
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;
- }
-
+ if (Add)
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->Exts.erase(ExtName.str());
}
+ ISAInfo->updateImplication();
ISAInfo->updateFLen();
+ if (Error Result = ISAInfo->checkDependency())
+ return std::move(Result);
+
return std::move(ISAInfo);
}
@@ -457,7 +463,6 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
// 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'.
@@ -478,8 +483,6 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
case 'g':
// g = imafd
StdExts = StdExts.drop_front(4);
- HasF = true;
- HasD = true;
break;
}
@@ -560,34 +563,14 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
// 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".
+ // Currently LLVM supports only "mafdcbv".
+ StringRef SupportedStandardExtension = "mafdcbv";
+ if (!SupportedStandardExtension.contains(C))
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;
- }
+ ISAInfo->addExtension(std::string(1, C), Major, Minor);
+
// Consume full extension name and version, including any optional '_'
// between this extension and the next
++I;
@@ -595,21 +578,6 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
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.
@@ -630,52 +598,53 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
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 '_'");
- 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));
- 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 + "'");
- 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;
- // 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 (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());
- }
+ 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);
+ 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());
+ // 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);
+ 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) {
@@ -686,11 +655,83 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
}
}
+ ISAInfo->updateImplication();
ISAInfo->updateFLen();
+ if (Error Result = ISAInfo->checkDependency())
+ return std::move(Result);
+
return std::move(ISAInfo);
}
+Error RISCVISAInfo::checkDependency() {
+ bool IsRv32 = XLen == 32;
+ bool HasE = Exts.count("e") == 1;
+ bool HasD = Exts.count("d") == 1;
+ bool HasF = Exts.count("f") == 1;
+
+ if (HasE && !IsRv32)
+ return createStringError(
+ errc::invalid_argument,
+ "standard user-level extension 'e' requires 'rv32'");
+
+ // 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'.
+
+ return Error::success();
+}
+
+static const char *ImpliedExtsV[] = {"zvlsseg"};
+static const char *ImpliedExtsZfh[] = {"zfhmin"};
+
+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}},
+ {{"zfh"}, {ImpliedExtsZfh}},
+};
+
+void RISCVISAInfo::updateImplication() {
+ bool HasE = Exts.count("e") == 1;
+ bool HasI = Exts.count("i") == 1;
+
+ // If not in e extension and i extension does not exist, i extension is
+ // implied
+ if (!HasE && !HasI) {
+ auto Version = findDefaultVersion("i");
+ addExtension("i", Version->Major, Version->Minor);
+ }
+
+ assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
+ for (auto &Ext : Exts) {
+ auto I = llvm::lower_bound(ImpliedExts, Ext.first);
+ if (I != std::end(ImpliedExts) && I->Name == Ext.first) {
+ for (auto &ImpliedExt : I->Exts) {
+ auto Version = findDefaultVersion(ImpliedExt);
+ addExtension(ImpliedExt, Version->Major, Version->Minor);
+ }
+ }
+ }
+}
+
void RISCVISAInfo::updateFLen() {
FLen = 0;
// TODO: Handle q extension.