[llvm] [RISCV] Simplify Extension Predicates, Compatibility (PR #181255)

Sam Elliott via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 13 11:22:51 PST 2026


https://github.com/lenary updated https://github.com/llvm/llvm-project/pull/181255

>From b4035e5636f7ea1363d7dfe62afc43181cc6bbe2 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Thu, 12 Feb 2026 14:25:37 -0800
Subject: [PATCH 1/3] [RISCV] Simplify Extension Predicates, Compatibility

This pushes some of our simplifications to extension dependencies into
other parts of RISCVISAInfo and into the tablegen predicates.
---
 llvm/lib/Target/RISCV/RISCVFeatures.td        |   2 +-
 llvm/lib/TargetParser/RISCVISAInfo.cpp        |  47 +++-----
 .../TargetParser/RISCVISAInfoTest.cpp         | 102 ++++++------------
 3 files changed, 53 insertions(+), 98 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 622a817cc1aeb..1d59c230f261a 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -445,7 +445,7 @@ def FeatureStdExtZcmp
                      "sequenced instructions for code-size reduction",
                      [FeatureStdExtZca]>,
       RISCVExtensionBitmask<1, 10>;
-def HasStdExtZcmp : Predicate<"Subtarget->hasStdExtZcmp() && !Subtarget->hasStdExtC()">,
+def HasStdExtZcmp : Predicate<"Subtarget->hasStdExtZcmp()">,
                     AssemblerPredicate<(all_of FeatureStdExtZcmp),
                         "'Zcmp' (sequenced instructions for code-size reduction)">;
 
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 4aa0e60a4570b..37a9869ec8a4a 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -738,7 +738,6 @@ static Error getExtensionRequiresError(StringRef Ext, StringRef ReqExt) {
 Error RISCVISAInfo::checkDependency() {
   bool HasE = Exts.count("e") != 0;
   bool HasI = Exts.count("i") != 0;
-  bool HasC = Exts.count("c") != 0;
   bool HasF = Exts.count("f") != 0;
   bool HasD = Exts.count("d") != 0;
   bool HasZfinx = Exts.count("zfinx") != 0;
@@ -747,13 +746,16 @@ Error RISCVISAInfo::checkDependency() {
   bool HasZcmp = Exts.count("zcmp") != 0;
   bool HasXqccmp = Exts.count("xqccmp") != 0;
 
-  static constexpr StringLiteral XqciExts[] = {
-      {"xqci"},    {"xqcia"},   {"xqciac"},  {"xqcibi"},  {"xqcibm"},
-      {"xqcicli"}, {"xqcicm"},  {"xqcics"},  {"xqcicsr"}, {"xqciint"},
-      {"xqciio"},  {"xqcilb"},  {"xqcili"},  {"xqcilia"}, {"xqcilo"},
-      {"xqcilsm"}, {"xqcisim"}, {"xqcisls"}, {"xqcisync"}};
   static constexpr StringLiteral ZcdOverlaps[] = {
-      {"zcmt"}, {"zcmp"}, {"xqccmp"}, {"xqciac"}, {"xqcicm"}};
+      {"zcmt"}, {"zcmp"}, {"xqccmp"}, {"xqciac"}, {"xqcicm"},
+  };
+  static constexpr StringLiteral RV32Only[] = {
+      {"zcf"},     {"zilsd"},   {"zclsd"},    {"xwchc"},   {"xqci"},
+      {"xqcia"},   {"xqciac"},  {"xqcibi"},   {"xqcibm"},  {"xqcicli"},
+      {"xqcicm"},  {"xqcics"},  {"xqcicsr"},  {"xqciint"}, {"xqciio"},
+      {"xqcilb"},  {"xqcili"},  {"xqcilia"},  {"xqcilo"},  {"xqcilsm"},
+      {"xqcisim"}, {"xqcisls"}, {"xqcisync"},
+  };
 
   if (HasI && HasE)
     return getIncompatibleError("i", "e");
@@ -770,20 +772,17 @@ Error RISCVISAInfo::checkDependency() {
                              "'xsfvfbfexp16e' requires 'zvfbfmin' or "
                              "'zvfbfa' extension to also be specified");
 
-  if (HasD && (HasC || Exts.count("zcd")))
+  if (Exts.count("zcd"))
     for (auto Ext : ZcdOverlaps)
       if (Exts.count(Ext.str()))
-        return getError(
-            Twine("'") + Ext + "' extension is incompatible with '" +
-            (HasC ? "c" : "zcd") + "' extension when 'd' extension is enabled");
+        return getIncompatibleError(Ext, "zcd");
 
-  if (XLen != 32 && Exts.count("zcf"))
-    return getError("'zcf' is only supported for 'rv32'");
+  if (XLen != 32)
+    for (auto Ext : RV32Only)
+      if (Exts.count(Ext.str()))
+        return getError("'zcf' is only supported for 'rv32'");
 
   if (Exts.count("xwchc") != 0) {
-    if (XLen != 32)
-      return getError("'xwchc' is only supported for 'rv32'");
-
     if (HasD)
       return getIncompatibleError("d", "xwchc");
 
@@ -791,20 +790,8 @@ Error RISCVISAInfo::checkDependency() {
       return getIncompatibleError("xwchc", "zcb");
   }
 
-  if (Exts.count("zclsd") != 0) {
-    if (XLen != 32)
-      return getError("'zclsd' is only supported for 'rv32'");
-
-    if (Exts.count("zcf") != 0)
-      return getIncompatibleError("zclsd", "zcf");
-  }
-
-  if (XLen != 32 && Exts.count("zilsd") != 0)
-    return getError("'zilsd' is only supported for 'rv32'");
-
-  for (auto Ext : XqciExts)
-    if (Exts.count(Ext.str()) && (XLen != 32))
-      return getError("'" + Twine(Ext) + "'" + " is only supported for 'rv32'");
+  if (Exts.count("zclsd") != 0 && Exts.count("zcf") != 0)
+    return getIncompatibleError("zclsd", "zcf");
 
   if (HasZcmp && HasXqccmp)
     return getIncompatibleError("zcmp", "xqccmp");
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index fa09135136889..8cba2c8d3f8bd 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -621,54 +621,24 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
               "'f' and 'zfinx' extensions are incompatible");
   }
 
-  for (StringRef Input : {"rv32idc_zcmp1p0", "rv64idc_zcmp1p0"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zcmp' extension is incompatible with 'c' extension when 'd' "
-              "extension is enabled");
-  }
-
-  // RV32 + D + Zcd doesn't synthesize C (needs Zcf), so error mentions 'zcd'
-  for (StringRef Input : {"rv32id_zcd1p0_zcmp1p0"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zcmp' extension is incompatible with 'zcd' extension when 'd' "
-              "extension is enabled");
-  }
-
-  // RV64 + D + Zcd synthesizes C, so error mentions 'c'
-  for (StringRef Input : {"rv64id_zcd1p0_zcmp1p0"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zcmp' extension is incompatible with 'c' extension when 'd' "
-              "extension is enabled");
-  }
-
-  for (StringRef Input : {"rv32idc_zcmt1p0", "rv64idc_zcmt1p0"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zcmt' extension is incompatible with 'c' extension when 'd' "
-              "extension is enabled");
-  }
-
-  // RV32 + D + Zcd doesn't synthesize C (needs Zcf), so error mentions 'zcd'
-  for (StringRef Input : {"rv32id_zcd1p0_zcmt1p0"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zcmt' extension is incompatible with 'zcd' extension when 'd' "
-              "extension is enabled");
-  }
-
-  // RV64 + D + Zcd synthesizes C, so error mentions 'c'
-  for (StringRef Input : {"rv64id_zcd1p0_zcmt1p0"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zcmt' extension is incompatible with 'c' extension when 'd' "
-              "extension is enabled");
-  }
-
-  for (StringRef Input : {"rv64if_zcf"}) {
+  for (StringRef Input : {
+           "rv32idc_zcmp1p0",
+           "rv64idc_zcmp1p0",
+           "rv32id_zcd1p0_zcmp1p0",
+           "rv64id_zcd1p0_zcmp1p0",
+       }) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zcf' is only supported for 'rv32'");
+              "'zcmp' and 'zcd' extensions are incompatible");
   }
 
-  for (StringRef Input : {"rv64i_xwchc"}) {
+  for (StringRef Input : {
+           "rv32idc_zcmt1p0",
+           "rv64idc_zcmt1p0",
+           "rv32id_zcd1p0_zcmt1p0",
+           "rv64id_zcd1p0_zcmt1p0",
+       }) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'xwchc' is only supported for 'rv32'");
+              "'zcmt' and 'zcd' extensions are incompatible");
   }
 
   for (StringRef Input : {"rv32id_xwchc"}) {
@@ -681,41 +651,39 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
               "'xwchc' and 'zcb' extensions are incompatible");
   }
 
-  for (StringRef Input : {"rv64i_zilsd"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zilsd' is only supported for 'rv32'");
-  }
-
-  for (StringRef Input : {"rv64i_zclsd"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zclsd' is only supported for 'rv32'");
-  }
-
   for (StringRef Input : {"rv32i_zcf_zclsd"}) {
     EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
               "'zclsd' and 'zcf' extensions are incompatible");
   }
 
-  for (StringRef Input :
-       {"rv64i_xqcia0p7", "rv64i_xqciac0p3", "rv64i_xqcibi0p2",
-        "rv64i_xqcibm0p8", "rv64i_xqcicli0p3", "rv64i_xqcicm0p2",
-        "rv64i_xqcics0p2", "rv64i_xqcicsr0p4", "rv64i_xqciint0p10",
-        "rv64i_xqciio0p1", "rv64i_xqcilb0p2", "rv64i_xqcili0p2",
-        "rv64i_xqcilia0p2", "rv64i_xqcilo0p3", "rv64i_xqcilsm0p6",
-        "rv64i_xqcisim0p2", "rv64i_xqcisls0p2", "rv64i_xqcisync0p3",
-        "rv64i_xqci0p13"}) {
+  for (StringRef Input : {
+           "rv64if_zcf",        "rv64i_zilsd",      "rv64i_zclsd",
+           "rv64i_xqcia0p7",    "rv64i_xwchc",      "rv64i_xqciac0p3",
+           "rv64i_xqcibi0p2",   "rv64i_xqcibm0p8",  "rv64i_xqcicli0p3",
+           "rv64i_xqcicm0p2",   "rv64i_xqcics0p2",  "rv64i_xqcicsr0p4",
+           "rv64i_xqciint0p10", "rv64i_xqciio0p1",  "rv64i_xqcilb0p2",
+           "rv64i_xqcili0p2",   "rv64i_xqcilia0p2", "rv64i_xqcilo0p3",
+           "rv64i_xqcilsm0p6",  "rv64i_xqcisim0p2", "rv64i_xqcisls0p2",
+           "rv64i_xqcisync0p3", "rv64i_xqci0p13",
+       }) {
     EXPECT_THAT(
         toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
         ::testing::EndsWith(" is only supported for 'rv32'"));
   }
 
-  for (StringRef Input :
-       {"rv32idc_xqciac0p3", "rv32i_zcd_xqciac0p3", "rv32idc_xqcicm0p2",
-        "rv32i_zcd_xqcicm0p2", "rv32idc_xqccmp0p3", "rv32i_zcd_xqccmp0p3",
-        "rv32idc_xqci0p13", "rv32i_zcd_xqci0p13"}) {
+  for (StringRef Input : {
+           "rv32idc_xqciac0p3",
+           "rv32i_zcd_xqciac0p3",
+           "rv32idc_xqcicm0p2",
+           "rv32i_zcd_xqcicm0p2",
+           "rv32idc_xqccmp0p3",
+           "rv32i_zcd_xqccmp0p3",
+           "rv32idc_xqci0p13",
+           "rv32i_zcd_xqci0p13",
+       }) {
     EXPECT_THAT(
         toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-        ::testing::EndsWith("extension when 'd' extension is enabled"));
+        ::testing::EndsWith(" and 'zcd' extensions are incompatible"));
   }
 
   for (StringRef Input : {"rv32i_zcmp_xqccmp0p3", "rv64i_zcmp_xqccmp0p3"}) {

>From 486fe9a654a49d6b09cd98235aa2fa30d9754836 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Thu, 12 Feb 2026 18:36:46 -0800
Subject: [PATCH 2/3] Review Updates, Fixes, etc

---
 llvm/lib/TargetParser/RISCVISAInfo.cpp        |  2 +-
 .../TargetParser/RISCVISAInfoTest.cpp         | 60 ++++++++++++-------
 2 files changed, 39 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 37a9869ec8a4a..18ec34b3cd71e 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -780,7 +780,7 @@ Error RISCVISAInfo::checkDependency() {
   if (XLen != 32)
     for (auto Ext : RV32Only)
       if (Exts.count(Ext.str()))
-        return getError("'zcf' is only supported for 'rv32'");
+        return getError(Twine("'") + Ext + "' is only supported for 'rv32'");
 
   if (Exts.count("xwchc") != 0) {
     if (HasD)
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 8cba2c8d3f8bd..0dbfb82801cce 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -656,34 +656,50 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
               "'zclsd' and 'zcf' extensions are incompatible");
   }
 
+  for (StringRef Input : {"rv64i_zilsd", "rv64i_zclsd"}) {
+    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+              "'zilsd' is only supported for 'rv32'");
+  }
+
+  // In these ISA strings, the non-rv32 extension should be last, after an
+  // underscore.
   for (StringRef Input : {
-           "rv64if_zcf",        "rv64i_zilsd",      "rv64i_zclsd",
-           "rv64i_xqcia0p7",    "rv64i_xwchc",      "rv64i_xqciac0p3",
-           "rv64i_xqcibi0p2",   "rv64i_xqcibm0p8",  "rv64i_xqcicli0p3",
-           "rv64i_xqcicm0p2",   "rv64i_xqcics0p2",  "rv64i_xqcicsr0p4",
-           "rv64i_xqciint0p10", "rv64i_xqciio0p1",  "rv64i_xqcilb0p2",
-           "rv64i_xqcili0p2",   "rv64i_xqcilia0p2", "rv64i_xqcilo0p3",
-           "rv64i_xqcilsm0p6",  "rv64i_xqcisim0p2", "rv64i_xqcisls0p2",
-           "rv64i_xqcisync0p3", "rv64i_xqci0p13",
+           "rv64if_zcf",    "rv64i_xwchc",   "rv64i_xqcia",   "rv64i_xqciac",
+           "rv64i_xqcibi",  "rv64i_xqcibm",  "rv64i_xqcicli", "rv64i_xqcicm",
+           "rv64i_xqcics",  "rv64i_xqcicsr", "rv64i_xqciint", "rv64i_xqciio",
+           "rv64i_xqcilb",  "rv64i_xqcili",  "rv64i_xqcilia", "rv64i_xqcilo",
+           "rv64i_xqcilsm", "rv64i_xqcisim", "rv64i_xqcisls", "rv64i_xqcisync",
+           "rv64i_xqci",
        }) {
-    EXPECT_THAT(
-        toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-        ::testing::EndsWith(" is only supported for 'rv32'"));
+
+    auto [_, ConflictingExt] = Input.rsplit('_');
+    std::string Error =
+        toString(RISCVISAInfo::parseArchString(Input, true).takeError());
+
+    EXPECT_THAT(Error, ::testing::EndsWith("' is only supported for 'rv32'"));
+    EXPECT_THAT(Error, ::testing::HasSubstr(ConflictingExt));
   }
 
+  // In these ISA strings, the non-zcd extension should be last, after an
+  // underscore.
   for (StringRef Input : {
-           "rv32idc_xqciac0p3",
-           "rv32i_zcd_xqciac0p3",
-           "rv32idc_xqcicm0p2",
-           "rv32i_zcd_xqcicm0p2",
-           "rv32idc_xqccmp0p3",
-           "rv32i_zcd_xqccmp0p3",
-           "rv32idc_xqci0p13",
-           "rv32i_zcd_xqci0p13",
+           "rv32idc_xqciac",
+           "rv32i_zcd_xqciac",
+           "rv32idc_xqcicm",
+           "rv32i_zcd_xqcicm",
+           "rv32idc_xqccmp",
+           "rv32i_zcd_xqccmp",
+           "rv32idc_xqci",
+           "rv32i_zcd_xqci",
        }) {
-    EXPECT_THAT(
-        toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-        ::testing::EndsWith(" and 'zcd' extensions are incompatible"));
+
+    auto [_, ConflictingExt] = Input.rsplit('_');
+    std::string Error =
+        toString(RISCVISAInfo::parseArchString(Input, true).takeError());
+
+    EXPECT_THAT(Error,
+                ::testing::EndsWith(" and 'zcd' extensions are incompatible"));
+    EXPECT_THAT(Error, ::testing::HasSubstr(ConflictingExt));
   }
 
   for (StringRef Input : {"rv32i_zcmp_xqccmp0p3", "rv64i_zcmp_xqccmp0p3"}) {

>From b518abe6e8b4189ce5be4114f9d796cf01fee033 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Fri, 13 Feb 2026 11:22:29 -0800
Subject: [PATCH 3/3] Reorder RV32Only to get better errors

---
 llvm/lib/TargetParser/RISCVISAInfo.cpp          |  2 +-
 .../unittests/TargetParser/RISCVISAInfoTest.cpp | 17 ++++++-----------
 2 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 18ec34b3cd71e..3d0bc6512ff59 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -750,7 +750,7 @@ Error RISCVISAInfo::checkDependency() {
       {"zcmt"}, {"zcmp"}, {"xqccmp"}, {"xqciac"}, {"xqcicm"},
   };
   static constexpr StringLiteral RV32Only[] = {
-      {"zcf"},     {"zilsd"},   {"zclsd"},    {"xwchc"},   {"xqci"},
+      {"zcf"},     {"zclsd"},   {"zilsd"},    {"xwchc"},   {"xqci"},
       {"xqcia"},   {"xqciac"},  {"xqcibi"},   {"xqcibm"},  {"xqcicli"},
       {"xqcicm"},  {"xqcics"},  {"xqcicsr"},  {"xqciint"}, {"xqciio"},
       {"xqcilb"},  {"xqcili"},  {"xqcilia"},  {"xqcilo"},  {"xqcilsm"},
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 0dbfb82801cce..f266c4b2d800c 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -656,20 +656,15 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
               "'zclsd' and 'zcf' extensions are incompatible");
   }
 
-  for (StringRef Input : {"rv64i_zilsd", "rv64i_zclsd"}) {
-    EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
-              "'zilsd' is only supported for 'rv32'");
-  }
-
   // In these ISA strings, the non-rv32 extension should be last, after an
   // underscore.
   for (StringRef Input : {
-           "rv64if_zcf",    "rv64i_xwchc",   "rv64i_xqcia",   "rv64i_xqciac",
-           "rv64i_xqcibi",  "rv64i_xqcibm",  "rv64i_xqcicli", "rv64i_xqcicm",
-           "rv64i_xqcics",  "rv64i_xqcicsr", "rv64i_xqciint", "rv64i_xqciio",
-           "rv64i_xqcilb",  "rv64i_xqcili",  "rv64i_xqcilia", "rv64i_xqcilo",
-           "rv64i_xqcilsm", "rv64i_xqcisim", "rv64i_xqcisls", "rv64i_xqcisync",
-           "rv64i_xqci",
+           "rv64if_zcf",    "rv64i_zclsd",    "rv64i_zilsd",   "rv64i_xwchc",
+           "rv64i_xqcia",   "rv64i_xqciac",   "rv64i_xqcibi",  "rv64i_xqcibm",
+           "rv64i_xqcicli", "rv64i_xqcicm",   "rv64i_xqcics",  "rv64i_xqcicsr",
+           "rv64i_xqciint", "rv64i_xqciio",   "rv64i_xqcilb",  "rv64i_xqcili",
+           "rv64i_xqcilia", "rv64i_xqcilo",   "rv64i_xqcilsm", "rv64i_xqcisim",
+           "rv64i_xqcisls", "rv64i_xqcisync", "rv64i_xqci",
        }) {
 
     auto [_, ConflictingExt] = Input.rsplit('_');



More information about the llvm-commits mailing list