Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2899,12 +2899,71 @@ BinaryOperator *Add, const APInt &C) { Value *Y = Add->getOperand(1); + Value *X = Add->getOperand(0); + + Value *Op0 = X, *Op1 = Y; + + // We handle all (s/zext i1 Op0 + s/zext i1 Op1 == 0/1/2) here. + if (Cmp.isEquality() && + match(Add, m_c_Add(m_OneUse(m_ZExtOrSExt(m_Value(Op0))), + m_OneUse(m_ZExtOrSExt(m_Value(Op1))))) && + Op0->getType()->isIntOrIntVectorTy(1) && + Op1->getType()->isIntOrIntVectorTy(1) && + (C.isZero() || C.isOne() || (C.exactLogBase2() == 1))) { + Value *Cond = Builder.getFalse(); + // Handle zext/zext additions + if (match(X, m_OneUse(m_ZExt(m_Value(Op0)))) && + match(Y, m_OneUse(m_ZExt(m_Value(Op1))))) { + // Case 1: zext i1 Op0 + zext i1 Op1 == 0 --> !(or i1 Op0, Op1) + if (C.isZero()) + Cond = Builder.CreateNot(Builder.CreateOr(Op0, Op1)); + else if (C.isOne()) + // Case 2: zext i1 Op0 + zext i1 Op1 == 1 --> xor i1 Op0, Op1 + Cond = Builder.CreateXor(Op0, Op1); + else if (C.exactLogBase2() == 1) + // Case 3: zext i1 Op0 + zext i1 Op1 == 2 --> xor i1 Op0, Op1 + Cond = Builder.CreateAnd(Op0, Op1); + return replaceInstUsesWith(Cmp, Cond); + } + + // Handles sext i1 Op0 + sext i1 Op1 == 0/1/2 + if (match(X, m_OneUse(m_SExt(m_Value(Op0)))) && + match(Y, m_OneUse(m_SExt(m_Value(Op1))))) { + // Case 1: sext i1 Op0 + sext i1 Op1 == 0 --> !(or i1 Op0, Op1) + if (C.isZero()) + Cond = Builder.CreateNot(Builder.CreateOr(Op0, Op1)); + // Case 2: sext i1 Op0 + sext i1 Op1 == 1 --> false + // Case 3: sext i1 Op0 + sext i1 Op2 == 2 --> false, + // these two cases were handled int initialization of Cond. + return replaceInstUsesWith(Cmp, Cond); + } + + // Sum is cummulative so swap the operations to avoid recompuations + if (match(X, m_OneUse(m_ZExt(m_OneUse(m_Value(Op0))))) && + match(Y, m_OneUse(m_SExt(m_OneUse(m_Value(Op1)))))) + std::swap(Op0, Op1); + + // Handles sext i1 Op0 + zext Op1 == 0/1/2 + if (match(X, m_OneUse(m_SExt(m_Value(Op0)))) && + match(Y, m_OneUse(m_ZExt(m_Value(Op1))))) { + // Case 1: sext i1 Op0 + zext i1 Op1 == 0 --> !(xor i1 Op0, Op1) + if (C.isZero()) + Cond = Builder.CreateNot(Builder.CreateXor(Op0, Op1)); + else if (C.isOne()) + // Case 2: sext i1 Op0 + zext i1 Op1 == 1 --> (!Op0) & Op1 + Cond = Builder.CreateAnd(Builder.CreateNot(Op0), Op1); + // Case 3: sext i1 Op0 + zext i1 Op1 == 2 --> false, + // already handled in the initilization of Cond. + return replaceInstUsesWith(Cmp, Cond); + } + return nullptr; + } + const APInt *C2; - if (Cmp.isEquality() || !match(Y, m_APInt(C2))) + if (!match(Y, m_APInt(C2))) return nullptr; // Fold icmp pred (add X, C2), C. - Value *X = Add->getOperand(0); Type *Ty = Add->getType(); const CmpInst::Predicate Pred = Cmp.getPredicate(); Index: llvm/test/Transforms/InstCombine/icmp-add.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-add.ll +++ llvm/test/Transforms/InstCombine/icmp-add.ll @@ -5,6 +5,133 @@ ; PR1949 +define i1 @cvt_icmp_0_zext_plus_zext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_0_zext_plus_zext( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[ARG1:%.*]], [[ARG:%.*]] +; CHECK-NEXT: [[I4:%.*]] = xor i1 [[TMP0]], true +; CHECK-NEXT: ret i1 [[I4]] +; +bb: + %i = zext i1 %arg to i32 + %i2 = zext i1 %arg1 to i32 + %i3 = add i32 %i2, %i + %i4 = icmp eq i32 %i3, 0 + ret i1 %i4 +} + +define i1 @cvt_icmp_1_zext_plus_zext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_1_zext_plus_zext( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[I4:%.*]] = xor i1 [[ARG1:%.*]], [[ARG:%.*]] +; CHECK-NEXT: ret i1 [[I4]] +; +bb: + %i = zext i1 %arg to i32 + %i2 = zext i1 %arg1 to i32 + %i3 = add i32 %i2, %i + %i4 = icmp eq i32 %i3, 1 + ret i1 %i4 +} + +define i1 @cvt_icmp_2_zext_plus_zext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_2_zext_plus_zext( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[T:%.*]] = and i1 [[ARG:%.*]], [[ARG1:%.*]] +; CHECK-NEXT: ret i1 [[T]] +; +bb: + %i = zext i1 %arg to i32 + %i2 = zext i1 %arg1 to i32 + %i3 = add i32 %i, %i2 + %t = icmp eq i32 %i3, 2 + ret i1 %t +} + +define i1 @cvt_icmp_0_sext_plus_sext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_0_sext_plus_sext( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[ARG:%.*]], [[ARG1:%.*]] +; CHECK-NEXT: [[T:%.*]] = xor i1 [[TMP0]], true +; CHECK-NEXT: ret i1 [[T]] +; +bb: + %i = sext i1 %arg to i32 + %i2 = sext i1 %arg1 to i32 + %i3 = add i32 %i, %i2 + %t = icmp eq i32 %i3, 0 + ret i1 %t +} + +define i1 @cvt_icmp_1_sext_plus_sext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_1_sext_plus_sext( +; CHECK-NEXT: bb: +; CHECK-NEXT: ret i1 false +; +bb: + %i = sext i1 %arg to i32 + %i2 = sext i1 %arg1 to i32 + %i3 = add i32 %i, %i2 + %t = icmp eq i32 %i3, 1 + ret i1 %t +} + +define i1 @cvt_icmp_2_sext_plus_sext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_2_sext_plus_sext( +; CHECK-NEXT: bb: +; CHECK-NEXT: ret i1 false +; +bb: + %i = sext i1 %arg to i32 + %i2 = sext i1 %arg1 to i32 + %i3 = add i32 %i, %i2 + %t = icmp eq i32 %i3, 2 + ret i1 %t +} + +define i1 @cvt_icmp_0_sext_plus_zext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_0_sext_plus_zext( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[ARG:%.*]], [[ARG1:%.*]] +; CHECK-NEXT: [[T:%.*]] = xor i1 [[TMP0]], true +; CHECK-NEXT: ret i1 [[T]] +; +bb: + %i = sext i1 %arg to i32 + %i2 = zext i1 %arg1 to i32 + %i3 = add i32 %i, %i2 + %t = icmp eq i32 %i3, 0 + ret i1 %t +} + +define i1 @cvt_icmp_1_sext_plus_zext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_1_sext_plus_zext( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[ARG:%.*]], true +; CHECK-NEXT: [[T:%.*]] = and i1 [[TMP0]], [[ARG1:%.*]] +; CHECK-NEXT: ret i1 [[T]] +; +bb: + %i = sext i1 %arg to i32 + %i2 = zext i1 %arg1 to i32 + %i3 = add i32 %i, %i2 + %t = icmp eq i32 %i3, 1 + ret i1 %t +} + +define i1 @cvt_icmp_2_sext_plus_zext(i1 %arg, i1 %arg1) { +; CHECK-LABEL: @cvt_icmp_2_sext_plus_zext( +; CHECK-NEXT: bb: +; CHECK-NEXT: ret i1 false +; +bb: + %i = sext i1 %arg to i32 + %i2 = zext i1 %arg1 to i32 + %i3 = add i32 %i, %i2 + %t = icmp eq i32 %i3, 2 + ret i1 %t +} + define i1 @test1(i32 %a) { ; CHECK-LABEL: @test1( ; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[A:%.*]], -5