[llvm] 265a994 - [RISCV] Add C/Zcf/Zcd/Zce implication rules to subtarget construction. (#179615)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 4 09:32:16 PST 2026
Author: Craig Topper
Date: 2026-02-04T09:32:11-08:00
New Revision: 265a994f4de2025aabc6f78b47777235af0ab48e
URL: https://github.com/llvm/llvm-project/commit/265a994f4de2025aabc6f78b47777235af0ab48e
DIFF: https://github.com/llvm/llvm-project/commit/265a994f4de2025aabc6f78b47777235af0ab48e.diff
LOG: [RISCV] Add C/Zcf/Zcd/Zce implication rules to subtarget construction. (#179615)
This ensures the feature bits and RISCVSubtarget flags match what
RISCVISAInfo would do.
I'm not excited about the code duplication, but I need to set the
RISCVSubtarget flags along with calling ToggleFeature. I'll think about
how to improve this.
Added:
Modified:
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
llvm/lib/Target/RISCV/RISCVFeatures.td
llvm/lib/Target/RISCV/RISCVSubtarget.cpp
llvm/lib/Target/RISCV/RISCVSubtarget.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
index eb51dba20c8a4..38d154d90d7e0 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -83,8 +83,66 @@ createRISCVMCObjectFileInfo(MCContext &Ctx, bool PIC,
return MOFI;
}
-static MCSubtargetInfo *createRISCVMCSubtargetInfo(const Triple &TT,
- StringRef CPU, StringRef FS) {
+void RISCV::updateCZceFeatureImplications(MCSubtargetInfo &STI) {
+ // Add Zcd if C and D are enabled.
+ if (STI.hasFeature(RISCV::FeatureStdExtC) &&
+ STI.hasFeature(RISCV::FeatureStdExtD) &&
+ !STI.hasFeature(RISCV::FeatureStdExtZcd))
+ STI.ToggleFeature(RISCV::FeatureStdExtZcd);
+
+ // Add Zcf if F and C or Zce are enabled on RV32.
+ if (!STI.hasFeature(RISCV::FeatureStdExtZcf) &&
+ !STI.hasFeature(RISCV::Feature64Bit) &&
+ STI.hasFeature(RISCV::FeatureStdExtF) &&
+ (STI.hasFeature(RISCV::FeatureStdExtC) ||
+ STI.hasFeature(RISCV::FeatureStdExtZce)))
+ STI.ToggleFeature(RISCV::FeatureStdExtZcf);
+
+ // Add C if Zca is enabled and the conditions are met.
+ // This follows the RISC-V spec rules for MISA.C and matches GCC behavior
+ // (PR119122). The rule is:
+ // For RV32:
+ // - No F and no D: Zca alone implies C
+ // - F but no D: Zca + Zcf implies C
+ // - F and D: Zca + Zcf + Zcd implies C
+ // For RV64:
+ // - No D: Zca alone implies C
+ // - D: Zca + Zcd implies C
+ if (!STI.hasFeature(RISCV::FeatureStdExtC) &&
+ STI.hasFeature(RISCV::FeatureStdExtZca)) {
+ bool ShouldAddC = false;
+ if (!STI.hasFeature(RISCV::Feature64Bit))
+ ShouldAddC = (!STI.hasFeature(RISCV::FeatureStdExtD) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcd)) &&
+ (!STI.hasFeature(RISCV::FeatureStdExtF) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcf));
+ else
+ ShouldAddC = (!STI.hasFeature(RISCV::FeatureStdExtD) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcd));
+ if (ShouldAddC)
+ STI.ToggleFeature(RISCV::FeatureStdExtC);
+ }
+
+ // Add Zce if Zca+Zcb+Zcmp+Zcmt are enabled and the conditions are met.
+ // For RV32:
+ // - No F and no D: Zca+Zcb+Zcmp+Zcmt alone implies Zce
+ // - F: Zca+Zcb+Zcmp+Zcmt + Zcf implies Zce
+ // For RV64:
+ // - Zca+Zcb+Zcmp+Zcmt alone implies Zce
+ if (!STI.hasFeature(RISCV::FeatureStdExtZce) &&
+ STI.hasFeature(RISCV::FeatureStdExtZca) &&
+ STI.hasFeature(RISCV::FeatureStdExtZcb) &&
+ STI.hasFeature(RISCV::FeatureStdExtZcmp) &&
+ STI.hasFeature(RISCV::FeatureStdExtZcmt)) {
+ if (STI.hasFeature(RISCV::Feature64Bit) ||
+ !STI.hasFeature(RISCV::FeatureStdExtF) ||
+ STI.hasFeature(RISCV::FeatureStdExtZcf))
+ STI.ToggleFeature(RISCV::FeatureStdExtZce);
+ }
+}
+
+static MCSubtargetInfo *
+createRISCVMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) {
if (CPU.empty() || CPU == "generic")
CPU = TT.isArch64Bit() ? "generic-rv64" : "generic-rv32";
@@ -103,6 +161,8 @@ static MCSubtargetInfo *createRISCVMCSubtargetInfo(const Triple &TT,
X->setFeatureBits(Features);
}
+ RISCV::updateCZceFeatureImplications(*X);
+
return X;
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
index 7ee6a20393e66..d1733886637f8 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
@@ -39,6 +39,11 @@ std::unique_ptr<MCObjectTargetWriter> createRISCVELFObjectWriter(uint8_t OSABI,
bool Is64Bit);
std::unique_ptr<MCObjectTargetWriter>
createRISCVMachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype);
+
+namespace RISCV {
+void updateCZceFeatureImplications(MCSubtargetInfo &STI);
+}
+
} // namespace llvm
// Defines symbolic names for RISC-V registers.
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index e8c8543992865..6a83ebd758c16 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -458,8 +458,7 @@ def FeatureStdExtZce
FeatureStdExtZcmt]>;
def HasStdExtCOrZcfOrZce
- : Predicate<"Subtarget->hasStdExtC() || Subtarget->hasStdExtZcf() ||"
- "Subtarget->hasStdExtZce()">,
+ : Predicate<"Subtarget->hasStdExtCOrZcfOrZce()">,
AssemblerPredicate<(any_of FeatureStdExtC, FeatureStdExtZcf,
FeatureStdExtZce),
"'C' (Compressed Instructions) or "
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index 88d32f25cb45f..ee86818805530 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -98,6 +98,15 @@ RISCVSubtarget::initializeSubtargetDependencies(const Triple &TT, StringRef CPU,
assert(TuneInfo && "TuneInfo shouldn't be nullptr!");
ParseSubtargetFeatures(CPU, TuneCPU, FS);
+
+ RISCV::updateCZceFeatureImplications(*this);
+
+ // Re-sync the flags.
+ HasStdExtZcd = hasFeature(RISCV::FeatureStdExtZcd);
+ HasStdExtZcf = hasFeature(RISCV::FeatureStdExtZcf);
+ HasStdExtC = hasFeature(RISCV::FeatureStdExtC);
+ HasStdExtZce = hasFeature(RISCV::FeatureStdExtZce);
+
TargetABI = RISCVABI::computeTargetABI(TT, getFeatureBits(), ABIName);
RISCVFeatures::validate(TT, getFeatureBits());
return *this;
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index cb45efe64dadf..2117b691f96aa 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -172,10 +172,9 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
LLVM_DEPRECATED("Now Equivalent to hasStdExtZca", "hasStdExtZca")
bool hasStdExtCOrZca() const { return HasStdExtZca; }
- bool hasStdExtCOrZcd() const { return HasStdExtC || HasStdExtZcd; }
- bool hasStdExtCOrZcfOrZce() const {
- return HasStdExtC || HasStdExtZcf || HasStdExtZce;
- }
+ // FIXME: Remove these and use hasStdExtZcd/hasStdExtZcf() instead.
+ bool hasStdExtCOrZcd() const { return HasStdExtZcd; }
+ bool hasStdExtCOrZcfOrZce() const { return HasStdExtZcf; }
bool hasStdExtZvl() const { return ZvlLen != 0; }
bool hasStdExtFOrZfinx() const { return HasStdExtF || HasStdExtZfinx; }
bool hasStdExtDOrZdinx() const { return HasStdExtD || HasStdExtZdinx; }
More information about the llvm-commits
mailing list