[llvm] [TableGen][SchedModel] Introduce a new SchedPredicate that checks against SubtargetFeature (PR #161888)

Min-Yih Hsu via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 3 11:17:46 PDT 2025


https://github.com/mshockwave created https://github.com/llvm/llvm-project/pull/161888

Introduce a new SchedPredicate, `FeatureSchedPredicate`, that holds true when a certain SubtargetFeature is enabled. This could be useful when we want to configure a scheduling model with subtarget features.

I add this as a separate SchedPredicate rather than piggy-back on the existing `SchedPredicate<[{....}]>` because first and foremost, `SchedPredicate` is expected to only operate on MachineInstr, so it does _not_ appear in `MCGenSubtargetInfo::resolveVariantSchedClass` but only show up in `TargetGenSubtargetInfo::resolveSchedClass`. Yet I think `FeatureSchedPredicate` will be useful for both MCInst and MachineInstr. There is another subtle difference between  `resolveVariantSchedClass` and `resolveSchedClass` regarding how we access the MCSubtargetInfo instance, if we really want to express `FeatureSchedPredicate` using `SchedPredicate<[{.....}]>`. 

So I thought it'll be easier to add another new SchedPredicate for SubtargetFeature.

------

This stacks on top of #161886 

>From e8d1130904dcf6777eddae79507ad262da690c46 Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Thu, 2 Oct 2025 15:09:04 -0700
Subject: [PATCH 1/2] [TableGen] Add a MCSubtargetInfo argument to
 resolveVariantSchedClassImpl

---
 llvm/test/TableGen/ResolveSchedClass.td  | 18 ++++++++++++++++++
 llvm/utils/TableGen/SubtargetEmitter.cpp | 10 ++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/TableGen/ResolveSchedClass.td

diff --git a/llvm/test/TableGen/ResolveSchedClass.td b/llvm/test/TableGen/ResolveSchedClass.td
new file mode 100644
index 0000000000000..8c9ef1eab3566
--- /dev/null
+++ b/llvm/test/TableGen/ResolveSchedClass.td
@@ -0,0 +1,18 @@
+// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+def TestTargetInstrInfo : InstrInfo;
+
+def TestTarget : Target {
+  let InstructionSet = TestTargetInstrInfo;
+}
+
+// CHECK:  unsigned resolveVariantSchedClassImpl(unsigned SchedClass,
+// CHECK-NEXT:      const MCInst *MI, const MCInstrInfo *MCII, const MCSubtargetInfo &STI, unsigned CPUID)
+
+// CHECK: unsigned resolveVariantSchedClass(unsigned SchedClass,
+// CHECK-NEXT:    const MCInst *MI, const MCInstrInfo *MCII,
+// CHECK-NEXT:    unsigned CPUID) const override {
+// CHECK-NEXT:   return TestTarget_MC::resolveVariantSchedClassImpl(SchedClass, MI, MCII, *this, CPUID);
+// CHECK-NEXT: }
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 0f42d49a6bea1..b0a309cdbfef8 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -1761,7 +1761,7 @@ void SubtargetEmitter::emitSchedModelHelpers(const std::string &ClassName,
      << "\n::resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI,"
      << " const MCInstrInfo *MCII, unsigned CPUID) const {\n"
      << "  return " << Target << "_MC"
-     << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n"
+     << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, *this, CPUID);\n"
      << "} // " << ClassName << "::resolveVariantSchedClass\n\n";
 
   STIPredicateExpander PE(Target, /*Indent=*/0);
@@ -1923,7 +1923,8 @@ void SubtargetEmitter::parseFeaturesFunction(raw_ostream &OS) {
 void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
   OS << "namespace " << Target << "_MC {\n"
      << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
-     << "    const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) {\n";
+     << "    const MCInst *MI, const MCInstrInfo *MCII, "
+     << "const MCSubtargetInfo &STI, unsigned CPUID) {\n";
   emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
   OS << "}\n";
   OS << "} // end namespace " << Target << "_MC\n\n";
@@ -1945,7 +1946,7 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
      << "      const MCInst *MI, const MCInstrInfo *MCII,\n"
      << "      unsigned CPUID) const override {\n"
      << "    return " << Target << "_MC"
-     << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, CPUID);\n";
+     << "::resolveVariantSchedClassImpl(SchedClass, MI, MCII, *this, CPUID);\n";
   OS << "  }\n";
   if (TGT.getHwModes().getNumModeIds() > 1) {
     OS << "  unsigned getHwModeSet() const override;\n";
@@ -2073,7 +2074,8 @@ void SubtargetEmitter::run(raw_ostream &OS) {
   OS << "class DFAPacketizer;\n";
   OS << "namespace " << Target << "_MC {\n"
      << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
-     << " const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID);\n"
+     << " const MCInst *MI, const MCInstrInfo *MCII, "
+     << "const MCSubtargetInfo &STI, unsigned CPUID);\n"
      << "} // end namespace " << Target << "_MC\n\n";
   OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
      << "  explicit " << ClassName << "(const Triple &TT, StringRef CPU, "

>From ebc2a49c34aaf8c29c29e876b436fd1c6a84f9f7 Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Fri, 3 Oct 2025 09:42:33 -0700
Subject: [PATCH 2/2] [TableGen][SchedModel] Introduce a new SchedPredicate
 that checks against SubtargetFeature

---
 llvm/include/llvm/Target/TargetSchedule.td |  5 +++
 llvm/test/TableGen/ResolveSchedClass.td    | 46 ++++++++++++++++++++++
 llvm/utils/TableGen/SubtargetEmitter.cpp   | 14 ++++++-
 3 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td
index f55bff16dcecd..95622b8e73e8b 100644
--- a/llvm/include/llvm/Target/TargetSchedule.td
+++ b/llvm/include/llvm/Target/TargetSchedule.td
@@ -377,6 +377,11 @@ class MCSchedPredicate<MCInstPredicate P> : SchedPredicateBase {
   SchedMachineModel SchedModel = ?;
 }
 
+class FeatureSchedPredicate<SubtargetFeature SF> : SchedPredicateBase {
+  SubtargetFeature Feature = SF;
+  SchedMachineModel SchedModel = ?;
+}
+
 // Define a predicate to determine which SchedVariant applies to a
 // particular MachineInstr. The code snippet is used as an
 // if-statement's expression. Available variables are MI, SchedModel,
diff --git a/llvm/test/TableGen/ResolveSchedClass.td b/llvm/test/TableGen/ResolveSchedClass.td
index 8c9ef1eab3566..c1cadb359ca03 100644
--- a/llvm/test/TableGen/ResolveSchedClass.td
+++ b/llvm/test/TableGen/ResolveSchedClass.td
@@ -8,11 +8,57 @@ def TestTarget : Target {
   let InstructionSet = TestTargetInstrInfo;
 }
 
+def FeatureFoo : SubtargetFeature<"foo", "HasFoo", "true", "enable foo">;
+
+def ResX0 : ProcResource<1>;
+
+let OutOperandList = (outs), InOperandList = (ins) in
+def Inst_A : Instruction;
+
+def SchedModel_A: SchedMachineModel {
+  let CompleteModel = false;
+}
+
+let SchedModel = SchedModel_A in {
+def SchedWriteResA : SchedWriteRes<[ResX0]> {
+  let Latency = 2;
+}
+def SchedWriteResB : SchedWriteRes<[ResX0]> {
+  let Latency = 4;
+}
+
+// Check SchedPredicate with subtarget feature.
+def FeatureFooPred : FeatureSchedPredicate<FeatureFoo>;
+
+def Variant : SchedWriteVariant<[
+  SchedVar<FeatureFooPred, [SchedWriteResA]>,
+  SchedVar<NoSchedPred,    [SchedWriteResB]>
+]>;
+
+def : InstRW<[Variant], (instrs Inst_A)>;
+}
+
+def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
+
 // CHECK:  unsigned resolveVariantSchedClassImpl(unsigned SchedClass,
 // CHECK-NEXT:      const MCInst *MI, const MCInstrInfo *MCII, const MCSubtargetInfo &STI, unsigned CPUID)
+// CHECK:  case {{.*}}: // Inst_A
+// CHECK-NEXT:   if (CPUID == {{.*}}) { // SchedModel_A
+// CHECK-NEXT:     if (STI.hasFeature(TestTarget::FeatureFoo))
+// CHECK-NEXT:       return {{.*}}; // SchedWriteResA
+// CHECK-NEXT:     return {{.*}}; // SchedWriteResB
 
 // CHECK: unsigned resolveVariantSchedClass(unsigned SchedClass,
 // CHECK-NEXT:    const MCInst *MI, const MCInstrInfo *MCII,
 // CHECK-NEXT:    unsigned CPUID) const override {
 // CHECK-NEXT:   return TestTarget_MC::resolveVariantSchedClassImpl(SchedClass, MI, MCII, *this, CPUID);
 // CHECK-NEXT: }
+
+// CHECK: unsigned TestTargetGenSubtargetInfo
+// CHECK-NEXT: ::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI, const TargetSchedModel *SchedModel) const {
+// CHECK-NEXT:   switch (SchedClass) {
+// CHECK-NEXT:   case {{.*}}: // Inst_A
+// CHECK-NEXT:     if (SchedModel->getProcessorID() == {{.*}}) { // SchedModel_A
+// CHECK-NEXT:       if (this->hasFeature(TestTarget::FeatureFoo))
+// CHECK-NEXT:         return {{.*}}; // SchedWriteResA
+// CHECK-NEXT:       return {{.*}}; // SchedWriteResB
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index b0a309cdbfef8..9d463228be682 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -1586,6 +1586,17 @@ static void emitPredicates(const CodeGenSchedTransition &T,
         continue;
       }
 
+      if (Rec->isSubClassOf("FeatureSchedPredicate")) {
+        const Record *FR = Rec->getValueAsDef("Feature");
+        if (PE.shouldExpandForMC())
+          SS << "STI.";
+        else
+          SS << "this->";
+        SS << "hasFeature(" << PE.getTargetName() << "::" << FR->getName()
+           << ")";
+        continue;
+      }
+
       // Expand this legacy predicate and wrap it around braces if there is more
       // than one predicate to expand.
       SS << ((NumNonTruePreds > 1) ? "(" : "")
@@ -1618,7 +1629,8 @@ static void emitSchedModelHelperEpilogue(raw_ostream &OS,
 
 static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) {
   return all_of(T.PredTerm, [](const Record *Rec) {
-    return Rec->isSubClassOf("MCSchedPredicate");
+    return Rec->isSubClassOf("MCSchedPredicate") ||
+           Rec->isSubClassOf("FeatureSchedPredicate");
   });
 }
 



More information about the llvm-commits mailing list