Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1713,24 +1713,53 @@ 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_LShr(m_Value(A), + m_SpecificInt(Op0->getType()->getScalarSizeInBits() - + 1))) && + match(Op1, m_ZExt(m_ICmp(Pred, m_Value(), m_Value()))) && + (Op0->hasOneUse() || Op1->hasOneUse()); + + 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()))); + ICmpInst *ICmpL = cast( + Builder.CreateICmpSLT(A, Constant::getNullValue(A->getType()))); + ICmpInst *ICmpR = cast(cast(Op1)->getOperand(0)); + auto *BitwiseOp = + cast(Builder.CreateBinOp(LogicOpc, ICmpL, ICmpR)); + + Value *Ret; + if (LogicOpc == BinaryOperator::Xor) + Ret = foldXorOfICmps(ICmpL, ICmpR, *BitwiseOp); + else + Ret = foldAndOrOfICmps(ICmpL, ICmpR, *BitwiseOp, + LogicOpc == BinaryOperator::And); + if (Ret) + return new ZExtInst(Ret, Op0->getType()); + + // remove the deferred 2 instructions : + // icmp slt A, 0 + // bitwise (A < 0, icmp) + // otherwise there will be infinite loops of combining + Worklist.popDeferred()->eraseFromParent(); + Worklist.popDeferred()->eraseFromParent(); + return nullptr; }; - 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,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]] ; @@ -2885,8 +2855,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]] ; @@ -2900,10 +2870,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]] ;