[llvm] [InstSimplify] Simplify `icmp X & C1, X & C2` when `(C1 & C2) == C1/C2` (PR #65905)

via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 17 05:44:06 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

<details>
<summary>Changes</summary>

This patch simplifies the pattern `icmp X & C1, X & C2` when one constant mask is the subset of the other.
Alive2: https://alive2.llvm.org/ce/z/s-IEK7
Fixes #<!-- -->65833.

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


3 Files Affected:

- (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+27-1) 
- (modified) llvm/test/Transforms/InstSimplify/compare.ll (+9-36) 
- (modified) llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll (+6-14) 


``````````diff
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 2a3011075e47ed7..1ca1f27b9ab992d 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3427,7 +3427,7 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS,
     switch (LBO->getOpcode()) {
     default:
       break;
-    case Instruction::Shl:
+    case Instruction::Shl: {
       bool NUW = Q.IIQ.hasNoUnsignedWrap(LBO) && Q.IIQ.hasNoUnsignedWrap(RBO);
       bool NSW = Q.IIQ.hasNoSignedWrap(LBO) && Q.IIQ.hasNoSignedWrap(RBO);
       if (!NUW || (ICmpInst::isSigned(Pred) && !NSW) ||
@@ -3436,6 +3436,32 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS,
       if (Value *V = simplifyICmpInst(Pred, LBO->getOperand(1),
                                       RBO->getOperand(1), Q, MaxRecurse - 1))
         return V;
+      break;
+    }
+    // icmp X & C1, X & C2 where (C1 & C2) == C1/C2
+    // icmp X | C1, X | C2 where (C1 & C2) == C1/C2
+    case Instruction::And:
+    case Instruction::Or: {
+      if (ICmpInst::isUnsigned(Pred)) {
+        const APInt *C1, *C2;
+        if (match(LBO->getOperand(1), m_APInt(C1)) &&
+            match(RBO->getOperand(1), m_APInt(C2))) {
+          if (C1->isSubsetOf(*C2)) {
+            if (Pred == ICmpInst::ICMP_ULE)
+              return ConstantInt::getTrue(getCompareTy(LHS));
+            if (Pred == ICmpInst::ICMP_UGT)
+              return ConstantInt::getFalse(getCompareTy(LHS));
+          }
+          if (C2->isSubsetOf(*C1)) {
+            if (Pred == ICmpInst::ICMP_UGE)
+              return ConstantInt::getTrue(getCompareTy(LHS));
+            if (Pred == ICmpInst::ICMP_ULT)
+              return ConstantInt::getFalse(getCompareTy(LHS));
+          }
+        }
+      }
+      break;
+    }
     }
   }
 
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index cb3805932cbc5be..d21af97494c88bc 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -1921,10 +1921,7 @@ define i1 @tautological8(i32 %A, i32 %B) {
 
 define i1 @tautological9(i32 %A) {
 ; CHECK-LABEL: @tautological9(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 false
 ;
   %C1 = and i32 %A, 1
   %C2 = and i32 %A, 3
@@ -1934,10 +1931,7 @@ define i1 @tautological9(i32 %A) {
 
 define <2 x i1> @tautological9_vec(<2 x i32> %A) {
 ; CHECK-LABEL: @tautological9_vec(
-; CHECK-NEXT:    [[C1:%.*]] = and <2 x i32> [[A:%.*]], <i32 1, i32 1>
-; CHECK-NEXT:    [[C2:%.*]] = and <2 x i32> [[A]], <i32 3, i32 3>
-; CHECK-NEXT:    [[D:%.*]] = icmp ugt <2 x i32> [[C1]], [[C2]]
-; CHECK-NEXT:    ret <2 x i1> [[D]]
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
 ;
   %C1 = and <2 x i32> %A, <i32 1, i32 1>
   %C2 = and <2 x i32> %A, <i32 3, i32 3>
@@ -1947,10 +1941,7 @@ define <2 x i1> @tautological9_vec(<2 x i32> %A) {
 
 define i1 @tautological10(i32 %A) {
 ; CHECK-LABEL: @tautological10(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 true
 ;
   %C1 = and i32 %A, 1
   %C2 = and i32 %A, 3
@@ -1960,10 +1951,7 @@ define i1 @tautological10(i32 %A) {
 
 define i1 @tautological11(i32 %A) {
 ; CHECK-LABEL: @tautological11(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 true
 ;
   %C1 = or i32 %A, 1
   %C2 = or i32 %A, 3
@@ -1973,10 +1961,7 @@ define i1 @tautological11(i32 %A) {
 
 define i1 @tautological12(i32 %A) {
 ; CHECK-LABEL: @tautological12(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 false
 ;
   %C1 = or i32 %A, 1
   %C2 = or i32 %A, 3
@@ -1986,10 +1971,7 @@ define i1 @tautological12(i32 %A) {
 
 define i1 @tautological13(i32 %A) {
 ; CHECK-LABEL: @tautological13(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 false
 ;
   %C1 = or i32 %A, 1
   %C2 = or i32 %A, 3
@@ -1999,10 +1981,7 @@ define i1 @tautological13(i32 %A) {
 
 define i1 @tautological14(i32 %A) {
 ; CHECK-LABEL: @tautological14(
-; CHECK-NEXT:    [[C1:%.*]] = or i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = or i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 true
 ;
   %C1 = or i32 %A, 1
   %C2 = or i32 %A, 3
@@ -2012,10 +1991,7 @@ define i1 @tautological14(i32 %A) {
 
 define i1 @tautological15(i32 %A) {
 ; CHECK-LABEL: @tautological15(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 true
 ;
   %C1 = and i32 %A, 1
   %C2 = and i32 %A, 3
@@ -2025,10 +2001,7 @@ define i1 @tautological15(i32 %A) {
 
 define i1 @tautological16(i32 %A) {
 ; CHECK-LABEL: @tautological16(
-; CHECK-NEXT:    [[C1:%.*]] = and i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[C2:%.*]] = and i32 [[A]], 3
-; CHECK-NEXT:    [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
-; CHECK-NEXT:    ret i1 [[D]]
+; CHECK-NEXT:    ret i1 false
 ;
   %C1 = and i32 %A, 1
   %C2 = and i32 %A, 3
diff --git a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll
index 179de804a0c090c..8828378b5315df0 100644
--- a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll
+++ b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll
@@ -2337,9 +2337,7 @@ false:
 define i8 @umin_and_mask(i8 %x) {
 ; CHECK-LABEL: @umin_and_mask(
 ; CHECK-NEXT:    [[AND1:%.*]] = and i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[AND2:%.*]] = and i8 [[X]], 3
-; CHECK-NEXT:    [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]])
-; CHECK-NEXT:    ret i8 [[VAL]]
+; CHECK-NEXT:    ret i8 [[AND1]]
 ;
   %and1 = and i8 %x, 1
   %and2 = and i8 %x, 3
@@ -2349,10 +2347,8 @@ define i8 @umin_and_mask(i8 %x) {
 
 define i8 @umax_and_mask(i8 %x) {
 ; CHECK-LABEL: @umax_and_mask(
-; CHECK-NEXT:    [[AND1:%.*]] = and i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[AND2:%.*]] = and i8 [[X]], 3
-; CHECK-NEXT:    [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]])
-; CHECK-NEXT:    ret i8 [[VAL]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i8 [[X:%.*]], 3
+; CHECK-NEXT:    ret i8 [[AND2]]
 ;
   %and1 = and i8 %x, 1
   %and2 = and i8 %x, 3
@@ -2363,9 +2359,7 @@ define i8 @umax_and_mask(i8 %x) {
 define i8 @umin_or_mask(i8 %x) {
 ; CHECK-LABEL: @umin_or_mask(
 ; CHECK-NEXT:    [[AND1:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[AND2:%.*]] = or i8 [[X]], 3
-; CHECK-NEXT:    [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]])
-; CHECK-NEXT:    ret i8 [[VAL]]
+; CHECK-NEXT:    ret i8 [[AND1]]
 ;
   %and1 = or i8 %x, 1
   %and2 = or i8 %x, 3
@@ -2375,10 +2369,8 @@ define i8 @umin_or_mask(i8 %x) {
 
 define i8 @umax_or_mask(i8 %x) {
 ; CHECK-LABEL: @umax_or_mask(
-; CHECK-NEXT:    [[AND1:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[AND2:%.*]] = or i8 [[X]], 3
-; CHECK-NEXT:    [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]])
-; CHECK-NEXT:    ret i8 [[VAL]]
+; CHECK-NEXT:    [[AND2:%.*]] = or i8 [[X:%.*]], 3
+; CHECK-NEXT:    ret i8 [[AND2]]
 ;
   %and1 = or i8 %x, 1
   %and2 = or i8 %x, 3

``````````

</details>


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


More information about the llvm-commits mailing list