diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 818099e7e12cd..54d74905b960e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4629,27 +4629,35 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, } bool NoOp0WrapProblem = false, NoOp1WrapProblem = false; - if (BO0 && isa(BO0)) - NoOp0WrapProblem = - ICmpInst::isEquality(Pred) || - (CmpInst::isUnsigned(Pred) && BO0->hasNoUnsignedWrap()) || - (CmpInst::isSigned(Pred) && BO0->hasNoSignedWrap()); - if (BO1 && isa(BO1)) - NoOp1WrapProblem = - ICmpInst::isEquality(Pred) || - (CmpInst::isUnsigned(Pred) && BO1->hasNoUnsignedWrap()) || - (CmpInst::isSigned(Pred) && BO1->hasNoSignedWrap()); - + bool Op0HasNUW = false, Op1HasNUW = false; + bool Op0HasNSW = false, Op1HasNSW = false; // Analyze the case when either Op0 or Op1 is an add instruction. // Op0 = A + B (or A and B are null); Op1 = C + D (or C and D are null). + auto hasNoWrapProblem = [](const BinaryOperator &BO, CmpInst::Predicate Pred, + bool &HasNSW, bool &HasNUW) -> bool { + if (isa(BO)) { + HasNUW = BO.hasNoUnsignedWrap(); + HasNSW = BO.hasNoSignedWrap(); + return ICmpInst::isEquality(Pred) || + (CmpInst::isUnsigned(Pred) && HasNUW) || + (CmpInst::isSigned(Pred) && HasNSW); + } else if (BO.getOpcode() == Instruction::Or) { + HasNUW = true; + HasNSW = true; + return true; + } else { + return false; + } + }; Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr; - if (BO0 && BO0->getOpcode() == Instruction::Add) { - A = BO0->getOperand(0); - B = BO0->getOperand(1); + + if (BO0) { + match(BO0, m_AddLike(m_Value(A), m_Value(B))); + NoOp0WrapProblem = hasNoWrapProblem(*BO0, Pred, Op0HasNSW, Op0HasNUW); } - if (BO1 && BO1->getOpcode() == Instruction::Add) { - C = BO1->getOperand(0); - D = BO1->getOperand(1); + if (BO1) { + match(BO1, m_AddLike(m_Value(C), m_Value(D))); + NoOp1WrapProblem = hasNoWrapProblem(*BO1, Pred, Op1HasNSW, Op1HasNUW); } // icmp (A+B), A -> icmp B, 0 for equalities or if there is no overflow. @@ -4769,17 +4777,15 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, APInt AP2Abs = AP2->abs(); if (AP1Abs.uge(AP2Abs)) { APInt Diff = *AP1 - *AP2; - bool HasNUW = BO0->hasNoUnsignedWrap() && Diff.ule(*AP1); - bool HasNSW = BO0->hasNoSignedWrap(); Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff); - Value *NewAdd = Builder.CreateAdd(A, C3, "", HasNUW, HasNSW); + Value *NewAdd = Builder.CreateAdd( + A, C3, "", Op0HasNUW && Diff.ule(*AP1), Op0HasNSW); return new ICmpInst(Pred, NewAdd, C); } else { APInt Diff = *AP2 - *AP1; - bool HasNUW = BO1->hasNoUnsignedWrap() && Diff.ule(*AP2); - bool HasNSW = BO1->hasNoSignedWrap(); Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff); - Value *NewAdd = Builder.CreateAdd(C, C3, "", HasNUW, HasNSW); + Value *NewAdd = Builder.CreateAdd( + C, C3, "", Op1HasNUW && Diff.ule(*AP2), Op1HasNSW); return new ICmpInst(Pred, A, NewAdd); } } @@ -4873,16 +4879,14 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT); // if Z != 0 and nsw(X * Z) and nsw(Y * Z) // X * Z eq/ne Y * Z -> X eq/ne Y - if (NonZero && BO0 && BO1 && BO0->hasNoSignedWrap() && - BO1->hasNoSignedWrap()) + if (NonZero && BO0 && BO1 && Op0HasNSW && Op1HasNSW) return new ICmpInst(Pred, X, Y); } else NonZero = isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT); // If Z != 0 and nuw(X * Z) and nuw(Y * Z) // X * Z u{lt/le/gt/ge}/eq/ne Y * Z -> X u{lt/le/gt/ge}/eq/ne Y - if (NonZero && BO0 && BO1 && BO0->hasNoUnsignedWrap() && - BO1->hasNoUnsignedWrap()) + if (NonZero && BO0 && BO1 && Op0HasNUW && Op1HasNUW) return new ICmpInst(Pred, X, Y); } } @@ -4982,8 +4986,8 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0)); case Instruction::Shl: { - bool NUW = BO0->hasNoUnsignedWrap() && BO1->hasNoUnsignedWrap(); - bool NSW = BO0->hasNoSignedWrap() && BO1->hasNoSignedWrap(); + bool NUW = Op0HasNUW && Op1HasNUW; + bool NSW = Op0HasNSW && Op1HasNSW; if (!NUW && !NSW) break; if (!NSW && I.isSigned()) diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll index 9b2e141bdb050..1f554c7b60256 100644 --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -3963,10 +3963,9 @@ define <8 x i1> @bitreverse_vec_ne(<8 x i16> %x, <8 x i16> %y) { define i1 @knownbits1(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits1( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 5 @@ -3980,10 +3979,9 @@ define i1 @knownbits1(i8 %a, i8 %b) { define i1 @knownbits2(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits2( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 5 @@ -3997,10 +3995,9 @@ define i1 @knownbits2(i8 %a, i8 %b) { define i1 @knownbits3(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits3( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], [[A1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 5 @@ -4014,10 +4011,9 @@ define i1 @knownbits3(i8 %a, i8 %b) { define <2 x i1> @knownbits4(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @knownbits4( ; CHECK-NEXT: [[A1:%.*]] = and <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[A2:%.*]] = or disjoint <2 x i8> [[A1]], ; CHECK-NEXT: [[B1:%.*]] = and <2 x i8> [[B:%.*]], -; CHECK-NEXT: [[B2:%.*]] = or disjoint <2 x i8> [[B1]], -; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint <2 x i8> [[B1]], +; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[TMP1]], [[A1]] ; CHECK-NEXT: ret <2 x i1> [[C]] ; %a1 = and <2 x i8> %a, @@ -4033,10 +4029,9 @@ define <2 x i1> @knownbits4(<2 x i8> %a, <2 x i8> %b) { define i1 @knownbits5(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits5( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 133 @@ -4050,10 +4045,9 @@ define i1 @knownbits5(i8 %a, i8 %b) { define i1 @knownbits6(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits6( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 133 @@ -4067,10 +4061,9 @@ define i1 @knownbits6(i8 %a, i8 %b) { define <2 x i1> @knownbits7(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @knownbits7( ; CHECK-NEXT: [[A1:%.*]] = and <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[A2:%.*]] = or disjoint <2 x i8> [[A1]], ; CHECK-NEXT: [[B1:%.*]] = and <2 x i8> [[B:%.*]], -; CHECK-NEXT: [[B2:%.*]] = or disjoint <2 x i8> [[B1]], -; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint <2 x i8> [[B1]], +; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[TMP1]], [[A1]] ; CHECK-NEXT: ret <2 x i1> [[C]] ; %a1 = and <2 x i8> %a, @@ -4084,10 +4077,9 @@ define <2 x i1> @knownbits7(<2 x i8> %a, <2 x i8> %b) { define i1 @knownbits8(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits8( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[TMP1]], [[A1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 133 @@ -5013,3 +5005,136 @@ define i1 @or_positive_sgt_zero_multi_use(i8 %a) { %cmp = icmp sgt i8 %b, 0 ret i1 %cmp } + + +define i1 @disjoint_or_sgt_1(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_sgt_1( +; CHECK-NEXT: [[B1:%.*]] = add nsw i8 [[B:%.*]], 2 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp sle i8 [[B1]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 1 + %b1 = add nsw i8 %b, 2 + %icmp_ = icmp sgt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_sgt_2(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_sgt_2( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp sgt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add i8 %b, 1 + %icmp_ = icmp sgt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_sgt_3(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_sgt_3( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add nuw i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp sgt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add nuw i8 %b, 1 + %icmp_ = icmp sgt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_ugt_1(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_ugt_1( +; CHECK-NEXT: [[B1:%.*]] = add nsw i8 [[B:%.*]], 2 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp ule i8 [[B1]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 1 + %b1 = add nsw i8 %b, 2 + %icmp_ = icmp ugt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_ugt_2(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_ugt_2( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp ugt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add i8 %b, 1 + %icmp_ = icmp ugt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_ugt_3(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_ugt_3( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add nuw i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp ugt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add nuw i8 %b, 1 + %icmp_ = icmp ugt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @deduce_nuw_flag_1(i8 %a, i8 %b) { +; CHECK-LABEL: @deduce_nuw_flag_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = add nuw i8 [[B:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP0]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %add1 = add nuw i8 %b, 2 + %add2 = add i8 %a, 1 + %cmp = icmp eq i8 %add1, %add2 + ret i1 %cmp +} + +define i1 @deduce_nuw_flag_2(i8 %a, i8 %b) { +; CHECK-LABEL: @deduce_nuw_flag_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = add nuw i8 [[B:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP0]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %add1 = add nuw i8 %b, 2 + %add2 = add i8 %a, 1 + %cmp = icmp eq i8 %add2, %add1 + ret i1 %cmp +} + +define i1 @dont_deduce_nuw_flag_1(i8 %a, i8 %b) { +; CHECK-LABEL: @dont_deduce_nuw_flag_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[B:%.*]], -1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP0]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %add1 = add nuw i8 %b, -2 + %add2 = add i8 %a, -1 + %cmp = icmp eq i8 %add1, %add2 + ret i1 %cmp +} + +define i1 @dont_deduce_nuw_flag_2(i8 %a, i8 %b) { +; CHECK-LABEL: @dont_deduce_nuw_flag_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[B:%.*]], -1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP0]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %add1 = add nuw i8 %b, -2 + %add2 = add i8 %a, -1 + %cmp = icmp eq i8 %add2, %add1 + ret i1 %cmp +}