Skip to content

Conversation

arsenm
Copy link
Contributor

@arsenm arsenm commented Sep 12, 2025

Replace the target uses of PointerLikeRegClass with RegClassByHwMode

Copy link
Contributor Author

arsenm commented Sep 12, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@llvmbot
Copy link
Member

llvmbot commented Sep 12, 2025

@llvm/pr-subscribers-backend-x86
@llvm/pr-subscribers-llvm-globalisel
@llvm/pr-subscribers-tablegen

@llvm/pr-subscribers-llvm-mc

Author: Matt Arsenault (arsenm)

Changes

Replace the target uses of PointerLikeRegClass with RegClassByHwMode


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

8 Files Affected:

  • (modified) llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp (+3)
  • (modified) llvm/lib/Target/X86/X86.td (+2)
  • (modified) llvm/lib/Target/X86/X86InstrInfo.td (+4-4)
  • (modified) llvm/lib/Target/X86/X86InstrOperands.td (+22-8)
  • (modified) llvm/lib/Target/X86/X86InstrPredicates.td (+14)
  • (modified) llvm/lib/Target/X86/X86RegisterInfo.cpp (+8-27)
  • (modified) llvm/lib/Target/X86/X86Subtarget.h (+2-2)
  • (modified) llvm/utils/TableGen/X86FoldTablesEmitter.cpp (+2-2)
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
index bb1e716c33ed5..1d5ef8b0996dc 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
@@ -55,6 +55,9 @@ std::string X86_MC::ParseX86Triple(const Triple &TT) {
   else
     FS = "-64bit-mode,-32bit-mode,+16bit-mode";
 
+  if (TT.isX32())
+    FS += ",+x32";
+
   return FS;
 }
 
diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td
index 7c9e821c02fda..3af8b3e060a16 100644
--- a/llvm/lib/Target/X86/X86.td
+++ b/llvm/lib/Target/X86/X86.td
@@ -25,6 +25,8 @@ def Is32Bit : SubtargetFeature<"32bit-mode", "Is32Bit", "true",
                                "32-bit mode (80386)">;
 def Is16Bit : SubtargetFeature<"16bit-mode", "Is16Bit", "true",
                                "16-bit mode (i8086)">;
+def IsX32 : SubtargetFeature<"x32", "IsX32", "true",
+                             "64-bit with ILP32 programming model (e.g. x32 ABI)">;
 
 //===----------------------------------------------------------------------===//
 // X86 Subtarget ISA features
diff --git a/llvm/lib/Target/X86/X86InstrInfo.td b/llvm/lib/Target/X86/X86InstrInfo.td
index 7f6c5614847e3..0c4abc2c400f6 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.td
+++ b/llvm/lib/Target/X86/X86InstrInfo.td
@@ -18,14 +18,14 @@ include "X86InstrFragments.td"
 include "X86InstrFragmentsSIMD.td"
 
 //===----------------------------------------------------------------------===//
-// X86 Operand Definitions.
+// X86 Predicate Definitions.
 //
-include "X86InstrOperands.td"
+include "X86InstrPredicates.td"
 
 //===----------------------------------------------------------------------===//
-// X86 Predicate Definitions.
+// X86 Operand Definitions.
 //
-include "X86InstrPredicates.td"
+include "X86InstrOperands.td"
 
 //===----------------------------------------------------------------------===//
 // X86 Instruction Format Definitions.
diff --git a/llvm/lib/Target/X86/X86InstrOperands.td b/llvm/lib/Target/X86/X86InstrOperands.td
index 80843f6bb80e6..5207ecad127a2 100644
--- a/llvm/lib/Target/X86/X86InstrOperands.td
+++ b/llvm/lib/Target/X86/X86InstrOperands.td
@@ -6,9 +6,15 @@
 //
 //===----------------------------------------------------------------------===//
 
+def x86_ptr_rc : RegClassByHwMode<
+  [X86_32, X86_64, X86_64_X32],
+  [GR32, GR64, LOW32_ADDR_ACCESS]>;
+
 // A version of ptr_rc which excludes SP, ESP, and RSP. This is used for
 // the index operand of an address, to conform to x86 encoding restrictions.
-def ptr_rc_nosp : PointerLikeRegClass<1>;
+def ptr_rc_nosp : RegClassByHwMode<
+  [X86_32, X86_64, X86_64_X32],
+  [GR32_NOSP, GR64_NOSP, GR32_NOSP]>;
 
 // *mem - Operand definitions for the funky X86 addressing mode operands.
 //
@@ -53,7 +59,7 @@ class X86MemOperand<string printMethod,
                     AsmOperandClass parserMatchClass = X86MemAsmOperand,
                     int size = 0> : Operand<iPTR> {
   let PrintMethod = printMethod;
-  let MIOperandInfo = (ops ptr_rc, i8imm, ptr_rc_nosp, i32imm, SEGMENT_REG);
+  let MIOperandInfo = (ops x86_ptr_rc, i8imm, ptr_rc_nosp, i32imm, SEGMENT_REG);
   let ParserMatchClass = parserMatchClass;
   let OperandType = "OPERAND_MEMORY";
   int Size = size;
@@ -63,7 +69,7 @@ class X86MemOperand<string printMethod,
 class X86VMemOperand<RegisterClass RC, string printMethod,
                      AsmOperandClass parserMatchClass, int size = 0>
     : X86MemOperand<printMethod, parserMatchClass, size> {
-  let MIOperandInfo = (ops ptr_rc, i8imm, RC, i32imm, SEGMENT_REG);
+  let MIOperandInfo = (ops x86_ptr_rc, i8imm, RC, i32imm, SEGMENT_REG);
 }
 
 def anymem : X86MemOperand<"printMemReference">;
@@ -113,8 +119,14 @@ def sdmem : X86MemOperand<"printqwordmem", X86Mem64AsmOperand>;
 
 // A version of i8mem for use on x86-64 and x32 that uses a NOREX GPR instead
 // of a plain GPR, so that it doesn't potentially require a REX prefix.
-def ptr_rc_norex : PointerLikeRegClass<2>;
-def ptr_rc_norex_nosp : PointerLikeRegClass<3>;
+def ptr_rc_norex : RegClassByHwMode<
+  [X86_32, X86_64, X86_64_X32],
+  [GR32_NOREX, GR64_NOREX, GR32_NOREX]>;
+
+def ptr_rc_norex_nosp : RegClassByHwMode<
+  [X86_32, X86_64, X86_64_X32],
+  [GR32_NOREX_NOSP, GR64_NOREX_NOSP, GR32_NOREX_NOSP]>;
+
 
 def i8mem_NOREX : X86MemOperand<"printbytemem", X86Mem8AsmOperand, 8> {
   let MIOperandInfo = (ops ptr_rc_norex, i8imm, ptr_rc_norex_nosp, i32imm,
@@ -123,7 +135,9 @@ def i8mem_NOREX : X86MemOperand<"printbytemem", X86Mem8AsmOperand, 8> {
 
 // GPRs available for tailcall.
 // It represents GR32_TC, GR64_TC or GR64_TCW64.
-def ptr_rc_tailcall : PointerLikeRegClass<4>;
+def ptr_rc_tailcall : RegClassByHwMode<
+  [X86_32, X86_64, X86_64_X32],
+  [GR32_TC, GR64_TC, GR64_TC]>;
 
 // Special i32mem for addresses of load folding tail calls. These are not
 // allowed to use callee-saved registers since they must be scheduled
@@ -270,12 +284,12 @@ let RenderMethod = "addMemOffsOperands" in {
 
 class X86SrcIdxOperand<string printMethod, AsmOperandClass parserMatchClass>
     : X86MemOperand<printMethod, parserMatchClass> {
-  let MIOperandInfo = (ops ptr_rc, SEGMENT_REG);
+  let MIOperandInfo = (ops x86_ptr_rc, SEGMENT_REG);
 }
 
 class X86DstIdxOperand<string printMethod, AsmOperandClass parserMatchClass>
     : X86MemOperand<printMethod, parserMatchClass> {
-  let MIOperandInfo = (ops ptr_rc);
+  let MIOperandInfo = (ops x86_ptr_rc);
 }
 
 def srcidx8  : X86SrcIdxOperand<"printSrcIdx8",  X86SrcIdx8Operand>;
diff --git a/llvm/lib/Target/X86/X86InstrPredicates.td b/llvm/lib/Target/X86/X86InstrPredicates.td
index 8339c2081842d..c20bb05018b4d 100644
--- a/llvm/lib/Target/X86/X86InstrPredicates.td
+++ b/llvm/lib/Target/X86/X86InstrPredicates.td
@@ -195,6 +195,12 @@ def Not64BitMode : Predicate<"!Subtarget->is64Bit()">,
                              AssemblerPredicate<(all_of (not Is64Bit)), "Not 64-bit mode">;
 def In64BitMode  : Predicate<"Subtarget->is64Bit()">,
                              AssemblerPredicate<(all_of Is64Bit), "64-bit mode">;
+
+def IsX32Mode  : Predicate<"Subtarget->getTargetTriple().isX32()">,
+                            AssemblerPredicate<(all_of IsX32), "x32 ABI">;
+def NotX32Mode  : Predicate<"!Subtarget->getTargetTriple().isX32()">,
+                            AssemblerPredicate<(all_of (not IsX32)), "not x32 ABI">;
+
 def IsLP64  : Predicate<"Subtarget->isTarget64BitLP64()">;
 def NotLP64 : Predicate<"!Subtarget->isTarget64BitLP64()">;
 def In16BitMode  : Predicate<"Subtarget->is16Bit()">,
@@ -250,3 +256,11 @@ def HasMFence    : Predicate<"Subtarget->hasMFence()">;
 def HasFastDPWSSD: Predicate<"Subtarget->hasFastDPWSSD()">;
 def UseIndirectThunkCalls : Predicate<"Subtarget->useIndirectThunkCalls()">;
 def NotUseIndirectThunkCalls : Predicate<"!Subtarget->useIndirectThunkCalls()">;
+
+//===----------------------------------------------------------------------===//
+// HwModes
+//===----------------------------------------------------------------------===//
+
+defvar X86_32 = DefaultMode;
+def X86_64 : HwMode<[In64BitMode, NotX32Mode]>;
+def X86_64_X32 : HwMode<[IsX32Mode]>;
diff --git a/llvm/lib/Target/X86/X86RegisterInfo.cpp b/llvm/lib/Target/X86/X86RegisterInfo.cpp
index c47bb3e67e625..efccf5c72596e 100644
--- a/llvm/lib/Target/X86/X86RegisterInfo.cpp
+++ b/llvm/lib/Target/X86/X86RegisterInfo.cpp
@@ -194,33 +194,14 @@ X86RegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC,
 
 const TargetRegisterClass *
 X86RegisterInfo::getPointerRegClass(unsigned Kind) const {
-  switch (Kind) {
-  default: llvm_unreachable("Unexpected Kind in getPointerRegClass!");
-  case 0: // Normal GPRs.
-    if (IsTarget64BitLP64)
-      return &X86::GR64RegClass;
-    // If the target is 64bit but we have been told to use 32bit addresses,
-    // we can still use 64-bit register as long as we know the high bits
-    // are zeros.
-    // Reflect that in the returned register class.
-    return Is64Bit ? &X86::LOW32_ADDR_ACCESSRegClass : &X86::GR32RegClass;
-  case 1: // Normal GPRs except the stack pointer (for encoding reasons).
-    if (IsTarget64BitLP64)
-      return &X86::GR64_NOSPRegClass;
-    // NOSP does not contain RIP, so no special case here.
-    return &X86::GR32_NOSPRegClass;
-  case 2: // NOREX GPRs.
-    if (IsTarget64BitLP64)
-      return &X86::GR64_NOREXRegClass;
-    return &X86::GR32_NOREXRegClass;
-  case 3: // NOREX GPRs except the stack pointer (for encoding reasons).
-    if (IsTarget64BitLP64)
-      return &X86::GR64_NOREX_NOSPRegClass;
-    // NOSP does not contain RIP, so no special case here.
-    return &X86::GR32_NOREX_NOSPRegClass;
-  case 4: // Available for tailcall (not callee-saved GPRs).
-    return Is64Bit ? &X86::GR64_TCRegClass : &X86::GR32_TCRegClass;
-  }
+  assert(Kind == 0 && "this should only be used for default cases");
+  if (IsTarget64BitLP64)
+    return &X86::GR64RegClass;
+  // If the target is 64bit but we have been told to use 32bit addresses,
+  // we can still use 64-bit register as long as we know the high bits
+  // are zeros.
+  // Reflect that in the returned register class.
+  return Is64Bit ? &X86::LOW32_ADDR_ACCESSRegClass : &X86::GR32RegClass;
 }
 
 const TargetRegisterClass *
diff --git a/llvm/lib/Target/X86/X86Subtarget.h b/llvm/lib/Target/X86/X86Subtarget.h
index fa3f3b59741df..a8802c4bf164d 100644
--- a/llvm/lib/Target/X86/X86Subtarget.h
+++ b/llvm/lib/Target/X86/X86Subtarget.h
@@ -170,10 +170,10 @@ class X86Subtarget final : public X86GenSubtargetInfo {
 #include "X86GenSubtargetInfo.inc"
 
   /// Is this x86_64 with the ILP32 programming model (x32 ABI)?
-  bool isTarget64BitILP32() const { return Is64Bit && (TargetTriple.isX32()); }
+  bool isTarget64BitILP32() const { return Is64Bit && IsX32; }
 
   /// Is this x86_64 with the LP64 programming model (standard AMD64, no x32)?
-  bool isTarget64BitLP64() const { return Is64Bit && (!TargetTriple.isX32()); }
+  bool isTarget64BitLP64() const { return Is64Bit && !IsX32; }
 
   PICStyles::Style getPICStyle() const { return PICStyle; }
   void setPICStyle(PICStyles::Style Style)  { PICStyle = Style; }
diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
index b1f7b9a6b4ad9..1e1e4ab650030 100644
--- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
@@ -553,10 +553,10 @@ void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInst,
     for (unsigned I = RegOutSize, E = RegInst->Operands.size(); I < E; I++) {
       const Record *RegOpRec = RegInst->Operands[I].Rec;
       const Record *MemOpRec = MemInst->Operands[I].Rec;
-      // PointerLikeRegClass: For instructions like TAILJMPr, TAILJMPr64,
+      // RegClassByHwMode: For instructions like TAILJMPr, TAILJMPr64,
       // TAILJMPr64_REX
       if ((isRegisterOperand(RegOpRec) ||
-           RegOpRec->isSubClassOf("PointerLikeRegClass")) &&
+           (RegOpRec->isSubClassOf("RegClassByHwMode"))) &&
           isMemoryOperand(MemOpRec)) {
         switch (I) {
         case 0:

@arsenm arsenm force-pushed the users/arsenm/codegen/targetinstrinfo-add-regclass-by-hwmode branch from ba508eb to b0954df Compare September 15, 2025 11:40
@arsenm arsenm force-pushed the users/arsenm/x86/use-regclassbyhwmode branch from cbdfe4d to 1a85c9c Compare September 15, 2025 11:40
@arsenm arsenm force-pushed the users/arsenm/codegen/targetinstrinfo-add-regclass-by-hwmode branch from b0954df to 480926a Compare September 16, 2025 04:51
@arsenm arsenm force-pushed the users/arsenm/x86/use-regclassbyhwmode branch 2 times, most recently from ca5e60c to f2baeeb Compare September 17, 2025 15:22
@arsenm arsenm force-pushed the users/arsenm/codegen/targetinstrinfo-add-regclass-by-hwmode branch from 480926a to bdfdc33 Compare September 17, 2025 15:22
Replace the target uses of PointerLikeRegClass with RegClassByHwMode
@arsenm arsenm force-pushed the users/arsenm/x86/use-regclassbyhwmode branch from f2baeeb to 1a834b6 Compare September 18, 2025 00:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants