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

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 24 13:58:48 PDT 2023


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/67273

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.

>From 4a59de712f25db1a6aec77df4ce0cb612dc49e9f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 25 Sep 2023 04:39:37 +0800
Subject: [PATCH] [InstCombine] Canonicalize `icmp eq/ne (A ^ C), B` to `icmp
 eq/ne (A ^ B), C`

---
 .../InstCombine/InstCombineCompares.cpp       |  9 ++++++
 .../InstCombine/icmp-equality-xor.ll          | 28 ++++++++-----------
 llvm/test/Transforms/InstCombine/icmp-or.ll   |  4 +--
 3 files changed, 23 insertions(+), 18 deletions(-)

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



More information about the llvm-commits mailing list