Skip to content

[InstCombine] Canonicalize icmp eq/ne (A ^ C), B to icmp eq/ne (A ^ B), C #67273

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

Merged
merged 3 commits into from
Sep 26, 2023

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Sep 24, 2023

This patch canonicalizes icmp eq/ne (A ^ Cst), B to icmp eq/ne (A ^ B), Cst since the latter form exposes more optimizations.
Proof: https://alive2.llvm.org/ce/z/9DbhGc
Fixes #65968.

@llvmbot
Copy link
Member

llvmbot commented Sep 24, 2023

@llvm/pr-subscribers-llvm-transforms

Changes

This patch canonicalizes icmp eq/ne (A ^ Cst), B to icmp eq/ne (A ^ B), Cst since the latter form exposes more optimizations.
Proof: https://alive2.llvm.org/ce/z/9DbhGc
Fixes #65968.


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

3 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+9)
  • (modified) llvm/test/Transforms/InstCombine/icmp-equality-xor.ll (+12-16)
  • (modified) llvm/test/Transforms/InstCombine/icmp-or.ll (+2-2)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 0903cd3f37b0f50..1a601ce46377e73 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -5437,6 +5437,15 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
         Pred, A,
         Builder.CreateIntrinsic(Op0->getType(), Intrinsic::fshl, {A, A, B}));
 
+  // Canonicalize:
+  // icmp eq/ne OneUse(A ^ Cst), B --> icmp eq/ne (A ^ B), Cst
+  Constant *Cst;
+  if (match(&I,
+            m_c_ICmp(PredUnused, m_OneUse(m_Xor(m_Value(A), m_Constant(Cst))),
+                     m_Value(B))))
+    return ICmpInst::Create(Instruction::ICmp, Pred, Builder.CreateXor(A, B),
+                            Cst);
+
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll b/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll
index 4443ee40049a1ab..8729f362c5bdb97 100644
--- a/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll
@@ -4,8 +4,8 @@
 declare void @use(i32)
 define i1 @cmpeq_xor_cst1(i32 %a, i32 %b) {
 ; CHECK-LABEL: @cmpeq_xor_cst1(
-; CHECK-NEXT:    [[C:%.*]] = xor i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %c = xor i32 %a, 10
@@ -37,8 +37,8 @@ define i1 @cmpeq_xor_cst3(i32 %a, i32 %b) {
 
 define i1 @cmpne_xor_cst1(i32 %a, i32 %b) {
 ; CHECK-LABEL: @cmpne_xor_cst1(
-; CHECK-NEXT:    [[C:%.*]] = xor i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[TMP1]], 10
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %c = xor i32 %a, 10
@@ -83,8 +83,8 @@ define i1 @cmpeq_xor_cst1_multiuse(i32 %a, i32 %b) {
 
 define i1 @cmpeq_xor_cst1_commuted(i32 %a, i32 %b) {
 ; CHECK-LABEL: @cmpeq_xor_cst1_commuted(
-; CHECK-NEXT:    [[C:%.*]] = xor i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP1]], 10
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %c = xor i32 %a, 10
@@ -94,8 +94,8 @@ define i1 @cmpeq_xor_cst1_commuted(i32 %a, i32 %b) {
 
 define <2 x i1> @cmpeq_xor_cst1_vec(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-LABEL: @cmpeq_xor_cst1_vec(
-; CHECK-NEXT:    [[C:%.*]] = xor <2 x i32> [[A:%.*]], <i32 10, i32 11>
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[TMP1]], <i32 10, i32 11>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %c = xor <2 x i32> %a, <i32 10, i32 11>
@@ -106,10 +106,8 @@ define <2 x i1> @cmpeq_xor_cst1_vec(<2 x i32> %a, <2 x i32> %b) {
 ; tests from PR65968
 define i1 @foo1(i32 %x, i32 %y) {
 ; CHECK-LABEL: @foo1(
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], -2147483648
-; CHECK-NEXT:    [[NEG:%.*]] = and i32 [[Y:%.*]], -2147483648
-; CHECK-NEXT:    [[AND1:%.*]] = xor i32 [[NEG]], -2147483648
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    [[NEG1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[NEG1]], 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %and = and i32 %x, -2147483648
@@ -121,10 +119,8 @@ define i1 @foo1(i32 %x, i32 %y) {
 
 define i1 @foo2(i32 %x, i32 %y) {
 ; CHECK-LABEL: @foo2(
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], -2147483648
-; CHECK-NEXT:    [[NEG:%.*]] = and i32 [[Y:%.*]], -2147483648
-; CHECK-NEXT:    [[AND1:%.*]] = xor i32 [[NEG]], -2147483648
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], [[AND1]]
+; CHECK-NEXT:    [[NEG1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[NEG1]], 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %and = and i32 %x, -2147483648
diff --git a/llvm/test/Transforms/InstCombine/icmp-or.ll b/llvm/test/Transforms/InstCombine/icmp-or.ll
index 6578cf753e2b9db..922845c1e7e2d82 100644
--- a/llvm/test/Transforms/InstCombine/icmp-or.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-or.ll
@@ -172,8 +172,8 @@ define i1 @eq_const_mask_not_same(i8 %x, i8 %y) {
 define i1 @eq_const_mask_wrong_opcode(i8 %x, i8 %y) {
 ; CHECK-LABEL: @eq_const_mask_wrong_opcode(
 ; CHECK-NEXT:    [[B0:%.*]] = or i8 [[X:%.*]], 5
-; CHECK-NEXT:    [[B1:%.*]] = xor i8 [[Y:%.*]], 5
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[B0]], [[B1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[B0]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 5
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %b0 = or i8 %x, 5

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.

Sounds plausible, LGTM.

@dtcxzyw dtcxzyw merged commit e158add into llvm:main Sep 26, 2023
@dtcxzyw dtcxzyw deleted the icmp-equality-xor branch September 26, 2023 11:33
@dyung
Copy link
Collaborator

dyung commented Sep 29, 2023

@dtcxzyw this change seems to be causing an infinite loop in the compiler in some of our tests. Can you take a look at #67783?

dtcxzyw added a commit that referenced this pull request Sep 29, 2023
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.

Simplification Comparison (Clang15 vs Clang16)
5 participants