Skip to content

[InstSimplify] Fold and A, (zext (icmp eq A, 0)) into 0 #66676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Sep 18, 2023

This patch folds the pattern and A, (zext (icmp eq A, 0)) into 0.
Fixes #66606.

@llvmbot
Copy link
Member

llvmbot commented Sep 18, 2023

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Changes

This patch folds the pattern and A, (zext (icmp eq A, 0)) into 0.
Fixes #66606.


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

2 Files Affected:

  • (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+7)
  • (modified) llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll (+2-8)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index e8f96e9f681f2d5..a835ca763e6565d 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2079,6 +2079,13 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
   if (match(Op0, m_Not(m_Specific(Op1))) || match(Op1, m_Not(m_Specific(Op0))))
     return Constant::getNullValue(Op0->getType());
 
+  // A & !A  =  !A & A  =  0
+  ICmpInst::Predicate EqPred;
+  if ((match(Op0, m_ZExt(m_ICmp(EqPred, m_Specific(Op1), m_Zero()))) ||
+       match(Op1, m_ZExt(m_ICmp(EqPred, m_Specific(Op0), m_Zero())))) &&
+      EqPred == ICmpInst::ICMP_EQ)
+    return Constant::getNullValue(Op0->getType());
+
   // (A | ?) & A = A
   if (match(Op0, m_c_Or(m_Specific(Op1), m_Value())))
     return Op1;
diff --git a/llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll b/llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll
index 3e50a5968b46087..022add2c4717419 100644
--- a/llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll
+++ b/llvm/test/Transforms/InstSimplify/and-or-icmp-zero.ll
@@ -265,10 +265,7 @@ define i1 @and_cmps_ptr_eq_zero_with_mask_commute4(ptr %p, i64 %y) {
 ; tests from PR66606
 define i32 @and_zext_eq_zero(i32 %a) {
 ; CHECK-LABEL: @and_zext_eq_zero(
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[NOT:%.*]] = zext i1 [[COND]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[NOT]]
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-NEXT:    ret i32 0
 ;
   %cond = icmp eq i32 %a, 0
   %not = zext i1 %cond to i32
@@ -278,10 +275,7 @@ define i32 @and_zext_eq_zero(i32 %a) {
 
 define i32 @and_zext_eq_zero_commuted(i32 %a) {
 ; CHECK-LABEL: @and_zext_eq_zero_commuted(
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[NOT:%.*]] = zext i1 [[COND]] to i32
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[NOT]], [[A]]
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-NEXT:    ret i32 0
 ;
   %cond = icmp eq i32 %a, 0
   %not = zext i1 %cond to i32

Copy link
Contributor

@goldsteinn goldsteinn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit niche, but LGTM.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general pattern here would be zext(c) & a, which is c ? (a & 1) : 0.

For the special case of c := a == C, if C is even then this reduces to 0, if C is odd it reduces to zext(c).

Possibly we shouldn't special case the a == C case though and just generally canonicalize to the select form, on which all possible folds can then be performed?

In any case, this needs to at least handle arbitrary constants.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Sep 18, 2023

The general pattern here would be zext(c) & a, which is c ? (a & 1) : 0.

For the special case of c := a == C, if C is even then this reduces to 0, if C is odd it reduces to zext(c).

Possibly we shouldn't special case the a == C case though and just generally canonicalize to the select form, on which all possible folds can then be performed?

In any case, this needs to at least handle arbitrary constants.

Proof: https://alive2.llvm.org/ce/z/xVWkj3

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Sep 19, 2023

The canonicalization is posted as #66740.

@dtcxzyw dtcxzyw closed this Sep 19, 2023
dtcxzyw added a commit that referenced this pull request Sep 28, 2023
#66740)

This patch canonicalizes the pattern `and(zext(A), B)` into `select A, B
& 1, 0`. Thus, we can reuse transforms `select B == even, B & 1, 0 -> 0`
and `select B == odd, B & 1, 0 -> zext(B == odd)` in `InstCombine`.
It is an alternative to #66676. 
Alive2: https://alive2.llvm.org/ce/z/598phE
Fixes #66733.
Fixes #66606.
Fixes #28612.
legrosbuffle pushed a commit to legrosbuffle/llvm-project that referenced this pull request Sep 29, 2023
llvm#66740)

This patch canonicalizes the pattern `and(zext(A), B)` into `select A, B
& 1, 0`. Thus, we can reuse transforms `select B == even, B & 1, 0 -> 0`
and `select B == odd, B & 1, 0 -> zext(B == odd)` in `InstCombine`.
It is an alternative to llvm#66676. 
Alive2: https://alive2.llvm.org/ce/z/598phE
Fixes llvm#66733.
Fixes llvm#66606.
Fixes llvm#28612.
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.

[InstCombine] a & !a is not optimized
4 participants