-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
@llvm/pr-subscribers-llvm-transforms ChangesThis patch canonicalizes Full diff: https://github.com/llvm/llvm-project/pull/67273.diff 3 Files Affected:
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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds plausible, LGTM.
This patch canonicalizes
icmp eq/ne (A ^ Cst), B
toicmp eq/ne (A ^ B), Cst
since the latter form exposes more optimizations.Proof: https://alive2.llvm.org/ce/z/9DbhGc
Fixes #65968.