diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1713,24 +1713,37 @@ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); - // ( A << (X - 1) ) | ((A > 0) zext to iX) - // <=> A < 0 | A > 0 - // <=> (A != 0) zext to iX - Value *A; - ICmpInst::Predicate Pred; + // fold bitwise(A >> BW - 1, zext(icmp)) (BW is the scalar bits of the + // type of A) + // -> bitwise(zext(A < 0), zext(icmp)) + // -> zext(bitwise(A < 0, icmp)) + auto FoldBitwiseICmpZeroWithICmp = [&](Value *Op0, + Value *Op1) -> Instruction * { + ICmpInst::Predicate Pred; + Value *A; + bool IsMatched = + match(Op0, + m_OneUse(m_LShr( + m_Value(A), + m_SpecificInt(Op0->getType()->getScalarSizeInBits() - 1)))) && + match(Op1, m_OneUse(m_ZExt(m_ICmp(Pred, m_Value(), m_Value())))); + + if (!IsMatched) + return nullptr; - auto MatchOrZExtICmp = [&](Value *Op0, Value *Op1) -> bool { - return match(Op0, m_LShr(m_Value(A), m_SpecificInt(Op0->getType()->getScalarSizeInBits() - 1))) && - match(Op1, m_ZExt(m_ICmp(Pred, m_Specific(A), m_Zero()))); + auto *ICmpL = + Builder.CreateICmpSLT(A, Constant::getNullValue(A->getType())); + auto *ICmpR = cast(Op1)->getOperand(0); + auto *BitwiseOp = Builder.CreateBinOp(LogicOpc, ICmpL, ICmpR); + + return new ZExtInst(BitwiseOp, Op0->getType()); }; - if (LogicOpc == Instruction::Or && - (MatchOrZExtICmp(Op0, Op1) || MatchOrZExtICmp(Op1, Op0)) && - Pred == ICmpInst::ICMP_SGT) { - Value *Cmp = - Builder.CreateICmpNE(A, Constant::getNullValue(A->getType())); - return new ZExtInst(Cmp, A->getType()); - } + if (auto *Ret = FoldBitwiseICmpZeroWithICmp(Op0, Op1)) + return Ret; + + if (auto *Ret = FoldBitwiseICmpZeroWithICmp(Op1, Op0)) + return Ret; CastInst *Cast0 = dyn_cast(Op0); if (!Cast0) diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll --- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll +++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll @@ -2669,10 +2669,8 @@ define <2 x i64> @icmp_slt_0_or_icmp_sgt_0_i64x2_fail(<2 x i64> %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64x2_fail( -; CHECK-NEXT: [[B:%.*]] = icmp sgt <2 x i64> [[X:%.*]], -; CHECK-NEXT: [[C:%.*]] = lshr <2 x i64> [[X]], -; CHECK-NEXT: [[D:%.*]] = zext <2 x i1> [[B]] to <2 x i64> -; CHECK-NEXT: [[E:%.*]] = or <2 x i64> [[C]], [[D]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <2 x i64> [[X:%.*]], +; CHECK-NEXT: [[E:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i64> ; CHECK-NEXT: ret <2 x i64> [[E]] ; %B = icmp sgt <2 x i64> %x, @@ -2685,11 +2683,7 @@ define i32 @icmp_slt_0_and_icmp_sge_neg1_i32(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg1_i32( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -1 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], [[B]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 0 ; %A = icmp sgt i32 %x, -1 %B = zext i1 %A to i32 @@ -2700,11 +2694,7 @@ define i32 @icmp_slt_0_or_icmp_sge_neg1_i32(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sge_neg1_i32( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = or i32 [[C]], [[B]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 1 ; %A = icmp sge i32 %x, -1 %B = zext i1 %A to i32 @@ -2715,10 +2705,8 @@ define i32 @icmp_slt_0_or_icmp_sge_100_i32(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sge_100_i32( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], 99 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = or i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X:%.*]], 99 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp sge i32 %x, 100 @@ -2730,10 +2718,8 @@ define i64 @icmp_slt_0_and_icmp_sge_neg1_i64(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg1_i64( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i64 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i64 -; CHECK-NEXT: [[C:%.*]] = lshr i64 [[X]], 63 -; CHECK-NEXT: [[D:%.*]] = and i64 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X:%.*]], -1 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[D]] ; %A = icmp sge i64 %x, -1 @@ -2745,10 +2731,8 @@ define i64 @icmp_slt_0_and_icmp_sge_neg2_i64(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg2_i64( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i64 [[X:%.*]], -3 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i64 -; CHECK-NEXT: [[C:%.*]] = lshr i64 [[X]], 63 -; CHECK-NEXT: [[D:%.*]] = and i64 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i64 [[X:%.*]], -3 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[D]] ; %A = icmp sge i64 %x, -2 @@ -2760,10 +2744,8 @@ define i64 @ashr_and_icmp_sge_neg1_i64(i64 %x) { ; CHECK-LABEL: @ashr_and_icmp_sge_neg1_i64( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i64 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i64 -; CHECK-NEXT: [[C1:%.*]] = lshr i64 [[X]], 63 -; CHECK-NEXT: [[D:%.*]] = and i64 [[C1]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X:%.*]], -1 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[D]] ; %A = icmp sge i64 %x, -1 @@ -2775,11 +2757,7 @@ define i64 @icmp_slt_0_and_icmp_sgt_neg1_i64(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sgt_neg1_i64( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i64 [[X:%.*]], -1 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i64 -; CHECK-NEXT: [[C:%.*]] = lshr i64 [[X]], 63 -; CHECK-NEXT: [[D:%.*]] = and i64 [[C]], [[B]] -; CHECK-NEXT: ret i64 [[D]] +; CHECK-NEXT: ret i64 0 ; %A = icmp sgt i64 %x, -1 %B = zext i1 %A to i64 @@ -2805,10 +2783,8 @@ define <2 x i32> @icmp_slt_0_and_icmp_sge_neg1_i32x2(<2 x i32> %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg1_i32x2( -; CHECK-NEXT: [[A:%.*]] = icmp sgt <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[B:%.*]] = zext <2 x i1> [[A]] to <2 x i32> -; CHECK-NEXT: [[C:%.*]] = lshr <2 x i32> [[X]], -; CHECK-NEXT: [[D:%.*]] = and <2 x i32> [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[D:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32> ; CHECK-NEXT: ret <2 x i32> [[D]] ; %A = icmp sge <2 x i32> %x, @@ -2820,10 +2796,8 @@ define <2 x i32> @icmp_slt_0_and_icmp_sge_neg2_i32x2(<2 x i32> %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg2_i32x2( -; CHECK-NEXT: [[A:%.*]] = icmp sgt <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[B:%.*]] = zext <2 x i1> [[A]] to <2 x i32> -; CHECK-NEXT: [[C:%.*]] = lshr <2 x i32> [[X]], -; CHECK-NEXT: [[D:%.*]] = and <2 x i32> [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[D:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32> ; CHECK-NEXT: ret <2 x i32> [[D]] ; %A = icmp sge <2 x i32> %x, @@ -2836,10 +2810,9 @@ define i32 @icmp_x_slt_0_xor_icmp_y_sgt_neg1_i32(i32 %x, i32 %y) { ; CHECK-LABEL: @icmp_x_slt_0_xor_icmp_y_sgt_neg1_i32( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -1 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[Y:%.*]], 31 -; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP2]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp sgt i32 %x, -1 @@ -2851,10 +2824,8 @@ define i32 @icmp_slt_0_xor_icmp_sgt_neg2_i32(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_xor_icmp_sgt_neg2_i32( -; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], -1 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp sgt i32 %x, -2 @@ -2867,9 +2838,8 @@ define i32 @icmp_slt_0_and_icmp_sge_neg1_i32_multiuse0(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg1_i32_multiuse0( ; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -3 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X]], -3 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: call void @use(i1 [[A]]) ; CHECK-NEXT: ret i32 [[D]] ; @@ -2988,9 +2958,9 @@ define i32 @icmp_slt_0_or_icmp_eq_100_i32_fail(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_eq_100_i32_fail( ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 100 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = or i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[A]] +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP2]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp eq i32 %x, 100 @@ -3003,9 +2973,9 @@ define i32 @icmp_slt_0_and_icmp_ne_neg2_i32_fail(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_ne_neg2_i32_fail( ; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[A]] +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP2]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp ne i32 %x, -2 @@ -3018,9 +2988,9 @@ define i32 @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_fail(i32 %x, i32 %y) { ; CHECK-LABEL: @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_fail( ; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], -2 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[Y:%.*]], 31 -; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[Y:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[A]] +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP2]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp ne i32 %x, -2 @@ -3033,9 +3003,9 @@ define i32 @icmp_x_slt_0_and_icmp_y_sgt_neg1_i32_fail(i32 %x, i32 %y) { ; CHECK-LABEL: @icmp_x_slt_0_and_icmp_y_sgt_neg1_i32_fail( ; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -1 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[Y:%.*]], 31 -; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[Y:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[A]] +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP2]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp sgt i32 %x, -1 @@ -3048,9 +3018,9 @@ define i32 @icmp_slt_0_xor_icmp_sge_neg2_i32_fail(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_xor_icmp_sge_neg2_i32_fail( ; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X:%.*]], -3 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[TMP1]], [[A]] +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP2]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %A = icmp sge i32 %x, -2 @@ -3064,9 +3034,9 @@ ; CHECK-LABEL: @icmp_slt_0_or_icmp_add_1_sge_100_i32_fail( ; CHECK-NEXT: [[X1:%.*]] = add i32 [[X:%.*]], 1 ; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[X1]], 99 -; CHECK-NEXT: [[B:%.*]] = zext i1 [[A]] to i32 -; CHECK-NEXT: [[C:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = or i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[A]] +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP2]] to i32 ; CHECK-NEXT: ret i32 [[D]] ; %X1 = add i32 %x, 1