[llvm] [TableGen][CodeGen] Remove feature string from HwMode (PR #157600)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 9 03:12:46 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-loongarch

Author: Sergei Barannikov (s-barannikov)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/157600.diff


12 Files Affected:

- (modified) llvm/include/llvm/Target/Target.td (+14-9) 
- (modified) llvm/lib/Target/AArch64/AArch64RegisterInfo.td (+1-1) 
- (modified) llvm/lib/Target/Hexagon/Hexagon.td (+5-2) 
- (modified) llvm/lib/Target/LoongArch/LoongArch.td (+1-1) 
- (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+1-1) 
- (modified) llvm/lib/Target/SystemZ/SystemZFeatures.td (+1-2) 
- (modified) llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp (+7-2) 
- (modified) llvm/utils/TableGen/Common/CodeGenHwModes.cpp (+8-14) 
- (modified) llvm/utils/TableGen/Common/CodeGenHwModes.h (+1-2) 
- (modified) llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp (+32) 
- (modified) llvm/utils/TableGen/Common/SubtargetFeatureInfo.h (+6) 
- (modified) llvm/utils/TableGen/SubtargetEmitter.cpp (+26-6) 


``````````diff
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 38c3b6064d267..6a7ecf78b2131 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -20,15 +20,20 @@ class Predicate; // Forward def
 // Register file description - These classes are used to fill in the target
 // description classes.
 
-class HwMode<string FS, list<Predicate> Ps> {
-  // A string representing subtarget features that turn on this HW mode.
-  // For example, "+feat1,-feat2" will indicate that the mode is active
-  // when "feat1" is enabled and "feat2" is disabled at the same time.
-  // Any other features are not checked.
-  // When multiple modes are used, they should be mutually exclusive,
-  // otherwise the results are unpredictable.
-  string Features = FS;
+// Code that will be inserted at the start of the generated
+// `*GenSubtargetInfo::getHwModeSet()` method. It is expected to define
+// variables used in Predicate::CondString. If this class is never instantiated,
+// the default
+//
+//   [[maybe_unused]] const auto *Subtarget =
+//        static_cast<const <TargetName>Subtarget *>(this);
+//
+// will be inserted, where <TargetName> is the name of the Target record.
+class HwModePredicateProlog<code c> {
+  code Code = c;
+}
 
+class HwMode<list<Predicate> Ps> {
   // A list of predicates that turn on this HW mode.
   list<Predicate> Predicates = Ps;
 }
@@ -36,7 +41,7 @@ class HwMode<string FS, list<Predicate> Ps> {
 // A special mode recognized by tablegen. This mode is considered active
 // when no other mode is active. For targets that do not use specific hw
 // modes, this is the only mode.
-def DefaultMode : HwMode<"", []>;
+def DefaultMode : HwMode<[]>;
 
 // A class used to associate objects with HW modes. It is only intended to
 // be used as a base class, where the derived class should contain a member
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 1a7609bfee8a1..431ed6ec34e74 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -983,7 +983,7 @@ class ZPRRegOp <string Suffix, AsmOperandClass C, ElementSizeEnum Size,
 
 // Note: This hardware mode is enabled in AArch64Subtarget::getHwModeSet()
 // (without the use of the table-gen'd predicates).
-def SMEWithZPRPredicateSpills : HwMode<"", [Predicate<"false">]>;
+def SMEWithZPRPredicateSpills : HwMode<[Predicate<"false">]>;
 
 def PPRSpillFillRI : RegInfoByHwMode<
       [DefaultMode,              SMEWithZPRPredicateSpills],
diff --git a/llvm/lib/Target/Hexagon/Hexagon.td b/llvm/lib/Target/Hexagon/Hexagon.td
index 0dbe743d13ede..6d0529fb42779 100644
--- a/llvm/lib/Target/Hexagon/Hexagon.td
+++ b/llvm/lib/Target/Hexagon/Hexagon.td
@@ -176,8 +176,11 @@ def UseSmallData       : Predicate<"HST->useSmallData()">;
 def UseCabac           : Predicate<"HST->useCabac()">,
                          AssemblerPredicate<(any_of FeatureCabac)>;
 
-def Hvx64:  HwMode<"+hvx-length64b", [UseHVX64B]>;
-def Hvx128: HwMode<"+hvx-length128b", [UseHVX128B]>;
+def : HwModePredicateProlog<[{
+  const auto *HST = static_cast<const HexagonSubtarget *>(this);
+}]>;
+def Hvx64:  HwMode<[UseHVX64B]>;
+def Hvx128: HwMode<[UseHVX128B]>;
 
 //===----------------------------------------------------------------------===//
 // Classes used for relation maps.
diff --git a/llvm/lib/Target/LoongArch/LoongArch.td b/llvm/lib/Target/LoongArch/LoongArch.td
index 39948b31fb9b9..6497ff999f6fa 100644
--- a/llvm/lib/Target/LoongArch/LoongArch.td
+++ b/llvm/lib/Target/LoongArch/LoongArch.td
@@ -39,7 +39,7 @@ def IsLA32
                          "LA32 Basic Integer and Privilege Instruction Set">;
 
 defvar LA32 = DefaultMode;
-def LA64 : HwMode<"+64bit", [IsLA64]>;
+def LA64 : HwMode<[IsLA64]>;
 
 // Single Precision floating point
 def FeatureBasicF
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index bf5dca481cd2b..063963d4ec36b 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1682,7 +1682,7 @@ def IsRV32 : Predicate<"!Subtarget->is64Bit()">,
                                 "RV32I Base Instruction Set">;
 
 defvar RV32 = DefaultMode;
-def RV64           : HwMode<"+64bit", [IsRV64]>;
+def RV64 : HwMode<[IsRV64]>;
 
 def FeatureRelax
     : SubtargetFeature<"relax", "EnableLinkerRelax", "true",
diff --git a/llvm/lib/Target/SystemZ/SystemZFeatures.td b/llvm/lib/Target/SystemZ/SystemZFeatures.td
index 2c48da8320fb9..4ccc3d3079fc2 100644
--- a/llvm/lib/Target/SystemZ/SystemZFeatures.td
+++ b/llvm/lib/Target/SystemZ/SystemZFeatures.td
@@ -196,7 +196,7 @@ def FeatureVector : SystemZFeature<
 >;
 def FeatureNoVector : SystemZMissingFeature<"Vector">;
 
-def NoVecHwMode : HwMode<"-vector", [FeatureNoVector]>;
+def NoVecHwMode : HwMode<[FeatureNoVector]>;
 
 def Arch11NewFeatures : SystemZFeatureList<[
     FeatureLoadAndZeroRightmostByte,
@@ -426,4 +426,3 @@ def Arch9UnsupportedFeatures
   : SystemZFeatureAdd<Arch10UnsupportedFeatures.List, Arch10NewFeatures.List>;
 def Arch8UnsupportedFeatures
   : SystemZFeatureAdd<Arch9UnsupportedFeatures.List,  Arch9NewFeatures.List>;
-
diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
index c3b406a545072..f1f7cd72ef9f2 100644
--- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp
@@ -14,6 +14,7 @@
 #include "CodeGenDAGPatterns.h"
 #include "CodeGenInstruction.h"
 #include "CodeGenRegisters.h"
+#include "SubtargetFeatureInfo.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/STLExtras.h"
@@ -4498,13 +4499,17 @@ void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {
 
       // Fill the map entry for this mode.
       const HwMode &HM = CGH.getMode(M);
-      AppendPattern(P, M, HM.Predicates);
+
+      SmallString<128> PredicateCheck;
+      raw_svector_ostream PS(PredicateCheck);
+      SubtargetFeatureInfo::emitPredicateCheck(PS, HM.Predicates);
+      AppendPattern(P, M, PredicateCheck);
 
       // Add negations of the HM's predicates to the default predicate.
       if (!DefaultCheck.empty())
         DefaultCheck += " && ";
       DefaultCheck += "!(";
-      DefaultCheck += HM.Predicates;
+      DefaultCheck.append(PredicateCheck);
       DefaultCheck += ")";
     }
 
diff --git a/llvm/utils/TableGen/Common/CodeGenHwModes.cpp b/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
index 09765113a4e7b..5a93c83be5933 100644
--- a/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
@@ -20,23 +20,17 @@ StringRef CodeGenHwModes::DefaultModeName = "DefaultMode";
 
 HwMode::HwMode(const Record *R) {
   Name = R->getName();
-  Features = R->getValueAsString("Features").str();
-
-  SmallString<128> PredicateCheck;
-  raw_svector_ostream OS(PredicateCheck);
-  ListSeparator LS(" && ");
-  for (const Record *Pred : R->getValueAsListOfDefs("Predicates")) {
-    StringRef CondString = Pred->getValueAsString("CondString");
-    if (CondString.empty())
-      continue;
-    OS << LS << '(' << CondString << ')';
-  }
-
-  Predicates = std::string(PredicateCheck);
+  Predicates = R->getValueAsListOfDefs("Predicates");
 }
 
 LLVM_DUMP_METHOD
-void HwMode::dump() const { dbgs() << Name << ": " << Features << '\n'; }
+void HwMode::dump() const {
+  dbgs() << Name << ": ";
+  ListSeparator LS;
+  for (const Record *R : Predicates)
+    dbgs() << LS << R->getName();
+  dbgs() << '\n';
+}
 
 HwModeSelect::HwModeSelect(const Record *R, CodeGenHwModes &CGH) {
   std::vector<const Record *> Modes = R->getValueAsListOfDefs("Modes");
diff --git a/llvm/utils/TableGen/Common/CodeGenHwModes.h b/llvm/utils/TableGen/Common/CodeGenHwModes.h
index 4ced4208cea07..5e1b31ae39e43 100644
--- a/llvm/utils/TableGen/Common/CodeGenHwModes.h
+++ b/llvm/utils/TableGen/Common/CodeGenHwModes.h
@@ -30,8 +30,7 @@ struct CodeGenHwModes;
 struct HwMode {
   HwMode(const Record *R);
   StringRef Name;
-  std::string Features;
-  std::string Predicates;
+  std::vector<const Record *> Predicates;
   void dump() const;
 };
 
diff --git a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
index 738ddf7760247..004e4b0c27ea5 100644
--- a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
@@ -163,6 +163,38 @@ static bool emitFeaturesAux(StringRef TargetName, const Init &Val,
   return true;
 }
 
+void SubtargetFeatureInfo::emitPredicateCheck(
+    raw_ostream &OS, ArrayRef<const Record *> Predicates) {
+  ListSeparator LS(" && ");
+  for (const Record *R : Predicates) {
+    StringRef CondString = R->getValueAsString("CondString");
+    if (CondString.empty())
+      continue;
+    OS << LS << '(' << CondString << ')';
+  }
+}
+
+void SubtargetFeatureInfo::emitMCPredicateCheck(
+    raw_ostream &OS, StringRef TargetName,
+    ArrayRef<const Record *> Predicates) {
+  auto MCPredicates = make_filter_range(Predicates, [](const Record *R) {
+    return R->getValueAsBit("AssemblerMatcherPredicate");
+  });
+
+  if (MCPredicates.empty()) {
+    OS << "false";
+    return;
+  }
+
+  ListSeparator LS(" && ");
+  bool ParenIfBinOp = range_size(MCPredicates) > 1;
+  for (const Record *R : Predicates) {
+    OS << LS;
+    emitFeaturesAux(TargetName, *R->getValueAsDag("AssemblerCondDag"),
+                    ParenIfBinOp, OS);
+  }
+}
+
 void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
     StringRef TargetName, StringRef ClassName, StringRef FuncName,
     SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS) {
diff --git a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h
index d75a9a41636de..2b2577b93c284 100644
--- a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h
+++ b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h
@@ -101,6 +101,12 @@ struct SubtargetFeatureInfo {
   static void emitComputeAssemblerAvailableFeatures(
       StringRef TargetName, StringRef ClassName, StringRef FuncName,
       SubtargetFeatureInfoMap &SubtargetFeatures, raw_ostream &OS);
+
+  static void emitPredicateCheck(raw_ostream &OS,
+                                 ArrayRef<const Record *> Predicates);
+
+  static void emitMCPredicateCheck(raw_ostream &OS, StringRef TargetName,
+                                   ArrayRef<const Record *> Predicates);
 };
 } // end namespace llvm
 
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 408fe544d260f..e218927621dd3 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -15,6 +15,7 @@
 #include "Common/CodeGenSchedule.h"
 #include "Common/CodeGenTarget.h"
 #include "Common/PredicateExpander.h"
+#include "Common/SubtargetFeatureInfo.h"
 #include "Common/Utils.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -124,7 +125,8 @@ class SubtargetEmitter : TargetFeaturesEmitter {
 
   void emitSchedModel(raw_ostream &OS);
   void emitGetMacroFusions(const std::string &ClassName, raw_ostream &OS);
-  void emitHwModeCheck(const std::string &ClassName, raw_ostream &OS);
+  void emitHwModeCheck(const std::string &ClassName, raw_ostream &OS,
+                       bool IsMC);
   void parseFeaturesFunction(raw_ostream &OS);
 
 public:
@@ -1772,7 +1774,7 @@ void SubtargetEmitter::emitSchedModelHelpers(const std::string &ClassName,
 }
 
 void SubtargetEmitter::emitHwModeCheck(const std::string &ClassName,
-                                       raw_ostream &OS) {
+                                       raw_ostream &OS, bool IsMC) {
   const CodeGenHwModes &CGH = TGT.getHwModes();
   assert(CGH.getNumModeIds() > 0);
   if (CGH.getNumModeIds() == 1)
@@ -1800,12 +1802,30 @@ void SubtargetEmitter::emitHwModeCheck(const std::string &ClassName,
 
   // Start emitting for getHwModeSet().
   OS << "unsigned " << ClassName << "::getHwModeSet() const {\n";
+  if (IsMC) {
+    OS << "  [[maybe_unused]] const FeatureBitset &FB = getFeatureBits();\n";
+  } else {
+    const ArrayRef<const Record *> &Prologs =
+        Records.getAllDerivedDefinitions("HwModePredicateProlog");
+    if (!Prologs.empty()) {
+      for (const Record *P : Prologs)
+        OS << P->getValueAsString("Code") << '\n';
+    } else {
+      // Works for most targets.
+      OS << "  [[maybe_unused]] const auto *Subtarget =\n"
+         << "      static_cast<const " << Target << "Subtarget *>(this);\n";
+    }
+  }
   OS << "  // Collect HwModes and store them as a bit set.\n";
   OS << "  unsigned Modes = 0;\n";
   for (unsigned M = 1, NumModes = CGH.getNumModeIds(); M != NumModes; ++M) {
     const HwMode &HM = CGH.getMode(M);
-    OS << "  if (checkFeatures(\"" << HM.Features << "\")) Modes |= (1 << "
-       << (M - 1) << ");\n";
+    OS << "  if (";
+    if (IsMC)
+      SubtargetFeatureInfo::emitMCPredicateCheck(OS, Target, HM.Predicates);
+    else
+      SubtargetFeatureInfo::emitPredicateCheck(OS, HM.Predicates);
+    OS << ") Modes |= (1 << " << (M - 1) << ");\n";
   }
   OS << "  return Modes;\n}\n";
   // End emitting for getHwModeSet().
@@ -1937,7 +1957,7 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
        << "    return MCSubtargetInfo::isCPUStringValid(CPU);\n"
        << "  }\n";
   OS << "};\n";
-  emitHwModeCheck(Target + "GenMCSubtargetInfo", OS);
+  emitHwModeCheck(Target + "GenMCSubtargetInfo", OS, /*IsMC=*/true);
 }
 
 void SubtargetEmitter::emitMcInstrAnalysisPredicateFunctions(raw_ostream &OS) {
@@ -2160,7 +2180,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
   OS << ") {}\n\n";
 
   emitSchedModelHelpers(ClassName, OS);
-  emitHwModeCheck(ClassName, OS);
+  emitHwModeCheck(ClassName, OS, /*IsMC=*/false);
   emitGetMacroFusions(ClassName, OS);
 
   OS << "} // end namespace llvm\n\n";

``````````

</details>


https://github.com/llvm/llvm-project/pull/157600


More information about the llvm-commits mailing list