[llvm] [TableGen] Add isReg check for CheckRegOperand predicate (PR #215230)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 06:06:51 PDT 2026


https://github.com/renndong updated https://github.com/llvm/llvm-project/pull/215230

>From 6f165d9537abd605645df3a63a1750a31a70e587 Mon Sep 17 00:00:00 2001
From: liumingliang <liumingliang.dev at bytedance.com>
Date: Mon, 10 Aug 2026 16:39:53 +0800
Subject: [PATCH 1/2] [TableGen] Add isReg check for CheckRegOperand predicate

CheckRegOperand and CheckRegOperandSimple currently call getReg()
without first verifying that the operand is a register. Users must
use CheckIsRegOperand explicitly to avoid errors for other operand
kinds, as exposed by #213815.

This PR adds isReg() check for two predicates before accessing the
register value. And remove redundant CheckIsRegOperand checks from
existing users for x86, ARM and RISCV backend.
---
 .../llvm/Target/TargetInstrPredicate.td       | 13 ++-
 .../Target/AArch64/AArch64SchedPredicates.td  | 85 ++++++++-----------
 llvm/lib/Target/ARM/ARMScheduleM85.td         |  4 +-
 llvm/lib/Target/RISCV/RISCVInstrPredicates.td |  4 -
 llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td |  5 --
 llvm/test/TableGen/MacroFusion.td             | 10 +--
 .../TableGen/Common/PredicateExpander.cpp     | 15 +++-
 7 files changed, 63 insertions(+), 73 deletions(-)

diff --git a/llvm/include/llvm/Target/TargetInstrPredicate.td b/llvm/include/llvm/Target/TargetInstrPredicate.td
index b5419cb9f3867..21ef96b95bfb8 100644
--- a/llvm/include/llvm/Target/TargetInstrPredicate.td
+++ b/llvm/include/llvm/Target/TargetInstrPredicate.td
@@ -28,7 +28,12 @@
 //
 // Every MCInstPredicate class has a well-known semantic in tablegen. For
 // example, `CheckOpcode` is a special type of predicate used to describe a
-// constraint on the value of an instruction opcode.
+// constraint on the value of an instruction opcode, while `CheckIsRegOperand` 
+// checks whether an instruction operand is a register operand.
+// `CheckRegOperand` performs this check implicitly before comparing the
+// register value. Therefore, a preceding `CheckIsRegOperand` is unnecessary
+// when we don't care about the type of the operand (e.g. an immediate or a 
+// register) but only care the fact that it is a target register.
 //
 // MCInstPredicate definitions are typically used by scheduling models to
 // construct MCSchedPredicate definitions (see the definition of class
@@ -44,7 +49,7 @@
 // def M3BranchLinkFastPred  : SchedPredicate<[{
 //    MI->getOpcode() == AArch64::BLR &&
 //    MI->getOperand(0).isReg() &&
-//    MI->getOperand(0).getReg() != AArch64::LR}]>;
+//    !(MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == AArch64::LR)}]>;
 //
 // The main advantage of using MCInstPredicate instead of SchedPredicate is
 // portability: users don't need to specify predicates in C++. As a consequence
@@ -123,8 +128,8 @@ class CheckOperandBase<int Index, string Fn = ""> : MCOperandPredicate<Index> {
 }
 
 // Check that the machine register operand at position `Index` references
-// register R. This predicate assumes that we already checked that the machine
-// operand at position `Index` is a register operand.
+// register R. This predicate checks whether the operand at position `Index`
+// is a register first and return false when not satisfied.
 class CheckRegOperand<int Index, Register R> : CheckOperandBase<Index> {
   Register Reg = R;
 }
diff --git a/llvm/lib/Target/AArch64/AArch64SchedPredicates.td b/llvm/lib/Target/AArch64/AArch64SchedPredicates.td
index 870a82bdffd74..cbaaafccd164d 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedPredicates.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedPredicates.td
@@ -294,9 +294,7 @@ def IsCopyIdiomFn     : TIIPredicate<"isCopyIdiom",
                                           [ADDWri, ADDXri],
                                           MCReturnStatement<
                                             CheckAll<
-                                              [CheckIsRegOperand<0>,
-                                               CheckIsRegOperand<1>,
-                                               CheckAny<
+                                              [CheckAny<
                                                  [CheckRegOperand<0, WSP>,
                                                   CheckRegOperand<0, SP>,
                                                   CheckRegOperand<1, WSP>,
@@ -391,40 +389,34 @@ def IsFastSBFMImmPred : MCSchedPredicate<CheckAny<[
        IsSBFMASRImm<SBFMXri, 64> ]>>;
 
 // Identify whether destination operand is a W-form register.
-def CheckIsWRegOp0 : CheckAll<[
-  CheckIsRegOperand<0>,
-  CheckAny<[
-    CheckRegOperand<0, W0>,  CheckRegOperand<0, W1>,  CheckRegOperand<0, W2>,
-    CheckRegOperand<0, W3>,  CheckRegOperand<0, W4>,  CheckRegOperand<0, W5>,
-    CheckRegOperand<0, W6>,  CheckRegOperand<0, W7>,  CheckRegOperand<0, W8>,
-    CheckRegOperand<0, W9>,  CheckRegOperand<0, W10>, CheckRegOperand<0, W11>,
-    CheckRegOperand<0, W12>, CheckRegOperand<0, W13>, CheckRegOperand<0, W14>,
-    CheckRegOperand<0, W15>, CheckRegOperand<0, W16>, CheckRegOperand<0, W17>,
-    CheckRegOperand<0, W18>, CheckRegOperand<0, W19>, CheckRegOperand<0, W20>,
-    CheckRegOperand<0, W21>, CheckRegOperand<0, W22>, CheckRegOperand<0, W23>,
-    CheckRegOperand<0, W24>, CheckRegOperand<0, W25>, CheckRegOperand<0, W26>,
-    CheckRegOperand<0, W27>, CheckRegOperand<0, W28>, CheckRegOperand<0, W29>,
-    CheckRegOperand<0, W30>, CheckRegOperand<0, WZR>, CheckRegOperand<0, WSP>
-  ]>
+def CheckIsWRegOp0 : CheckAny<[
+  CheckRegOperand<0, W0>,  CheckRegOperand<0, W1>,  CheckRegOperand<0, W2>,
+  CheckRegOperand<0, W3>,  CheckRegOperand<0, W4>,  CheckRegOperand<0, W5>,
+  CheckRegOperand<0, W6>,  CheckRegOperand<0, W7>,  CheckRegOperand<0, W8>,
+  CheckRegOperand<0, W9>,  CheckRegOperand<0, W10>, CheckRegOperand<0, W11>,
+  CheckRegOperand<0, W12>, CheckRegOperand<0, W13>, CheckRegOperand<0, W14>,
+  CheckRegOperand<0, W15>, CheckRegOperand<0, W16>, CheckRegOperand<0, W17>,
+  CheckRegOperand<0, W18>, CheckRegOperand<0, W19>, CheckRegOperand<0, W20>,
+  CheckRegOperand<0, W21>, CheckRegOperand<0, W22>, CheckRegOperand<0, W23>,
+  CheckRegOperand<0, W24>, CheckRegOperand<0, W25>, CheckRegOperand<0, W26>,
+  CheckRegOperand<0, W27>, CheckRegOperand<0, W28>, CheckRegOperand<0, W29>,
+  CheckRegOperand<0, W30>, CheckRegOperand<0, WZR>, CheckRegOperand<0, WSP>
 ]>;
 def IsWFormPred : MCSchedPredicate<CheckIsWRegOp0>;
 
 // Identify whether destination operand is an X-form register.
-def CheckIsXRegOp0 : CheckAll<[
-  CheckIsRegOperand<0>,
-  CheckAny<[
-    CheckRegOperand<0, X0>,  CheckRegOperand<0, X1>,  CheckRegOperand<0, X2>,
-    CheckRegOperand<0, X3>,  CheckRegOperand<0, X4>,  CheckRegOperand<0, X5>,
-    CheckRegOperand<0, X6>,  CheckRegOperand<0, X7>,  CheckRegOperand<0, X8>,
-    CheckRegOperand<0, X9>,  CheckRegOperand<0, X10>, CheckRegOperand<0, X11>,
-    CheckRegOperand<0, X12>, CheckRegOperand<0, X13>, CheckRegOperand<0, X14>,
-    CheckRegOperand<0, X15>, CheckRegOperand<0, X16>, CheckRegOperand<0, X17>,
-    CheckRegOperand<0, X18>, CheckRegOperand<0, X19>, CheckRegOperand<0, X20>,
-    CheckRegOperand<0, X21>, CheckRegOperand<0, X22>, CheckRegOperand<0, X23>,
-    CheckRegOperand<0, X24>, CheckRegOperand<0, X25>, CheckRegOperand<0, X26>,
-    CheckRegOperand<0, X27>, CheckRegOperand<0, X28>, CheckRegOperand<0, FP>,
-    CheckRegOperand<0, LR>, CheckRegOperand<0, XZR>, CheckRegOperand<0, SP>
-  ]>
+def CheckIsXRegOp0 : CheckAny<[
+  CheckRegOperand<0, X0>,  CheckRegOperand<0, X1>,  CheckRegOperand<0, X2>,
+  CheckRegOperand<0, X3>,  CheckRegOperand<0, X4>,  CheckRegOperand<0, X5>,
+  CheckRegOperand<0, X6>,  CheckRegOperand<0, X7>,  CheckRegOperand<0, X8>,
+  CheckRegOperand<0, X9>,  CheckRegOperand<0, X10>, CheckRegOperand<0, X11>,
+  CheckRegOperand<0, X12>, CheckRegOperand<0, X13>, CheckRegOperand<0, X14>,
+  CheckRegOperand<0, X15>, CheckRegOperand<0, X16>, CheckRegOperand<0, X17>,
+  CheckRegOperand<0, X18>, CheckRegOperand<0, X19>, CheckRegOperand<0, X20>,
+  CheckRegOperand<0, X21>, CheckRegOperand<0, X22>, CheckRegOperand<0, X23>,
+  CheckRegOperand<0, X24>, CheckRegOperand<0, X25>, CheckRegOperand<0, X26>,
+  CheckRegOperand<0, X27>, CheckRegOperand<0, X28>, CheckRegOperand<0, FP>,
+  CheckRegOperand<0, LR>, CheckRegOperand<0, XZR>, CheckRegOperand<0, SP>
 ]>;
 def IsXFormPred : MCSchedPredicate<CheckIsXRegOp0>;
 
@@ -432,21 +424,18 @@ def IsXOrWDest : MCSchedPredicate<
   CheckAll<[CheckAny<[CheckIsXRegOp0, CheckIsWRegOp0]>]>
 >;
 
-def CheckIsZRegOp0 : CheckAll<[
-  CheckIsRegOperand<0>,
-  CheckAny<[
-    CheckRegOperand<0, Z0>,  CheckRegOperand<0, Z1>,  CheckRegOperand<0, Z2>,
-    CheckRegOperand<0, Z3>,  CheckRegOperand<0, Z4>,  CheckRegOperand<0, Z5>,
-    CheckRegOperand<0, Z6>,  CheckRegOperand<0, Z7>,  CheckRegOperand<0, Z8>,
-    CheckRegOperand<0, Z9>,  CheckRegOperand<0, Z10>, CheckRegOperand<0, Z11>,
-    CheckRegOperand<0, Z12>, CheckRegOperand<0, Z13>, CheckRegOperand<0, Z14>,
-    CheckRegOperand<0, Z15>, CheckRegOperand<0, Z16>, CheckRegOperand<0, Z17>,
-    CheckRegOperand<0, Z18>, CheckRegOperand<0, Z19>, CheckRegOperand<0, Z20>,
-    CheckRegOperand<0, Z21>, CheckRegOperand<0, Z22>, CheckRegOperand<0, Z23>,
-    CheckRegOperand<0, Z24>, CheckRegOperand<0, Z25>, CheckRegOperand<0, Z26>,
-    CheckRegOperand<0, Z27>, CheckRegOperand<0, Z28>, CheckRegOperand<0, Z29>,
-    CheckRegOperand<0, Z30>, CheckRegOperand<0, Z31>
-  ]>
+def CheckIsZRegOp0 : CheckAny<[
+  CheckRegOperand<0, Z0>,  CheckRegOperand<0, Z1>,  CheckRegOperand<0, Z2>,
+  CheckRegOperand<0, Z3>,  CheckRegOperand<0, Z4>,  CheckRegOperand<0, Z5>,
+  CheckRegOperand<0, Z6>,  CheckRegOperand<0, Z7>,  CheckRegOperand<0, Z8>,
+  CheckRegOperand<0, Z9>,  CheckRegOperand<0, Z10>, CheckRegOperand<0, Z11>,
+  CheckRegOperand<0, Z12>, CheckRegOperand<0, Z13>, CheckRegOperand<0, Z14>,
+  CheckRegOperand<0, Z15>, CheckRegOperand<0, Z16>, CheckRegOperand<0, Z17>,
+  CheckRegOperand<0, Z18>, CheckRegOperand<0, Z19>, CheckRegOperand<0, Z20>,
+  CheckRegOperand<0, Z21>, CheckRegOperand<0, Z22>, CheckRegOperand<0, Z23>,
+  CheckRegOperand<0, Z24>, CheckRegOperand<0, Z25>, CheckRegOperand<0, Z26>,
+  CheckRegOperand<0, Z27>, CheckRegOperand<0, Z28>, CheckRegOperand<0, Z29>,
+  CheckRegOperand<0, Z30>, CheckRegOperand<0, Z31>
 ]>;
 
 
diff --git a/llvm/lib/Target/ARM/ARMScheduleM85.td b/llvm/lib/Target/ARM/ARMScheduleM85.td
index beeda468397ec..8b5e19501516b 100644
--- a/llvm/lib/Target/ARM/ARMScheduleM85.td
+++ b/llvm/lib/Target/ARM/ARMScheduleM85.td
@@ -605,9 +605,7 @@ let SingleIssue = 1 in {
   def M85VMSRLate  : SchedWriteRes<[M85UnitVPort]> { let Latency = 3; }
 }
 
-def M85FPSCRFlagPred : MCSchedPredicate<
-                           CheckAll<[CheckIsRegOperand<0>,
-                                     CheckRegOperand<0, PC>]>>;
+def M85FPSCRFlagPred : MCSchedPredicate<CheckRegOperand<0, PC>>;
 
 def M85VMRSFPSCR : SchedWriteVariant<[
   SchedVar<M85FPSCRFlagPred, [M85VMRSEarly]>,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrPredicates.td b/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
index cff834150cfeb..ff045c32759d3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
@@ -43,7 +43,6 @@ def isZEXT_W
                    MCReturnStatement<CheckAll<[
                      CheckOpcode<[ADD_UW]>,
                      CheckIsRegOperand<1>,
-                     CheckIsRegOperand<2>,
                      CheckRegOperand<2, X0>
                    ]>>>;
 
@@ -184,7 +183,6 @@ def isLoadImmediate
     : TIIPredicate<"isLoadImmediate",
                    MCReturnStatement<CheckAll<[
                      CheckOpcode<[ADDI]>,
-                     CheckIsRegOperand<1>,
                      CheckRegOperand<1, X0>,
                      CheckIsImmOperand<2>
                    ]>>>;
@@ -193,7 +191,6 @@ def isNonZeroLoadImmediate
     : TIIPredicate<"isNonZeroLoadImmediate",
                    MCReturnStatement<CheckAll<[
                      CheckOpcode<[ADDI]>,
-                     CheckIsRegOperand<1>,
                      CheckRegOperand<1, X0>,
                      CheckIsImmOperand<2>,
                      CheckNot<CheckImmOperand<2, 0>>
@@ -203,7 +200,6 @@ def isLPAD
     : TIIPredicate<"isLPAD",
                    MCReturnStatement<CheckAll<[
                      CheckOpcode<[AUIPC]>,
-                     CheckIsRegOperand<0>,
                      CheckRegOperand<0, X0>,
                    ]>>>;
 
diff --git a/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td b/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td
index 2fedb06bb3006..42c1e5c8e50b8 100644
--- a/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td
+++ b/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td
@@ -24,7 +24,6 @@ def TuneMOVIMMALUXqciFusion
                  CheckAny<[
                    CheckAll<[
                      CheckOpcode<[ADDI]>,
-                     CheckIsRegOperand<1>,
                      CheckRegOperand<1, X0>
                    ]>,
                    CheckOpcode<LoadImmOp>,
@@ -45,7 +44,6 @@ def TuneMOVIMMMULXqciFusion
                  CheckAny<[
                    CheckAll<[
                      CheckOpcode<[ADDI]>,
-                     CheckIsRegOperand<1>,
                      CheckRegOperand<1, X0>
                    ]>,
                    CheckOpcode<LoadImmOp>,
@@ -59,7 +57,6 @@ def TuneMOVIMMLoadStoreXqciFusion
                  CheckAny<[
                    CheckAll<[
                      CheckOpcode<[ADDI]>,
-                     CheckIsRegOperand<1>,
                      CheckRegOperand<1, X0>
                    ]>,
                    CheckOpcode<LoadImmOp>,
@@ -73,7 +70,6 @@ def TuneMOVIMMJumpXqciFusion
                  CheckAny<[
                    CheckAll<[
                      CheckOpcode<[ADDI]>,
-                     CheckIsRegOperand<1>,
                      CheckRegOperand<1, X0>
                    ]>,
                    CheckOpcode<LoadImmOp>,
@@ -90,7 +86,6 @@ def TuneMOVIMMLongAccumXciFusion
                  CheckAny<[
                    CheckAll<[
                      CheckOpcode<[ADDI]>,
-                     CheckIsRegOperand<1>,
                      CheckRegOperand<1, X0>
                    ]>,
                    CheckOpcode<LoadImmOp>,
diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td
index da4adf75ac7eb..909298f0f4bd3 100644
--- a/llvm/test/TableGen/MacroFusion.td
+++ b/llvm/test/TableGen/MacroFusion.td
@@ -117,12 +117,12 @@ def TestPostRAOnlyFusion: SimpleFusion<"test-postra-only", "HasTestPostRAOnlyFus
 // CHECK-PREDICATOR-NEXT:    {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} auto &MRI = SecondMI.getMF()->getRegInfo();
 // CHECK-PREDICATOR-NEXT:    {
 // CHECK-PREDICATOR-NEXT:      {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = FirstMI;
-// CHECK-PREDICATOR-NEXT:      if (MI->getOperand(0).getReg() != Test::X0)
+// CHECK-PREDICATOR-NEXT:      if (!(MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == Test::X0))
 // CHECK-PREDICATOR-NEXT:        return false;
 // CHECK-PREDICATOR-NEXT:    }
 // CHECK-PREDICATOR-NEXT:    {
 // CHECK-PREDICATOR-NEXT:      {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
-// CHECK-PREDICATOR-NEXT:      if (MI->getOperand(0).getReg() != Test::X0)
+// CHECK-PREDICATOR-NEXT:      if (!(MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == Test::X0))
 // CHECK-PREDICATOR-NEXT:        return false;
 // CHECK-PREDICATOR-NEXT:    }
 // CHECK-PREDICATOR-NEXT:    if (SecondMI.getMF()->getProperties().hasNoVRegs())
@@ -145,7 +145,7 @@ def TestPostRAOnlyFusion: SimpleFusion<"test-postra-only", "HasTestPostRAOnlyFus
 // CHECK-PREDICATOR-NEXT:      {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
 // CHECK-PREDICATOR-NEXT:      if (!(
 // CHECK-PREDICATOR-NEXT:          ( MI->getOpcode() == Test::Inst1 )
-// CHECK-PREDICATOR-NEXT:          && MI->getOperand(0).getReg() == Test::X0
+// CHECK-PREDICATOR-NEXT:          && (MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == Test::X0)
 // CHECK-PREDICATOR-NEXT:        ))
 // CHECK-PREDICATOR-NEXT:        return false;
 // CHECK-PREDICATOR-NEXT:    }
@@ -227,7 +227,7 @@ def TestPostRAOnlyFusion: SimpleFusion<"test-postra-only", "HasTestPostRAOnlyFus
 // CHECK-PREDICATOR-NEXT:      {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
 // CHECK-PREDICATOR-NEXT:      if (!(
 // CHECK-PREDICATOR-NEXT:          ( MI->getOpcode() == Test::Inst1 )
-// CHECK-PREDICATOR-NEXT:          && MI->getOperand(0).getReg() == Test::X0
+// CHECK-PREDICATOR-NEXT:          && (MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == Test::X0)
 // CHECK-PREDICATOR-NEXT:        ))
 // CHECK-PREDICATOR-NEXT:        return false;
 // CHECK-PREDICATOR-NEXT:    }
@@ -349,7 +349,7 @@ def TestPostRAOnlyFusion: SimpleFusion<"test-postra-only", "HasTestPostRAOnlyFus
 // CHECK-PREDICATOR-NEXT:      {{[[]}}{{[[]}}maybe_unused{{[]]}}{{[]]}} const MachineInstr *MI = &SecondMI;
 // CHECK-PREDICATOR-NEXT:      if (!(
 // CHECK-PREDICATOR-NEXT:          ( MI->getOpcode() == Test::Inst2 )
-// CHECK-PREDICATOR-NEXT:          && MI->getOperand(0).getReg() == Test::X0
+// CHECK-PREDICATOR-NEXT:          && (MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == Test::X0)
 // CHECK-PREDICATOR-NEXT:        ))
 // CHECK-PREDICATOR-NEXT:        return false;
 // CHECK-PREDICATOR-NEXT:    }
diff --git a/llvm/utils/TableGen/Common/PredicateExpander.cpp b/llvm/utils/TableGen/Common/PredicateExpander.cpp
index c6d73f9c6721b..ac0942df3d112 100644
--- a/llvm/utils/TableGen/Common/PredicateExpander.cpp
+++ b/llvm/utils/TableGen/Common/PredicateExpander.cpp
@@ -88,30 +88,37 @@ void PredicateExpander::expandCheckRegOperand(raw_ostream &OS, int OpIndex,
                                               StringRef FunctionMapper) {
   assert(Reg->isSubClassOf("Register") && "Expected a register Record!");
 
+  OS << (shouldNegate() ? "!(" : "(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").isReg()";
+  OS << " && ";
   if (!FunctionMapper.empty())
     OS << FunctionMapper << "(";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getReg()";
   if (!FunctionMapper.empty())
     OS << ")";
-  OS << (shouldNegate() ? " != " : " == ");
+  OS << " == ";
   const StringRef Str = Reg->getValueAsString("Namespace");
   if (!Str.empty())
     OS << Str << "::";
-  OS << Reg->getName();
+  OS << Reg->getName() << ")";
 }
 
 void PredicateExpander::expandCheckRegOperandSimple(raw_ostream &OS,
                                                     int OpIndex,
                                                     StringRef FunctionMapper) {
-  if (shouldNegate())
-    OS << "!";
+  OS << (shouldNegate() ? "!(" : "(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").isReg()";
+  OS << " && ";
   if (!FunctionMapper.empty())
     OS << FunctionMapper << "(";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getReg()";
   if (!FunctionMapper.empty())
     OS << ")";
+  OS << ")";
 }
 
 void PredicateExpander::expandCheckInvalidRegOperand(raw_ostream &OS,

>From fe65a2cd17b0d9adb23a301207058771439e8182 Mon Sep 17 00:00:00 2001
From: liumingliang <liumingliang.dev at bytedance.com>
Date: Wed, 12 Aug 2026 21:05:41 +0800
Subject: [PATCH 2/2] [TableGen] Add isImm check for CheckImmOperand predicate

---
 .../llvm/Target/TargetInstrPredicate.td       |  88 +++---
 .../AArch64/AArch64SchedPredNeoverse.td       |   2 -
 llvm/lib/Target/RISCV/RISCVInstrPredicates.td |   2 -
 llvm/lib/Target/RISCV/RISCVMacroFusion.td     |   8 -
 llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td |   1 -
 llvm/test/TableGen/PredicateExpander.td       | 285 ++++++++++++++++++
 llvm/test/TableGen/ResolveSchedClass.td       |  10 +-
 .../TableGen/Common/PredicateExpander.cpp     | 141 ++++++---
 .../utils/TableGen/Common/PredicateExpander.h |  13 +-
 9 files changed, 441 insertions(+), 109 deletions(-)
 create mode 100644 llvm/test/TableGen/PredicateExpander.td

diff --git a/llvm/include/llvm/Target/TargetInstrPredicate.td b/llvm/include/llvm/Target/TargetInstrPredicate.td
index 21ef96b95bfb8..3cf3dfed167c8 100644
--- a/llvm/include/llvm/Target/TargetInstrPredicate.td
+++ b/llvm/include/llvm/Target/TargetInstrPredicate.td
@@ -15,25 +15,23 @@
 //
 // def MCInstPredicateExample : CheckAll<[
 //    CheckOpcode<[BLR]>,
-//    CheckIsRegOperand<0>,
 //    CheckNot<CheckRegOperand<0, LR>>]>;
 //
 // The syntax for MCInstPredicate is declarative, and predicate definitions can
 // be composed together in order to generate more complex constraints.
 //
-// The `CheckAll` from the example defines a composition of three different
+// The `CheckAll` from the example defines a composition of two different
 // predicates.  Definition `MCInstPredicateExample` identifies instructions
-// whose opcode is BLR, and whose first operand is a register different from
-// register `LR`.
+// whose opcode is BLR, and whose first operand is either not a register
+// operand or does not reference register `LR`.
 //
 // Every MCInstPredicate class has a well-known semantic in tablegen. For
 // example, `CheckOpcode` is a special type of predicate used to describe a
-// constraint on the value of an instruction opcode, while `CheckIsRegOperand` 
-// checks whether an instruction operand is a register operand.
-// `CheckRegOperand` performs this check implicitly before comparing the
-// register value. Therefore, a preceding `CheckIsRegOperand` is unnecessary
-// when we don't care about the type of the operand (e.g. an immediate or a 
-// register) but only care the fact that it is a target register.
+// constraint on the value of an instruction opcode, while `CheckRegOperand`
+// checks whether an instruction operand is a register operand and matches a
+// specified register. Therefore, a preceding `CheckIsRegOperand` is unnecessary
+// as the `CheckRegOperand` predicate will necessarily be false if the operand
+// isn't a register.
 //
 // MCInstPredicate definitions are typically used by scheduling models to
 // construct MCSchedPredicate definitions (see the definition of class
@@ -48,8 +46,8 @@
 //
 // def M3BranchLinkFastPred  : SchedPredicate<[{
 //    MI->getOpcode() == AArch64::BLR &&
-//    MI->getOperand(0).isReg() &&
-//    !(MI->getOperand(0).isReg() && MI->getOperand(0).getReg() == AArch64::LR)}]>;
+//    !(MI->getOperand(0).isReg() &&
+//      MI->getOperand(0).getReg() == AArch64::LR)}]>;
 //
 // The main advantage of using MCInstPredicate instead of SchedPredicate is
 // portability: users don't need to specify predicates in C++. As a consequence
@@ -127,9 +125,8 @@ class CheckOperandBase<int Index, string Fn = ""> : MCOperandPredicate<Index> {
   string FunctionMapper = Fn;
 }
 
-// Check that the machine register operand at position `Index` references
-// register R. This predicate checks whether the operand at position `Index`
-// is a register first and return false when not satisfied.
+// Check that the machine register operand at position `Index` is a
+// register operand that references register `R`.
 class CheckRegOperand<int Index, Register R> : CheckOperandBase<Index> {
   Register Reg = R;
 }
@@ -142,10 +139,10 @@ class CheckInvalidRegOperand<int Index> : CheckOperandBase<Index>;
 class CheckValidRegOperand<int Index> :
   CheckNot<CheckInvalidRegOperand<Index>>;
 
-// Check that the operand at position `Index` is immediate `Imm`.
-// If field `FunctionMapper` is a non-empty string, then function
-// `FunctionMapper` is applied to the operand value, and the return value is then
-// compared against `Imm`.
+// Check that the operand at position `Index` is an immediate operand whose
+// value equals `Imm`. If field `FunctionMapper` is a non-empty string, then 
+// function `FunctionMapper` is applied to the operand value, and the return
+// value is then compared against `Imm`.
 class CheckImmOperand<int Index, int Imm> : CheckOperandBase<Index> {
   int ImmVal = Imm;
 }
@@ -157,33 +154,37 @@ class CheckImmOperand_s<int Index, string Value> : CheckOperandBase<Index> {
   string ImmVal = Value;
 }
 
-// Check that the operand at position `Index` is less than `Imm`.
-// If field `FunctionMapper` is a non-empty string, then function
-// `FunctionMapper` is applied to the operand value, and the return value is then
-// compared against `Imm`.
+// Check that the operand at position `Index` is an immediate operand whose
+// value is less than `Imm`. If field `FunctionMapper` is a non-empty string,
+// then function `FunctionMapper` is applied to the operand value, and the
+// return value is then compared against `Imm`.
 class CheckImmOperandLT<int Index, int Imm> : CheckOperandBase<Index> {
   int ImmVal = Imm;
 }
 
-// Check that the operand at position `Index` is greater than `Imm`.
-// If field `FunctionMapper` is a non-empty string, then function
-// `FunctionMapper` is applied to the operand value, and the return value is then
-// compared against `Imm`.
+// Check that the operand at position `Index` is an immediate operand whose
+// value is greater than `Imm`. If field `FunctionMapper` is a non-empty string,
+// then function `FunctionMapper` is applied to the operand value, and the
+// return value is then compared against `Imm`.
 class CheckImmOperandGT<int Index, int Imm> : CheckOperandBase<Index> {
   int ImmVal = Imm;
 }
 
-// Check that the operand at position `Index` is less than or equal to `Imm`.
-// If field `FunctionMapper` is a non-empty string, then function
-// `FunctionMapper` is applied to the operand value, and the return value is then
-// compared against `Imm`.
-class CheckImmOperandLE<int Index, int Imm> : CheckNot<CheckImmOperandGT<Index, Imm>>;
+// Check that the operand at position `Index` is an immediate operand whose
+// value is less than or equal to `Imm`. If field `FunctionMapper` is a
+// non-empty string, then function `FunctionMapper` is applied to the operand
+// value, and the return value is then compared against `Imm`.
+class CheckImmOperandLE<int Index, int Imm> : CheckOperandBase<Index> {
+  int ImmVal = Imm;
+}
 
-// Check that the operand at position `Index` is greater than or equal to `Imm`.
-// If field `FunctionMapper` is a non-empty string, then function
-// `FunctionMapper` is applied to the operand value, and the return value is then
-// compared against `Imm`.
-class CheckImmOperandGE<int Index, int Imm> : CheckNot<CheckImmOperandLT<Index, Imm>>;
+// Check that the operand at position `Index` is an immediate operand whose
+// value is greater than or equal to `Imm`. If field `FunctionMapper` is a
+// non-empty string, then function `FunctionMapper` is applied to the operand
+// value, and the return value is then compared against `Imm`.
+class CheckImmOperandGE<int Index, int Imm> : CheckOperandBase<Index> {
+  int ImmVal = Imm;
+}
 
 // Expands to a call to `FunctionMapper` if field `FunctionMapper` is set.
 // Otherwise, it expands to a CheckNot<CheckInvalidRegOperand<Index>>.
@@ -236,12 +237,15 @@ class CheckAll<list<MCInstPredicate> Sequence>
 class CheckAny<list<MCInstPredicate> Sequence>
     : CheckPredicateSequence<Sequence>;
 
-// Check that the operand at position `Index` is in range [Start, End].
-// If field `FunctionMapper` is a non-empty string, then function
-// `FunctionMapper` is applied to the operand value, and the return value is then
-// compared against range [Start, End].
+// Check that the operand at position `Index` is an immediate operand whose
+// value is in range [Start, End]. If field `FunctionMapper` is a non-empty
+// string, then function `FunctionMapper` is applied to the operand value,
+// and the return value is then compared against range [Start, End].
 class CheckImmOperandRange<int Index, int Start, int End>
-  : CheckAll<[CheckImmOperandGE<Index, Start>, CheckImmOperandLE<Index, End>]>;
+    : CheckOperandBase<Index> {
+  int StartVal = Start;
+  int EndVal = End;
+}
 
 // Used to expand the body of a function predicate. See the definition of
 // TIIPredicate below.
diff --git a/llvm/lib/Target/AArch64/AArch64SchedPredNeoverse.td b/llvm/lib/Target/AArch64/AArch64SchedPredNeoverse.td
index 41ea3551f35c0..737d7fe9ecc8c 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedPredNeoverse.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedPredNeoverse.td
@@ -66,7 +66,6 @@ def NeoverseZeroMove : MCSchedPredicate<
                            // MOV Wd, #0
                            // MOV Xd, #0
                            CheckAll<[CheckOpcode<[MOVZWi, MOVZXi]>,
-                                     CheckIsImmOperand<1>,
                                      CheckImmOperand<1, 0>,
                                      CheckImmOperand<2, 0>]>,
                            // MOV Wd, WZR
@@ -103,7 +102,6 @@ def NeoverseAllActivePredicate : MCSchedPredicate<
                                        CheckOpcode<[
                                          PTRUE_B, PTRUE_H, PTRUE_S, PTRUE_D,
                                          PTRUES_B, PTRUES_H, PTRUES_S, PTRUES_D]>,
-                                       CheckIsImmOperand<1>,
                                        CheckImmOperand<1, 31>]>,
                                    ]>>;
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrPredicates.td b/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
index ff045c32759d3..e90ee9996d30c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
@@ -33,7 +33,6 @@ def isSEXT_W
                    MCReturnStatement<CheckAll<[
                      CheckOpcode<[ADDIW]>,
                      CheckIsRegOperand<1>,
-                     CheckIsImmOperand<2>,
                      CheckImmOperand<2, 0>
                    ]>>>;
 
@@ -52,7 +51,6 @@ def isZEXT_B
                    MCReturnStatement<CheckAll<[
                      CheckOpcode<[ANDI]>,
                      CheckIsRegOperand<1>,
-                     CheckIsImmOperand<2>,
                      CheckImmOperand<2, 255>
                    ]>>>;
 
diff --git a/llvm/lib/Target/RISCV/RISCVMacroFusion.td b/llvm/lib/Target/RISCV/RISCVMacroFusion.td
index cf11cbac583e6..875cbebc67f0b 100644
--- a/llvm/lib/Target/RISCV/RISCVMacroFusion.td
+++ b/llvm/lib/Target/RISCV/RISCVMacroFusion.td
@@ -36,12 +36,10 @@ def TuneZExtHFusion
                  "Enable SLLI+SRLI to be fused to zero extension of halfword",
                  CheckAll<[
                    CheckOpcode<[SLLI]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperand<2, 48>
                  ]>,
                  CheckAll<[
                    CheckOpcode<[SRLI]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperand<2, 48>
                  ]>>;
 
@@ -53,12 +51,10 @@ def TuneZExtWFusion
                  "Enable SLLI+SRLI to be fused to zero extension of word",
                  CheckAll<[
                    CheckOpcode<[SLLI]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperand<2, 32>
                  ]>,
                  CheckAll<[
                    CheckOpcode<[SRLI]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperand<2, 32>
                  ]>>;
 
@@ -71,12 +67,10 @@ def TuneShiftedZExtWFusion
                  "Enable SLLI+SRLI to be fused when computing (shifted) word zero extension",
                  CheckAll<[
                    CheckOpcode<[SLLI]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperand<2, 32>
                  ]>,
                  CheckAll<[
                    CheckOpcode<[SRLI]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperandRange<2, 0, 31>
                  ]>>;
 
@@ -88,7 +82,6 @@ def TuneLDADDFusion
                  CheckOpcode<[ADD]>,
                  CheckAll<[
                    CheckOpcode<[LD]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperand<2, 0>
                  ]>>;
 
@@ -227,7 +220,6 @@ def TuneFusionAddMem
              SecondFusionPredicateWithMCInstPredicate<
                CheckAll<[
                  CheckOpcode<LoadStore>,
-                 CheckIsImmOperand<2>,
                  CheckImmOperand<2, 0>
                ]>
              >,
diff --git a/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td b/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td
index 42c1e5c8e50b8..d1fc6ca0db983 100644
--- a/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td
+++ b/llvm/lib/Target/RISCV/RISCVMacroFusionXQCI.td
@@ -99,7 +99,6 @@ def TuneMovALUXqciFusion
                  "Enable MOV + long accumulate macrofusion",
                  CheckAll<[
                    CheckOpcode<[ADDI]>,
-                   CheckIsImmOperand<2>,
                    CheckImmOperand<2, 0>,
                  ]>,
                  CheckOpcode<LongAccumXqciOp>,
diff --git a/llvm/test/TableGen/PredicateExpander.td b/llvm/test/TableGen/PredicateExpander.td
new file mode 100644
index 0000000000000..b98bc6b2eb153
--- /dev/null
+++ b/llvm/test/TableGen/PredicateExpander.td
@@ -0,0 +1,285 @@
+// RUN: llvm-tblgen -gen-instr-info -I %p/../../include %s | FileCheck %s
+
+include "llvm/Target/Target.td"
+
+def TestInstrInfo : InstrInfo;
+def Test : Target {
+  let InstructionSet = TestInstrInfo;
+}
+
+let Namespace = "Test" in {
+  def R0 : Register<"r0">;
+  def GPR : RegisterClass<"GPR", [i32], 32, (add R0)>;
+
+  let OutOperandList = (outs), InOperandList = (ins) in
+  def Inst : Instruction;
+}
+
+defm : RemapAllTargetPseudoPointerOperands<GPR>;
+
+def CheckImmEq
+  : TIIPredicate<"checkImmEq", MCReturnStatement<CheckImmOperand<0, 7>>>;
+def CheckImmEqString
+  : TIIPredicate<"checkImmEqString",
+      MCReturnStatement<CheckImmOperand_s<1, "Test::Value">>>;
+def CheckImmSimple
+  : TIIPredicate<"checkImmSimple", MCReturnStatement<CheckImmOperandSimple<1>>>;
+def CheckImmLT
+  : TIIPredicate<"checkImmLT", MCReturnStatement<CheckImmOperandLT<2, 17>>>;
+def CheckImmLE
+  : TIIPredicate<"checkImmLE", MCReturnStatement<CheckImmOperandLE<2, 18>>>;
+def CheckImmGT
+  : TIIPredicate<"checkImmGT", MCReturnStatement<CheckImmOperandGT<2, 19>>>;
+def CheckImmGE
+  : TIIPredicate<"checkImmGE", MCReturnStatement<CheckImmOperandGE<2, 20>>>;
+def CheckImmRange
+  : TIIPredicate<"checkImmRange", MCReturnStatement<CheckImmOperandRange<2, 21, 23>>>;
+
+def CheckNotImmEq
+  : TIIPredicate<"checkNotImmEq", MCReturnStatement<CheckNot<CheckImmOperand<1, 15>>>>;
+def CheckNotImmSimple
+  : TIIPredicate<"checkNotImmSimple", MCReturnStatement<CheckNot<CheckImmOperandSimple<1>>>>;
+
+def CheckRegEq
+  : TIIPredicate<"checkRegEq",
+      MCReturnStatement<CheckRegOperand<1, R0>>>;
+def CheckRegSimple
+  : TIIPredicate<"checkRegSimple",
+      MCReturnStatement<CheckRegOperandSimple<1>>>;
+
+def CheckNotRegEq
+  : TIIPredicate<"checkNotRegEq", MCReturnStatement<CheckNot<CheckRegOperand<2, R0>>>>;
+def CheckNotRegSimple
+  : TIIPredicate<"checkNotRegSimple", MCReturnStatement<CheckNot<CheckRegOperandSimple<2>>>>;
+
+let FunctionMapper = "mapImm" in {
+  def MappedImmEq : CheckImmOperand<2, 9>;
+  def MappedImmEqString : CheckImmOperand_s<2, "Test::Value">;
+  def MappedImmGE : CheckImmOperandGE<2, 25>;
+  def MappedImmSimple : CheckImmOperandSimple<1>;
+  def MappedImmLE : CheckImmOperandLE<2, 10>;
+  def MappedImmLT : CheckImmOperandLT<2, 11>;
+  def MappedImmGT : CheckImmOperandGT<2, 13>;
+  def MappedImmRange : CheckImmOperandRange<2, 9, 31>;
+}
+
+let FunctionMapper = "mapReg" in {
+  def MappedRegEq : CheckRegOperand<1, R0>;
+  def MappedRegSimple : CheckRegOperandSimple<1>;
+}
+
+def CheckMappedImmEq
+  : TIIPredicate<"checkMappedImmEq", MCReturnStatement<MappedImmEq>>;
+def CheckMappedImmEqString
+  : TIIPredicate<"checkMappedImmEqString", MCReturnStatement<MappedImmEqString>>;
+def CheckMappedImmSimple
+  : TIIPredicate<"checkMappedImmSimple", MCReturnStatement<MappedImmSimple>>;
+def CheckMappedImmLT
+  : TIIPredicate<"checkMappedImmLT", MCReturnStatement<MappedImmLT>>;
+def CheckMappedImmLE
+  : TIIPredicate<"checkMappedImmLE", MCReturnStatement<MappedImmLE>>;
+def CheckMappedImmGT
+  : TIIPredicate<"checkMappedImmGT", MCReturnStatement<MappedImmGT>>;
+def CheckMappedImmGE
+  : TIIPredicate<"checkMappedImmGE", MCReturnStatement<MappedImmGE>>;
+def CheckMappedImmRange
+  : TIIPredicate<"checkMappedImmRange", MCReturnStatement<MappedImmRange>>;
+
+def CheckMappedRegEq
+  : TIIPredicate<"checkMappedRegEq", MCReturnStatement<MappedRegEq>>;
+def CheckMappedRegSimple
+  : TIIPredicate<"checkMappedRegSimple", MCReturnStatement<MappedRegSimple>>;
+
+// CHECK: bool TestInstrInfo::checkImmEq(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(0).isImm() && MI.getOperand(0).getImm() == 7);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkImmEqString(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == Test::Value);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkImmGE(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() >= 20);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkImmGT(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() > 19);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkImmLE(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() <= 18);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkImmLT(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() < 17);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkImmRange(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() >= 21 && MI.getOperand(2).getImm() <= 23);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkImmSimple(const MachineInstr &MI) {
+// CHECK-NEXT:   return true;
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmEq(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) == 9);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmEqString(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) == Test::Value);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmGE(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) >= 25);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmGT(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) > 13);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmLE(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) <= 10);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmLT(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) < 11);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmRange(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) >= 9 && mapImm(MI.getOperand(2).getImm()) <= 31);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedImmSimple(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isImm() && mapImm(MI.getOperand(1).getImm()));
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedRegEq(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && mapReg(MI.getOperand(1).getReg()) == Test::R0);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkMappedRegSimple(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && mapReg(MI.getOperand(1).getReg()));
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkNotImmEq(const MachineInstr &MI) {
+// CHECK-NEXT:   return !(MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == 15);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkNotImmSimple(const MachineInstr &MI) {
+// CHECK-NEXT:   return false;
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkNotRegEq(const MachineInstr &MI) {
+// CHECK-NEXT:   return !(MI.getOperand(2).isReg() && MI.getOperand(2).getReg() == Test::R0);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkNotRegSimple(const MachineInstr &MI) {
+// CHECK-NEXT:   return !(MI.getOperand(2).isReg() && MI.getOperand(2).getReg().isValid());
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkRegEq(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == Test::R0);
+// CHECK-NEXT: }
+
+// CHECK: bool TestInstrInfo::checkRegSimple(const MachineInstr &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isValid());
+// CHECK-NEXT: }
+
+// CHECK: namespace llvm::Test_MC {
+
+// CHECK: bool checkImmEq(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(0).isImm() && MI.getOperand(0).getImm() == 7);
+// CHECK-NEXT: }
+
+// CHECK: bool checkImmEqString(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == Test::Value);
+// CHECK-NEXT: }
+
+// CHECK: bool checkImmGE(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() >= 20);
+// CHECK-NEXT: }
+
+// CHECK: bool checkImmGT(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() > 19);
+// CHECK-NEXT: }
+
+// CHECK: bool checkImmLE(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() <= 18);
+// CHECK-NEXT: }
+
+// CHECK: bool checkImmLT(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() < 17);
+// CHECK-NEXT: }
+
+// CHECK: bool checkImmRange(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && MI.getOperand(2).getImm() >= 21 && MI.getOperand(2).getImm() <= 23);
+// CHECK-NEXT: }
+
+// CHECK: bool checkImmSimple(const MCInst &MI) {
+// CHECK-NEXT:   return true;
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmEq(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) == 9);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmEqString(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) == Test::Value);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmGE(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) >= 25);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmGT(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) > 13);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmLE(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) <= 10);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmLT(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) < 11);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmRange(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(2).isImm() && mapImm(MI.getOperand(2).getImm()) >= 9 && mapImm(MI.getOperand(2).getImm()) <= 31);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedImmSimple(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isImm() && mapImm(MI.getOperand(1).getImm()));
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedRegEq(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && mapReg(MI.getOperand(1).getReg()) == Test::R0);
+// CHECK-NEXT: }
+
+// CHECK: bool checkMappedRegSimple(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && mapReg(MI.getOperand(1).getReg()));
+// CHECK-NEXT: }
+
+// CHECK: bool checkNotImmEq(const MCInst &MI) {
+// CHECK-NEXT:   return !(MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == 15);
+// CHECK-NEXT: }
+
+// CHECK: bool checkNotImmSimple(const MCInst &MI) {
+// CHECK-NEXT:   return false;
+// CHECK-NEXT: }
+
+// CHECK: bool checkNotRegEq(const MCInst &MI) {
+// CHECK-NEXT:   return !(MI.getOperand(2).isReg() && MI.getOperand(2).getReg() == Test::R0);
+// CHECK-NEXT: }
+
+// CHECK: bool checkNotRegSimple(const MCInst &MI) {
+// CHECK-NEXT:   return !(MI.getOperand(2).isReg() && MI.getOperand(2).getReg().isValid());
+// CHECK-NEXT: }
+
+// CHECK: bool checkRegEq(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == Test::R0);
+// CHECK-NEXT: }
+
+// CHECK: bool checkRegSimple(const MCInst &MI) {
+// CHECK-NEXT:   return (MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isValid());
+// CHECK-NEXT: }
diff --git a/llvm/test/TableGen/ResolveSchedClass.td b/llvm/test/TableGen/ResolveSchedClass.td
index 665f5db85f227..dc5ac9ca07d54 100644
--- a/llvm/test/TableGen/ResolveSchedClass.td
+++ b/llvm/test/TableGen/ResolveSchedClass.td
@@ -72,9 +72,9 @@ def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
 // CHECK-NEXT:   if (CPUID == {{.*}}) { // SchedModel_A
 // CHECK-NEXT:     if (STI.hasFeature(TestTarget::FeatureFoo))
 // CHECK-NEXT:       return {{.*}}; // SchedWriteResA
-// CHECK-NEXT:     if (STI.hasFeature(TestTarget::FeatureFoo) && MI->getOperand(1).getImm() == 0)
+// CHECK-NEXT:     if (STI.hasFeature(TestTarget::FeatureFoo) && (MI->getOperand(1).isImm() && MI->getOperand(1).getImm() == 0))
 // CHECK-NEXT:       return {{.*}}; // SchedWriteResC
-// CHECK-NEXT:     if (!(MI->getOperand(3).getImm() == 0 && !STI.hasFeature(TestTarget::FeatureFoo)))
+// CHECK-NEXT:     if (!((MI->getOperand(3).isImm() && MI->getOperand(3).getImm() == 0) && !STI.hasFeature(TestTarget::FeatureFoo)))
 // CHECK-NEXT: 	     return {{.*}}; // SchedWriteResE
 // CHECK-NEXT:     return {{.*}}; // SchedWriteResB
 
@@ -91,10 +91,10 @@ def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>;
 // CHECK-NEXT:     if (SchedModel->getProcessorID() == {{.*}}) { // SchedModel_A
 // CHECK-NEXT:       if (this->hasFeature(TestTarget::FeatureFoo))
 // CHECK-NEXT:         return {{.*}}; // SchedWriteResA
-// CHECK-NEXT:       if (this->hasFeature(TestTarget::FeatureFoo) && MI->getOperand(1).getImm() == 0)
+// CHECK-NEXT:       if (this->hasFeature(TestTarget::FeatureFoo) && (MI->getOperand(1).isImm() && MI->getOperand(1).getImm() == 0))
 // CHECK-NEXT:         return {{.*}}; // SchedWriteResC
-// CHECK-NEXT:       if ((this->hasFeature(TestTarget::FeatureFoo) && MI->getOperand(1).getImm() == 0) || !(this->hasFeature(TestTarget::FeatureBar) || (/*hello=*/false)))
+// CHECK-NEXT:       if ((this->hasFeature(TestTarget::FeatureFoo) && (MI->getOperand(1).isImm() && MI->getOperand(1).getImm() == 0)) || !(this->hasFeature(TestTarget::FeatureBar) || (/*hello=*/false)))
 // CHECK-NEXT:         return {{.*}}; // SchedWriteResD
-// CHECK-NEXT:       if (!(MI->getOperand(3).getImm() == 0 && !this->hasFeature(TestTarget::FeatureFoo)))
+// CHECK-NEXT:       if (!((MI->getOperand(3).isImm() && MI->getOperand(3).getImm() == 0) && !this->hasFeature(TestTarget::FeatureFoo)))
 // CHECK-NEXT: 	       return {{.*}}; // SchedWriteResE
 // CHECK-NEXT:       return {{.*}}; // SchedWriteResB
diff --git a/llvm/utils/TableGen/Common/PredicateExpander.cpp b/llvm/utils/TableGen/Common/PredicateExpander.cpp
index ac0942df3d112..4d4826c6ec3be 100644
--- a/llvm/utils/TableGen/Common/PredicateExpander.cpp
+++ b/llvm/utils/TableGen/Common/PredicateExpander.cpp
@@ -19,68 +19,86 @@ using namespace llvm;
 void PredicateExpander::expandTrue(raw_ostream &OS) { OS << "true"; }
 void PredicateExpander::expandFalse(raw_ostream &OS) { OS << "false"; }
 
-void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex,
-                                              int ImmVal,
-                                              StringRef FunctionMapper) {
+void PredicateExpander::expandCheckImmOperandCommon(raw_ostream &OS,
+                                                    int OpIndex, int ImmVal,
+                                                    StringRef FunctionMapper,
+                                                    StringRef CmpOperator) {
+  OS << (shouldNegate() ? "!(" : "(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").isImm()";
+  OS << " && ";
   if (!FunctionMapper.empty())
     OS << FunctionMapper << "(";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getImm()";
   if (!FunctionMapper.empty())
     OS << ")";
-  OS << (shouldNegate() ? " != " : " == ") << ImmVal;
+  OS << " " << CmpOperator << " " << ImmVal;
+  OS << ")";
 }
 
 void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex,
                                               StringRef ImmVal,
                                               StringRef FunctionMapper) {
   if (ImmVal.empty())
-    expandCheckImmOperandSimple(OS, OpIndex, FunctionMapper);
+    return expandCheckImmOperandSimple(OS, OpIndex, FunctionMapper);
 
+  OS << (shouldNegate() ? "!(" : "(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").isImm()";
+  OS << " && ";
   if (!FunctionMapper.empty())
     OS << FunctionMapper << "(";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getImm()";
   if (!FunctionMapper.empty())
     OS << ")";
-  OS << (shouldNegate() ? " != " : " == ") << ImmVal;
+  OS << " == " << ImmVal;
+  OS << ")";
 }
 
 void PredicateExpander::expandCheckImmOperandSimple(raw_ostream &OS,
                                                     int OpIndex,
                                                     StringRef FunctionMapper) {
-  if (shouldNegate())
-    OS << "!";
-  if (!FunctionMapper.empty())
-    OS << FunctionMapper << "(";
+  if (FunctionMapper.empty())
+    return shouldNegate() ? expandFalse(OS) : expandTrue(OS);
+
+  OS << (shouldNegate() ? "!(" : "(");
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
-     << ").getImm()";
-  if (!FunctionMapper.empty())
-    OS << ")";
+     << ").isImm()";
+  OS << " && ";
+  OS << FunctionMapper << "("
+     << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").getImm()"
+     << ")"
+     << ")";
 }
 
-void PredicateExpander::expandCheckImmOperandLT(raw_ostream &OS, int OpIndex,
-                                                int ImmVal,
-                                                StringRef FunctionMapper) {
+void PredicateExpander::expandCheckImmOperandRange(raw_ostream &OS, int OpIndex,
+                                                   int StartVal, int EndVal,
+                                                   StringRef FunctionMapper) {
+  OS << (shouldNegate() ? "!(" : "(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").isImm()";
+  OS << " && ";
+
   if (!FunctionMapper.empty())
     OS << FunctionMapper << "(";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getImm()";
   if (!FunctionMapper.empty())
     OS << ")";
-  OS << (shouldNegate() ? " >= " : " < ") << ImmVal;
-}
+  OS << " >= " << StartVal;
+  OS << " && ";
 
-void PredicateExpander::expandCheckImmOperandGT(raw_ostream &OS, int OpIndex,
-                                                int ImmVal,
-                                                StringRef FunctionMapper) {
   if (!FunctionMapper.empty())
     OS << FunctionMapper << "(";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getImm()";
   if (!FunctionMapper.empty())
     OS << ")";
-  OS << (shouldNegate() ? " <= " : " > ") << ImmVal;
+  OS << " <= " << EndVal;
+  OS << ")";
 }
 
 void PredicateExpander::expandCheckRegOperand(raw_ostream &OS, int OpIndex,
@@ -108,32 +126,51 @@ void PredicateExpander::expandCheckRegOperand(raw_ostream &OS, int OpIndex,
 void PredicateExpander::expandCheckRegOperandSimple(raw_ostream &OS,
                                                     int OpIndex,
                                                     StringRef FunctionMapper) {
+  // Expand to CheckNot<CheckInvalidRegOperand<OpIndex>> when
+  // FunctionMapper is not set.
+  if (FunctionMapper.empty()) {
+    flipNegatePredicate();
+    expandCheckInvalidRegOperand(OS, OpIndex);
+    flipNegatePredicate();
+    return;
+  }
   OS << (shouldNegate() ? "!(" : "(");
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").isReg()";
   OS << " && ";
-  if (!FunctionMapper.empty())
-    OS << FunctionMapper << "(";
+  OS << FunctionMapper << "(";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getReg()";
-  if (!FunctionMapper.empty())
-    OS << ")";
-  OS << ")";
+  OS << ")"
+     << ")";
 }
 
 void PredicateExpander::expandCheckInvalidRegOperand(raw_ostream &OS,
                                                      int OpIndex) {
-  if (!shouldNegate())
-    OS << "!";
+  OS << (shouldNegate() ? "(" : "!(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").isReg()";
+  OS << " && ";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
      << ").getReg().isValid()";
+  OS << ")";
 }
 
 void PredicateExpander::expandCheckSameRegOperand(raw_ostream &OS, int First,
                                                   int Second) {
+  OS << (shouldNegate() ? "!(" : "(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << First
+     << ").isReg()";
+  OS << " && ";
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << Second
+     << ").isReg()";
+  OS << " && ";
   OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << First
-     << ").getReg() " << (shouldNegate() ? "!=" : "==") << " MI"
-     << (isByRef() ? "." : "->") << "getOperand(" << Second << ").getReg()";
+     << ").getReg() "
+     << "=="
+     << " MI" << (isByRef() ? "." : "->") << "getOperand(" << Second
+     << ").getReg()";
+  OS << ")";
 }
 
 void PredicateExpander::expandCheckNumOperands(raw_ostream &OS, int NumOps) {
@@ -212,8 +249,13 @@ void PredicateExpander::expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) {
 }
 
 void PredicateExpander::expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) {
-  OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->")
-     << "getOperand(" << OpIndex << ").getReg().isVirtual()";
+  OS << (shouldNegate() ? "!(" : "(");
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").isReg()";
+  OS << " && ";
+  OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+     << ").getReg().isVirtual()";
+  OS << ")";
 }
 
 void PredicateExpander::expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) {
@@ -352,9 +394,9 @@ void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) {
     return expandCheckInvalidRegOperand(OS, Rec->getValueAsInt("OpIndex"));
 
   if (Rec->isSubClassOf("CheckImmOperand"))
-    return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"),
-                                 Rec->getValueAsInt("ImmVal"),
-                                 Rec->getValueAsString("FunctionMapper"));
+    return expandCheckImmOperandCommon(
+        OS, Rec->getValueAsInt("OpIndex"), Rec->getValueAsInt("ImmVal"),
+        Rec->getValueAsString("FunctionMapper"), "==");
 
   if (Rec->isSubClassOf("CheckImmOperand_s"))
     return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"),
@@ -362,14 +404,29 @@ void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) {
                                  Rec->getValueAsString("FunctionMapper"));
 
   if (Rec->isSubClassOf("CheckImmOperandLT"))
-    return expandCheckImmOperandLT(OS, Rec->getValueAsInt("OpIndex"),
-                                   Rec->getValueAsInt("ImmVal"),
-                                   Rec->getValueAsString("FunctionMapper"));
+    return expandCheckImmOperandCommon(
+        OS, Rec->getValueAsInt("OpIndex"), Rec->getValueAsInt("ImmVal"),
+        Rec->getValueAsString("FunctionMapper"), "<");
 
   if (Rec->isSubClassOf("CheckImmOperandGT"))
-    return expandCheckImmOperandGT(OS, Rec->getValueAsInt("OpIndex"),
-                                   Rec->getValueAsInt("ImmVal"),
-                                   Rec->getValueAsString("FunctionMapper"));
+    return expandCheckImmOperandCommon(
+        OS, Rec->getValueAsInt("OpIndex"), Rec->getValueAsInt("ImmVal"),
+        Rec->getValueAsString("FunctionMapper"), ">");
+
+  if (Rec->isSubClassOf("CheckImmOperandLE"))
+    return expandCheckImmOperandCommon(
+        OS, Rec->getValueAsInt("OpIndex"), Rec->getValueAsInt("ImmVal"),
+        Rec->getValueAsString("FunctionMapper"), "<=");
+
+  if (Rec->isSubClassOf("CheckImmOperandGE"))
+    return expandCheckImmOperandCommon(
+        OS, Rec->getValueAsInt("OpIndex"), Rec->getValueAsInt("ImmVal"),
+        Rec->getValueAsString("FunctionMapper"), ">=");
+
+  if (Rec->isSubClassOf("CheckImmOperandRange"))
+    return expandCheckImmOperandRange(
+        OS, Rec->getValueAsInt("OpIndex"), Rec->getValueAsInt("StartVal"),
+        Rec->getValueAsInt("EndVal"), Rec->getValueAsString("FunctionMapper"));
 
   if (Rec->isSubClassOf("CheckImmOperandSimple"))
     return expandCheckImmOperandSimple(OS, Rec->getValueAsInt("OpIndex"),
diff --git a/llvm/utils/TableGen/Common/PredicateExpander.h b/llvm/utils/TableGen/Common/PredicateExpander.h
index 4439327af2b03..6555c89d02217 100644
--- a/llvm/utils/TableGen/Common/PredicateExpander.h
+++ b/llvm/utils/TableGen/Common/PredicateExpander.h
@@ -52,16 +52,15 @@ class PredicateExpander {
 
   void expandTrue(raw_ostream &OS);
   void expandFalse(raw_ostream &OS);
-  void expandCheckImmOperand(raw_ostream &OS, int OpIndex, int ImmVal,
-                             StringRef FunctionMapper);
+  void expandCheckImmOperandCommon(raw_ostream &OS, int OpIndex, int ImmVal,
+                                   StringRef FunctionMapper,
+                                   StringRef CmpOperator);
   void expandCheckImmOperand(raw_ostream &OS, int OpIndex, StringRef ImmVal,
-                             StringRef FunctionMapperer);
+                             StringRef FunctionMapper);
   void expandCheckImmOperandSimple(raw_ostream &OS, int OpIndex,
                                    StringRef FunctionMapper);
-  void expandCheckImmOperandLT(raw_ostream &OS, int OpIndex, int ImmVal,
-                               StringRef FunctionMapper);
-  void expandCheckImmOperandGT(raw_ostream &OS, int OpIndex, int ImmVal,
-                               StringRef FunctionMapper);
+  void expandCheckImmOperandRange(raw_ostream &OS, int OpIndex, int StartVal,
+                                  int EndVal, StringRef FunctionMapper);
   void expandCheckRegOperand(raw_ostream &OS, int OpIndex, const Record *Reg,
                              StringRef FunctionMapper);
   void expandCheckRegOperandSimple(raw_ostream &OS, int OpIndex,



More information about the llvm-commits mailing list