From ea9f69fec6ef5b85923036d7039dfcd08217b850 Mon Sep 17 00:00:00 2001 From: Hanbum Park 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 a4e7acbca930d..c0582e3fcc760 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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[NOT]], [[X]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i128> [[NOT]], [[X]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i128> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[NOT]], [[X]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i8> %x, + %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:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i128> [[NOT]], [[X]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %not = xor <2 x i128> %x, + %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 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 7129499e0f8f9..2595424f2b685 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 c0582e3fcc760..c73fc75b7d5bc 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:%.*]], -; 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, @@ -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:%.*]], -; 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, @@ -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:%.*]], -; 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, @@ -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:%.*]], -; 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, @@ -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:%.*]], -; 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, @@ -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:%.*]], -; 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, @@ -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:%.*]], -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %not = xor <2 x i8> %x, @@ -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:%.*]], -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %not = xor <2 x i8> %x, @@ -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:%.*]], -; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %not = xor <2 x i8> %x, @@ -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:%.*]], -; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i8> [[X]], [[NOT]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %not = xor <2 x i8> %x, @@ -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:%.*]], -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[NOT]], [[X]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %not = xor <2 x i8> %x, @@ -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:%.*]], -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i128> [[NOT]], [[X]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i128> [[X:%.*]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %not = xor <2 x i128> %x, From e9aba12e988a04ff36f54755e33db0a58baef8ca Mon Sep 17 00:00:00 2001 From: hanbeom 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 2595424f2b685..623585fd9e483 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 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 623585fd9e483..1f738b5197f78 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;