[llvm] [GlobalISel] Use GINodeEquiv for `G_PTRADD` as `add` (PR #214109)

Demetrius Kanios via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 17:54:58 PDT 2026


https://github.com/QuantumSegfault created https://github.com/llvm/llvm-project/pull/214109

None

>From 9860fc14eea4e0fba246f6ba024231518db2ac8e Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Tue, 4 Aug 2026 17:53:49 -0700
Subject: [PATCH] WIP: Try using DAG `add` instead of custom selction for
 G_PTRMASK

---
 .../Target/GlobalISel/SelectionDAGCompat.td   |   1 +
 .../GISel/AArch64InstructionSelector.cpp      |  15 ---
 .../AMDGPU/AMDGPUInstructionSelector.cpp      | 115 ------------------
 .../Target/AMDGPU/AMDGPUInstructionSelector.h |   1 -
 .../RISCV/GISel/RISCVInstructionSelector.cpp  |   8 --
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |  56 ---------
 6 files changed, 1 insertion(+), 195 deletions(-)

diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
index e06c96fa837df..1a7e99f126426 100644
--- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
+++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
@@ -82,6 +82,7 @@ def : GINodeEquiv<G_UREM, urem>;
 def : GINodeEquiv<G_SDIVREM, sdivrem>;
 def : GINodeEquiv<G_UDIVREM, udivrem>;
 def : GINodeEquiv<G_AND, and>;
+def : GINodeEquiv<G_PTRMASK, and>;
 def : GINodeEquiv<G_OR, or>;
 def : GINodeEquiv<G_XOR, xor>;
 def : GINodeEquiv<G_SHL, shl>;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 0c2f3f97ec07d..aaa39f6e8a738 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -3208,21 +3208,6 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
   case TargetOpcode::G_USUBO:
     return selectOverflowOp(I, MRI);
 
-  case TargetOpcode::G_PTRMASK: {
-    Register MaskReg = I.getOperand(2).getReg();
-    std::optional<int64_t> MaskVal = getIConstantVRegSExtVal(MaskReg, MRI);
-    // TODO: Implement arbitrary cases
-    if (!MaskVal || !isShiftedMask_64(*MaskVal))
-      return false;
-
-    uint64_t Mask = *MaskVal;
-    I.setDesc(TII.get(AArch64::ANDXri));
-    I.getOperand(2).ChangeToImmediate(
-        AArch64_AM::encodeLogicalImmediate(Mask, 64));
-
-    constrainSelectedInstRegOperands(I, TII, TRI, RBI);
-    return true;
-  }
   case TargetOpcode::G_PTRTOINT:
   case TargetOpcode::G_TRUNC: {
     const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
index 22b8b10554928..bda4b91c2a053 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
@@ -3271,119 +3271,6 @@ bool AMDGPUInstructionSelector::selectG_GLOBAL_VALUE(
     DstReg, IsVGPR ? AMDGPU::VGPR_32RegClass : AMDGPU::SReg_32RegClass, *MRI);
 }
 
-bool AMDGPUInstructionSelector::selectG_PTRMASK(MachineInstr &I) const {
-  Register DstReg = I.getOperand(0).getReg();
-  Register SrcReg = I.getOperand(1).getReg();
-  Register MaskReg = I.getOperand(2).getReg();
-  LLT Ty = MRI->getType(DstReg);
-  LLT MaskTy = MRI->getType(MaskReg);
-  MachineBasicBlock *BB = I.getParent();
-  const DebugLoc &DL = I.getDebugLoc();
-
-  const RegisterBank *DstRB = RBI.getRegBank(DstReg, *MRI, TRI);
-  const RegisterBank *SrcRB = RBI.getRegBank(SrcReg, *MRI, TRI);
-  const RegisterBank *MaskRB = RBI.getRegBank(MaskReg, *MRI, TRI);
-  const bool IsVGPR = DstRB->getID() == AMDGPU::VGPRRegBankID;
-  if (DstRB != SrcRB) // Should only happen for hand written MIR.
-    return false;
-
-  // Try to avoid emitting a bit operation when we only need to touch half of
-  // the 64-bit pointer.
-  APInt MaskOnes = VT->getKnownOnes(MaskReg).zext(64);
-  const APInt MaskHi32 = APInt::getHighBitsSet(64, 32);
-  const APInt MaskLo32 = APInt::getLowBitsSet(64, 32);
-
-  const bool CanCopyLow32 = (MaskOnes & MaskLo32) == MaskLo32;
-  const bool CanCopyHi32 = (MaskOnes & MaskHi32) == MaskHi32;
-
-  if (!IsVGPR && Ty.getSizeInBits() == 64 &&
-      !CanCopyLow32 && !CanCopyHi32) {
-    auto MIB = BuildMI(*BB, &I, DL, TII.get(AMDGPU::S_AND_B64), DstReg)
-      .addReg(SrcReg)
-      .addReg(MaskReg)
-      .setOperandDead(3); // Dead scc
-    I.eraseFromParent();
-    constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
-    return true;
-  }
-
-  unsigned NewOpc = IsVGPR ? AMDGPU::V_AND_B32_e64 : AMDGPU::S_AND_B32;
-  const TargetRegisterClass &RegRC
-    = IsVGPR ? AMDGPU::VGPR_32RegClass : AMDGPU::SReg_32RegClass;
-
-  const TargetRegisterClass *DstRC = TRI.getRegClassForTypeOnBank(Ty, *DstRB);
-  const TargetRegisterClass *SrcRC = TRI.getRegClassForTypeOnBank(Ty, *SrcRB);
-  const TargetRegisterClass *MaskRC =
-      TRI.getRegClassForTypeOnBank(MaskTy, *MaskRB);
-
-  if (!RBI.constrainGenericRegister(DstReg, *DstRC, *MRI) ||
-      !RBI.constrainGenericRegister(SrcReg, *SrcRC, *MRI) ||
-      !RBI.constrainGenericRegister(MaskReg, *MaskRC, *MRI))
-    return false;
-
-  if (Ty.getSizeInBits() == 32) {
-    assert(MaskTy.getSizeInBits() == 32 &&
-           "ptrmask should have been narrowed during legalize");
-
-    auto NewOp = BuildMI(*BB, &I, DL, TII.get(NewOpc), DstReg)
-      .addReg(SrcReg)
-      .addReg(MaskReg);
-
-    if (!IsVGPR)
-      NewOp.setOperandDead(3); // Dead scc
-    I.eraseFromParent();
-    return true;
-  }
-
-  Register HiReg = MRI->createVirtualRegister(&RegRC);
-  Register LoReg = MRI->createVirtualRegister(&RegRC);
-
-  // Extract the subregisters from the source pointer.
-  BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), LoReg)
-      .addReg(SrcReg, {}, AMDGPU::sub0);
-  BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), HiReg)
-      .addReg(SrcReg, {}, AMDGPU::sub1);
-
-  Register MaskedLo, MaskedHi;
-
-  if (CanCopyLow32) {
-    // If all the bits in the low half are 1, we only need a copy for it.
-    MaskedLo = LoReg;
-  } else {
-    // Extract the mask subregister and apply the and.
-    Register MaskLo = MRI->createVirtualRegister(&RegRC);
-    MaskedLo = MRI->createVirtualRegister(&RegRC);
-
-    BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), MaskLo)
-        .addReg(MaskReg, {}, AMDGPU::sub0);
-    BuildMI(*BB, &I, DL, TII.get(NewOpc), MaskedLo)
-      .addReg(LoReg)
-      .addReg(MaskLo);
-  }
-
-  if (CanCopyHi32) {
-    // If all the bits in the high half are 1, we only need a copy for it.
-    MaskedHi = HiReg;
-  } else {
-    Register MaskHi = MRI->createVirtualRegister(&RegRC);
-    MaskedHi = MRI->createVirtualRegister(&RegRC);
-
-    BuildMI(*BB, &I, DL, TII.get(AMDGPU::COPY), MaskHi)
-        .addReg(MaskReg, {}, AMDGPU::sub1);
-    BuildMI(*BB, &I, DL, TII.get(NewOpc), MaskedHi)
-      .addReg(HiReg)
-      .addReg(MaskHi);
-  }
-
-  BuildMI(*BB, &I, DL, TII.get(AMDGPU::REG_SEQUENCE), DstReg)
-    .addReg(MaskedLo)
-    .addImm(AMDGPU::sub0)
-    .addReg(MaskedHi)
-    .addImm(AMDGPU::sub1);
-  I.eraseFromParent();
-  return true;
-}
-
 /// Return the register to use for the index value, and the subregister to use
 /// for the indirectly accessed register.
 static std::pair<Register, unsigned>
@@ -4671,8 +4558,6 @@ bool AMDGPUInstructionSelector::select(MachineInstr &I) {
     return selectG_BRCOND(I);
   case TargetOpcode::G_GLOBAL_VALUE:
     return selectG_GLOBAL_VALUE(I);
-  case TargetOpcode::G_PTRMASK:
-    return selectG_PTRMASK(I);
   case TargetOpcode::G_EXTRACT_VECTOR_ELT:
     return selectG_EXTRACT_VECTOR_ELT(I);
   case TargetOpcode::G_INSERT_VECTOR_ELT:
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
index 1f9531ce2fa13..c5778d313ed2f 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
@@ -141,7 +141,6 @@ class AMDGPUInstructionSelector final : public InstructionSelector {
   bool selectG_SELECT(MachineInstr &I) const;
   bool selectG_BRCOND(MachineInstr &I) const;
   bool selectG_GLOBAL_VALUE(MachineInstr &I) const;
-  bool selectG_PTRMASK(MachineInstr &I) const;
   bool selectG_EXTRACT_VECTOR_ELT(MachineInstr &I) const;
   bool selectG_INSERT_VECTOR_ELT(MachineInstr &I) const;
   bool selectBufferLoadLds(MachineInstr &MI) const;
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 16af89c715861..c468aa369d92c 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -1505,14 +1505,6 @@ void RISCVInstructionSelector::preISelLower(MachineInstr &MI) {
     MRI->setType(DstReg, sXLen);
     break;
   }
-  case TargetOpcode::G_PTRMASK: {
-    Register DstReg = MI.getOperand(0).getReg();
-    const LLT sXLen = LLT::scalar(STI.getXLen());
-    replacePtrWithInt(MI.getOperand(1));
-    MI.setDesc(TII.get(TargetOpcode::G_AND));
-    MRI->setType(DstReg, sXLen);
-    break;
-  }
   }
 }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index f798cfe9641be..d1ccae1c01814 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1288,8 +1288,6 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
     return selectBitcast(ResVReg, ResType, I);
   case TargetOpcode::G_ADDRSPACE_CAST:
     return selectAddrSpaceCast(ResVReg, ResType, I);
-  case TargetOpcode::G_PTRMASK:
-    return selectPtrMask(ResVReg, ResType, I);
   case TargetOpcode::G_PTR_ADD: {
     // Currently, we get G_PTR_ADD only applied to global variables.
     assert(I.getOperand(1).isReg() && I.getOperand(2).isReg());
@@ -2936,60 +2934,6 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
   return false;
 }
 
-// G_PTRMASK - Apply a bitmask to a pointer value.
-// Result = Ptr & Mask
-// We need to convert the pointer to an integer, perform the AND operation,
-// and convert back to a pointer.
-bool SPIRVInstructionSelector::selectPtrMask(Register ResVReg,
-                                             SPIRVTypeInst ResType,
-                                             MachineInstr &I) const {
-  if (STI.isLogicalSPIRV())
-    return diagnoseUnsupported(
-        I, "G_PTRMASK is not supported with logical SPIR-V");
-  MachineBasicBlock &BB = *I.getParent();
-  MachineFunction &MF = *BB.getParent();
-  const DebugLoc &DL = I.getDebugLoc();
-
-  Register PtrReg = I.getOperand(1).getReg();
-  Register MaskReg = I.getOperand(2).getReg();
-
-  SPIRVTypeInst MaskType = GR.getSPIRVTypeForVReg(MaskReg);
-
-  // Convert pointer to integer.
-  Register PtrAsInt = MRI->createVirtualRegister(GR.getRegClass(MaskType));
-  GR.assignSPIRVTypeToVReg(MaskType, PtrAsInt, MF);
-
-  BuildMI(BB, I, DL, TII.get(SPIRV::OpConvertPtrToU))
-      .addDef(PtrAsInt)
-      .addUse(GR.getSPIRVTypeID(MaskType))
-      .addUse(PtrReg)
-      .constrainAllUses(TII, TRI, RBI);
-
-  // Perform bitwise AND.
-  Register MaskedInt = MRI->createVirtualRegister(GR.getRegClass(MaskType));
-  GR.assignSPIRVTypeToVReg(MaskType, MaskedInt, MF);
-
-  unsigned AndOpcode = GR.getScalarOrVectorComponentCount(MaskType) > 1
-                           ? SPIRV::OpBitwiseAndV
-                           : SPIRV::OpBitwiseAndS;
-
-  BuildMI(BB, I, DL, TII.get(AndOpcode))
-      .addDef(MaskedInt)
-      .addUse(GR.getSPIRVTypeID(MaskType))
-      .addUse(PtrAsInt)
-      .addUse(MaskReg)
-      .constrainAllUses(TII, TRI, RBI);
-
-  // Convert integer back to pointer.
-  BuildMI(BB, I, DL, TII.get(SPIRV::OpConvertUToPtr))
-      .addDef(ResVReg)
-      .addUse(GR.getSPIRVTypeID(ResType))
-      .addUse(MaskedInt)
-      .constrainAllUses(TII, TRI, RBI);
-
-  return true;
-}
-
 static unsigned getFCmpOpcode(unsigned PredNum) {
   auto Pred = static_cast<CmpInst::Predicate>(PredNum);
   switch (Pred) {



More information about the llvm-commits mailing list