[llvm] [AMDGPU] Remove more redundant ANDs (PR #216900)

Lukas Sommer via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 01:50:47 PDT 2026


================
@@ -1855,26 +1852,74 @@ bool SIFoldOperandsImpl::tryFoldCndMask(MachineInstr &MI) const {
   return true;
 }
 
-bool SIFoldOperandsImpl::tryFoldZeroHighBits(MachineInstr &MI) const {
-  if (MI.getOpcode() != AMDGPU::V_AND_B32_e64 &&
-      MI.getOpcode() != AMDGPU::V_AND_B32_e32)
+// Eliminate redundant AND operations by detecting when ChildMI's mask contains
+// ParentMI's mask.
+//
+// For example:
+//   ParentMI: %1 = AND %0, 0x7fff
+//   ChildMI:  %2 = AND %1, 0xffff
+//
+// This also handles cases where ParentMI implicitly zeros high bits (e.g., f16
+// operations that write 16-bit results into 32-bit registers), making a
+// subsequent AND with 0xffff redundant.
+bool SIFoldOperandsImpl::tryFoldRedundantAnd(MachineInstr &ChildMI) const {
+  // Ensure implicit defs (e.g., $scc) are not live.
+  if (!ChildMI.allImplicitDefsAreDead())
     return false;
 
-  std::optional<int64_t> Src0Imm =
-      TII->getImmOrMaterializedImm(MI.getOperand(1));
-  if (!Src0Imm || *Src0Imm != 0xffff || !MI.getOperand(2).isReg())
+  // Helper to extract mask, register, and register operand index from an AND
+  // instruction. Mask can be detected in either operand 1 or 2. Returns {mask,
+  // register, operand_index}.
+  auto getMaskAndReg = [this](MachineInstr &AndMI)
+      -> std::optional<std::tuple<int64_t, Register, unsigned>> {
+    unsigned Opc = AndMI.getOpcode();
+    if (Opc != AMDGPU::V_AND_B32_e64 && Opc != AMDGPU::V_AND_B32_e32 &&
+        Opc != AMDGPU::S_AND_B32)
+      return std::nullopt;
+
+    std::optional<int64_t> MaskImm =
+        TII->getImmOrMaterializedImm(AndMI.getOperand(1));
+    if (MaskImm && AndMI.getOperand(2).isReg())
+      return std::make_tuple(*MaskImm, AndMI.getOperand(2).getReg(), 2);
+
+    MaskImm = TII->getImmOrMaterializedImm(AndMI.getOperand(2));
+    if (MaskImm && AndMI.getOperand(1).isReg())
+      return std::make_tuple(*MaskImm, AndMI.getOperand(1).getReg(), 1);
+
+    return std::nullopt;
+  };
+
+  auto ChildMaskAndReg = getMaskAndReg(ChildMI);
+  if (!ChildMaskAndReg)
     return false;
 
-  Register Src1 = MI.getOperand(2).getReg();
-  MachineInstr *SrcDef = MRI->getVRegDef(Src1);
-  if (!ST->zeroesHigh16BitsOfDest(SrcDef->getOpcode()))
+  auto [ChildMask, ChildReg, ChildRegIdx] = *ChildMaskAndReg;
+  MachineInstr *ParentMI = MRI->getVRegDef(ChildReg);
+
+  int64_t ParentMask;
+  auto ParentMaskAndReg = getMaskAndReg(*ParentMI);
+  if (ParentMaskAndReg) {
+    // Parent is an AND - extract its mask.
+    ParentMask = std::get<0>(*ParentMaskAndReg);
+  } else if (ST->zeroesHigh16BitsOfDest(ParentMI->getOpcode())) {
+    // Parent instruction implicitly zeros high 16 bits.
+    ParentMask = 0xffff;
+  } else {
     return false;
+  }
 
-  Register Dst = MI.getOperand(0).getReg();
-  MRI->replaceRegWith(Dst, Src1);
-  if (!MI.getOperand(2).isKill())
-    MRI->clearKillFlags(Src1);
-  MI.eraseFromParent();
+  // Check if ChildMI is not redundant.
+  if ((ParentMask & ChildMask) != ParentMask)
+    return false;
+
+  Register Dst = ChildMI.getOperand(0).getReg();
----------------
sommerlukas wrote:

Does this work correctly for sub-registers?

https://github.com/llvm/llvm-project/pull/216900


More information about the llvm-commits mailing list