[llvm] [InstCombine] simplify `icmp pred x, ~x` (PR #73990)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 16 03:16:00 PDT 2024
https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/73990
>From ea9f69fec6ef5b85923036d7039dfcd08217b850 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 1 Dec 2023 06:28:23 +0900
Subject: [PATCH 1/4] [InstCombine] Add test for simplify `X comp X^Neg_C`
This patch add testcase for comparison between X and X^Neg_X.
comparison between X and X^Neg_C is determined solely by
presence of the sign bit, so we can simplify it to checking
whether X is negative or not.
---
.../Transforms/InstCombine/icmp-of-xor-x.ll | 363 ++++++++++++++++++
1 file changed, 363 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index a4e7acbca930dc..c0582e3fcc760b 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -5,6 +5,369 @@ declare void @llvm.assume(i1)
declare void @barrier()
declare void @use.i8(i8)
+; Test case of X comp X^Neg_C, which have Transform to SLT.
+; X s< X^Neg_C --> X s< 0
+define i1 @src_slt(i8 %x) {
+; CHECK-LABEL: @src_slt(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp slt i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_slt_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_slt_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp slt <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; X s<= X^Neg_C --> X s< 0
+define i1 @src_sle(i8 %x) {
+; CHECK-LABEL: @src_sle(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sle i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_sle_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_sle_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp sle <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; X u> X^Neg_C --> X s< 0
+define i1 @src_ugt(i8 %x) {
+; CHECK-LABEL: @src_ugt(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ugt i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_ugt_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_ugt_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp ugt <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; X u>= X^Neg_C --> X s< 0
+define i1 @src_uge(i8 %x) {
+; CHECK-LABEL: @src_uge(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp uge i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_uge_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_uge_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp uge <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @src_uge_vec_min(<2 x i8> %x) {
+; CHECK-LABEL: @src_uge_vec_min(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[NOT]], [[X]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -128, i8 -128>
+ %cmp = icmp uge <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @src_uge_vec_128(<2 x i128> %x) {
+; CHECK-LABEL: @src_uge_vec_128(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i128> [[X:%.*]], <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i128> [[NOT]], [[X]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
+ %cmp = icmp uge <2 x i128> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; Test case of X comp X^Neg_C, which have Transform to SGT.
+; X s> X^Neg_C --> X s> -1
+define i1 @src_sgt(i8 %x) {
+; CHECK-LABEL: @src_sgt(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sgt i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_sgt_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_sgt_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp sgt <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; X s>= X^Neg_C --> X s> -1
+define i1 @src_sge(i8 %x) {
+; CHECK-LABEL: @src_sge(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sge i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_sge_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_sge_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp sge <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; X u< X^Neg_C --> X s> -1
+define i1 @src_ult(i8 %x) {
+; CHECK-LABEL: @src_ult(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ult i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_ult_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_ult_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp ult <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; X u<= X^Neg_C --> X s> -1
+define i1 @src_ule(i8 %x) {
+; CHECK-LABEL: @src_ule(
+; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X]], [[NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ule i8 %x, %not
+ ret i1 %cmp
+}
+
+define <2 x i1> @src_ule_vec(<2 x i8> %x) {
+; CHECK-LABEL: @src_ule_vec(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -1, i8 -1>
+ %cmp = icmp ule <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @src_ule_vec_min(<2 x i8> %x) {
+; CHECK-LABEL: @src_ule_vec_min(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[NOT]], [[X]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i8> %x, <i8 -128, i8 -128>
+ %cmp = icmp ule <2 x i8> %x, %not
+ ret <2 x i1> %cmp
+}
+
+define <2 x i1> @src_ule_vec_128(<2 x i128> %x) {
+; CHECK-LABEL: @src_ule_vec_128(
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i128> [[X:%.*]], <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i128> [[NOT]], [[X]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
+ %cmp = icmp ule <2 x i128> %x, %not
+ ret <2 x i1> %cmp
+}
+
+; X comp X^Neg_C tests. negative
+; X comp Y
+define i1 @src_sle_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sle_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sle i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_sle_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sle_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sle i8 %y.not, %x
+ ret i1 %cmp
+}
+define i1 @src_sge_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sge_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sge i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_sge_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sge_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sge i8 %y.not, %x
+ ret i1 %cmp
+}
+define i1 @src_ule_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_ule_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp ule i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_ule_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_ule_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp ule i8 %y.not, %x
+ ret i1 %cmp
+}
+define i1 @src_uge_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_uge_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp uge i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_uge_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_uge_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X:%.*]], [[Y_NOT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp uge i8 %y.not, %x
+ ret i1 %cmp
+}
+
+; X comp X^Neg_C tests. negative
+; (X+1) comp X^Neg_C
+define i1 @src_sle_incx_nx(i8 %x) {
+; CHECK-LABEL: @src_sle_incx_nx(
+; CHECK-NEXT: [[TMP1:%.*]] = sub i8 -2, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[TMP1]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %nx = xor i8 %x, -1
+ %inc.x = add i8 %x, 1
+ %cmp = icmp sle i8 %inc.x, %nx
+ ret i1 %cmp
+}
+; (X-1) comp X^Neg_C
+define i1 @src_sle_decx_nx(i8 %x) {
+; CHECK-LABEL: @src_sle_decx_nx(
+; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[TMP1]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %nx = xor i8 %x, -1
+ %dec.x = add i8 %x, -1
+ %cmp = icmp sle i8 %dec.x, %nx
+ ret i1 %cmp
+}
+; X comp (X+1)^Neg_C
+define i1 @src_sle_x_nincx(i8 %x) {
+; CHECK-LABEL: @src_sle_x_nincx(
+; CHECK-NEXT: [[NOT_INC_X:%.*]] = sub i8 -2, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[NOT_INC_X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %inc.x = add i8 %x, 1
+ %not.inc.x = xor i8 %inc.x, -1
+ %cmp = icmp sle i8 %x, %not.inc.x
+ ret i1 %cmp
+}
+; X comp (X-1)^Neg_C
+define i1 @src_sle_x_ndecx(i8 %x) {
+; CHECK-LABEL: @src_sle_x_ndecx(
+; CHECK-NEXT: [[NOT_DEC_X:%.*]] = sub i8 0, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[NOT_DEC_X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %dec.x = add i8 %x, -1
+ %not.dec.x = xor i8 %dec.x, -1
+ %cmp = icmp sle i8 %x, %not.dec.x
+ ret i1 %cmp
+}
+
; test for (~x ^ y) < ~z
define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @test_xor1(
>From 0d681e7b7a971b16ba4150b1528c0cf8086f1326 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 1 Dec 2023 06:32:35 +0900
Subject: [PATCH 2/4] [InstCombine] simplify `X (comp) X^Neg_C` (#57532)
This patch simplifies the comparison between X and X^Neg_X.
comparison between X and X^Neg_C is determined solely by
presence of the sign bit, so we can simplify it to checking
whether X is negative or not.
Proof: https://alive2.llvm.org/ce/z/bsDjdT
---
.../InstCombine/InstCombineCompares.cpp | 21 +++++++
.../Transforms/InstCombine/icmp-of-xor-x.ll | 60 +++++++------------
2 files changed, 41 insertions(+), 40 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7129499e0f8f9d..2595424f2b685c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4964,6 +4964,27 @@ static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
if (PredOut != Pred && isKnownNonZero(A, Q))
return new ICmpInst(PredOut, Op0, Op1);
+ // These transform works when C is negative.
+ // X s< X^C, X s<= X^C, X u> X^C, X u>= X^C --> X s< 0
+ // X s> X^C, X s>= X^C, X u< X^C, X u<= X^C --> X s>= 0
+ if (match(A, m_Negative())) {
+ CmpInst::Predicate NewPred;
+ switch (ICmpInst::getStrictPredicate(Pred)) {
+ default:
+ llvm_unreachable("not a valid predicate");
+ case ICmpInst::ICMP_SLT:
+ case ICmpInst::ICMP_UGT:
+ NewPred = ICmpInst::ICMP_SLT;
+ break;
+ case ICmpInst::ICMP_SGT:
+ case ICmpInst::ICMP_ULT:
+ NewPred = ICmpInst::ICMP_SGE;
+ break;
+ }
+ Constant *Const = Constant::getNullValue(Op0->getType());
+ return new ICmpInst(NewPred, Op0, Const);
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index c0582e3fcc760b..c73fc75b7d5bc9 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -9,8 +9,7 @@ declare void @use.i8(i8)
; X s< X^Neg_C --> X s< 0
define i1 @src_slt(i8 %x) {
; CHECK-LABEL: @src_slt(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -20,8 +19,7 @@ define i1 @src_slt(i8 %x) {
define <2 x i1> @src_slt_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_slt_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -32,8 +30,7 @@ define <2 x i1> @src_slt_vec(<2 x i8> %x) {
; X s<= X^Neg_C --> X s< 0
define i1 @src_sle(i8 %x) {
; CHECK-LABEL: @src_sle(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -43,8 +40,7 @@ define i1 @src_sle(i8 %x) {
define <2 x i1> @src_sle_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_sle_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -55,8 +51,7 @@ define <2 x i1> @src_sle_vec(<2 x i8> %x) {
; X u> X^Neg_C --> X s< 0
define i1 @src_ugt(i8 %x) {
; CHECK-LABEL: @src_ugt(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -66,8 +61,7 @@ define i1 @src_ugt(i8 %x) {
define <2 x i1> @src_ugt_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_ugt_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -78,8 +72,7 @@ define <2 x i1> @src_ugt_vec(<2 x i8> %x) {
; X u>= X^Neg_C --> X s< 0
define i1 @src_uge(i8 %x) {
; CHECK-LABEL: @src_uge(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -89,8 +82,7 @@ define i1 @src_uge(i8 %x) {
define <2 x i1> @src_uge_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_uge_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -100,8 +92,7 @@ define <2 x i1> @src_uge_vec(<2 x i8> %x) {
define <2 x i1> @src_uge_vec_min(<2 x i8> %x) {
; CHECK-LABEL: @src_uge_vec_min(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[NOT]], [[X]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -128, i8 -128>
@@ -111,8 +102,7 @@ define <2 x i1> @src_uge_vec_min(<2 x i8> %x) {
define <2 x i1> @src_uge_vec_128(<2 x i128> %x) {
; CHECK-LABEL: @src_uge_vec_128(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i128> [[X:%.*]], <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i128> [[NOT]], [[X]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i128> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
@@ -124,8 +114,7 @@ define <2 x i1> @src_uge_vec_128(<2 x i128> %x) {
; X s> X^Neg_C --> X s> -1
define i1 @src_sgt(i8 %x) {
; CHECK-LABEL: @src_sgt(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -135,8 +124,7 @@ define i1 @src_sgt(i8 %x) {
define <2 x i1> @src_sgt_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_sgt_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -147,8 +135,7 @@ define <2 x i1> @src_sgt_vec(<2 x i8> %x) {
; X s>= X^Neg_C --> X s> -1
define i1 @src_sge(i8 %x) {
; CHECK-LABEL: @src_sge(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -158,8 +145,7 @@ define i1 @src_sge(i8 %x) {
define <2 x i1> @src_sge_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_sge_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -170,8 +156,7 @@ define <2 x i1> @src_sge_vec(<2 x i8> %x) {
; X u< X^Neg_C --> X s> -1
define i1 @src_ult(i8 %x) {
; CHECK-LABEL: @src_ult(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -181,8 +166,7 @@ define i1 @src_ult(i8 %x) {
define <2 x i1> @src_ult_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_ult_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -193,8 +177,7 @@ define <2 x i1> @src_ult_vec(<2 x i8> %x) {
; X u<= X^Neg_C --> X s> -1
define i1 @src_ule(i8 %x) {
; CHECK-LABEL: @src_ule(
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[X:%.*]], -1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[CMP]]
;
%not = xor i8 %x, -1
@@ -204,8 +187,7 @@ define i1 @src_ule(i8 %x) {
define <2 x i1> @src_ule_vec(<2 x i8> %x) {
; CHECK-LABEL: @src_ule_vec(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
@@ -215,8 +197,7 @@ define <2 x i1> @src_ule_vec(<2 x i8> %x) {
define <2 x i1> @src_ule_vec_min(<2 x i8> %x) {
; CHECK-LABEL: @src_ule_vec_min(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -128, i8 -128>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[NOT]], [[X]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i8> %x, <i8 -128, i8 -128>
@@ -226,8 +207,7 @@ define <2 x i1> @src_ule_vec_min(<2 x i8> %x) {
define <2 x i1> @src_ule_vec_128(<2 x i128> %x) {
; CHECK-LABEL: @src_ule_vec_128(
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i128> [[X:%.*]], <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i128> [[NOT]], [[X]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i128> [[X:%.*]], <i128 -1, i128 -1>
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
>From e9aba12e988a04ff36f54755e33db0a58baef8ca Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Wed, 16 Oct 2024 19:08:56 +0900
Subject: [PATCH 3/4] Updated comments to use A instead of C
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 2595424f2b685c..623585fd9e4839 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4964,9 +4964,9 @@ static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
if (PredOut != Pred && isKnownNonZero(A, Q))
return new ICmpInst(PredOut, Op0, Op1);
- // These transform works when C is negative.
- // X s< X^C, X s<= X^C, X u> X^C, X u>= X^C --> X s< 0
- // X s> X^C, X s>= X^C, X u< X^C, X u<= X^C --> X s>= 0
+ // These transform work when A is negative.
+ // X s< X^A, X s<= X^A, X u> X^A, X u>= X^A --> X s< 0
+ // X s> X^A, X s>= X^A, X u< X^A, X u<= X^A --> X s>= 0
if (match(A, m_Negative())) {
CmpInst::Predicate NewPred;
switch (ICmpInst::getStrictPredicate(Pred)) {
>From 11efb035ea110558e6fba9e264f5dfbc5a8cf588 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Wed, 16 Oct 2024 19:09:08 +0900
Subject: [PATCH 4/4] Replace llvm_unreachable with conservative nullptr return
to handle potential equality predicates
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 623585fd9e4839..1f738b5197f78c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4971,7 +4971,7 @@ static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
CmpInst::Predicate NewPred;
switch (ICmpInst::getStrictPredicate(Pred)) {
default:
- llvm_unreachable("not a valid predicate");
+ return nullptr;
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_UGT:
NewPred = ICmpInst::ICMP_SLT;
More information about the llvm-commits
mailing list