[llvm] [RISC-V][RVY] Initial ISAInfo support for RVY (PR #201931)
Alexander Richardson via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 5 00:44:12 PDT 2026
https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/201931
>From 07852a54eb40726f0659f276079e9000da16e600 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 5 Jun 2026 13:21:37 -0700
Subject: [PATCH 1/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
=?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.8-beta.1
---
llvm/lib/TargetParser/RISCVISAInfo.cpp | 82 +++++--
.../TargetParser/RISCVISAInfoTest.cpp | 200 ++++++++++++++++--
2 files changed, 252 insertions(+), 30 deletions(-)
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 7b04b42f8d000..363ae4148a621 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -593,7 +593,7 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
if (XLen == 0 || Arch.empty())
return getError(
- "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
+ "string must begin with rv32{i,e,g,y}, rv64{i,e,g,y}, or a supported "
"profile name");
std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
@@ -606,11 +606,11 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
unsigned Major, Minor, ConsumeLength;
- // First letter should be 'e', 'i' or 'g'.
+ // First letter should be 'e', 'i', 'g' or 'y'.
switch (Baseline) {
default:
return getError("first letter after \'rv" + Twine(XLen) +
- "\' should be 'e', 'i' or 'g'");
+ "\' should be 'e', 'i', 'g' or 'y'");
case 'e':
case 'i':
// Baseline is `i` or `e`
@@ -621,6 +621,23 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
ISAInfo->Exts[std::string(1, Baseline)] = {Major, Minor};
break;
+ case 'y':
+ // If the first character is 'y', this is equivalent to "iy".
+ // TODO: arch string syntax for RVE+RVY (and y in non-first position) will
+ // be included following conclusion of "long base name" syntax
+ // https://lists.riscv.org/g/tech-unprivileged/message/1134
+ if (auto E = getExtensionVersion("y", Arch, Major, Minor, ConsumeLength,
+ EnableExperimentalExtension,
+ ExperimentalExtensionVersionCheck))
+ return std::move(E);
+
+ ISAInfo->Exts["y"] = {Major, Minor};
+ if (auto IVersion = findDefaultVersion("i")) {
+ ISAInfo->Exts["i"] = {IVersion->Major, IVersion->Minor};
+ } else {
+ llvm_unreachable("Default 'i' extension version not found?");
+ }
+ break;
case 'g':
// g expands to extensions in RISCVGImplications.
if (!Arch.empty() && isDigit(Arch.front()))
@@ -730,6 +747,10 @@ static Error getIncompatibleError(StringRef Ext1, StringRef Ext2) {
"' extensions are incompatible");
}
+static Error getBaseIncompatibleError(StringRef Ext, StringRef Base) {
+ return getError("'" + Ext + "' is incompatible with " + Base + " base");
+}
+
static Error getExtensionRequiresError(StringRef Ext, StringRef ReqExt) {
return getError("'" + Ext + "' requires '" + ReqExt +
"' extension to also be specified");
@@ -795,6 +816,20 @@ Error RISCVISAInfo::checkDependency() {
if (Exts.count("zclsd") != 0 && Exts.count("zcf") != 0)
return getIncompatibleError("zclsd", "zcf");
+ if (Exts.count("y") != 0) {
+ if (XLen == 32) {
+ // On RVY32 systems the zclsd/zcf encodings are used for y load/stores.
+ if (Exts.count("zclsd") != 0)
+ return getBaseIncompatibleError("zclsd", "rv32y");
+ if (Exts.count("zcf") != 0)
+ return getBaseIncompatibleError("zcf", "rv32y");
+ } else {
+ // On RVY64 systems the zcd encodings are used for y load/stores.
+ if (Exts.count("zcd") != 0)
+ return getBaseIncompatibleError("zcd", "rv64y");
+ }
+ }
+
if (HasZcmp && HasXqccmp)
return getIncompatibleError("zcmp", "xqccmp");
@@ -848,21 +883,23 @@ void RISCVISAInfo::updateImplication() {
}
}
- // Add Zcd if C and D are enabled.
- if (Exts.count("c") && Exts.count("d") && !Exts.count("zcd")) {
+ // Add Zcd if C and D are enabled and we aren't targeting 64-bit RVY.
+ if (Exts.count("c") && Exts.count("d") && !Exts.count("zcd") &&
+ (XLen == 32 || !Exts.count("y"))) {
auto Version = findDefaultVersion("zcd");
Exts["zcd"] = *Version;
}
- // Add Zcf if C and F are enabled on RV32.
- if (XLen == 32 && Exts.count("c") && Exts.count("f") && !Exts.count("zcf")) {
+ // Add Zcf if C and F are enabled on RV32 and Y is not enabled.
+ if (XLen == 32 && Exts.count("c") && Exts.count("f") && !Exts.count("zcf") &&
+ !Exts.count("y")) {
auto Version = findDefaultVersion("zcf");
Exts["zcf"] = *Version;
}
- // Add Zcf if Zce and F are enabled on RV32.
+ // Add Zcf if Zce and F are enabled on RV32 and Y is not enabled.
if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
- !Exts.count("zcf")) {
+ !Exts.count("zcf") && !Exts.count("y")) {
auto Version = findDefaultVersion("zcf");
Exts["zcf"] = *Version;
}
@@ -877,18 +914,24 @@ void RISCVISAInfo::updateImplication() {
// For RV64:
// - No D: Zca alone implies C
// - D: Zca + Zcd implies C
+ // For RV32Y (Zcf incompatible):
+ // - No D (but maybe F): Zca alone implies C
+ // - F and D: Zca + Zcd implies C
+ // For RV64Y (Zcf and Zcd incompatible):
+ // - Zca alone implies C
if (Exts.count("zca") && !Exts.count("c")) {
bool ShouldAddC = false;
if (XLen == 32) {
if (Exts.count("d"))
- ShouldAddC = Exts.count("zcf") && Exts.count("zcd");
+ ShouldAddC =
+ Exts.count("zcd") && (Exts.count("y") || Exts.count("zcf"));
else if (Exts.count("f"))
- ShouldAddC = Exts.count("zcf");
+ ShouldAddC = Exts.count("y") || Exts.count("zcf");
else
ShouldAddC = true;
} else if (XLen == 64) {
if (Exts.count("d"))
- ShouldAddC = Exts.count("zcd");
+ ShouldAddC = Exts.count("y") || Exts.count("zcd");
else
ShouldAddC = true;
}
@@ -898,13 +941,16 @@ void RISCVISAInfo::updateImplication() {
}
}
- if (!Exts.count("zce") && Exts.count("zca") && Exts.count("zcb") &&
- Exts.count("zcmp") && Exts.count("zcmt")) {
+ if (!Exts.count("zce") && Exts.count("zca") && Exts.count("zcb")) {
bool ShouldAddZce = false;
- if (XLen == 32) {
- ShouldAddZce = !Exts.count("f") || Exts.count("zcf");
- } else if (XLen == 64) {
- ShouldAddZce = true;
+ if (Exts.count("zcmp") && Exts.count("zcmt")) {
+ if (XLen == 32) {
+ ShouldAddZce = !Exts.count("f") || Exts.count("zcf") || Exts.count("y");
+ } else if (XLen == 64) {
+ ShouldAddZce = true;
+ }
+ } else if (Exts.count("y") && XLen == 64) {
+ ShouldAddZce = true; // For RV64Y only Zce only includes Zca and Zcb
}
if (ShouldAddZce)
Exts["zce"] = *findDefaultVersion("zce");
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 9e7f23e2b4f76..5e32d56d89d28 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -172,25 +172,104 @@ TEST(ParseArchString, RejectsInvalidChars) {
TEST(ParseArchString, RejectsInvalidBaseISA) {
for (StringRef Input : {"rv32", "rv64", "rv65i"}) {
- EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
- "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
- "profile name");
+ EXPECT_EQ(
+ toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+ "string must begin with rv32{i,e,g,y}, rv64{i,e,g,y}, or a supported "
+ "profile name");
}
for (StringRef Input : {"rv32j", "rv32_i"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
- "first letter after 'rv32' should be 'e', 'i' or 'g'");
+ "first letter after 'rv32' should be 'e', 'i', 'g' or 'y'");
}
EXPECT_EQ(toString(RISCVISAInfo::parseArchString("rv64k", true).takeError()),
- "first letter after 'rv64' should be 'e', 'i' or 'g'");
+ "first letter after 'rv64' should be 'e', 'i', 'g' or 'y'");
+
+ // rv32yi/ye fail because rv32y implicitly enables i, and i/e are not valid
+ // extensions to follow it.
+ for (StringRef Input : {"rv32yi", "rv64yi"}) {
+ EXPECT_EQ(
+ toString(RISCVISAInfo::parseArchString(Input, true, false).takeError()),
+ "invalid standard user-level extension 'i'");
+ }
+ // TODO: arch string syntax for RVE+RVY (and y in non-first position) will be
+ // included following conclusion of
+ // https://lists.riscv.org/g/tech-unprivileged/message/1134
+ for (StringRef Input : {"rv32ye", "rv64ye"}) {
+ EXPECT_EQ(
+ toString(RISCVISAInfo::parseArchString(Input, true, false).takeError()),
+ "invalid standard user-level extension 'e'");
+ }
+ for (StringRef Input : {"rv32y0p98i", "rv64y0p98i"}) {
+ EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+ "invalid standard user-level extension 'i'");
+ }
+ for (StringRef Input : {"rv32y0p98e", "rv64y0p98e"}) {
+ EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+ "invalid standard user-level extension 'e'");
+ }
+}
+
+TEST(ParseArchString, RejectsInvalidYPosition) {
+ // y in non-first position is rejected.
+ for (StringRef Input :
+ {"rv32ey0p98", "rv64ey0p98", "rv32iy0p98", "rv64iy0p98"}) {
+ EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+ "invalid standard user-level extension 'y'");
+ }
+ for (StringRef Input : {"rv32ey", "rv64ey", "rv32iy", "rv64iy"}) {
+ EXPECT_EQ(
+ toString(RISCVISAInfo::parseArchString(Input, true, false).takeError()),
+ "invalid standard user-level extension 'y'");
+ }
+}
+
+TEST(ParseArchString, MissingBaseISA) {
+ // With version check enabled (default), we must specify the version for
+ // experimental extension 'y'.
+ auto MaybeRV32Y = RISCVISAInfo::parseArchString("rv32y0p98", true);
+ ASSERT_THAT_EXPECTED(MaybeRV32Y, Succeeded());
+ RISCVISAInfo &InfoRV32Y = **MaybeRV32Y;
+ const auto &ExtsRV32Y = InfoRV32Y.getExtensions();
+ EXPECT_EQ(ExtsRV32Y.size(), 2UL); // i, y
+ EXPECT_TRUE(ExtsRV32Y.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
+ EXPECT_TRUE(ExtsRV32Y.at("y") == (RISCVISAUtils::ExtensionVersion{0, 98}));
+ EXPECT_EQ(InfoRV32Y.getXLen(), 32U);
+
+ // rv32y0p98m should succeed and contain i, m, y0p98, zmmul
+ auto MaybeRV32YM = RISCVISAInfo::parseArchString("rv32y0p98m", true);
+ ASSERT_THAT_EXPECTED(MaybeRV32YM, Succeeded());
+ RISCVISAInfo &InfoRV32YM = **MaybeRV32YM;
+ EXPECT_EQ(InfoRV32YM.getExtensions().size(), 4UL); // i, m, y, zmmul
+ EXPECT_TRUE(InfoRV32YM.getExtensions().at("i") ==
+ (RISCVISAUtils::ExtensionVersion{2, 1}));
+ EXPECT_TRUE(InfoRV32YM.getExtensions().at("m") ==
+ (RISCVISAUtils::ExtensionVersion{2, 0}));
+ EXPECT_TRUE(InfoRV32YM.getExtensions().at("y") ==
+ (RISCVISAUtils::ExtensionVersion{0, 98}));
+
+ // We can also parse it without version if we disable the version check.
+ auto MaybeRV32YNoVal = RISCVISAInfo::parseArchString("rv32y", true, false);
+ ASSERT_THAT_EXPECTED(MaybeRV32YNoVal, Succeeded());
+ EXPECT_EQ((*MaybeRV32YNoVal)->getExtensions().size(), 2UL);
+
+ auto MaybeRV64Y = RISCVISAInfo::parseArchString("rv64y0p98", true);
+ ASSERT_THAT_EXPECTED(MaybeRV64Y, Succeeded());
+ RISCVISAInfo &InfoRV64Y = **MaybeRV64Y;
+ const auto &ExtsRV64Y = InfoRV64Y.getExtensions();
+ EXPECT_EQ(ExtsRV64Y.size(), 2UL); // i, y
+ EXPECT_TRUE(ExtsRV64Y.at("i") == (RISCVISAUtils::ExtensionVersion{2, 1}));
+ EXPECT_TRUE(ExtsRV64Y.at("y") == (RISCVISAUtils::ExtensionVersion{0, 98}));
+ EXPECT_EQ(InfoRV64Y.getXLen(), 64U);
}
TEST(ParseArchString, RejectsUnsupportedBaseISA) {
for (StringRef Input : {"rv128i", "rv128g"}) {
- EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
- "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
- "profile name");
+ EXPECT_EQ(
+ toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+ "string must begin with rv32{i,e,g,y}, rv64{i,e,g,y}, or a supported "
+ "profile name");
}
}
@@ -479,7 +558,7 @@ TEST(ParseArchString, AcceptsAmbiguousFromRelaxExtensions) {
TEST(ParseArchString, RejectsRelaxExtensionsNotStartWithEorIorG) {
EXPECT_EQ(
toString(RISCVISAInfo::parseArchString("rv32zba_im", true).takeError()),
- "first letter after 'rv32' should be 'e', 'i' or 'g'");
+ "first letter after 'rv32' should be 'e', 'i', 'g' or 'y'");
}
TEST(ParseArchString,
@@ -581,6 +660,10 @@ TEST(ParseArchString, RejectsUnrecognizedVersionForExperimentalExtension) {
toString(RISCVISAInfo::parseArchString("rv64izibi9p9", true).takeError()),
"unsupported version number 9.9 for experimental extension 'zibi' "
"(this compiler supports 0.1)");
+ EXPECT_EQ(
+ toString(RISCVISAInfo::parseArchString("rv64y0p97", true).takeError()),
+ "unsupported version number 0.97 for experimental extension 'y' "
+ "(this compiler supports 0.98)");
}
TEST(ParseArchString, RejectsExtensionVersionForG) {
@@ -674,6 +757,18 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
EXPECT_THAT(Error, ::testing::EndsWith("' is only supported for 'rv32'"));
EXPECT_THAT(Error, ::testing::HasSubstr(ConflictingExt));
}
+ EXPECT_EQ(
+ toString(
+ RISCVISAInfo::parseArchString("rv32y0p98_zcf", true).takeError()),
+ "'zcf' is incompatible with rv32y base");
+ EXPECT_EQ(
+ toString(
+ RISCVISAInfo::parseArchString("rv32y0p98_zclsd", true).takeError()),
+ "'zclsd' is incompatible with rv32y base");
+ EXPECT_EQ(
+ toString(
+ RISCVISAInfo::parseArchString("rv64y0p98_zcd", true).takeError()),
+ "'zcd' is incompatible with rv64y base");
// In these ISA strings, the non-zcd extension should be last, after an
// underscore.
@@ -740,9 +835,10 @@ TEST(ParseArchString, MissingDepency) {
TEST(ParseArchString, RejectsUnrecognizedProfileNames) {
for (StringRef Input : {"rvi23u99", "rvz23u64", "rva99u32"}) {
- EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
- "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
- "profile name");
+ EXPECT_EQ(
+ toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+ "string must begin with rv32{i,e,g,y}, rv64{i,e,g,y}, or a supported "
+ "profile name");
}
}
@@ -1028,6 +1124,51 @@ TEST(ParseArchString, ZcaImpliesC) {
EXPECT_EQ(ExtsRV64IDZca.count("c"), 0U);
}
+TEST(ParseArchString, RVYZcaImpliesC) {
+ // RV32Y without D (maybe with F): Zca implies C (Zcf opcodes remapped in Y).
+ for (StringRef Input : {"rv32y_zca", "rv32yf_zca"}) {
+ auto ISAInfo = RISCVISAInfo::parseArchString(Input, true, false);
+ ASSERT_THAT_EXPECTED(ISAInfo, Succeeded());
+ const auto &Exts = (*ISAInfo)->getExtensions();
+ EXPECT_EQ(Exts.count("c"), 1U);
+ EXPECT_EQ(Exts.count("zca"), 1U);
+ EXPECT_EQ(Exts.count("zcf"), 0U);
+ EXPECT_EQ(Exts.count("zcd"), 0U);
+ }
+ // RV32Y with D: Zca+Zcd implies C (Zcf opcodes remapped in Y)
+ for (StringRef Input : {"rv32yfd_zca_zcd"}) {
+ auto MaybeRV32YDZcaZcd = RISCVISAInfo::parseArchString(Input, true, false);
+ ASSERT_THAT_EXPECTED(MaybeRV32YDZcaZcd, Succeeded());
+ const auto &ExtsRV32YDZcaZcd = (*MaybeRV32YDZcaZcd)->getExtensions();
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("c"), 1U);
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("zca"), 1U);
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("zcf"), 0U);
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("zcd"), 1U);
+ }
+ // RV32Y with D but no Zcd: no C
+ for (StringRef Input : {"rv32yfd_zca"}) {
+ auto MaybeRV32YDZcaZcd = RISCVISAInfo::parseArchString(Input, true, false);
+ ASSERT_THAT_EXPECTED(MaybeRV32YDZcaZcd, Succeeded());
+ const auto &ExtsRV32YDZcaZcd = (*MaybeRV32YDZcaZcd)->getExtensions();
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("c"), 0U);
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("zca"), 1U);
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("zcf"), 0U);
+ EXPECT_EQ(ExtsRV32YDZcaZcd.count("zcd"), 0U);
+ }
+
+ // RV64Y: Zca always implies C (regardless of F/D) since Zcf opcodes are
+ // repurposed for 64-bit loads/stores and Zcd for capability loads/stores.
+ for (StringRef Input : {"rv64y_zca", "rv64yf_zca", "rv64yfd_zca"}) {
+ auto ISAInfo = RISCVISAInfo::parseArchString(Input, true, false);
+ ASSERT_THAT_EXPECTED(ISAInfo, Succeeded());
+ const auto &Exts = (*ISAInfo)->getExtensions();
+ EXPECT_EQ(Exts.count("c"), 1U);
+ EXPECT_EQ(Exts.count("zca"), 1U);
+ EXPECT_EQ(Exts.count("zcf"), 0U);
+ EXPECT_EQ(Exts.count("zcd"), 0U);
+ }
+}
+
TEST(ParseArchString, ZcaZcbZcmpZcmtImpliesZce) {
// Test Zca+Zcb+Zcmp+Zcmt implies Zce behavior.
@@ -1112,6 +1253,41 @@ TEST(ParseArchString, ZcaZcbZcmpZcmtImpliesZce) {
EXPECT_EQ(ExtsRV64IFZcaZcbZcmpZcmt.count("zce"), 1U);
EXPECT_EQ(ExtsRV64IFZcaZcbZcmpZcmt.count("zcmp"), 1U);
EXPECT_EQ(ExtsRV64IFZcaZcbZcmpZcmt.count("zcmt"), 1U);
+
+ // RV32Y Zca+Zcb+Zcmp+Zcmt implies Zce regardless of F (Zcf incompatible)
+ for (StringRef Input : {"rv32y_zca_zcb_zcmp_zcmt", "rv32yf_zca_zcb_zcmp_zcmt",
+ "rv32yfd_zca_zcb_zcmp_zcmt"}) {
+ auto ISAInfo = RISCVISAInfo::parseArchString(Input, true, false);
+ ASSERT_THAT_EXPECTED(ISAInfo, Succeeded());
+ const auto &Exts = (*ISAInfo)->getExtensions();
+ EXPECT_EQ(Exts.count("i"), 1U);
+ EXPECT_EQ(Exts.count("y"), 1U);
+ EXPECT_EQ(Exts.count("c"), !Exts.count("d")); // Zcd missing
+ EXPECT_EQ(Exts.count("zicsr"), 1U);
+ EXPECT_EQ(Exts.count("zca"), 1U);
+ EXPECT_EQ(Exts.count("zcb"), 1U);
+ EXPECT_EQ(Exts.count("zce"), 1U);
+ EXPECT_EQ(Exts.count("zcmp"), 1U);
+ EXPECT_EQ(Exts.count("zcmt"), 1U);
+ EXPECT_EQ(Exts.size(), 9UL + Exts.count("f"));
+ }
+ // RV64Y Zca+Zcb implies Zce regardless of F (Zcf+Zcmp+Zcmt incompatible)
+ for (StringRef Input :
+ {"rv64y_zca_zcb", "rv64yf_zca_zcb", "rv64yfd_zca_zcb"}) {
+ auto ISAInfo = RISCVISAInfo::parseArchString(Input, true, false);
+ ASSERT_THAT_EXPECTED(ISAInfo, Succeeded());
+ const auto &Exts = (*ISAInfo)->getExtensions();
+ EXPECT_EQ(Exts.count("i"), 1U);
+ EXPECT_EQ(Exts.count("y"), 1U);
+ EXPECT_EQ(Exts.count("c"), 1U);
+ EXPECT_EQ(Exts.count("zicsr"), Exts.count("f"));
+ EXPECT_EQ(Exts.count("zca"), 1U);
+ EXPECT_EQ(Exts.count("zcb"), 1U);
+ EXPECT_EQ(Exts.count("zce"), 1U);
+ EXPECT_EQ(Exts.count("zcmp"), 0U);
+ EXPECT_EQ(Exts.count("zcmt"), 0U);
+ EXPECT_EQ(Exts.size(), 6UL + Exts.count("d") + 2 * Exts.count("f"));
+ }
}
TEST(isSupportedExtensionWithVersion, AcceptsSingleExtensionWithVersion) {
>From 62889d409f21b5d4cfe1dd8c7d0debc882c1b306 Mon Sep 17 00:00:00 2001
From: Alexander Richardson <alexrichardson at google.com>
Date: Sat, 6 Jun 2026 11:44:14 -0700
Subject: [PATCH 2/4] Update llvm/lib/TargetParser/RISCVISAInfo.cpp
Co-authored-by: Craig Topper <craig.topper at sifive.com>
---
llvm/lib/TargetParser/RISCVISAInfo.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 363ae4148a621..09bbf7cd93a10 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -632,11 +632,9 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
return std::move(E);
ISAInfo->Exts["y"] = {Major, Minor};
- if (auto IVersion = findDefaultVersion("i")) {
- ISAInfo->Exts["i"] = {IVersion->Major, IVersion->Minor};
- } else {
- llvm_unreachable("Default 'i' extension version not found?");
- }
+ auto IVersion = findDefaultVersion("i");
+ assert(IVersion && "Default 'i' extension version not found?");
+ ISAInfo->Exts["i"] = {IVersion->Major, IVersion->Minor};
break;
case 'g':
// g expands to extensions in RISCVGImplications.
>From 30b43bcebde1ebd604a12f7d94415d73da991f4b Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Sun, 7 Jun 2026 21:56:00 -0700
Subject: [PATCH 3/4] clang-format
Created using spr 1.3.8-beta.1
---
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
index f93c88c66dea1..21e859a7d72a0 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -90,7 +90,7 @@ void RISCV::updateCZceFeatureImplications(MCSubtargetInfo &STI) {
STI.hasFeature(RISCV::FeatureStdExtD) &&
!STI.hasFeature(RISCV::FeatureStdExtZcd) &&
!(STI.hasFeature(RISCV::Feature64Bit) &&
- STI.hasFeature(RISCV::FeatureStdExtY)))
+ STI.hasFeature(RISCV::FeatureStdExtY)))
STI.ToggleFeature(RISCV::FeatureStdExtZcd);
// Add Zcf if F and C or Zce are enabled on RV32 and Y is not enabled.
>From 5dd67cf5850471e5c83c12d7c991ef301c1d2c98 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Sun, 5 Jul 2026 00:43:47 -0700
Subject: [PATCH 4/4] address review feedback
Created using spr 1.3.8-beta.1
---
.../RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp | 52 +++++++------------
llvm/lib/TargetParser/RISCVISAInfo.cpp | 18 +++----
llvm/test/MC/RISCV/rvy-build-attributes.s | 24 ++++-----
llvm/test/MC/RISCV/rvy-invalid-attributes.s | 26 +++++-----
4 files changed, 53 insertions(+), 67 deletions(-)
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
index 21e859a7d72a0..1cd95f3677c45 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -114,24 +114,17 @@ void RISCV::updateCZceFeatureImplications(MCSubtargetInfo &STI) {
// - D: Zca + Zcd/Y implies C
if (!STI.hasFeature(RISCV::FeatureStdExtC) &&
STI.hasFeature(RISCV::FeatureStdExtZca)) {
- bool ShouldAddC = false;
- if (!STI.hasFeature(RISCV::Feature64Bit)) {
- if (STI.hasFeature(RISCV::FeatureStdExtD))
- ShouldAddC = STI.hasFeature(RISCV::FeatureStdExtZcd) &&
- (STI.hasFeature(RISCV::FeatureStdExtY) ||
- STI.hasFeature(RISCV::FeatureStdExtZcf));
- else if (STI.hasFeature(RISCV::FeatureStdExtF))
- ShouldAddC = STI.hasFeature(RISCV::FeatureStdExtY) ||
- STI.hasFeature(RISCV::FeatureStdExtZcf);
- else
- ShouldAddC = true;
- } else {
- if (STI.hasFeature(RISCV::FeatureStdExtD))
- ShouldAddC = STI.hasFeature(RISCV::FeatureStdExtY) ||
- STI.hasFeature(RISCV::FeatureStdExtZcd);
- else
- ShouldAddC = true;
- }
+ bool ShouldAddC;
+ if (!STI.hasFeature(RISCV::Feature64Bit))
+ ShouldAddC = (!STI.hasFeature(RISCV::FeatureStdExtD) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcd)) &&
+ (STI.hasFeature(RISCV::FeatureStdExtY) ||
+ !STI.hasFeature(RISCV::FeatureStdExtF) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcf));
+ else
+ ShouldAddC = STI.hasFeature(RISCV::FeatureStdExtY) ||
+ !STI.hasFeature(RISCV::FeatureStdExtD) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcd);
if (ShouldAddC)
STI.ToggleFeature(RISCV::FeatureStdExtC);
}
@@ -142,23 +135,16 @@ void RISCV::updateCZceFeatureImplications(MCSubtargetInfo &STI) {
// - F: Zca+Zcb+Zcmp+Zcmt + Zcf/Y implies Zce
// For RV64:
// - Zca+Zcb+Zcmp+Zcmt alone implies Zce
- // - RV64Y: Zca+Zcb alone implies Zce
+ // - Note: RV64Y is incompatible with Zcmp/Zcmt, never implies Zce
if (!STI.hasFeature(RISCV::FeatureStdExtZce) &&
STI.hasFeature(RISCV::FeatureStdExtZca) &&
- STI.hasFeature(RISCV::FeatureStdExtZcb)) {
- bool ShouldAddZce = false;
- if (STI.hasFeature(RISCV::FeatureStdExtZcmp) &&
- STI.hasFeature(RISCV::FeatureStdExtZcmt)) {
- if (!STI.hasFeature(RISCV::Feature64Bit)) {
- ShouldAddZce = !STI.hasFeature(RISCV::FeatureStdExtF) ||
- STI.hasFeature(RISCV::FeatureStdExtZcf) ||
- STI.hasFeature(RISCV::FeatureStdExtY);
- } else {
- ShouldAddZce = true;
- }
- }
-
- if (ShouldAddZce)
+ STI.hasFeature(RISCV::FeatureStdExtZcb) &&
+ STI.hasFeature(RISCV::FeatureStdExtZcmp) &&
+ STI.hasFeature(RISCV::FeatureStdExtZcmt)) {
+ if (STI.hasFeature(RISCV::Feature64Bit) ||
+ STI.hasFeature(RISCV::FeatureStdExtY) ||
+ !STI.hasFeature(RISCV::FeatureStdExtF) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcf))
STI.ToggleFeature(RISCV::FeatureStdExtZce);
}
}
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index cabdf6241662f..3e9664e6ba070 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -817,13 +817,13 @@ Error RISCVISAInfo::checkDependency() {
if (Exts.count("y") != 0) {
if (XLen == 32) {
- // On RVY32 systems the zclsd/zcf encodings are used for y load/stores.
+ // On RV32Y systems the zclsd/zcf encodings are used for y load/stores.
if (Exts.count("zclsd") != 0)
return getBaseIncompatibleError("zclsd", "rv32y");
if (Exts.count("zcf") != 0)
return getBaseIncompatibleError("zcf", "rv32y");
} else {
- // On RVY64 systems the zcd encodings are used for y load/stores.
+ // On RV64Y systems the zcd encodings are used for y load/stores.
if (Exts.count("zcd") != 0)
return getBaseIncompatibleError("zcd", "rv64y");
for (auto Ext : ZcdOverlaps)
@@ -943,14 +943,14 @@ void RISCVISAInfo::updateImplication() {
}
}
- if (!Exts.count("zce") && Exts.count("zca") && Exts.count("zcb")) {
+ if (!Exts.count("zce") && Exts.count("zca") && Exts.count("zcb") &&
+ Exts.count("zcmp") && Exts.count("zcmt")) {
bool ShouldAddZce = false;
- if (Exts.count("zcmp") && Exts.count("zcmt")) {
- if (XLen == 32) {
- ShouldAddZce = !Exts.count("f") || Exts.count("zcf") || Exts.count("y");
- } else if (XLen == 64) {
- ShouldAddZce = true;
- }
+ if (XLen == 32) {
+ ShouldAddZce = !Exts.count("f") || Exts.count("zcf") || Exts.count("y");
+ } else if (XLen == 64) {
+ // Zce is incompatible with RV64Y, only add it if Y is not enabled.
+ ShouldAddZce = !Exts.count("y");
}
if (ShouldAddZce)
Exts["zce"] = *findDefaultVersion("zce");
diff --git a/llvm/test/MC/RISCV/rvy-build-attributes.s b/llvm/test/MC/RISCV/rvy-build-attributes.s
index 4a754ea91a398..2b1c8cae53c6f 100644
--- a/llvm/test/MC/RISCV/rvy-build-attributes.s
+++ b/llvm/test/MC/RISCV/rvy-build-attributes.s
@@ -1,23 +1,23 @@
# RUN: llvm-mc %s -triple=riscv64 -filetype=asm -riscv-add-build-attributes \
-# RUN: -mattr=+experimental-y,+c,+d | FileCheck %s --check-prefixes=RV64Y-CD
+# RUN: -mattr=+experimental-y,+d,+c | FileCheck %s --check-prefix=RV64YDC
# RUN: llvm-mc %s -triple=riscv32 -filetype=asm -riscv-add-build-attributes \
-# RUN: -mattr=+experimental-y,+c,+f | FileCheck %s --check-prefixes=RV32Y-CF
+# RUN: -mattr=+experimental-y,+f,+c | FileCheck %s --check-prefix=RV32YFC
# RUN: llvm-mc %s -triple=riscv32 -filetype=asm -riscv-add-build-attributes \
-# RUN: -mattr=+experimental-y,+zca,+f | FileCheck %s --check-prefixes=RV32Y-ZCA-F
+# RUN: -mattr=+experimental-y,+zca,+f | FileCheck %s --check-prefix=RV32Y-ZCA-F
# RUN: llvm-mc %s -triple=riscv64 -filetype=asm -riscv-add-build-attributes \
-# RUN: -mattr=+experimental-y,+zca,+d | FileCheck %s --check-prefixes=RV64Y-ZCA-D
+# RUN: -mattr=+experimental-y,+zca,+d | FileCheck %s --check-prefix=RV64Y-ZCA-D
# RUN: llvm-mc %s -triple=riscv64 -filetype=asm -riscv-add-build-attributes \
-# RUN: -mattr=+experimental-y,+zca,+zcb | FileCheck %s --check-prefixes=RV64Y-ZCA-ZCB
+# RUN: -mattr=+experimental-y,+zca,+zcb | FileCheck %s --check-prefix=RV64Y-ZCA-ZCB
# RUN: llvm-mc %s -triple=riscv32 -filetype=asm -riscv-add-build-attributes \
-# RUN: -mattr=+experimental-y,+zce | FileCheck %s --check-prefixes=RV32Y-ZCE
+# RUN: -mattr=+experimental-y,+zce | FileCheck %s --check-prefix=RV32Y-ZCE
# RUN: llvm-mc %s -triple=riscv32 -filetype=asm -riscv-add-build-attributes \
-# RUN: -mattr=+experimental-y,+zce,+f | FileCheck %s --check-prefixes=RV32Y-ZCE-F
+# RUN: -mattr=+experimental-y,+zce,+f | FileCheck %s --check-prefix=RV32Y-ZCE-F
-## RV64Y + C + D: y is enabled, so zcd is not implied.
-# RV64Y-CD: .attribute 5, "rv64i2p1_f2p2_d2p2_c2p0_y0p98_zicsr2p0_zca1p0"
+## RV64Y + D + C: y is enabled, so zcd is not implied.
+# RV64YDC: .attribute 5, "rv64i2p1_f2p2_d2p2_c2p0_y0p98_zicsr2p0_zca1p0"
-## RV32Y + C + F: y is enabled, so zcf is not implied.
-# RV32Y-CF: .attribute 5, "rv32i2p1_f2p2_c2p0_y0p98_zicsr2p0_zca1p0"
+## RV32Y + F + C: y is enabled, so zcf is not implied.
+# RV32YFC: .attribute 5, "rv32i2p1_f2p2_c2p0_y0p98_zicsr2p0_zca1p0"
## RV32Y + ZCA + F: zca + y implies c on RV32 (y replaces zcf in the implication).
# RV32Y-ZCA-F: .attribute 5, "rv32i2p1_f2p2_c2p0_y0p98_zicsr2p0_zca1p0"
@@ -32,4 +32,4 @@
# RV32Y-ZCE: .attribute 5, "rv32i2p1_c2p0_y0p98_zicsr2p0_zca1p0_zcb1p0_zce1p0_zcmp1p0_zcmt1p0"
## RV32Y + ZCE + F: y is enabled, so zcf is not implied by zce + f. zca + y + f implies c.
-# RV32Y-ZCE-F: .attribute 5, "rv32i2p1_f2p2_c2p0_y0p98_zicsr2p0_zca1p0_zcb1p0_zce1p0_zcmp1p0_zcmt1p0"
+# RV32Y-ZCE-F: .attribute 5, "rv32i2p1_f2p2_c2p0_y0p98_zicsr2p0_zca1p0_zcb1p0_zce1p0_zcmp1p0_zcmt1p0"
\ No newline at end of file
diff --git a/llvm/test/MC/RISCV/rvy-invalid-attributes.s b/llvm/test/MC/RISCV/rvy-invalid-attributes.s
index 3f37f832fff36..7ba9deb840f54 100644
--- a/llvm/test/MC/RISCV/rvy-invalid-attributes.s
+++ b/llvm/test/MC/RISCV/rvy-invalid-attributes.s
@@ -1,18 +1,18 @@
-# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+zce /dev/null 2>&1 | FileCheck %s --check-prefix=CLI-RV64Y-ZCE
-# RUN: not llvm-mc -triple=riscv32 -mattr=+experimental-y,+zcf /dev/null 2>&1 | FileCheck %s --check-prefix=CLI-RV32Y-ZCF
-# RUN: not llvm-mc -triple=riscv32 -mattr=+experimental-y,+zclsd /dev/null 2>&1 | FileCheck %s --check-prefix=CLI-RV32Y-ZCLSD
-# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+zcd /dev/null 2>&1 | FileCheck %s --check-prefix=CLI-RV64Y-ZCD
-# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+c,+zcmp /dev/null 2>&1 | FileCheck %s --check-prefix=CLI-RV64Y-C-ZCMP
-# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+zca,+zcmp /dev/null 2>&1 | FileCheck %s --check-prefix=CLI-RV64Y-ZCA-ZCMP
+# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+zce /dev/null 2>&1 | FileCheck %s --check-prefix=RV64Y-ZCE
+# RUN: not llvm-mc -triple=riscv32 -mattr=+experimental-y,+zcf /dev/null 2>&1 | FileCheck %s --check-prefix=RV32Y-ZCF
+# RUN: not llvm-mc -triple=riscv32 -mattr=+experimental-y,+zclsd /dev/null 2>&1 | FileCheck %s --check-prefix=RV32Y-ZCLSD
+# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+zcd /dev/null 2>&1 | FileCheck %s --check-prefix=RV64Y-ZCD
+# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+c,+zcmp /dev/null 2>&1 | FileCheck %s --check-prefix=RV64Y-C-ZCMP
+# RUN: not llvm-mc -triple=riscv64 -mattr=+experimental-y,+zca,+zcmp /dev/null 2>&1 | FileCheck %s --check-prefix=RV64Y-ZCA-ZCMP
# RUN: not llvm-mc -triple=riscv64 < %s 2>&1 | FileCheck %s --check-prefix=ATTR --implicit-check-not="error:"
-# CLI-RV64Y-ZCE: LLVM ERROR: 'zcmt' is incompatible with rv64y base
-# CLI-RV32Y-ZCF: LLVM ERROR: 'zcf' is incompatible with rv32y base
-# CLI-RV32Y-ZCLSD: LLVM ERROR: 'zclsd' is incompatible with rv32y base
-# CLI-RV64Y-ZCD: LLVM ERROR: 'zcd' is incompatible with rv64y base
-# CLI-RV64Y-C-ZCMP: LLVM ERROR: 'zcmp' is incompatible with rv64y base
-# CLI-RV64Y-ZCA-ZCMP: LLVM ERROR: 'zcmp' is incompatible with rv64y base
+# RV64Y-ZCE: LLVM ERROR: 'zcmt' is incompatible with rv64y base
+# RV32Y-ZCF: LLVM ERROR: 'zcf' is incompatible with rv32y base
+# RV32Y-ZCLSD: LLVM ERROR: 'zclsd' is incompatible with rv32y base
+# RV64Y-ZCD: LLVM ERROR: 'zcd' is incompatible with rv64y base
+# RV64Y-C-ZCMP: LLVM ERROR: 'zcmp' is incompatible with rv64y base
+# RV64Y-ZCA-ZCMP: LLVM ERROR: 'zcmp' is incompatible with rv64y base
.attribute arch, "rv64y0p98_zce"
# ATTR: error: invalid arch name 'rv64y0p98_zce', 'zcmt' is incompatible with rv64y base
@@ -30,4 +30,4 @@
# ATTR: error: invalid arch name 'rv64y0p98_c_zcmp', 'zcmp' is incompatible with rv64y base
.attribute arch, "rv64y0p98_zca_zcmp"
-# ATTR: error: invalid arch name 'rv64y0p98_zca_zcmp', 'zcmp' is incompatible with rv64y base
+# ATTR: error: invalid arch name 'rv64y0p98_zca_zcmp', 'zcmp' is incompatible with rv64y base
\ No newline at end of file
More information about the llvm-commits
mailing list