[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