Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1712,6 +1712,35 @@ assert(I.isBitwiseLogicOp() && "Unexpected opcode for bitwise logic folding"); 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; + Constant *B; + ICmpInst::Predicate Pred; + + auto MatchOrZextIcmp = [&](Value *Op0, Value *Op1) -> bool { + return match(Op0, m_LShr(m_Value(A), m_Constant(B))) && + match(Op1, m_ZExt(m_ICmp(Pred, m_Specific(A), m_Zero()))); + }; + + if (LogicOpc == Instruction::Or && + (MatchOrZextIcmp(Op0, Op1) || MatchOrZextIcmp(Op1, Op0))) { + uint64_t X = A->getType()->getScalarSizeInBits(); + bool MatchBAndX; + if (B->getType()->isIntegerTy()) + MatchBAndX = cast(B)->equalsInt(X - 1); + else + MatchBAndX = cast(B->getSplatValue())->equalsInt(X - 1); + + if (Pred == ICmpInst::ICMP_SGT && MatchBAndX) { + Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_NE, A, + Constant::getNullValue(A->getType())); + return new ZExtInst(Cmp, A->getType()); + } + } + CastInst *Cast0 = dyn_cast(Op0); if (!Cast0) return nullptr; 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 @@ -2569,12 +2569,11 @@ ret <2 x i1> %r } + define i32 @icmp_slt_0_or_icmp_sgt_0_i32(i32 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i32( -; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X:%.*]], 0 -; CHECK-NEXT: [[X_LOBIT:%.*]] = lshr i32 [[X]], 31 -; CHECK-NEXT: [[D:%.*]] = zext i1 [[B]] to i32 -; CHECK-NEXT: [[E:%.*]] = or i32 [[X_LOBIT]], [[D]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[E]] ; %A = icmp slt i32 %x, 0 @@ -2585,12 +2584,11 @@ ret i32 %E } + define i64 @icmp_slt_0_or_icmp_sgt_0_i64(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64( -; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 [[X:%.*]], 0 -; CHECK-NEXT: [[X_LOBIT:%.*]] = lshr i64 [[X]], 63 -; CHECK-NEXT: [[D:%.*]] = zext i1 [[B]] to i64 -; CHECK-NEXT: [[E:%.*]] = or i64 [[X_LOBIT]], [[D]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[X:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = zext i1 [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[E]] ; %A = icmp slt i64 %x, 0 @@ -2601,6 +2599,7 @@ ret i64 %E } + define i64 @icmp_slt_0_or_icmp_sgt_0_i64_neg0(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64_neg0( ; CHECK-NEXT: [[E:%.*]] = lshr i64 [[X:%.*]], 63 @@ -2613,6 +2612,7 @@ ret i64 %E } + define i64 @icmp_slt_0_or_icmp_sgt_0_i64_neg1(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64_neg1( ; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 [[X:%.*]], 0 @@ -2628,6 +2628,7 @@ ret i64 %E } + define i64 @icmp_slt_0_or_icmp_sgt_0_i64_neg2(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64_neg2( ; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 [[X:%.*]], 0 @@ -2643,6 +2644,7 @@ ret i64 %E } + define i64 @icmp_slt_0_or_icmp_sgt_0_i64_neg3(i64 %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64_neg3( ; CHECK-NEXT: [[C:%.*]] = ashr i64 [[X:%.*]], 62 @@ -2657,12 +2659,11 @@ ret i64 %E } + define <2 x i64> @icmp_slt_0_or_icmp_sgt_0_i64x2(<2 x i64> %x) { ; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64x2( -; CHECK-NEXT: [[B:%.*]] = icmp sgt <2 x i64> [[X:%.*]], zeroinitializer -; CHECK-NEXT: [[X_LOBIT:%.*]] = lshr <2 x i64> [[X]], -; CHECK-NEXT: [[D:%.*]] = zext <2 x i1> [[B]] to <2 x i64> -; CHECK-NEXT: [[E:%.*]] = or <2 x i64> [[X_LOBIT]], [[D]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i64> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[E:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i64> ; CHECK-NEXT: ret <2 x i64> [[E]] ; %A = icmp slt <2 x i64> %x, @@ -2672,3 +2673,20 @@ %E = or <2 x i64> %C, %D ret <2 x i64> %E } + + +define <2 x i64> @icmp_slt_0_or_icmp_sgt_0_i64x2_neg(<2 x i64> %x) { +; CHECK-LABEL: @icmp_slt_0_or_icmp_sgt_0_i64x2_neg( +; CHECK-NEXT: [[B:%.*]] = icmp sgt <2 x i64> [[X:%.*]], zeroinitializer +; 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: ret <2 x i64> [[E]] +; + %B = icmp sgt <2 x i64> %x, zeroinitializer + %C = lshr <2 x i64> %x, + %D = zext <2 x i1> %B to <2 x i64> + %E = or <2 x i64> %C, %D + ret <2 x i64> %E + +}