[llvm] [InstCombine] Fold icmp (zext X), (and (trunc Y), Mask) -> icmp X, trunc Y (PR #221189)

armandeep singh via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 15 12:03:13 PDT 2026


================
@@ -5327,6 +5328,36 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
 
   Value *X;
 
+  // Catch the mirrored operand order: icmp Pred (and (trunc Y), Mask), (zext
+  // X). Canonicalization (like ugt -> ult) often swaps operands, pushing the
+  // zext to Operand 1. We need to handle this to avoid missing optimizations.
+  {
+    Value *X, *Y;
+    const APInt *Mask;
+
+    // Ensure we have an unsigned compare with a zext on the right side.
+    // Then look for our one use AND with a mask on the left.
+    if (match(I.getOperand(1), m_ZExt(m_Value(X))) && !I.isSigned() &&
+        match(I.getOperand(0),
+              m_OneUse(m_And(m_Trunc(m_Value(Y)), m_APInt(Mask))))) {
+
+      Type *SmallType = X->getType();
+      unsigned SmallWidth = SmallType->getScalarSizeInBits();
+
+      // If the mask exactly covers the bits of the narrower type, the higher
+      // bits are already guaranteed to be zero. We can bypass the extension and
+      // compare the truncated values directly.
+      if (Mask->isMask(SmallWidth)) {
+        Value *NewTrunc = Builder.CreateTrunc(Y, SmallType);
+
+        // Preserve the original comparison logic by swapping the predicate back
+        // and comparing our newly truncated Y against X.
+
+        return new ICmpInst(I.getUnsignedPredicate(), NewTrunc, X);
----------------
armandeep23947 wrote:

updated.

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


More information about the llvm-commits mailing list