[llvm] 779a0f4 - [TableGen] Support HwMode registers in CompressInstEmitter (#203599)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 29 17:08:49 PDT 2026


Author: Alexander Richardson
Date: 2026-09-30T00:08:43Z
New Revision: 779a0f4938d487a97c82ea583c30501327ba6dff

URL: https://github.com/llvm/llvm-project/commit/779a0f4938d487a97c82ea583c30501327ba6dff
DIFF: https://github.com/llvm/llvm-project/commit/779a0f4938d487a97c82ea583c30501327ba6dff.diff

LOG: [TableGen] Support HwMode registers in CompressInstEmitter (#203599)

Previously, CompressInstEmitter only handled plain Register and
RegisterClass records when matching and validating operands in
CompressPat definitions. Attempting to use a RegisterByHwMode (such as a
mode-dependent stack pointer) or a RegClassByHwMode with mode-dependent
registers failed because CompressInstEmitter could not resolve the
underlying register or register class for a given subtarget
configuration.

Introduce HwModePredicates in CodeGenHwModes to resolve HwModeSelect
records using the subtarget features required by a CompressPat (with
predicates implying the absence of all non-default modes resolving to
DefaultMode). This allows using a single instruction definition for
compressed instructions like RISC-V C_ADDI4SPN/C_ADDI16SP across HwModes
instead of duplicating the instruction definitions for each mode.

This commit was created with the help of AI tools

Added: 
    llvm/test/TableGen/RegClassByHwModeCompressPat4Modes.td
    llvm/test/TableGen/RegClassByHwModeCompressPatError.td

Modified: 
    llvm/test/TableGen/RegClassByHwModeCompressPat.td
    llvm/utils/TableGen/Common/CodeGenHwModes.cpp
    llvm/utils/TableGen/Common/CodeGenHwModes.h
    llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
    llvm/utils/TableGen/Common/SubtargetFeatureInfo.h
    llvm/utils/TableGen/CompressInstEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/TableGen/RegClassByHwModeCompressPat.td b/llvm/test/TableGen/RegClassByHwModeCompressPat.td
index 36441d0d9a6e9..ea1cf1352f467 100644
--- a/llvm/test/TableGen/RegClassByHwModeCompressPat.td
+++ b/llvm/test/TableGen/RegClassByHwModeCompressPat.td
@@ -2,10 +2,20 @@
 
 include "Common/RegClassByHwModeCommon.td"
 
-def IsPtr64 : Predicate<"Subtarget->isPtr64()">;
+def FeaturePtr64 : SubtargetFeature<"ptr64", "IsPtr64", "true", "Ptr64 mode">;
+
+def IsPtr64 : Predicate<"Subtarget->isPtr64()">,
+              AssemblerPredicate<(all_of FeaturePtr64)>;
+def NotPtr64 : Predicate<"!Subtarget->isPtr64()">,
+               AssemblerPredicate<(all_of (not FeaturePtr64))>;
 defvar Ptr32 = DefaultMode;
 def Ptr64 : HwMode<[IsPtr64]>;
 def PtrRC : RegClassByHwMode<[Ptr32, Ptr64], [XRegs, YRegs]>;
+// Define a subclass of PtrRC to test type compatibility check for HwMode-dependent register classes.
+// PtrRCSub is a subclass of PtrRC in all modes because XRegsSub is subclass of XRegs, and YRegsSub is subclass of YRegs.
+def XRegsSub : RegisterClass<"MyTarget", [i64], 64, (add X1, X2)>;
+def YRegsSub : RegisterClass<"MyTarget", [i64], 64, (add Y1, Y2)>;
+def PtrRCSub : RegClassByHwMode<[Ptr32, Ptr64], [XRegsSub, YRegsSub]>;
 def NullReg : RegisterByHwMode<PtrRC, [Ptr32, Ptr64], [X0, Y0]>;
 
 def X_MOV : TestInstruction {
@@ -38,6 +48,13 @@ def X_MOV_TIED : TestInstruction {
   let Size = 1;
 }
 
+def Y_MOV : TestInstruction {
+  let OutOperandList = (outs YRegs:$dst);
+  let InOperandList = (ins YRegs:$src);
+  let AsmString = "y_mov $dst, $src";
+  let opcode = 5;
+}
+
 def PTR_MOV : TestInstruction {
   let OutOperandList = (outs PtrRC:$dst);
   let InOperandList = (ins PtrRC:$src);
@@ -80,6 +97,22 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$dst),
                   (PTR_MOV_TIED PtrRC:$dst)>;
 def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
                   (PTR_MOV_SMALL PtrRC:$dst, PtrRC:$src)>;
+// Test type compatibility when both pattern and instruction operands are mode-dependent
+// but 
diff erent register classes. PTR_MOV expects PtrRC, but the pattern uses PtrRCSub.
+// This is allowed because PtrRCSub is a subclass of PtrRC in all modes.
+def : CompressPat<(PTR_MOV PtrRCSub:$dst, PtrRCSub:$src),
+                  (PTR_MOV_SMALL PtrRCSub:$dst, PtrRCSub:$src)>;
+
+// Test compression/uncompression when HwMode can be resolved by pattern predicates.
+// X_MOV (XRegs) -> PTR_MOV_SMALL (PtrRC) is valid in 32-bit mode (NotPtr64).
+let Predicates = [NotPtr64] in
+def : CompressPat<(X_MOV XRegs:$dst, XRegs:$src),
+                  (PTR_MOV_SMALL XRegs:$dst, XRegs:$src)>;
+
+// Y_MOV (YRegs) -> PTR_MOV_SMALL (PtrRC) is valid in 64-bit mode (IsPtr64).
+let Predicates = [IsPtr64] in
+def : CompressPat<(Y_MOV YRegs:$dst, YRegs:$src),
+                  (PTR_MOV_SMALL YRegs:$dst, YRegs:$src)>;
 
 // CHECK:     static bool compressInst(MCInst &OutInst,
 // CHECK-NEXT:                          const MCInst &MI,
@@ -125,6 +158,19 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
 // CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
 // CHECK-NEXT:       return true;
 // CHECK-NEXT:     } // if
+// CHECK-NEXT:     if (MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRCSub]).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRCSub]).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::PTR_MOV_SMALL);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
 // CHECK-NEXT:     break;
 // CHECK-NEXT:   } // case PTR_MOV
 // CHECK-NEXT:   case MyTarget::X_MOV: {
@@ -165,8 +211,39 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
 // CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
 // CHECK-NEXT:       return true;
 // CHECK-NEXT:     } // if
+// CHECK-NEXT:     if (!STI.getFeatureBits()[MyTarget::FeaturePtr64] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::PTR_MOV_SMALL);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
 // CHECK-NEXT:     break;
 // CHECK-NEXT:   } // case X_MOV
+// CHECK-NEXT:   case MyTarget::Y_MOV: {
+// CHECK-NEXT:     if (STI.getFeatureBits()[MyTarget::FeaturePtr64] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::PTR_MOV_SMALL);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
+// CHECK-NEXT:     break;
+// CHECK-NEXT:   } // case Y_MOV
 // CHECK-NEXT:   } // switch
 // CHECK-NEXT:   return false;
 // CHECK-NEXT: }
@@ -191,6 +268,47 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
 // CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
 // CHECK-NEXT:       return true;
 // CHECK-NEXT:     } // if
+// CHECK-NEXT:     if (MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRCSub]).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRCSub]).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::PTR_MOV);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
+// CHECK-NEXT:     if (!STI.getFeatureBits()[MyTarget::FeaturePtr64] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // x_mov $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::X_MOV);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
+// CHECK-NEXT:     if (STI.getFeatureBits()[MyTarget::FeaturePtr64] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // y_mov $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::Y_MOV);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
 // CHECK-NEXT:     break;
 // CHECK-NEXT:   } // case PTR_MOV_SMALL
 // CHECK-NEXT:   case MyTarget::PTR_MOV_TIED: {
@@ -288,6 +406,16 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
 // CHECK-NEXT:       // Operand: dst
 // CHECK-NEXT:       // Operand: src
 
+// CHECK-NEXT:       return 1;
+// CHECK-NEXT:     } // if
+// CHECK-NEXT:     if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRCSub]).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTargetRegClassByHwModeTables[HwModeId][MyTarget::PtrRCSub]).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       // Operand: src
+
 // CHECK-NEXT:       return 1;
 // CHECK-NEXT:     } // if
 // CHECK-NEXT:     if (MI.getOperand(1).isReg() && MI.getOperand(0).isReg() &&
@@ -312,6 +440,17 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
 // CHECK-NEXT:     break;
 // CHECK-NEXT:   } // case PTR_MOV
 // CHECK-NEXT:   case MyTarget::X_MOV: {
+// CHECK-NEXT:     if (!STI.getFeatureBits()[MyTarget::FeaturePtr64] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       // Operand: src
+
+// CHECK-NEXT:       return 1;
+// CHECK-NEXT:     } // if
 // CHECK-NEXT:     if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
 // CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
 // CHECK-NEXT:         MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
@@ -343,6 +482,20 @@ def : CompressPat<(PTR_MOV PtrRC:$dst, PtrRC:$src),
 // CHECK-NEXT:     } // if
 // CHECK-NEXT:     break;
 // CHECK-NEXT:   } // case X_MOV
+// CHECK-NEXT:   case MyTarget::Y_MOV: {
+// CHECK-NEXT:     if (STI.getFeatureBits()[MyTarget::FeaturePtr64] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() && MI.getOperand(0).getReg().isPhysical() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() && MI.getOperand(1).getReg().isPhysical() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       // Operand: src
+
+// CHECK-NEXT:       return 1;
+// CHECK-NEXT:     } // if
+// CHECK-NEXT:     break;
+// CHECK-NEXT:   } // case Y_MOV
 // CHECK-NEXT:   } // switch
 // CHECK-NEXT:   return 0;
 // CHECK-NEXT: }

diff  --git a/llvm/test/TableGen/RegClassByHwModeCompressPat4Modes.td b/llvm/test/TableGen/RegClassByHwModeCompressPat4Modes.td
new file mode 100644
index 0000000000000..aa0156c6ac0ac
--- /dev/null
+++ b/llvm/test/TableGen/RegClassByHwModeCompressPat4Modes.td
@@ -0,0 +1,116 @@
+// RUN: llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -o - | FileCheck %s
+
+include "Common/RegClassByHwModeCommon.td"
+
+// Define features
+def Feature64Bit : SubtargetFeature<"64bit", "Is64Bit", "true", "64-bit mode">;
+def FeatureCap : SubtargetFeature<"cap", "IsCap", "true", "Capability mode">;
+
+// Define predicates
+def Is64Bit : Predicate<"Subtarget->is64Bit()">,
+              AssemblerPredicate<(all_of Feature64Bit)>;
+def Not64Bit : Predicate<"!Subtarget->is64Bit()">,
+               AssemblerPredicate<(all_of (not Feature64Bit))>;
+def IsCap : Predicate<"Subtarget->isCap()">,
+            AssemblerPredicate<(all_of FeatureCap)>;
+def NotCap : Predicate<"!Subtarget->isCap()">,
+             AssemblerPredicate<(all_of (not FeatureCap))>;
+
+// Define 4 modes (similar to RISC-V RV32I, RV64I, RV32Y, RV64Y)
+def Mode32I : HwMode<[Not64Bit, NotCap]>;
+def Mode64I : HwMode<[Is64Bit, NotCap]>;
+def Mode32C : HwMode<[Not64Bit, IsCap]>;
+def Mode64C : HwMode<[Is64Bit, IsCap]>;
+
+// Define mode-dependent register class (SP-like)
+// Resolves to XRegs in Integer modes, and YRegs in Capability modes
+def PtrRC : RegClassByHwMode<[Mode32I, Mode64I, Mode32C, Mode64C],
+                             [XRegs,   XRegs,   YRegs,   YRegs]>;
+
+def X_MOV : TestInstruction {
+  let OutOperandList = (outs XRegs:$dst);
+  let InOperandList = (ins XRegs:$src);
+  let AsmString = "x_mov $dst, $src";
+  let opcode = 0;
+}
+
+def Y_MOV : TestInstruction {
+  let OutOperandList = (outs YRegs:$dst);
+  let InOperandList = (ins YRegs:$src);
+  let AsmString = "y_mov $dst, $src";
+  let opcode = 5;
+}
+
+def PTR_MOV_SMALL : TestInstruction {
+  let OutOperandList = (outs PtrRC:$dst);
+  let InOperandList = (ins PtrRC:$src);
+  let AsmString = "ptr_mov.small $dst, $src";
+  let opcode = 4;
+  let Size = 1;
+}
+
+// Test partial resolution with 4 modes.
+// NotCap only resolves the 'Type' dimension (to Integer), leaving 32-bit and 64-bit modes active.
+// Both active modes (Mode32I, Mode64I) resolve PtrRC to XRegs, so it should resolve successfully.
+let Predicates = [NotCap] in
+def : CompressPat<(X_MOV XRegs:$dst, XRegs:$src),
+                  (PTR_MOV_SMALL XRegs:$dst, XRegs:$src)>;
+
+// IsCap only resolves the 'Type' dimension (to Capability), leaving 32-bit and 64-bit modes active.
+// Both active modes (Mode32C, Mode64C) resolve PtrRC to YRegs, so it should resolve successfully.
+let Predicates = [IsCap] in
+def : CompressPat<(Y_MOV YRegs:$dst, YRegs:$src),
+                  (PTR_MOV_SMALL YRegs:$dst, YRegs:$src)>;
+
+// CHECK:     static bool compressInst(MCInst &OutInst,
+// CHECK-NEXT:                          const MCInst &MI,
+// CHECK-NEXT:                          const MCSubtargetInfo &STI) {
+// CHECK-NEXT:   {{\[\[}}maybe_unused]] unsigned HwModeId = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);
+// CHECK-NEXT:   switch (MI.getOpcode()) {
+// CHECK-NEXT:   default: return false;
+// CHECK-NEXT:   case MyTarget::X_MOV: {
+// CHECK-NEXT:     if (!STI.getFeatureBits()[MyTarget::FeatureCap] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::XRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::PTR_MOV_SMALL);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
+// CHECK-NEXT:     break;
+// CHECK-NEXT:   } // case X_MOV
+// CHECK-NEXT:   case MyTarget::Y_MOV: {
+// CHECK-NEXT:     if (STI.getFeatureBits()[MyTarget::FeatureCap] &&
+// CHECK-NEXT:         MI.getOperand(0).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(0).getReg()) &&
+// CHECK-NEXT:         MI.getOperand(1).isReg() &&
+// CHECK-NEXT:         getMyTargetMCRegisterClass(MyTarget::YRegsRegClassID).contains(MI.getOperand(1).getReg())) {
+// CHECK-NEXT:       // ptr_mov.small $dst, $src
+// CHECK-NEXT:       OutInst.setOpcode(MyTarget::PTR_MOV_SMALL);
+// CHECK-NEXT:       // Operand: dst
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(0));
+// CHECK-NEXT:       // Operand: src
+// CHECK-NEXT:       OutInst.addOperand(MI.getOperand(1));
+// CHECK-NEXT:       OutInst.setLoc(MI.getLoc());
+// CHECK-NEXT:       return true;
+// CHECK-NEXT:     } // if
+// CHECK-NEXT:     break;
+// CHECK-NEXT:   } // case Y_MOV
+// CHECK-NEXT:   } // switch
+// CHECK-NEXT:   return false;
+// CHECK-NEXT: }
+
+def MyTargetISA : InstrInfo;
+def MyTargetAsmWriter : AsmWriter {
+  let PassSubtarget = 1;
+}
+def MyTarget : Target {
+  let InstructionSet = MyTargetISA;
+  let AssemblyWriters = [MyTargetAsmWriter];
+}

diff  --git a/llvm/test/TableGen/RegClassByHwModeCompressPatError.td b/llvm/test/TableGen/RegClassByHwModeCompressPatError.td
new file mode 100644
index 0000000000000..94270f9fa5232
--- /dev/null
+++ b/llvm/test/TableGen/RegClassByHwModeCompressPatError.td
@@ -0,0 +1,129 @@
+// Test that TableGen emits an error when RegClassByHwMode cannot be resolved
+// due to missing or contradictory predicates, leading to a type mismatch.
+// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -DERROR_UNRESOLVED 2>&1 | FileCheck %s --check-prefix=UNRESOLVED
+// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -DERROR_CONTRADICTORY_PAT 2>&1 | FileCheck %s --check-prefix=CONTRADICTORY_PAT
+// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -DERROR_WRONG_PRED 2>&1 | FileCheck %s --check-prefix=WRONG_PRED
+// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -DERROR_CONTRADICTORY_MODE 2>&1 | FileCheck %s --check-prefix=CONTRADICTORY_MODE
+// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -DERROR_INCOMPATIBLE_HWMODE 2>&1 | FileCheck %s --check-prefix=INCOMPATIBLE_HWMODE
+// RUN: not llvm-tblgen --gen-compress-inst-emitter -I %p/../../include -I %S %s -DERROR_NON_ASM_PRED_MODE 2>&1 | FileCheck %s --check-prefix=NON_ASM_PRED_MODE
+
+include "Common/RegClassByHwModeCommon.td"
+
+def FeaturePtr64 : SubtargetFeature<"ptr64", "IsPtr64", "true", "Ptr64 mode">;
+
+def IsPtr64 : Predicate<"Subtarget->isPtr64()">,
+              AssemblerPredicate<(all_of FeaturePtr64)>;
+def NotPtr64 : Predicate<"!Subtarget->isPtr64()">,
+               AssemblerPredicate<(all_of (not FeaturePtr64))>;
+
+defvar Ptr32 = DefaultMode;
+#ifdef ERROR_NON_ASM_PRED_MODE
+/// NonAsmPred has no AssemblerPredicate, so NonAsmMode is only active when both
+/// IsPtr64 and NonAsmPred hold. DefaultMode can still be active when IsPtr64
+/// is true and NonAsmPred is false, so a pattern predicated only on IsPtr64
+/// cannot uniquely resolve PtrRC to YRegs.
+def NonAsmPred : Predicate<"Subtarget->someOtherCheck()">;
+def NonAsmMode : HwMode<[IsPtr64, NonAsmPred]>;
+def PtrRC : RegClassByHwMode<[Ptr32, NonAsmMode], [XRegs, YRegs]>;
+#else
+def Ptr64 : HwMode<[IsPtr64]>;
+#ifdef ERROR_CONTRADICTORY_MODE
+// BadMode has contradictory predicates, so it can never be active.
+def BadMode : HwMode<[IsPtr64, NotPtr64]>;
+def PtrRC : RegClassByHwMode<[Ptr32, BadMode], [XRegs, YRegs]>;
+#else
+def PtrRC : RegClassByHwMode<[Ptr32, Ptr64], [XRegs, YRegs]>;
+#endif
+def OtherRC : RegClassByHwMode<[Ptr32, Ptr64], [YRegs, XRegs]>;
+#endif
+
+def X_MOV : TestInstruction {
+  let OutOperandList = (outs XRegs:$dst);
+  let InOperandList = (ins XRegs:$src);
+  let AsmString = "x_mov $dst, $src";
+  let opcode = 0;
+}
+
+def Y_MOV : TestInstruction {
+  let OutOperandList = (outs YRegs:$dst);
+  let InOperandList = (ins YRegs:$src);
+  let AsmString = "y_mov $dst, $src";
+  let opcode = 5;
+}
+
+def PTR_MOV : TestInstruction {
+  let OutOperandList = (outs PtrRC:$dst);
+  let InOperandList = (ins PtrRC:$src);
+  let AsmString = "ptr_mov $dst, $src";
+  let opcode = 3;
+}
+
+def PTR_MOV_SMALL : TestInstruction {
+  let OutOperandList = (outs PtrRC:$dst);
+  let InOperandList = (ins PtrRC:$src);
+  let AsmString = "ptr_mov.small $dst, $src";
+  let opcode = 4;
+  let Size = 1;
+}
+
+#ifdef ERROR_UNRESOLVED
+// X_MOV uses XRegs, but PTR_MOV_SMALL uses PtrRC.
+// Since there are no predicates, PtrRC cannot be resolved.
+def : CompressPat<(X_MOV XRegs:$dst, XRegs:$src),
+                  (PTR_MOV_SMALL XRegs:$dst, XRegs:$src)>;
+// UNRESOLVED: {{.*}}RegClassByHwModeCompressPatError.td:[[@LINE-2]]:{{[0-9]+}}: error: Error in Dag '{{.*}}'. Operand 'dst' has type 'XRegs' which does not match the type 'PtrRC' in the corresponding instruction operand!
+#endif
+
+#ifdef ERROR_CONTRADICTORY_PAT
+// Pattern has contradictory predicates, so no modes can be active.
+let Predicates = [IsPtr64, NotPtr64] in
+def : CompressPat<(X_MOV XRegs:$dst, XRegs:$src),
+                  (PTR_MOV_SMALL XRegs:$dst, XRegs:$src)>;
+// CONTRADICTORY_PAT: {{.*}}RegClassByHwModeCompressPatError.td:[[@LINE-2]]:{{[0-9]+}}: error: Error in Dag '{{.*}}'. Operand 'dst' has type 'XRegs' which does not match the type 'PtrRC' in the corresponding instruction operand!
+#endif
+
+#ifdef ERROR_WRONG_PRED
+// Pattern has NotPtr64 predicate, so PtrRC resolves to XRegs.
+// But Y_MOV uses YRegs, which is incompatible with XRegs.
+let Predicates = [NotPtr64] in
+def : CompressPat<(Y_MOV YRegs:$dst, YRegs:$src),
+                  (PTR_MOV_SMALL YRegs:$dst, YRegs:$src)>;
+// WRONG_PRED: {{.*}}RegClassByHwModeCompressPatError.td:[[@LINE-2]]:{{[0-9]+}}: error: Error in Dag '{{.*}}'. Operand 'dst' has type 'YRegs' which does not match the type 'PtrRC' in the corresponding instruction operand!
+#endif
+
+#ifdef ERROR_CONTRADICTORY_MODE
+// Pattern has IsPtr64 predicate, which should resolve PtrRC to YRegs (from BadMode).
+// But BadMode is incompatible because it has contradictory predicates.
+// So PtrRC cannot be resolved.
+let Predicates = [IsPtr64] in
+def : CompressPat<(Y_MOV YRegs:$dst, YRegs:$src),
+                  (PTR_MOV_SMALL YRegs:$dst, YRegs:$src)>;
+// CONTRADICTORY_MODE: {{.*}}RegClassByHwModeCompressPatError.td:[[@LINE-2]]:{{[0-9]+}}: error: Error in Dag '{{.*}}'. Operand 'dst' has type 'YRegs' which does not match the type 'PtrRC' in the corresponding instruction operand!
+#endif
+
+#ifdef ERROR_INCOMPATIBLE_HWMODE
+// OtherRC has YRegs for Ptr32 and XRegs for Ptr64.
+// PtrRC has XRegs for Ptr32 and YRegs for Ptr64.
+// They are incompatible because they don't have subclass relationship in all modes.
+def : CompressPat<(PTR_MOV OtherRC:$dst, OtherRC:$src),
+                  (PTR_MOV_SMALL PtrRC:$dst, PtrRC:$src)>;
+// INCOMPATIBLE_HWMODE: {{.*}}RegClassByHwModeCompressPatError.td:[[@LINE-2]]:{{[0-9]+}}: error: Error in Dag '{{.*}}'. Operand 'dst' has type 'OtherRC' which does not match the type 'PtrRC' in the corresponding instruction operand!
+#endif
+
+#ifdef ERROR_NON_ASM_PRED_MODE
+/// Pattern has IsPtr64 predicate, but NonAsmMode also requires NonAsmPred, so
+/// DefaultMode (XRegs) is still possible when IsPtr64 holds.
+let Predicates = [IsPtr64] in
+def : CompressPat<(Y_MOV YRegs:$dst, YRegs:$src),
+                  (PTR_MOV_SMALL YRegs:$dst, YRegs:$src)>;
+// NON_ASM_PRED_MODE: {{.*}}RegClassByHwModeCompressPatError.td:[[@LINE-2]]:{{[0-9]+}}: error: Error in Dag '{{.*}}'. Operand 'dst' has type 'YRegs' which does not match the type 'PtrRC' in the corresponding instruction operand!
+#endif
+
+def MyTargetISA : InstrInfo;
+def MyTargetAsmWriter : AsmWriter {
+  let PassSubtarget = 1;
+}
+def MyTarget : Target {
+  let InstructionSet = MyTargetISA;
+  let AssemblyWriters = [MyTargetAsmWriter];
+}

diff  --git a/llvm/utils/TableGen/Common/CodeGenHwModes.cpp b/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
index 5a93c83be5933..2c44cc06ea1b3 100644
--- a/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenHwModes.cpp
@@ -9,13 +9,18 @@
 //===----------------------------------------------------------------------===//
 
 #include "CodeGenHwModes.h"
+#include "SubtargetFeatureInfo.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
+#include <algorithm>
+#include <set>
 
 using namespace llvm;
 
+#define DEBUG_TYPE "codegen-hwmodes"
+
 StringRef CodeGenHwModes::DefaultModeName = "DefaultMode";
 
 HwMode::HwMode(const Record *R) {
@@ -48,6 +53,134 @@ void HwModeSelect::dump() const {
     dbgs() << " (" << P.first << ',' << P.second->getName() << ')';
   dbgs() << " }\n";
 }
+// Helper to represent predicates semantically.
+HwModePredicates::HwModePredicates(ArrayRef<const Record *> Preds) {
+  HasNonAsmPredicates =
+      !getRequiredFeatures(FeaturesSet, AnyOfFeatureSets, Preds);
+}
+
+// DefaultMode is implicitly active only when *none* of the other target
+// HwModes are active.
+//
+// Mathematically: DefaultMode = !(Mode_1 || Mode_2 || ... || Mode_N)
+//                            = !Mode_1 && !Mode_2 && ... && !Mode_N
+//
+// If Mode_1 requires (FeatureA && FeatureB), then !Mode_1 requires
+// (!FeatureA || !FeatureB). We construct these implicit OR-sets for all
+// other modes and add them to DefaultMode's requirements.
+HwModePredicates
+HwModePredicates::createForDefaultMode(const CodeGenHwModes &CGH) {
+  HwModePredicates SP;
+  for (unsigned M = 1; M < CGH.getNumModeIds(); ++M) {
+    const HwMode &Mode = CGH.getMode(M);
+    HwModePredicates ModePreds(Mode.Predicates);
+    if (ModePreds.HasNonAsmPredicates) {
+      LLVM_DEBUG(dbgs().indent(2)
+                 << "Warning: HwMode '" << Mode.Name
+                 << "' has non-assembler predicates. Ignoring for "
+                    "DefaultMode negation.\n");
+      SP.HasNonAsmPredicates = true;
+      continue;
+    }
+
+    // Negate the features in FeaturesSet: !(F1 && F2) = !F1 || !F2
+    std::set<SubtargetFeatureLiteral> NegatedFeatures;
+    for (const auto &Op : ModePreds.FeaturesSet) {
+      NegatedFeatures.insert({Op.Feature, !Op.IsNot});
+    }
+
+    if (ModePreds.AnyOfFeatureSets.empty()) {
+      if (!NegatedFeatures.empty())
+        SP.AnyOfFeatureSets.insert(std::move(NegatedFeatures));
+    } else if (ModePreds.AnyOfFeatureSets.size() == 1) {
+      // Negate a mode with a single OR-set:
+      // !(F1 && F2 && (L1 || L2)) = !F1 || !F2 || (!L1 && !L2)
+      // In CNF: (!F1 || !F2 || !L1) && (!F1 || !F2 || !L2)
+      const auto &OrSet = *ModePreds.AnyOfFeatureSets.begin();
+      for (const auto &Op : OrSet) {
+        std::set<SubtargetFeatureLiteral> NewOrSet = NegatedFeatures;
+        NewOrSet.insert({Op.Feature, !Op.IsNot});
+        SP.AnyOfFeatureSets.insert(std::move(NewOrSet));
+      }
+    } else {
+      LLVM_DEBUG(dbgs().indent(2)
+                 << "Warning: HwMode '" << Mode.Name
+                 << "' has multiple complex predicates. Ignoring for "
+                    "DefaultMode negation.\n");
+    }
+  }
+  return SP;
+}
+
+void HwModePredicates::add(const HwModePredicates &Other) {
+  FeaturesSet.insert(Other.FeaturesSet.begin(), Other.FeaturesSet.end());
+  AnyOfFeatureSets.insert(Other.AnyOfFeatureSets.begin(),
+                          Other.AnyOfFeatureSets.end());
+  HasNonAsmPredicates |= Other.HasNonAsmPredicates;
+}
+
+// Evaluates if the current set of predicates contains a contradiction.
+// Performs unit propagation: if we have a known feature F, we can simplify
+// OR-sets (A || B) containing F or !F.
+// Returns true if the OrSet is satisfied, false otherwise.
+// If not satisfied, fills SimplifiedSet with remaining active literals.
+static bool simplifyOrSet(const std::set<SubtargetFeatureLiteral> &OrSet,
+                          const std::set<SubtargetFeatureLiteral> &FeaturesSet,
+                          std::set<SubtargetFeatureLiteral> &SimplifiedSet) {
+  for (const auto &Lit : OrSet) {
+    if (FeaturesSet.count(Lit))
+      return true; // Satisfied
+    if (!FeaturesSet.count({Lit.Feature, !Lit.IsNot}))
+      SimplifiedSet.insert(Lit);
+  }
+  return false;
+}
+
+// Evaluates if the current set of predicates contains a contradiction.
+// Performs unit propagation: if we have a known feature F, we can simplify
+// OR-sets (A || B) containing F or !F.
+bool HwModePredicates::isSelfContradictory() {
+  // Check for immediate contradictions (e.g. requiring both F and !F).
+  for (const auto &Lit : FeaturesSet) {
+    if (FeaturesSet.count({Lit.Feature, !Lit.IsNot}))
+      return true;
+  }
+
+  std::set<std::set<SubtargetFeatureLiteral>> NewAnyOfs;
+  bool FeaturesChanged = false;
+
+  for (const auto &OrSet : AnyOfFeatureSets) {
+    std::set<SubtargetFeatureLiteral> SimplifiedSet;
+    if (simplifyOrSet(OrSet, FeaturesSet, SimplifiedSet))
+      continue; // Discard satisfied set
+
+    // All literals in this OR-set are false, causing a contradiction.
+    if (SimplifiedSet.empty())
+      return true;
+
+    if (SimplifiedSet.size() == 1) {
+      // Unit clause: only one choice remains, so it must be true.
+      FeaturesSet.insert(*SimplifiedSet.begin());
+      FeaturesChanged = true;
+    } else {
+      NewAnyOfs.insert(std::move(SimplifiedSet));
+    }
+  }
+
+  if (FeaturesChanged) {
+    AnyOfFeatureSets = std::move(NewAnyOfs);
+    return isSelfContradictory();
+  }
+
+  return false;
+}
+
+// Two predicate sets conflict if their union is self-contradictory.
+bool HwModePredicates::conflictsWith(const HwModePredicates &Other) const {
+  HwModePredicates Combined(*this);
+  Combined.add(Other);
+  return Combined.isSelfContradictory();
+}
 
 CodeGenHwModes::CodeGenHwModes(const RecordKeeper &RK) : Records(RK) {
   for (const Record *R : Records.getAllDerivedDefinitions("HwMode")) {
@@ -68,6 +201,18 @@ CodeGenHwModes::CodeGenHwModes(const RecordKeeper &RK) : Records(RK) {
   }
 }
 
+const HwModePredicates &
+CodeGenHwModes::getModePredicates(unsigned ModeId) const {
+  if (PredicatesByMode.empty()) {
+    PredicatesByMode.resize(getNumModeIds());
+    PredicatesByMode[DefaultMode] =
+        HwModePredicates::createForDefaultMode(*this);
+    for (unsigned M = 1; M < getNumModeIds(); ++M)
+      PredicatesByMode[M] = HwModePredicates(getMode(M).Predicates);
+  }
+  return PredicatesByMode[ModeId];
+}
+
 unsigned CodeGenHwModes::getHwModeId(const Record *R) const {
   if (R->getName() == DefaultModeName)
     return DefaultMode;
@@ -103,3 +248,52 @@ void CodeGenHwModes::dump() const {
   }
   dbgs() << "}\n";
 }
+
+// Resolves a HwModeSelect record based on pattern predicates.
+// Returns a unique resolved record if compatible, or nullptr if ambiguous.
+const Record *
+CodeGenHwModes::resolveModeSelect(const Record *SelectRec,
+                                  ArrayRef<const Record *> PatPreds) const {
+  if (!SelectRec->isSubClassOf("HwModeSelect"))
+    return SelectRec;
+
+  LLVM_DEBUG(dbgs() << "Trying to resolve HwModeSelect '"
+                    << SelectRec->getName() << "'\n");
+
+  const HwModeSelect &MS = getHwModeSelect(SelectRec);
+
+  std::set<const Record *> ResolvedObjects;
+
+  // Construct and parse the pattern predicates ONCE here
+  HwModePredicates PatPredsSet(PatPreds);
+
+  for (const auto &[ModeId, Obj] : MS.Items) {
+    const HwModePredicates &ModePreds = getModePredicates(ModeId);
+
+    if (!ModePreds.conflictsWith(PatPredsSet)) {
+      LLVM_DEBUG(dbgs() << "  HwMode '" << getModeName(ModeId, true)
+                        << "' is compatible -> " << Obj->getName() << "\n");
+      ResolvedObjects.insert(Obj);
+    } else {
+      LLVM_DEBUG(dbgs() << "  HwMode '" << getModeName(ModeId, true)
+                        << "' is incompatible due to semantic conflict\n");
+    }
+  }
+
+  if (ResolvedObjects.size() == 1) {
+    const Record *Resolved = *ResolvedObjects.begin();
+    LLVM_DEBUG(dbgs() << "  Resolved to unique object: " << Resolved->getName()
+                      << "\n");
+    return Resolved;
+  }
+
+  if (ResolvedObjects.empty()) {
+    LLVM_DEBUG(dbgs() << "  No active modes resolved for '"
+                      << SelectRec->getName() << "'\n");
+  } else {
+    LLVM_DEBUG(
+        dbgs() << "  Multiple active modes resolved to 
diff erent objects for '"
+               << SelectRec->getName() << "'\n");
+  }
+  return nullptr;
+}

diff  --git a/llvm/utils/TableGen/Common/CodeGenHwModes.h b/llvm/utils/TableGen/Common/CodeGenHwModes.h
index 7e45f8ef1de49..e605c22357533 100644
--- a/llvm/utils/TableGen/Common/CodeGenHwModes.h
+++ b/llvm/utils/TableGen/Common/CodeGenHwModes.h
@@ -11,10 +11,13 @@
 #ifndef LLVM_UTILS_TABLEGEN_COMMON_CODEGENHWMODES_H
 #define LLVM_UTILS_TABLEGEN_COMMON_CODEGENHWMODES_H
 
+#include "SubtargetFeatureInfo.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
 #include <cassert>
 #include <map>
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -26,6 +29,20 @@ class RecordKeeper;
 
 struct CodeGenHwModes;
 
+struct HwModePredicates {
+  std::set<SubtargetFeatureLiteral> FeaturesSet;
+  std::set<std::set<SubtargetFeatureLiteral>> AnyOfFeatureSets;
+  bool HasNonAsmPredicates = false;
+
+  HwModePredicates() = default;
+  HwModePredicates(ArrayRef<const Record *> Preds);
+
+  static HwModePredicates createForDefaultMode(const CodeGenHwModes &CGH);
+  void add(const HwModePredicates &Other);
+  bool isSelfContradictory();
+  bool conflictsWith(const HwModePredicates &Other) const;
+};
+
 struct HwMode {
   HwMode(const Record *R);
   StringRef Name;
@@ -56,6 +73,9 @@ struct CodeGenHwModes {
     return getMode(Id).Name;
   }
   const HwModeSelect &getHwModeSelect(const Record *R) const;
+  const HwModePredicates &getModePredicates(unsigned ModeId) const;
+  const Record *resolveModeSelect(const Record *SelectRec,
+                                  ArrayRef<const Record *> PatPreds) const;
   const std::map<const Record *, HwModeSelect> &getHwModeSelects() const {
     return ModeSelects;
   }
@@ -67,6 +87,7 @@ struct CodeGenHwModes {
   DenseMap<const Record *, unsigned> ModeIds; // HwMode Record -> HwModeId
   std::vector<HwMode> Modes;
   std::map<const Record *, HwModeSelect> ModeSelects;
+  mutable std::vector<HwModePredicates> PredicatesByMode;
 };
 } // namespace llvm
 

diff  --git a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
index f0afbd1b6ddd1..62a7f086ca1ae 100644
--- a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
+++ b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.cpp
@@ -210,3 +210,53 @@ void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures(
   OS << "  return Features;\n";
   OS << "}\n\n";
 }
+
+bool llvm::getRequiredFeatures(
+    std::set<SubtargetFeatureLiteral> &FeaturesSet,
+    std::set<std::set<SubtargetFeatureLiteral>> &AnyOfFeatureSets,
+    ArrayRef<const Record *> ReqPredicates) {
+  bool AllPredicatesParsed = true;
+  for (const Record *R : ReqPredicates) {
+    if (!R->getValueAsBit("AssemblerMatcherPredicate")) {
+      AllPredicatesParsed = false;
+      continue;
+    }
+    const RecordVal *V = R->getValue("AssemblerCondDag");
+    if (!V || !V->getValue() || !isa<DagInit>(V->getValue())) {
+      // Ignore this predicate for semantic analysis, as it has no subtarget
+      // features.
+      AllPredicatesParsed = false;
+      continue;
+    }
+    const DagInit *D = cast<DagInit>(V->getValue());
+    std::string CombineType = D->getOperator()->getAsString();
+    if (CombineType != "any_of" && CombineType != "all_of")
+      PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
+    if (D->getNumArgs() == 0)
+      PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
+    bool IsOr = CombineType == "any_of";
+    std::set<SubtargetFeatureLiteral> AnyOfSet;
+
+    for (auto *Arg : D->getArgs()) {
+      bool IsNot = false;
+      if (auto *NotArg = dyn_cast<DagInit>(Arg)) {
+        if (NotArg->getOperator()->getAsString() != "not" ||
+            NotArg->getNumArgs() != 1)
+          PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
+        Arg = NotArg->getArg(0);
+        IsNot = true;
+      }
+      if (!isa<DefInit>(Arg) ||
+          !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature"))
+        PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
+      if (IsOr)
+        AnyOfSet.insert({cast<DefInit>(Arg)->getDef()->getName(), IsNot});
+      else
+        FeaturesSet.insert({cast<DefInit>(Arg)->getDef()->getName(), IsNot});
+    }
+
+    if (IsOr)
+      AnyOfFeatureSets.insert(std::move(AnyOfSet));
+  }
+  return AllPredicatesParsed;
+}

diff  --git a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h
index 2b2577b93c284..b74cdc4903e47 100644
--- a/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h
+++ b/llvm/utils/TableGen/Common/SubtargetFeatureInfo.h
@@ -12,7 +12,9 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/TableGen/Record.h"
 #include <map>
+#include <set>
 #include <string>
+#include <tuple>
 #include <utility>
 #include <vector>
 
@@ -108,6 +110,26 @@ struct SubtargetFeatureInfo {
   static void emitMCPredicateCheck(raw_ostream &OS, StringRef TargetName,
                                    ArrayRef<const Record *> Predicates);
 };
+
+struct SubtargetFeatureLiteral {
+  StringRef Feature;
+  bool IsNot;
+
+  bool operator<(const SubtargetFeatureLiteral &Other) const {
+    return std::tie(Feature, IsNot) < std::tie(Other.Feature, Other.IsNot);
+  }
+  bool operator==(const SubtargetFeatureLiteral &Other) const {
+    return Feature == Other.Feature && IsNot == Other.IsNot;
+  }
+};
+
+/// Populates \p FeaturesSet and \p AnyOfFeatureSets from \p ReqPredicates.
+/// Returns true if all predicates were assembler predicates with a valid
+/// AssemblerCondDag, or false if any non-assembler predicates were skipped.
+bool getRequiredFeatures(
+    std::set<SubtargetFeatureLiteral> &FeaturesSet,
+    std::set<std::set<SubtargetFeatureLiteral>> &AnyOfFeatureSets,
+    ArrayRef<const Record *> ReqPredicates);
 } // end namespace llvm
 
 #endif // LLVM_UTIL_TABLEGEN_COMMON_SUBTARGETFEATUREINFO_H

diff  --git a/llvm/utils/TableGen/CompressInstEmitter.cpp b/llvm/utils/TableGen/CompressInstEmitter.cpp
index 3fe54dd97ab53..3bf1e84a7f0e3 100644
--- a/llvm/utils/TableGen/CompressInstEmitter.cpp
+++ b/llvm/utils/TableGen/CompressInstEmitter.cpp
@@ -65,9 +65,12 @@
 
 //===----------------------------------------------------------------------===//
 
+#include "Common/CodeGenHwModes.h"
 #include "Common/CodeGenInstruction.h"
 #include "Common/CodeGenRegisters.h"
 #include "Common/CodeGenTarget.h"
+#include "Common/InfoByHwMode.h"
+#include "Common/SubtargetFeatureInfo.h"
 #include "llvm/ADT/IndexedMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
@@ -139,13 +142,14 @@ class CompressInstEmitter {
   void addDagOperandMapping(const Record *Rec, const DagInit *Dag,
                             const CodeGenInstruction &Inst,
                             IndexedMap<OpData> &OperandMap,
-                            StringMap<ArgData> &Operands, bool IsSourceInst);
+                            StringMap<ArgData> &Operands, bool IsSourceInst,
+                            ArrayRef<const Record *> PatPreds);
   void evaluateCompressPat(const Record *Compress);
   void emitCompressInstEmitter(raw_ostream &OS, EmitterType EType);
   bool validateTypes(const Record *DagOpType, const Record *InstOpType,
-                     bool IsSourceInst);
+                     bool IsSourceInst, ArrayRef<const Record *> PatPreds);
   bool validateRegister(const Record *Reg, const Record *RegClass,
-                        ArrayRef<SMLoc> Loc);
+                        ArrayRef<SMLoc> Loc, ArrayRef<const Record *> PatPreds);
   void checkDagOperandMapping(const Record *Rec,
                               const StringMap<ArgData> &DestOperands,
                               const DagInit *SourceDag, const DagInit *DestDag);
@@ -166,18 +170,68 @@ class CompressInstEmitter {
 
 bool CompressInstEmitter::validateRegister(const Record *Reg,
                                            const Record *RegClass,
-                                           ArrayRef<SMLoc> Loc) {
+                                           ArrayRef<SMLoc> Loc,
+                                           ArrayRef<const Record *> PatPreds) {
   assert((Reg->isSubClassOf("Register") ||
           Reg->isSubClassOf("RegisterByHwMode")) &&
          "Reg record should be a Register");
   assert(RegClass->isSubClassOf("RegisterClassLike") &&
          "RegClass record should be RegisterClassLike");
+
+  if (const Record *RC =
+          Target.getHwModes().resolveModeSelect(RegClass, PatPreds))
+    RegClass = RC;
+  if (const Record *R = Target.getHwModes().resolveModeSelect(Reg, PatPreds))
+    Reg = R;
+
   return Target.getRegBank().regClassContainsReg(RegClass, Reg, Loc);
 }
 
 bool CompressInstEmitter::validateTypes(const Record *DagOpType,
                                         const Record *InstOpType,
-                                        bool IsSourceInst) {
+                                        bool IsSourceInst,
+                                        ArrayRef<const Record *> PatPreds) {
+  if (DagOpType == InstOpType)
+    return true;
+
+  const Record *ResolvedDag =
+      Target.getHwModes().resolveModeSelect(DagOpType, PatPreds);
+  const Record *ResolvedInst =
+      Target.getHwModes().resolveModeSelect(InstOpType, PatPreds);
+
+  if (ResolvedDag && ResolvedInst) {
+    DagOpType = ResolvedDag;
+    InstOpType = ResolvedInst;
+  } else if (DagOpType->isSubClassOf("RegClassByHwMode") &&
+             InstOpType->isSubClassOf("RegClassByHwMode")) {
+    RegClassByHwMode DagRC(DagOpType, Target.getRegBank());
+    RegClassByHwMode InstRC(InstOpType, Target.getRegBank());
+    const CodeGenHwModes &CGH = Target.getHwModes();
+    HwModePredicates PatPredsSet(PatPreds);
+    bool HasCompatibleMode = false;
+    for (const auto &[Mode, DagClass] : DagRC) {
+      if (CGH.getModePredicates(Mode).conflictsWith(PatPredsSet))
+        continue;
+      if (!InstRC.hasMode(Mode))
+        return false;
+      const CodeGenRegisterClass *InstClass = InstRC.get(Mode);
+      if (!InstClass->hasSubClass(DagClass))
+        return false;
+      HasCompatibleMode = true;
+    }
+    for (const auto &[Mode, InstClass] : InstRC) {
+      if (CGH.getModePredicates(Mode).conflictsWith(PatPredsSet))
+        continue;
+      if (!DagRC.hasMode(Mode))
+        return false;
+    }
+    return HasCompatibleMode;
+  } else if (DagOpType->isSubClassOf("HwModeSelect") ||
+             InstOpType->isSubClassOf("HwModeSelect")) {
+    return false;
+  }
+
+  // Concrete check (when resolved uniquely).
   if (DagOpType == InstOpType)
     return true;
 
@@ -214,12 +268,10 @@ static bool validateArgsTypes(const Init *Arg1, const Init *Arg2) {
 /// operands and fixed registers it expects the Dag operand type to be contained
 /// in the instantiated instruction operand type. For immediate operands and
 /// immediates no validation checks are enforced at pattern validation time.
-void CompressInstEmitter::addDagOperandMapping(const Record *Rec,
-                                               const DagInit *Dag,
-                                               const CodeGenInstruction &Inst,
-                                               IndexedMap<OpData> &OperandMap,
-                                               StringMap<ArgData> &Operands,
-                                               bool IsSourceInst) {
+void CompressInstEmitter::addDagOperandMapping(
+    const Record *Rec, const DagInit *Dag, const CodeGenInstruction &Inst,
+    IndexedMap<OpData> &OperandMap, StringMap<ArgData> &Operands,
+    bool IsSourceInst, ArrayRef<const Record *> PatPreds) {
   unsigned NumMIOperands = 0;
   if (!Inst.Operands.empty())
     NumMIOperands =
@@ -259,7 +311,7 @@ void CompressInstEmitter::addDagOperandMapping(const Record *Rec,
         if (DI->getDef()->isSubClassOf("Register") ||
             DI->getDef()->isSubClassOf("RegisterByHwMode")) {
           // Check if the fixed register belongs to the Register class.
-          if (!validateRegister(DI->getDef(), OpndRec, Rec->getLoc()))
+          if (!validateRegister(DI->getDef(), OpndRec, Rec->getLoc(), PatPreds))
             PrintFatalError(Rec->getLoc(),
                             "Error in Dag '" + Dag->getAsString() +
                                 "': Register '" + DI->getDef()->getName() +
@@ -273,7 +325,7 @@ void CompressInstEmitter::addDagOperandMapping(const Record *Rec,
         // corresponding instruction. Operands in the input and output Dag
         // patterns are allowed to be a subclass of the type specified in the
         // corresponding instruction operand instead of being an exact match.
-        if (!validateTypes(DI->getDef(), OpndRec, IsSourceInst))
+        if (!validateTypes(DI->getDef(), OpndRec, IsSourceInst, PatPreds))
           PrintFatalError(Rec->getLoc(),
                           "Error in Dag '" + Dag->getAsString() +
                               "'. Operand '" + Dag->getArgNameStr(DAGOpNo) +
@@ -466,6 +518,13 @@ void CompressInstEmitter::evaluateCompressPat(const Record *Rec) {
             "'is not strictly smaller than the uncompressed instruction '" +
             SourceOperator->getName() + "' !");
 
+  // Get the target features for the CompressPat.
+  std::vector<const Record *> PatReqFeatures;
+  std::vector<const Record *> RF = Rec->getValueAsListOfDefs("Predicates");
+  copy_if(RF, std::back_inserter(PatReqFeatures), [](const Record *R) {
+    return R->getValueAsBit("AssemblerMatcherPredicate");
+  });
+
   // Fill the mapping from the source to destination instructions.
 
   IndexedMap<OpData> SourceOperandMap;
@@ -473,7 +532,7 @@ void CompressInstEmitter::evaluateCompressPat(const Record *Rec) {
   StringMap<ArgData> SourceOperands;
   // Create a mapping between source Dag operands and source Inst operands.
   addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap,
-                       SourceOperands, /*IsSourceInst*/ true);
+                       SourceOperands, /*IsSourceInst*/ true, PatReqFeatures);
 
   IndexedMap<OpData> DestOperandMap;
   // Map from arg name to DAG operand number and MI operand number.
@@ -481,62 +540,18 @@ void CompressInstEmitter::evaluateCompressPat(const Record *Rec) {
   // Create a mapping between destination Dag operands and destination Inst
   // operands.
   addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap, DestOperands,
-                       /*IsSourceInst*/ false);
+                       /*IsSourceInst*/ false, PatReqFeatures);
 
   checkDagOperandMapping(Rec, DestOperands, SourceDag, DestDag);
   // Create operand mapping between the source and destination instructions.
   createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap,
                            DestOperandMap, SourceOperands, DestInst);
 
-  // Get the target features for the CompressPat.
-  std::vector<const Record *> PatReqFeatures;
-  std::vector<const Record *> RF = Rec->getValueAsListOfDefs("Predicates");
-  copy_if(RF, std::back_inserter(PatReqFeatures), [](const Record *R) {
-    return R->getValueAsBit("AssemblerMatcherPredicate");
-  });
-
   CompressPatterns.emplace_back(SourceInst, DestInst, std::move(PatReqFeatures),
                                 SourceOperandMap, DestOperandMap,
                                 Rec->getValueAsBit("isCompressOnly"));
 }
 
-static void
-getReqFeatures(std::set<std::pair<bool, StringRef>> &FeaturesSet,
-               std::set<std::set<std::pair<bool, StringRef>>> &AnyOfFeatureSets,
-               ArrayRef<const Record *> ReqFeatures) {
-  for (const Record *R : ReqFeatures) {
-    const DagInit *D = R->getValueAsDag("AssemblerCondDag");
-    std::string CombineType = D->getOperator()->getAsString();
-    if (CombineType != "any_of" && CombineType != "all_of")
-      PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
-    if (D->getNumArgs() == 0)
-      PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
-    bool IsOr = CombineType == "any_of";
-    std::set<std::pair<bool, StringRef>> AnyOfSet;
-
-    for (auto *Arg : D->getArgs()) {
-      bool IsNot = false;
-      if (auto *NotArg = dyn_cast<DagInit>(Arg)) {
-        if (NotArg->getOperator()->getAsString() != "not" ||
-            NotArg->getNumArgs() != 1)
-          PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
-        Arg = NotArg->getArg(0);
-        IsNot = true;
-      }
-      if (!isa<DefInit>(Arg) ||
-          !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature"))
-        PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
-      if (IsOr)
-        AnyOfSet.emplace(IsNot, cast<DefInit>(Arg)->getDef()->getName());
-      else
-        FeaturesSet.emplace(IsNot, cast<DefInit>(Arg)->getDef()->getName());
-    }
-
-    if (IsOr)
-      AnyOfFeatureSets.insert(std::move(AnyOfSet));
-  }
-}
-
 static unsigned getPredicates(DenseMap<const Record *, unsigned> &PredicateMap,
                               std::vector<const Record *> &Predicates,
                               const Record *Rec, StringRef Name) {
@@ -703,10 +718,11 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &OS,
       CaseStream.indent(2) << "case " + TargetName + "::" + CurOp + ": {\n";
     }
 
-    std::set<std::pair<bool, StringRef>> FeaturesSet;
-    std::set<std::set<std::pair<bool, StringRef>>> AnyOfFeatureSets;
+    std::set<SubtargetFeatureLiteral> FeaturesSet;
+    std::set<std::set<SubtargetFeatureLiteral>> AnyOfFeatureSets;
     // Add CompressPat required features.
-    getReqFeatures(FeaturesSet, AnyOfFeatureSets, CompressPat.PatReqFeatures);
+    getRequiredFeatures(FeaturesSet, AnyOfFeatureSets,
+                        CompressPat.PatReqFeatures);
 
     // Add Dest instruction required features.
     std::vector<const Record *> ReqFeatures;
@@ -715,25 +731,25 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &OS,
     copy_if(RF, std::back_inserter(ReqFeatures), [](const Record *R) {
       return R->getValueAsBit("AssemblerMatcherPredicate");
     });
-    getReqFeatures(FeaturesSet, AnyOfFeatureSets, ReqFeatures);
+    getRequiredFeatures(FeaturesSet, AnyOfFeatureSets, ReqFeatures);
 
     ListSeparator CondSep(" &&\n        ");
 
     // Emit checks for all required features.
-    for (auto &Op : FeaturesSet) {
-      StringRef Not = Op.first ? "!" : "";
+    for (const auto &Op : FeaturesSet) {
+      StringRef Not = Op.IsNot ? "!" : "";
       CondStream << CondSep << Not << "STI.getFeatureBits()[" << TargetName
-                 << "::" << Op.second << "]";
+                 << "::" << Op.Feature << "]";
     }
 
     // Emit checks for all required feature groups.
-    for (auto &Set : AnyOfFeatureSets) {
+    for (const auto &Set : AnyOfFeatureSets) {
       CondStream << CondSep << "(";
-      for (auto &Op : Set) {
+      for (const auto &Op : Set) {
         bool IsLast = &Op == &*Set.rbegin();
-        StringRef Not = Op.first ? "!" : "";
+        StringRef Not = Op.IsNot ? "!" : "";
         CondStream << Not << "STI.getFeatureBits()[" << TargetName
-                   << "::" << Op.second << "]";
+                   << "::" << Op.Feature << "]";
         if (!IsLast)
           CondStream << " || ";
       }


        


More information about the llvm-commits mailing list