[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