[llvm] [InstCombine] Fold xored one-complemented operand comparisons (PR #69882)

via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 24 07:42:10 PDT 2023


https://github.com/elhewaty updated https://github.com/llvm/llvm-project/pull/69882

>From 52f74973cd095ddee69913d6835e9c8c526d3fb5 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sun, 22 Oct 2023 12:11:21 +0300
Subject: [PATCH 1/6] [InstCombine] Add test coverage for comparisons of
 operands including one-complemented oparands(NFC).

---
 .../Transforms/InstCombine/icmp-of-xor-x.ll   | 120 ++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 9b6572697cf5e8f..6e17443807ae25a 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -4,6 +4,126 @@
 declare void @llvm.assume(i1)
 declare void @barrier()
 
+define i32 @test_slt_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_slt_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp slt i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
+define i32 @test_sle_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_sle_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp sle i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
+define i32 @test_sgt_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_sgt_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp sgt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp sgt i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
+define i32 @test_sge_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_sge_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp sge i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
+define i32 @test_ult_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_ult_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp ult i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
+define i32 @test_ule_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_ule_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp ule i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
+define i32 @test_ugt_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_ugt_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp ugt i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
+define i32 @test_uge_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_uge_xor(
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %3 = xor i32 %0, -1
+  %4 = xor i32 %3, %1
+  %5 = icmp uge i32 %4, %3
+  %6 = zext i1 %5 to i32
+  ret i32 %6
+}
+
 define i1 @xor_uge(i8 %x, i8 %y) {
 ; CHECK-LABEL: @xor_uge(
 ; CHECK-NEXT:    [[YNZ:%.*]] = icmp ne i8 [[Y:%.*]], 0

>From 1a4e700abfa7c9b84c9817cf95f33f0d69dffc53 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sun, 22 Oct 2023 18:07:40 +0300
Subject: [PATCH 2/6] [InstCombine] Fold xored one-complemented operand
 comparisons.

---
 .../InstCombine/InstCombineCompares.cpp       | 29 ++++++++
 .../Transforms/InstCombine/icmp-of-xor-x.ll   | 72 +++++++++----------
 2 files changed, 61 insertions(+), 40 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 66e2b6c72cce46c..4c19edfb27d2f2b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6929,6 +6929,23 @@ static Instruction *foldReductionIdiom(ICmpInst &I,
   return nullptr;
 }
 
+// Gets the inverse of the predicate, but not the full predicate,
+// it doesn't change the equality, e.g SLE <-> SGE, SLT <-> SGT,
+// ULE <-> UGE, ULT <-> UGT
+static ICmpInst::Predicate ConvertPred(ICmpInst::Predicate Pred) {
+  switch(Pred) {
+    case ICmpInst::ICMP_SLE: return ICmpInst::ICMP_SGE;
+    case ICmpInst::ICMP_SGE: return ICmpInst::ICMP_SLE;
+    case ICmpInst::ICMP_SLT: return ICmpInst::ICMP_SGT;
+    case ICmpInst::ICMP_SGT: return ICmpInst::ICMP_SLT;
+    case ICmpInst::ICMP_ULE: return ICmpInst::ICMP_UGE;
+    case ICmpInst::ICMP_UGE: return ICmpInst::ICMP_ULE;
+    case ICmpInst::ICMP_ULT: return ICmpInst::ICMP_UGT;
+    case ICmpInst::ICMP_UGT: return ICmpInst::ICMP_ULT;
+    default: llvm_unreachable("Invalid Predicate");
+  }
+}
+
 Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   bool Changed = false;
   const SimplifyQuery Q = SQ.getWithInstruction(&I);
@@ -7127,6 +7144,18 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
       return new ICmpInst(I.getInversePredicate(), Builder.CreateAnd(A, B),
                           Op1);
 
+    // Transform (~A ^ B) s< ~A --> (A ^ B) s> A,
+    //           (~A ^ B) s> ~A --> (A ^ B) s< A,
+    //           (~A ^ B) s<= ~A --> (A ^ B) s>= A,
+    //           (~A ^ B) s>= ~A --> (A ^ B) s<= A,
+    //           (~A ^ B) u< ~A --> (A ^ B) u< A,
+    //           (~A ^ B) u> ~A --> (A ^ B) u< A,
+    //           (~A ^ B) u<= ~A --> (A ^ B) u>= A,
+    // and       (~A ^ B) u>= ~A --> (A ^ B) <= A
+    if (match(Op0, m_Xor(m_Not(m_Value(A)), m_Value(B))) &&
+        match(Op1, m_Not(m_Value(A))) && !I.isEquality())
+      return new ICmpInst(ConvertPred(Pred), Builder.CreateXor(A, B), A);
+
     // ~X < ~Y --> Y < X
     // ~X < C -->  X > ~C
     if (match(Op0, m_Not(m_Value(A)))) {
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 6e17443807ae25a..893fb868e6adc77 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -6,11 +6,10 @@ declare void @barrier()
 
 define i32 @test_slt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_slt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -21,11 +20,10 @@ define i32 @test_slt_xor(i32 %0, i32 %1) {
 
 define i32 @test_sle_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sle_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sge i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -36,11 +34,10 @@ define i32 @test_sle_xor(i32 %0, i32 %1) {
 
 define i32 @test_sgt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sgt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sgt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp slt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -51,11 +48,10 @@ define i32 @test_sgt_xor(i32 %0, i32 %1) {
 
 define i32 @test_sge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sle i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -66,11 +62,10 @@ define i32 @test_sge_xor(i32 %0, i32 %1) {
 
 define i32 @test_ult_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ult_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -81,11 +76,10 @@ define i32 @test_ult_xor(i32 %0, i32 %1) {
 
 define i32 @test_ule_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ule_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp uge i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -96,11 +90,10 @@ define i32 @test_ule_xor(i32 %0, i32 %1) {
 
 define i32 @test_ugt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ugt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -111,11 +104,10 @@ define i32 @test_ugt_xor(i32 %0, i32 %1) {
 
 define i32 @test_uge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_uge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT:    ret i32 [[TMP6]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1

>From 3f911c9b57c97d22382f3d1ef666de8b703ebbd7 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sun, 22 Oct 2023 23:38:37 +0300
Subject: [PATCH 3/6] [InstCombine] Add test coverage for comparisons of
 operands including one-complemented oparands(NFC).

---
 .../Transforms/InstCombine/icmp-of-xor-x.ll   | 220 +++++++++++++-----
 1 file changed, 161 insertions(+), 59 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 893fb868e6adc77..33e889c94932911 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -4,116 +4,218 @@
 declare void @llvm.assume(i1)
 declare void @barrier()
 
-define i32 @test_slt_xor(i32 %0, i32 %1) {
+; test for (~x ^ y) < ~z
+define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor1(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %xor = xor i8 %x, -1
+  %xor2 = xor i8 %xor, %y
+  %nz = xor i8 %z, -1
+  %r = icmp slt i8 %xor2, %nz
+  ret i1 %r
+}
+
+; test for ~z <= (x ^ ~y)
+define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor2(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %y, -1
+  %xor2 = xor i8 %xor, %x
+  %r = icmp sle i8 %nz, %xor2
+  ret i1 %r
+}
+
+; test for ~z > (~x ^ y)
+define i1 @test_xor3(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor3(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %x, -1
+  %xor2 = xor i8 %xor, %y
+  %r = icmp sgt i8 %nz, %xor2
+  ret i1 %r
+}
+
+define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor4(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %x, -1
+  %xor2 = xor i8 %xor, %y
+  %r = icmp sge i8 %xor2, %nz
+  ret i1 %r
+}
+
+define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor5(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %x, -1
+  %xor2 = xor i8 %xor, %y
+  %r = icmp ult i8 %xor2, %nz
+  ret i1 %r
+}
+
+define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor6(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %x, -1
+  %xor2 = xor i8 %xor, %y
+  %r = icmp ule i8 %xor2, %nz
+  ret i1 %r
+}
+
+define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor7(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %x, -1
+  %xor2 = xor i8 %xor, %y
+  %r = icmp ugt i8 %xor2, %nz
+  ret i1 %r
+}
+
+define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor8(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %x, -1
+  %xor2 = xor i8 %xor, %y
+  %r = icmp uge i8 %xor2, %nz
+  ret i1 %r
+}
+
+; test (~a ^ b) < ~a
+define i1 @test_slt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_slt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
   %5 = icmp slt i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  ret i1 %5
 }
 
-define i32 @test_sle_xor(i32 %0, i32 %1) {
+; test (a ^ ~b) <= ~b
+define i1 @test_sle_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sle_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp sge i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP0:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
-  %3 = xor i32 %0, -1
-  %4 = xor i32 %3, %1
+  %3 = xor i32 %1, -1
+  %4 = xor i32 %3, %0
   %5 = icmp sle i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  ret i1 %5
 }
 
-define i32 @test_sgt_xor(i32 %0, i32 %1) {
+; test ~a > (~a ^ b)
+define i1 @test_sgt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sgt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp slt i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
-  %5 = icmp sgt i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  %5 = icmp sgt i32 %3, %4
+  ret i1 %5
 }
 
-define i32 @test_sge_xor(i32 %0, i32 %1) {
+define i1 @test_sge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp sle i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
   %5 = icmp sge i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  ret i1 %5
 }
 
-define i32 @test_ult_xor(i32 %0, i32 %1) {
+define i1 @test_ult_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ult_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
   %5 = icmp ult i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  ret i1 %5
 }
 
-define i32 @test_ule_xor(i32 %0, i32 %1) {
+define i1 @test_ule_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ule_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp uge i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
   %5 = icmp ule i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  ret i1 %5
 }
 
-define i32 @test_ugt_xor(i32 %0, i32 %1) {
+define i1 @test_ugt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ugt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
   %5 = icmp ugt i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  ret i1 %5
 }
 
-define i32 @test_uge_xor(i32 %0, i32 %1) {
+define i1 @test_uge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_uge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
-; CHECK-NEXT:    ret i32 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
   %5 = icmp uge i32 %4, %3
-  %6 = zext i1 %5 to i32
-  ret i32 %6
+  ret i1 %5
 }
 
 define i1 @xor_uge(i8 %x, i8 %y) {

>From df596acb178d9d803cd98a5ceff6c979f9bb594f Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sun, 22 Oct 2023 23:58:43 +0300
Subject: [PATCH 4/6] [InstCombine] Fold xored one-complemented operand
 comparisons.

---
 .../InstCombine/InstCombineCompares.cpp       | 27 ++----
 .../Transforms/InstCombine/icmp-of-xor-x.ll   | 97 +++++++++++--------
 2 files changed, 63 insertions(+), 61 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 4c19edfb27d2f2b..1205fa76c0afbf5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6929,23 +6929,6 @@ static Instruction *foldReductionIdiom(ICmpInst &I,
   return nullptr;
 }
 
-// Gets the inverse of the predicate, but not the full predicate,
-// it doesn't change the equality, e.g SLE <-> SGE, SLT <-> SGT,
-// ULE <-> UGE, ULT <-> UGT
-static ICmpInst::Predicate ConvertPred(ICmpInst::Predicate Pred) {
-  switch(Pred) {
-    case ICmpInst::ICMP_SLE: return ICmpInst::ICMP_SGE;
-    case ICmpInst::ICMP_SGE: return ICmpInst::ICMP_SLE;
-    case ICmpInst::ICMP_SLT: return ICmpInst::ICMP_SGT;
-    case ICmpInst::ICMP_SGT: return ICmpInst::ICMP_SLT;
-    case ICmpInst::ICMP_ULE: return ICmpInst::ICMP_UGE;
-    case ICmpInst::ICMP_UGE: return ICmpInst::ICMP_ULE;
-    case ICmpInst::ICMP_ULT: return ICmpInst::ICMP_UGT;
-    case ICmpInst::ICMP_UGT: return ICmpInst::ICMP_ULT;
-    default: llvm_unreachable("Invalid Predicate");
-  }
-}
-
 Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   bool Changed = false;
   const SimplifyQuery Q = SQ.getWithInstruction(&I);
@@ -7134,7 +7117,7 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
     return Res;
 
   {
-    Value *A, *B;
+    Value *A, *B, *C;
     // Transform (A & ~B) == 0 --> (A & B) != 0
     // and       (A & ~B) != 0 --> (A & B) == 0
     // if A is a power of 2.
@@ -7152,9 +7135,11 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
     //           (~A ^ B) u> ~A --> (A ^ B) u< A,
     //           (~A ^ B) u<= ~A --> (A ^ B) u>= A,
     // and       (~A ^ B) u>= ~A --> (A ^ B) <= A
-    if (match(Op0, m_Xor(m_Not(m_Value(A)), m_Value(B))) &&
-        match(Op1, m_Not(m_Value(A))) && !I.isEquality())
-      return new ICmpInst(ConvertPred(Pred), Builder.CreateXor(A, B), A);
+    if (match(&I, m_c_ICmp(Pred, m_c_Xor(m_Not(m_Value(A)), m_Value(B)),
+                           m_Not(m_Value(C)))) &&
+        !I.isEquality())
+      return new ICmpInst(I.getSwappedPredicate(Pred), Builder.CreateXor(A, B),
+                          C);
 
     // ~X < ~Y --> Y < X
     // ~X < C -->  X > ~C
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 33e889c94932911..087e30f48dd52c1 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -3,15 +3,19 @@
 
 declare void @llvm.assume(i1)
 declare void @barrier()
+declare void @use.i8(i8)
 
 ; test for (~x ^ y) < ~z
 define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor1(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xor = xor i8 %x, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %y
   %nz = xor i8 %z, -1
   %r = icmp slt i8 %xor2, %nz
@@ -21,12 +25,15 @@ define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
 ; test for ~z <= (x ^ ~y)
 define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor2(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y]], [[X:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
   %xor = xor i8 %y, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %x
   %r = icmp sle i8 %nz, %xor2
   ret i1 %r
@@ -35,12 +42,15 @@ define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
 ; test for ~z > (~x ^ y)
 define i1 @test_xor3(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor3(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
   %xor = xor i8 %x, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %y
   %r = icmp sgt i8 %nz, %xor2
   ret i1 %r
@@ -48,12 +58,15 @@ define i1 @test_xor3(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor4(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
   %xor = xor i8 %x, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %y
   %r = icmp sge i8 %xor2, %nz
   ret i1 %r
@@ -61,12 +74,15 @@ define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor5(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
   %xor = xor i8 %x, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %y
   %r = icmp ult i8 %xor2, %nz
   ret i1 %r
@@ -74,12 +90,15 @@ define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor6(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
   %xor = xor i8 %x, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %y
   %r = icmp ule i8 %xor2, %nz
   ret i1 %r
@@ -87,12 +106,15 @@ define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor7(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
   %xor = xor i8 %x, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %y
   %r = icmp ugt i8 %xor2, %nz
   ret i1 %r
@@ -100,12 +122,15 @@ define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor8(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
   %xor = xor i8 %x, -1
+  call void @use.i8(i8 %xor)
   %xor2 = xor i8 %xor, %y
   %r = icmp uge i8 %xor2, %nz
   ret i1 %r
@@ -114,10 +139,9 @@ define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
 ; test (~a ^ b) < ~a
 define i1 @test_slt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_slt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -128,10 +152,9 @@ define i1 @test_slt_xor(i32 %0, i32 %1) {
 ; test (a ^ ~b) <= ~b
 define i1 @test_sle_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sle_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP0:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], [[TMP0:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sge i32 [[TMP3]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %1, -1
   %4 = xor i32 %3, %0
@@ -142,10 +165,9 @@ define i1 @test_sle_xor(i32 %0, i32 %1) {
 ; test ~a > (~a ^ b)
 define i1 @test_sgt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sgt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -155,10 +177,9 @@ define i1 @test_sgt_xor(i32 %0, i32 %1) {
 
 define i1 @test_sge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sle i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -168,10 +189,9 @@ define i1 @test_sge_xor(i32 %0, i32 %1) {
 
 define i1 @test_ult_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ult_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -181,10 +201,9 @@ define i1 @test_ult_xor(i32 %0, i32 %1) {
 
 define i1 @test_ule_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ule_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp uge i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -194,10 +213,9 @@ define i1 @test_ule_xor(i32 %0, i32 %1) {
 
 define i1 @test_ugt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ugt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -207,10 +225,9 @@ define i1 @test_ugt_xor(i32 %0, i32 %1) {
 
 define i1 @test_uge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_uge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1

>From 28961c877ce73c4edb57adf7feb4364f6d8b31ae Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Tue, 24 Oct 2023 16:54:14 +0300
Subject: [PATCH 5/6] [InstCombine] Add test coverage for comparisons of
 operands including one-complemented oparands(NFC)

---
 .../Transforms/InstCombine/icmp-of-xor-x.ll   | 124 ++++++++++++------
 1 file changed, 84 insertions(+), 40 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 087e30f48dd52c1..74ffc9f39c849d0 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -10,8 +10,9 @@ define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor1(
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xor = xor i8 %x, -1
@@ -25,10 +26,11 @@ define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
 ; test for ~z <= (x ^ ~y)
 define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor2(
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[Y:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sge i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -42,10 +44,11 @@ define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
 ; test for ~z > (~x ^ y)
 define i1 @test_xor3(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor3(
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -56,12 +59,41 @@ define i1 @test_xor3(i8 %x, i8 %y, i8 %z) {
   ret i1 %r
 }
 
+; tests for equality
+define i1 @test_xor_ne(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor_ne(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %y, -1
+  %xor2 = xor i8 %xor, %x
+  %r = icmp ne i8 %nz, %xor2
+  ret i1 %r
+}
+
+define i1 @test_xor_eq(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @test_xor_e1(
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %nz = xor i8 %z, -1
+  %xor = xor i8 %y, -1
+  %xor2 = xor i8 %xor, %x
+  %r = icmp eq i8 %nz, %xor2
+  ret i1 %r
+}
+
+; other tests
 define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor4(
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sge i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -74,10 +106,11 @@ define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor5(
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -90,10 +123,11 @@ define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor6(
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -106,10 +140,11 @@ define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor7(
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -122,10 +157,11 @@ define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor8(
+; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[XOR2]], [[NZ]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -139,9 +175,10 @@ define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
 ; test (~a ^ b) < ~a
 define i1 @test_slt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_slt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -152,9 +189,10 @@ define i1 @test_slt_xor(i32 %0, i32 %1) {
 ; test (a ^ ~b) <= ~b
 define i1 @test_sle_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sle_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], [[TMP0:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp sge i32 [[TMP3]], [[TMP1]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP0:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %1, -1
   %4 = xor i32 %3, %0
@@ -165,9 +203,10 @@ define i1 @test_sle_xor(i32 %0, i32 %1) {
 ; test ~a > (~a ^ b)
 define i1 @test_sgt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sgt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -177,9 +216,10 @@ define i1 @test_sgt_xor(i32 %0, i32 %1) {
 
 define i1 @test_sge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp sle i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -189,9 +229,10 @@ define i1 @test_sge_xor(i32 %0, i32 %1) {
 
 define i1 @test_ult_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ult_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -201,9 +242,10 @@ define i1 @test_ult_xor(i32 %0, i32 %1) {
 
 define i1 @test_ule_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ule_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp uge i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -213,9 +255,10 @@ define i1 @test_ule_xor(i32 %0, i32 %1) {
 
 define i1 @test_ugt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ugt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -225,9 +268,10 @@ define i1 @test_ugt_xor(i32 %0, i32 %1) {
 
 define i1 @test_uge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_uge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[TMP3]], [[TMP0]]
-; CHECK-NEXT:    ret i1 [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1

>From 1f52ac639953f76df206431d5292dda0a6ea0bde Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Tue, 24 Oct 2023 16:58:02 +0300
Subject: [PATCH 6/6] [InstCombine] Fold xored one-complemented operand
 comparisons.

---
 .../InstCombine/InstCombineCompares.cpp       | 15 +--
 .../Transforms/InstCombine/icmp-of-xor-x.ll   | 98 ++++++++-----------
 2 files changed, 49 insertions(+), 64 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 1205fa76c0afbf5..c68f4ae1c93d8bf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7127,17 +7127,18 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
       return new ICmpInst(I.getInversePredicate(), Builder.CreateAnd(A, B),
                           Op1);
 
-    // Transform (~A ^ B) s< ~A --> (A ^ B) s> A,
-    //           (~A ^ B) s> ~A --> (A ^ B) s< A,
+    // Transform (~A ^ B) s< ~A  --> (A ^ B) s> A,
+    //           (~A ^ B) s> ~A  --> (A ^ B) s< A,
     //           (~A ^ B) s<= ~A --> (A ^ B) s>= A,
     //           (~A ^ B) s>= ~A --> (A ^ B) s<= A,
-    //           (~A ^ B) u< ~A --> (A ^ B) u< A,
-    //           (~A ^ B) u> ~A --> (A ^ B) u< A,
+    //           (~A ^ B) u< ~A  --> (A ^ B) u< A,
+    //           (~A ^ B) u> ~A  --> (A ^ B) u< A,
     //           (~A ^ B) u<= ~A --> (A ^ B) u>= A,
-    // and       (~A ^ B) u>= ~A --> (A ^ B) <= A
+    //           (~A ^ B) u>= ~A --> (A ^ B) <= A
+    //           (~A ^ B) == ~A  --> (A ^ B) != A
+    // and       (~A ^ B) != ~A  --> (A ^ B) == A
     if (match(&I, m_c_ICmp(Pred, m_c_Xor(m_Not(m_Value(A)), m_Value(B)),
-                           m_Not(m_Value(C)))) &&
-        !I.isEquality())
+                           m_Not(m_Value(C)))))
       return new ICmpInst(I.getSwappedPredicate(Pred), Builder.CreateXor(A, B),
                           C);
 
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 74ffc9f39c849d0..42299cd090e3cce 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -10,9 +10,8 @@ define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor1(
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xor = xor i8 %x, -1
@@ -26,11 +25,10 @@ define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
 ; test for ~z <= (x ^ ~y)
 define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor2(
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[Y:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp sge i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -44,11 +42,10 @@ define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
 ; test for ~z > (~x ^ y)
 define i1 @test_xor3(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor3(
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -74,7 +71,7 @@ define i1 @test_xor_ne(i8 %x, i8 %y, i8 %z) {
 }
 
 define i1 @test_xor_eq(i8 %x, i8 %y, i8 %z) {
-; CHECK-LABEL: @test_xor_e1(
+; CHECK-LABEL: @test_xor_eq(
 ; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], [[X:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
@@ -89,11 +86,10 @@ define i1 @test_xor_eq(i8 %x, i8 %y, i8 %z) {
 ; other tests
 define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor4(
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp sge i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -106,11 +102,10 @@ define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor5(
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -123,11 +118,10 @@ define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor6(
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -140,11 +134,10 @@ define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor7(
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -157,11 +150,10 @@ define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
 
 define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @test_xor8(
-; CHECK-NEXT:    [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use.i8(i8 [[XOR]])
-; CHECK-NEXT:    [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[XOR2]], [[NZ]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[TMP1]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nz = xor i8 %z, -1
@@ -175,10 +167,9 @@ define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
 ; test (~a ^ b) < ~a
 define i1 @test_slt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_slt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -189,10 +180,9 @@ define i1 @test_slt_xor(i32 %0, i32 %1) {
 ; test (a ^ ~b) <= ~b
 define i1 @test_sle_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sle_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP0:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], [[TMP0:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sge i32 [[TMP3]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %1, -1
   %4 = xor i32 %3, %0
@@ -203,10 +193,9 @@ define i1 @test_sle_xor(i32 %0, i32 %1) {
 ; test ~a > (~a ^ b)
 define i1 @test_sgt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sgt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -216,10 +205,9 @@ define i1 @test_sgt_xor(i32 %0, i32 %1) {
 
 define i1 @test_sge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_sge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp sle i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -229,10 +217,9 @@ define i1 @test_sge_xor(i32 %0, i32 %1) {
 
 define i1 @test_ult_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ult_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -242,10 +229,9 @@ define i1 @test_ult_xor(i32 %0, i32 %1) {
 
 define i1 @test_ule_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ule_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp uge i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -255,10 +241,9 @@ define i1 @test_ule_xor(i32 %0, i32 %1) {
 
 define i1 @test_ugt_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_ugt_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1
@@ -268,10 +253,9 @@ define i1 @test_ugt_xor(i32 %0, i32 %1) {
 
 define i1 @test_uge_xor(i32 %0, i32 %1) {
 ; CHECK-LABEL: @test_uge_xor(
-; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT:    [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT:    ret i1 [[TMP5]]
+; CHECK-NEXT:    [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ule i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT:    ret i1 [[TMP4]]
 ;
   %3 = xor i32 %0, -1
   %4 = xor i32 %3, %1



More information about the llvm-commits mailing list