[clang] [llvm] [RISC-V][RVY] Fix round-trip and order of arch strings with 'y' (PR #227865)

Alexander Richardson via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 00:08:09 PDT 2026


https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/227865

>From 18dd6895afc58b5dd4829fe298e6d1ed4c91d117 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Wed, 30 Sep 2026 13:50:51 -0700
Subject: [PATCH 1/3] [RISC-V][RVY] Fix round-trip and order of arch strings
 with 'y'

Because 'y' is not in AllStdExts, singleLetterExtensionRank previously
fell through to the unknown single-letter extension case which results
in incorrect behaviour for the RVY base ISA.
For normalized RVY ISA strings and '.attribute arch' round-tripping, we
have two options: omit 'i' when 'y' is present, or always emit both the
'i'/'e' base and 'y' (and accept 'y' immediately after 'i' or 'e' in
parseArchString). This commit does the latter to align with the "longer
base name" proposal (https://lists.riscv.org/g/tech-unprivileged/topic/longer_base_name_proposal/116854896)
of using `RV{32,64}L{I,E}Y`, Adding support for parsing 'i'/'e' also
makes it easier to support the CHERIoT 'rv32ey.

This commit was created with the help of AI tools
---
 .../Driver/print-supported-extensions-riscv.c     |  2 +-
 llvm/lib/Support/RISCVISAUtils.cpp                |  6 ++++--
 llvm/test/MC/RISCV/rvy-build-attributes.s         | 14 +++++++-------
 llvm/unittests/TargetParser/RISCVISAInfoTest.cpp  | 15 +++++++++++----
 4 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index f916bef0a6519..1d1714314d6e2 100644
--- a/clang/test/Driver/print-supported-extensions-riscv.c
+++ b/clang/test/Driver/print-supported-extensions-riscv.c
@@ -247,8 +247,8 @@
 // CHECK-NEXT:     xwchc                2.2       'Xwchc' (WCH/QingKe additional compressed opcodes)
 // CHECK-EMPTY:
 // CHECK-NEXT: Experimental extensions
-// CHECK-NEXT:     p                    0.21      'P' ('Base P' (Packed SIMD))
 // CHECK-NEXT:     y                    0.910     'Y' ('Base Y' (CHERI))
+// CHECK-NEXT:     p                    0.21      'P' ('Base P' (Packed SIMD))
 // CHECK-NEXT:     zibi                 0.1       'Zibi' (Branch with Immediate)
 // CHECK-NEXT:     zicfilp              1.0       'Zicfilp' (Landing pad)
 // CHECK-NEXT:     zilx                 0.1       'Zilx' (Indexed Integer Load Instructions)
diff --git a/llvm/lib/Support/RISCVISAUtils.cpp b/llvm/lib/Support/RISCVISAUtils.cpp
index d6b002e66e7ab..2166d2f30bbb9 100644
--- a/llvm/lib/Support/RISCVISAUtils.cpp
+++ b/llvm/lib/Support/RISCVISAUtils.cpp
@@ -44,15 +44,17 @@ static unsigned singleLetterExtensionRank(char Ext) {
     return 0;
   case 'e':
     return 1;
+  case 'y':
+    return 2;
   }
 
   size_t Pos = RISCVISAUtils::AllStdExts.find(Ext);
   if (Pos != StringRef::npos)
-    return Pos + 2; // Skip 'e' and 'i' from above.
+    return Pos + 3; // Skip 'e', 'i', and 'y' from above.
 
   // If we got an unknown extension letter, then give it an alphabetical
   // order, but after all known standard extensions.
-  return 2 + RISCVISAUtils::AllStdExts.size() + (Ext - 'a');
+  return 3 + RISCVISAUtils::AllStdExts.size() + (Ext - 'a');
 }
 
 // Get the rank for multi-letter extension, lower value meaning higher
diff --git a/llvm/test/MC/RISCV/rvy-build-attributes.s b/llvm/test/MC/RISCV/rvy-build-attributes.s
index f7db55b382ec8..b5abbcb31a8d6 100644
--- a/llvm/test/MC/RISCV/rvy-build-attributes.s
+++ b/llvm/test/MC/RISCV/rvy-build-attributes.s
@@ -14,22 +14,22 @@
 # RUN:   -mattr=+experimental-y,+zce,+f | FileCheck %s --check-prefix=RV32Y-ZCE-F
 
 ## RV64Y + D + C: y is enabled, so zcd is not implied.
-# RV64YDC: .attribute 5, "rv64i2p1_f2p2_d2p2_c2p0_y0p910_zicsr2p0_zca1p0"
+# RV64YDC: .attribute 5, "rv64i2p1_y0p910_f2p2_d2p2_c2p0_zicsr2p0_zca1p0"
 
 ## RV32Y + F + C: y is enabled, so zcf is not implied.
-# RV32YFC: .attribute 5, "rv32i2p1_f2p2_c2p0_y0p910_zicsr2p0_zca1p0"
+# RV32YFC: .attribute 5, "rv32i2p1_y0p910_f2p2_c2p0_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_y0p910_zicsr2p0_zca1p0"
+# RV32Y-ZCA-F: .attribute 5, "rv32i2p1_y0p910_f2p2_c2p0_zicsr2p0_zca1p0"
 
 ## RV64Y + ZCA + D: zca + y implies c on RV64 (y replaces zcd in the implication).
-# RV64Y-ZCA-D: .attribute 5, "rv64i2p1_f2p2_d2p2_c2p0_y0p910_zicsr2p0_zca1p0"
+# RV64Y-ZCA-D: .attribute 5, "rv64i2p1_y0p910_f2p2_d2p2_c2p0_zicsr2p0_zca1p0"
 
 ## RV64Y + ZCA + ZCB: zca + zcb + y does NOT imply zce on RV64Y because Zce is incompatible. zca also implies c.
-# RV64Y-ZCA-ZCB: .attribute 5, "rv64i2p1_c2p0_y0p910_zca1p0_zcb1p0"
+# RV64Y-ZCA-ZCB: .attribute 5, "rv64i2p1_y0p910_c2p0_zca1p0_zcb1p0"
 
 ## RV32Y + ZCE: zce implies zca, zcb, zcmp, zcmt. zca implies c.
-# RV32Y-ZCE: .attribute 5, "rv32i2p1_c2p0_y0p910_zicsr2p0_zca1p0_zcb1p0_zce1p0_zcmp1p0_zcmt1p0"
+# RV32Y-ZCE: .attribute 5, "rv32i2p1_y0p910_c2p0_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_y0p910_zicsr2p0_zca1p0_zcb1p0_zce1p0_zcmp1p0_zcmt1p0"
+# RV32Y-ZCE-F: .attribute 5, "rv32i2p1_y0p910_f2p2_c2p0_zicsr2p0_zca1p0_zcb1p0_zce1p0_zcmp1p0_zcmt1p0"
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 3994eaf599a82..9c6077bb41e80 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -415,6 +415,13 @@ TEST(RISCVISAInfoTest, CanonicalExtensionOrderVP) {
       Info.toString(),
       "rv64i2p1_f2p2_d2p2_v1p0_p0p21_zicsr2p0_zmmul1p0_zba1p0_zbb1p0_zve32f1p0_"
       "zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0");
+
+  auto MaybeRVY = RISCVISAInfo::parseArchString("rv64y0p910_m_a_f_d_c", true);
+  ASSERT_THAT_EXPECTED(MaybeRVY, Succeeded());
+  // The canonical string should place 'y' immediately after 'i' (before 'm').
+  EXPECT_EQ((*MaybeRVY)->toString(),
+            "rv64i2p1_y0p910_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zmmul1p0_"
+            "zaamo1p0_zalrsc1p0_zca1p0");
 }
 
 TEST(ParseArchString, RejectsUnrecognizedExtensionNamesByDefault) {
@@ -1004,10 +1011,10 @@ TEST(OrderedExtensionMap, ExtensionsAreCorrectlyOrdered) {
   for (const auto &Ext : Exts)
     ExtNames.push_back(Ext.first);
 
-  // FIXME: 'l' and 'y' should be ordered after 'i', 'm', 'c'.
+  // FIXME: 'l' should be ordered after 'i', 'm', 'c'.
   EXPECT_THAT(ExtNames,
-              ElementsAre("i", "m", "l", "c", "y", "zicsr", "zmfoo", "zfinx",
-                           "zzfoo", "sbar", "sfoo", "xbar", "xfoo"));
+              ElementsAre("i", "y", "m", "l", "c", "zicsr", "zmfoo", "zfinx",
+                          "zzfoo", "sbar", "sfoo", "xbar", "xfoo"));
 }
 
 TEST(ParseArchString, ZceImplication) {
@@ -1673,8 +1680,8 @@ R"(All available -march extensions for RISC-V
     xwchc                2.2
 
 Experimental extensions
-    p                    0.21
     y                    0.910
+    p                    0.21
     zibi                 0.1
     zicfilp              1.0       This is a long dummy description
     zilx                 0.1

>From 04c75f9e492e5c1601b8a00785dc353dac1ebeba Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Thu, 1 Oct 2026 00:02:12 -0700
Subject: [PATCH 2/3] fix round-tripping and simpify the parsing to also allow
 rv32iy (matching long base name proposal)

---
 llvm/lib/TargetParser/RISCVISAInfo.cpp        | 20 ++--
 llvm/test/MC/RISCV/rvy-build-attributes.s     | 23 +++--
 .../TargetParser/RISCVISAInfoTest.cpp         | 96 ++++++++++++-------
 3 files changed, 87 insertions(+), 52 deletions(-)

diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index fae0fdac3f824..6899242358274 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -620,23 +620,23 @@ RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
       return std::move(E);
 
     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
+    Arch = Arch.drop_front(ConsumeLength);
+    ConsumeLength = 0;
+    // Allow 'y' immediately after 'i' or 'e' (e.g. rv64iy0p910, rv32ey0p910,
+    // or normalized strings such as rv64i2p1_y0p910).
+    if (!Arch.consume_front("y") && !Arch.consume_front("_y"))
+      break;
+    [[fallthrough]];
+  case 'y':
+    // If the first character is 'y', this is a shorthand for "iy" ('i' will be
+    // added by updateImplication()).
     if (auto E = getExtensionVersion("y", Arch, Major, Minor, ConsumeLength,
                                      EnableExperimentalExtension,
                                      ExperimentalExtensionVersionCheck))
       return std::move(E);
 
     ISAInfo->Exts["y"] = {Major, Minor};
-    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.
     if (!Arch.empty() && isDigit(Arch.front()))
diff --git a/llvm/test/MC/RISCV/rvy-build-attributes.s b/llvm/test/MC/RISCV/rvy-build-attributes.s
index b5abbcb31a8d6..a69aadb03ad48 100644
--- a/llvm/test/MC/RISCV/rvy-build-attributes.s
+++ b/llvm/test/MC/RISCV/rvy-build-attributes.s
@@ -1,17 +1,26 @@
+## Pipe the assembly output through a second llvm-mc invocation to ensure the
+## emitted '.attribute 5, "..."' arch string round-trips cleanly.
 # RUN: llvm-mc %s -triple=riscv64 -filetype=asm -riscv-add-build-attributes \
-# RUN:   -mattr=+experimental-y,+d,+c | FileCheck %s --check-prefix=RV64YDC
+# RUN:   -mattr=+experimental-y,+d,+c | llvm-mc -triple=riscv64 -filetype=asm \
+# RUN:   | FileCheck %s --check-prefix=RV64YDC
 # RUN: llvm-mc %s -triple=riscv32 -filetype=asm -riscv-add-build-attributes \
-# RUN:   -mattr=+experimental-y,+f,+c | FileCheck %s --check-prefix=RV32YFC
+# RUN:   -mattr=+experimental-y,+f,+c | llvm-mc -triple=riscv32 -filetype=asm \
+# RUN:   | 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-prefix=RV32Y-ZCA-F
+# RUN:   -mattr=+experimental-y,+zca,+f | llvm-mc -triple=riscv32 -filetype=asm \
+# RUN:   | 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-prefix=RV64Y-ZCA-D
+# RUN:   -mattr=+experimental-y,+zca,+d | llvm-mc -triple=riscv64 -filetype=asm \
+# RUN:   | 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-prefix=RV64Y-ZCA-ZCB
+# RUN:   -mattr=+experimental-y,+zca,+zcb | llvm-mc -triple=riscv64 -filetype=asm \
+# RUN:   | 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-prefix=RV32Y-ZCE
+# RUN:   -mattr=+experimental-y,+zce | llvm-mc -triple=riscv32 -filetype=asm \
+# RUN:   | 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-prefix=RV32Y-ZCE-F
+# RUN:   -mattr=+experimental-y,+zce,+f | llvm-mc -triple=riscv32 -filetype=asm \
+# RUN:   | FileCheck %s --check-prefix=RV32Y-ZCE-F
 
 ## RV64Y + D + C: y is enabled, so zcd is not implied.
 # RV64YDC: .attribute 5, "rv64i2p1_y0p910_f2p2_d2p2_c2p0_zicsr2p0_zca1p0"
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 9c6077bb41e80..1ac95e24176b8 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -212,32 +212,52 @@ TEST(ParseArchString, RejectsInvalidBaseISA) {
 }
 
 TEST(ParseArchString, RejectsInvalidYPosition) {
-  // y in non-first position is rejected.
-  for (StringRef Input :
-       {"rv32ey0p910", "rv64ey0p910", "rv32iy0p910", "rv64iy0p910"}) {
+  // 'y' is only allowed as a singular base ISA ('rv32y'/'rv64y') or immediately
+  // after 'i' or 'e' ('rv32iy'/'rv32ey'). Anything else should be rejected.
+  for (StringRef Input : {"rv32gy0p910", "rv64gy0p910", "rv32imy0p910",
+                          "rv64imy0p910", "rv32i_m_y0p910", "rv64y0p910_y0p910",
+                          "rv64iy0p910_y0p910"}) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
               "invalid standard user-level extension 'y'");
   }
-  for (StringRef Input : {"rv32ey", "rv64ey", "rv32iy", "rv64iy"}) {
+  for (StringRef Input :
+       {"rv32gy", "rv64gy", "rv32imy", "rv64imy", "rv32yy", "rv64iyy"}) {
     EXPECT_EQ(
         toString(RISCVISAInfo::parseArchString(Input, true, false).takeError()),
         "invalid standard user-level extension 'y'");
   }
 }
 
-TEST(ParseArchString, MissingBaseISA) {
+TEST(ParseArchString, AcceptsRVYBaseISA) {
   // With version check enabled (default), we must specify the version for
-  // experimental extension 'y'.
-  auto MaybeRV32Y = RISCVISAInfo::parseArchString("rv32y0p910", 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, 910}));
-  EXPECT_EQ(InfoRV32Y.getXLen(), 32U);
-
-  // rv32y0p910m should succeed and contain i, m, y0p910, zmmul
+  // experimental extension 'y'. Both 'rv32y0p910' (shorthand) and explicit
+  // 'rv32iy0p910' / 'rv32i2p1_y0p910' produce the same result.
+  for (StringRef Input : {"rv32y0p910", "rv32iy0p910", "rv32i2p1_y0p910"}) {
+    auto MaybeRV32Y = RISCVISAInfo::parseArchString(Input, 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, 910}));
+    EXPECT_EQ(InfoRV32Y.getXLen(), 32U);
+    EXPECT_EQ(InfoRV32Y.toString(), "rv32i2p1_y0p910");
+  }
+
+  for (StringRef Input : {"rv32ey0p910", "rv32e2p0_y0p910"}) {
+    auto MaybeRV32EY = RISCVISAInfo::parseArchString(Input, true);
+    ASSERT_THAT_EXPECTED(MaybeRV32EY, Succeeded());
+    RISCVISAInfo &InfoRV32EY = **MaybeRV32EY;
+    const auto &ExtsRV32EY = InfoRV32EY.getExtensions();
+    EXPECT_EQ(ExtsRV32EY.size(), 2UL); // e, y
+    EXPECT_TRUE(ExtsRV32EY.at("e") == (RISCVISAUtils::ExtensionVersion{2, 0}));
+    EXPECT_TRUE(ExtsRV32EY.at("y") == (RISCVISAUtils::ExtensionVersion{0, 910}));
+    EXPECT_EQ(InfoRV32EY.getXLen(), 32U);
+    EXPECT_EQ(InfoRV32EY.toString(), "rv32e2p0_y0p910");
+  }
+
+  // rv32y0p910m should succeed and contain i, m, y0p910, zmmul, with 'y'
+  // ordered between 'i' and 'm' and round-tripping through both parsers.
   auto MaybeRV32YM = RISCVISAInfo::parseArchString("rv32y0p910m", true);
   ASSERT_THAT_EXPECTED(MaybeRV32YM, Succeeded());
   RISCVISAInfo &InfoRV32YM = **MaybeRV32YM;
@@ -248,20 +268,33 @@ TEST(ParseArchString, MissingBaseISA) {
               (RISCVISAUtils::ExtensionVersion{2, 0}));
   EXPECT_TRUE(InfoRV32YM.getExtensions().at("y") ==
               (RISCVISAUtils::ExtensionVersion{0, 910}));
+  std::string RV32YMStr = InfoRV32YM.toString();
+  EXPECT_EQ(RV32YMStr, "rv32i2p1_y0p910_m2p0_zmmul1p0");
+  auto RoundTripArch = RISCVISAInfo::parseArchString(RV32YMStr, true);
+  ASSERT_THAT_EXPECTED(RoundTripArch, Succeeded());
+  EXPECT_EQ((*RoundTripArch)->toString(), RV32YMStr);
+  auto RoundTripNorm = RISCVISAInfo::parseNormalizedArchString(RV32YMStr);
+  ASSERT_THAT_EXPECTED(RoundTripNorm, Succeeded());
+  EXPECT_EQ((*RoundTripNorm)->toString(), RV32YMStr);
 
   // 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("rv64y0p910", 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, 910}));
-  EXPECT_EQ(InfoRV64Y.getXLen(), 64U);
+  for (StringRef Input : {"rv32y", "rv32iy", "rv32ey"}) {
+    auto MaybeNoVal = RISCVISAInfo::parseArchString(Input, true, false);
+    ASSERT_THAT_EXPECTED(MaybeNoVal, Succeeded());
+    EXPECT_EQ((*MaybeNoVal)->getExtensions().size(), 2UL);
+  }
+
+  for (StringRef Input : {"rv64y0p910", "rv64iy0p910", "rv64i2p1_y0p910"}) {
+    auto MaybeRV64Y = RISCVISAInfo::parseArchString(Input, 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, 910}));
+    EXPECT_EQ(InfoRV64Y.getXLen(), 64U);
+    EXPECT_EQ(InfoRV64Y.toString(), "rv64i2p1_y0p910");
+  }
 }
 
 TEST(ParseArchString, RejectsUnsupportedBaseISA) {
@@ -415,13 +448,6 @@ TEST(RISCVISAInfoTest, CanonicalExtensionOrderVP) {
       Info.toString(),
       "rv64i2p1_f2p2_d2p2_v1p0_p0p21_zicsr2p0_zmmul1p0_zba1p0_zbb1p0_zve32f1p0_"
       "zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0");
-
-  auto MaybeRVY = RISCVISAInfo::parseArchString("rv64y0p910_m_a_f_d_c", true);
-  ASSERT_THAT_EXPECTED(MaybeRVY, Succeeded());
-  // The canonical string should place 'y' immediately after 'i' (before 'm').
-  EXPECT_EQ((*MaybeRVY)->toString(),
-            "rv64i2p1_y0p910_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zmmul1p0_"
-            "zaamo1p0_zalrsc1p0_zca1p0");
 }
 
 TEST(ParseArchString, RejectsUnrecognizedExtensionNamesByDefault) {

>From a920ad7b75eafb19265c6b99036f917486465863 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Thu, 1 Oct 2026 00:07:34 -0700
Subject: [PATCH 3/3] clang-format

---
 llvm/unittests/TargetParser/RISCVISAInfoTest.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 1ac95e24176b8..6f4d171f2c783 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -214,9 +214,9 @@ TEST(ParseArchString, RejectsInvalidBaseISA) {
 TEST(ParseArchString, RejectsInvalidYPosition) {
   // 'y' is only allowed as a singular base ISA ('rv32y'/'rv64y') or immediately
   // after 'i' or 'e' ('rv32iy'/'rv32ey'). Anything else should be rejected.
-  for (StringRef Input : {"rv32gy0p910", "rv64gy0p910", "rv32imy0p910",
-                          "rv64imy0p910", "rv32i_m_y0p910", "rv64y0p910_y0p910",
-                          "rv64iy0p910_y0p910"}) {
+  for (StringRef Input :
+       {"rv32gy0p910", "rv64gy0p910", "rv32imy0p910", "rv64imy0p910",
+        "rv32i_m_y0p910", "rv64y0p910_y0p910", "rv64iy0p910_y0p910"}) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
               "invalid standard user-level extension 'y'");
   }
@@ -251,7 +251,8 @@ TEST(ParseArchString, AcceptsRVYBaseISA) {
     const auto &ExtsRV32EY = InfoRV32EY.getExtensions();
     EXPECT_EQ(ExtsRV32EY.size(), 2UL); // e, y
     EXPECT_TRUE(ExtsRV32EY.at("e") == (RISCVISAUtils::ExtensionVersion{2, 0}));
-    EXPECT_TRUE(ExtsRV32EY.at("y") == (RISCVISAUtils::ExtensionVersion{0, 910}));
+    EXPECT_TRUE(ExtsRV32EY.at("y") ==
+                (RISCVISAUtils::ExtensionVersion{0, 910}));
     EXPECT_EQ(InfoRV32EY.getXLen(), 32U);
     EXPECT_EQ(InfoRV32EY.toString(), "rv32e2p0_y0p910");
   }



More information about the llvm-commits mailing list