Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1713,24 +1713,35 @@ 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 and/or(A << BW - 1, zext(icmp)) (BW is the scalar bits of the type of A) + // -> and/or(zext(A < 0), zext(icmp)) + // -> zext(and/or(A < 0, icmp)) + auto FoldBitwiseICmpZeroWithICmp = [&](Value *Op0, + Value *Op1) -> Instruction * { + ICmpInst::Predicate Pred; + Value *A; + bool IsMatched = + match(Op0, m_LShr(m_Value(A), + m_SpecificInt(Op0->getType()->getScalarSizeInBits() - 1))) && + match(Op1, m_ZExt(m_ICmp(Pred, m_Value(), m_Value()))) && + LogicOpc != Instruction::Xor; + + 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()))); + return new ZExtInst( + Builder.CreateBinOp( + LogicOpc, + Builder.CreateICmpSLT(A, Constant::getNullValue(A->getType())), + cast(Op1)->getOperand(0)), + 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) Index: llvm/test/Transforms/InstCombine/and-or-icmps.ll =================================================================== --- llvm/test/Transforms/InstCombine/and-or-icmps.ll +++ 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,9 +2810,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]] ; @@ -2854,8 +2827,8 @@ ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse1( ; 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 @use32(i32 [[B]]) ; CHECK-NEXT: ret i32 [[D]] ; @@ -2869,10 +2842,9 @@ define i32 @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse2(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_and_icmp_sge_neg2_i32_multiuse2( -; 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: [[C:%.*]] = lshr i32 [[X:%.*]], 31 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X]], -3 +; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: call void @use32(i32 [[C]]) ; CHECK-NEXT: ret i32 [[D]] ; @@ -2889,7 +2861,8 @@ ; 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 @use32(i32 [[B]]) ; CHECK-NEXT: call void @use32(i32 [[C]]) ; CHECK-NEXT: ret i32 [[D]] @@ -2906,9 +2879,10 @@ define i32 @icmp_slt_0_or_icmp_eq_100_i32_multiuse_fail1(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_eq_100_i32_multiuse_fail1( ; 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: call void @use32(i32 [[C]]) ; CHECK-NEXT: ret i32 [[D]] ; @@ -2923,9 +2897,10 @@ define i32 @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_multiuse_fail2(i32 %x, i32 %y) { ; CHECK-LABEL: @icmp_x_slt_0_and_icmp_y_ne_neg2_i32_multiuse_fail2( ; 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: call void @use32(i32 [[C]]) ; CHECK-NEXT: ret i32 [[D]] ; @@ -2941,8 +2916,9 @@ ; CHECK-LABEL: @icmp_slt_0_or_icmp_eq_100_i32_multiuse_fail3( ; 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: call void @use32(i32 [[B]]) ; CHECK-NEXT: ret i32 [[D]] ; @@ -2957,9 +2933,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 @@ -2972,9 +2948,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 @@ -2987,9 +2963,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 @@ -3002,9 +2978,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 @@ -3033,9 +3009,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