Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -5862,6 +5862,50 @@ Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE) return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y); + const APInt *CmpC; + if (match(I.getOperand(0), + m_OneUse(m_c_Add(m_ZExt(m_Value(X)), m_SExt(m_Value(Y))))) && + match(I.getOperand(1), m_APInt(CmpC)) && + X->getType()->isIntOrIntVectorTy(1) && + Y->getType()->isIntOrIntVectorTy(1) && CmpC->abs().ule(1)) { + Pred = I.getPredicate(); + switch (CmpC->getSExtValue()) { + case -1: + // (zext i1 X) + (sext i1 Y)) == -1 --> ~X & Y + if (Pred == ICmpInst::ICMP_EQ) + return BinaryOperator::CreateAnd(Builder.CreateNot(X), Y); + // (zext i1 X) + (sext i1 Y)) != -1 --> X | ~Y + // (zext i1 X) + (sext i1 Y)) s> -1 --> X | ~Y + // (zext i1 X) + (sext i1 Y)) u< -1 --> X | ~Y + if (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_SGT || + Pred == ICmpInst::ICMP_ULT) + return BinaryOperator::CreateOr(X, Builder.CreateNot(Y)); + break; + case 0: + // (zext i1 X) + (sext i1 Y)) s> 0 --> X & ~Y + if (Pred == ICmpInst::ICMP_SGT) + return BinaryOperator::CreateAnd(X, Builder.CreateNot(Y)); + // (zext i1 X) + (sext i1 Y)) s< 0 --> ~X & Y + if (Pred == ICmpInst::ICMP_SLT) + return BinaryOperator::CreateAnd(Builder.CreateNot(X), Y); + break; + case 1: + // (zext i1 X) + (sext i1 Y)) == 1 --> X & ~Y + if (Pred == ICmpInst::ICMP_EQ) + return BinaryOperator::CreateAnd(X, Builder.CreateNot(Y)); + // (zext i1 X) + (sext i1 Y)) != 1 --> ~X | Y + // (zext i1 X) + (sext i1 Y)) s< 1 --> ~X | Y + if (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_SLT) + return BinaryOperator::CreateOr(Builder.CreateNot(X), Y); + // (zext i1 X) + (sext i1 Y)) u> 1 --> ~X & Y + if (Pred == ICmpInst::ICMP_UGT) + return BinaryOperator::CreateAnd(Builder.CreateNot(X), Y); + break; + default: + llvm_unreachable("CmpC should be also one of [-1, 0, 1]"); + } + } + return nullptr; } Index: llvm/test/Transforms/InstCombine/icmp-range.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-range.ll +++ llvm/test/Transforms/InstCombine/icmp-range.ll @@ -628,13 +628,12 @@ %r = icmp uge i8 %a, %s ret i1 %r } +; (zext i1 a) + (sext i1 b)) == -1 --> ~a & b define i1 @zext_sext_add_icmp_eq_minus1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_eq_minus1( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 -; CHECK-NEXT: [[SEXT_B:%.*]] = sext i1 [[B:%.*]] to i8 -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[ADD]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[A:%.*]], true +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -644,12 +643,13 @@ ret i1 %r } + +; (zext i1 a) + (sext i1 b)) != -1 --> a | ~b + define i1 @zext_sext_add_icmp_ne_minus1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_ne_minus1( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 -; CHECK-NEXT: [[SEXT_B:%.*]] = sext i1 [[B:%.*]] to i8 -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[ADD]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[B:%.*]], true +; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -659,10 +659,12 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) s> -1 --> a | ~b + define i1 @zext_sext_add_icmp_sgt_minus1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_sgt_minus1( -; CHECK-NEXT: [[B_NOT:%.*]] = xor i1 [[B:%.*]], true -; CHECK-NEXT: [[R:%.*]] = or i1 [[B_NOT]], [[A:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[B:%.*]], true +; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -672,12 +674,12 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) u< -1 --> a | ~b + define i1 @zext_sext_add_icmp_ult_minus1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_ult_minus1( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 -; CHECK-NEXT: [[SEXT_B:%.*]] = sext i1 [[B:%.*]] to i8 -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[ADD]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[B:%.*]], true +; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -687,12 +689,12 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) s> 0 --> a & ~b + define i1 @zext_sext_add_icmp_sgt_0(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_sgt_0( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 -; CHECK-NEXT: [[SEXT_B:%.*]] = sext i1 [[B:%.*]] to i8 -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[ADD]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[B:%.*]], true +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -702,11 +704,13 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) s< 0 --> ~a & b + define i1 @zext_sext_add_icmp_slt_0(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_slt_0( ; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[A:%.*]], true -; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[B:%.*]] -; CHECK-NEXT: ret i1 [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 %sext.b = sext i1 %b to i8 @@ -715,12 +719,12 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) == 1 --> a & ~b + define i1 @zext_sext_add_icmp_eq_1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_eq_1( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 -; CHECK-NEXT: [[SEXT_B:%.*]] = sext i1 [[B:%.*]] to i8 -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[ADD]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[B:%.*]], true +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[A:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -730,12 +734,12 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) != 1 --> ~a | b + define i1 @zext_sext_add_icmp_ne_1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_ne_1( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 -; CHECK-NEXT: [[SEXT_B:%.*]] = sext i1 [[B:%.*]] to i8 -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[ADD]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[A:%.*]], true +; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[B:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -745,12 +749,12 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) s< 1 --> ~a | b + define i1 @zext_sext_add_icmp_slt_1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_slt_1( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 -; CHECK-NEXT: [[SEXT_B:%.*]] = sext i1 [[B:%.*]] to i8 -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[ADD]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[A:%.*]], true +; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[B:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 @@ -760,11 +764,13 @@ ret i1 %r } +; (zext i1 a) + (sext i1 b)) u> 1 --> ~a & b + define i1 @zext_sext_add_icmp_ugt_1(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_ugt_1( ; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[A:%.*]], true -; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[B:%.*]] -; CHECK-NEXT: ret i1 [[TMP2]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: ret i1 [[R]] ; %zext.a = zext i1 %a to i8 %sext.b = sext i1 %b to i8 @@ -775,10 +781,8 @@ define <2 x i1> @vector_zext_sext_add_icmp_slt_1(<2 x i1> %a, <2 x i1> %b) { ; CHECK-LABEL: @vector_zext_sext_add_icmp_slt_1( -; CHECK-NEXT: [[ZEXT_A:%.*]] = zext <2 x i1> [[A:%.*]] to <2 x i8> -; CHECK-NEXT: [[SEXT_B:%.*]] = sext <2 x i1> [[B:%.*]] to <2 x i8> -; CHECK-NEXT: [[ADD:%.*]] = add nsw <2 x i8> [[ZEXT_A]], [[SEXT_B]] -; CHECK-NEXT: [[R:%.*]] = icmp slt <2 x i8> [[ADD]], +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i1> [[A:%.*]], +; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[TMP1]], [[B:%.*]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %zext.a = zext <2 x i1> %a to <2 x i8> @@ -803,6 +807,8 @@ ret <2 x i1> %r } +; Negative test, more than one use for icmp LHS + define i1 @zext_sext_add_icmp_slt_1_no_oneuse(i1 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_slt_1_no_oneuse( ; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 @@ -820,6 +826,8 @@ ret i1 %r } +; Negative test, icmp RHS is not a constant + define i1 @zext_sext_add_icmp_slt_1_rhs_not_const(i1 %a, i1 %b, i8 %c) { ; CHECK-LABEL: @zext_sext_add_icmp_slt_1_rhs_not_const( ; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i8 @@ -835,6 +843,8 @@ ret i1 %r } +; Negative test, ext source is not i1 + define i1 @zext_sext_add_icmp_slt_1_type_not_i1(i2 %a, i1 %b) { ; CHECK-LABEL: @zext_sext_add_icmp_slt_1_type_not_i1( ; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i2 [[A:%.*]] to i8