diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 2a3011075e47e..e8f96e9f681f2 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -3427,7 +3427,7 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, switch (LBO->getOpcode()) { default: break; - case Instruction::Shl: + case Instruction::Shl: { bool NUW = Q.IIQ.hasNoUnsignedWrap(LBO) && Q.IIQ.hasNoUnsignedWrap(RBO); bool NSW = Q.IIQ.hasNoSignedWrap(LBO) && Q.IIQ.hasNoSignedWrap(RBO); if (!NUW || (ICmpInst::isSigned(Pred) && !NSW) || @@ -3436,6 +3436,38 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, if (Value *V = simplifyICmpInst(Pred, LBO->getOperand(1), RBO->getOperand(1), Q, MaxRecurse - 1)) return V; + break; + } + // If C1 & C2 == C1, A = X and/or C1, B = X and/or C2: + // icmp ule A, B -> true + // icmp ugt A, B -> false + // icmp sle A, B -> true (C1 and C2 are the same sign) + // icmp sgt A, B -> false (C1 and C2 are the same sign) + case Instruction::And: + case Instruction::Or: { + const APInt *C1, *C2; + if (ICmpInst::isRelational(Pred) && + match(LBO->getOperand(1), m_APInt(C1)) && + match(RBO->getOperand(1), m_APInt(C2))) { + if (!C1->isSubsetOf(*C2)) { + std::swap(C1, C2); + Pred = ICmpInst::getSwappedPredicate(Pred); + } + if (C1->isSubsetOf(*C2)) { + if (Pred == ICmpInst::ICMP_ULE) + return ConstantInt::getTrue(getCompareTy(LHS)); + if (Pred == ICmpInst::ICMP_UGT) + return ConstantInt::getFalse(getCompareTy(LHS)); + if (C1->isNonNegative() == C2->isNonNegative()) { + if (Pred == ICmpInst::ICMP_SLE) + return ConstantInt::getTrue(getCompareTy(LHS)); + if (Pred == ICmpInst::ICMP_SGT) + return ConstantInt::getFalse(getCompareTy(LHS)); + } + } + } + break; + } } } diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll index 827f7e887ddae..ac2ebf52ed629 100644 --- a/llvm/test/Transforms/InstSimplify/compare.ll +++ b/llvm/test/Transforms/InstSimplify/compare.ll @@ -1921,10 +1921,7 @@ define i1 @tautological8(i32 %A, i32 %B) { define i1 @tautological9(i32 %A) { ; CHECK-LABEL: @tautological9( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -1934,10 +1931,7 @@ define i1 @tautological9(i32 %A) { define <2 x i1> @tautological9_vec(<2 x i32> %A) { ; CHECK-LABEL: @tautological9_vec( -; CHECK-NEXT: [[C1:%.*]] = and <2 x i32> [[A:%.*]], -; CHECK-NEXT: [[C2:%.*]] = and <2 x i32> [[A]], -; CHECK-NEXT: [[D:%.*]] = icmp ugt <2 x i32> [[C1]], [[C2]] -; CHECK-NEXT: ret <2 x i1> [[D]] +; CHECK-NEXT: ret <2 x i1> zeroinitializer ; %C1 = and <2 x i32> %A, %C2 = and <2 x i32> %A, @@ -1947,10 +1941,7 @@ define <2 x i1> @tautological9_vec(<2 x i32> %A) { define i1 @tautological10(i32 %A) { ; CHECK-LABEL: @tautological10( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -1960,10 +1951,7 @@ define i1 @tautological10(i32 %A) { define i1 @tautological11(i32 %A) { ; CHECK-LABEL: @tautological11( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -1973,10 +1961,7 @@ define i1 @tautological11(i32 %A) { define i1 @tautological12(i32 %A) { ; CHECK-LABEL: @tautological12( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -1986,10 +1971,7 @@ define i1 @tautological12(i32 %A) { define i1 @tautological13(i32 %A) { ; CHECK-LABEL: @tautological13( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -1999,10 +1981,7 @@ define i1 @tautological13(i32 %A) { define i1 @tautological14(i32 %A) { ; CHECK-LABEL: @tautological14( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -2012,10 +1991,7 @@ define i1 @tautological14(i32 %A) { define i1 @tautological15(i32 %A) { ; CHECK-LABEL: @tautological15( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -2025,10 +2001,7 @@ define i1 @tautological15(i32 %A) { define i1 @tautological16(i32 %A) { ; CHECK-LABEL: @tautological16( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -2142,10 +2115,7 @@ define i1 @tautological16_negative(i32 %A) { define i1 @tautological17_subset1(i32 %A) { ; CHECK-LABEL: @tautological17_subset1( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -2155,10 +2125,7 @@ define i1 @tautological17_subset1(i32 %A) { define i1 @tautological17_subset2(i32 %A) { ; CHECK-LABEL: @tautological17_subset2( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], -4 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3 -; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = and i32 %A, -4 %C2 = and i32 %A, -3 @@ -2181,10 +2148,7 @@ define i1 @tautological17_negative(i32 %A) { define i1 @tautological18_subset1(i32 %A) { ; CHECK-LABEL: @tautological18_subset1( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp sle i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -2194,10 +2158,7 @@ define i1 @tautological18_subset1(i32 %A) { define i1 @tautological18_subset2(i32 %A) { ; CHECK-LABEL: @tautological18_subset2( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], -4 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3 -; CHECK-NEXT: [[D:%.*]] = icmp sle i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, -4 %C2 = and i32 %A, -3 @@ -2220,10 +2181,7 @@ define i1 @tautological18_negative(i32 %A) { define i1 @tautological19_subset1(i32 %A) { ; CHECK-LABEL: @tautological19_subset1( -; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = or i32 %A, 1 %C2 = or i32 %A, 3 @@ -2233,10 +2191,7 @@ define i1 @tautological19_subset1(i32 %A) { define i1 @tautological19_subset2(i32 %A) { ; CHECK-LABEL: @tautological19_subset2( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], -4 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3 -; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 false ; %C1 = and i32 %A, -4 %C2 = and i32 %A, -3 @@ -2259,10 +2214,7 @@ define i1 @tautological19_negative(i32 %A) { define i1 @tautological20_subset1(i32 %A) { ; CHECK-LABEL: @tautological20_subset1( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 3 -; CHECK-NEXT: [[D:%.*]] = icmp sle i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, 1 %C2 = and i32 %A, 3 @@ -2272,10 +2224,7 @@ define i1 @tautological20_subset1(i32 %A) { define i1 @tautological20_subset2(i32 %A) { ; CHECK-LABEL: @tautological20_subset2( -; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], -4 -; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3 -; CHECK-NEXT: [[D:%.*]] = icmp sle i32 [[C1]], [[C2]] -; CHECK-NEXT: ret i1 [[D]] +; CHECK-NEXT: ret i1 true ; %C1 = and i32 %A, -4 %C2 = and i32 %A, -3 diff --git a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll index 083b4f1525d15..17f39a23d4f7a 100644 --- a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll +++ b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll @@ -2337,9 +2337,7 @@ false: define i8 @umin_and_mask(i8 %x) { ; CHECK-LABEL: @umin_and_mask( ; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = and i8 %x, 1 %and2 = and i8 %x, 3 @@ -2349,10 +2347,8 @@ define i8 @umin_and_mask(i8 %x) { define i8 @umax_and_mask(i8 %x) { ; CHECK-LABEL: @umax_and_mask( -; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = and i8 %x, 1 %and2 = and i8 %x, 3 @@ -2363,9 +2359,7 @@ define i8 @umax_and_mask(i8 %x) { define i8 @umin_or_mask(i8 %x) { ; CHECK-LABEL: @umin_or_mask( ; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = or i8 %x, 1 %and2 = or i8 %x, 3 @@ -2375,10 +2369,8 @@ define i8 @umin_or_mask(i8 %x) { define i8 @umax_or_mask(i8 %x) { ; CHECK-LABEL: @umax_or_mask( -; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = or i8 %x, 1 %and2 = or i8 %x, 3 @@ -2441,9 +2433,7 @@ define i8 @umax_or_mask_negative(i8 %x) { define i8 @smin_and_mask_subset1(i8 %x) { ; CHECK-LABEL: @smin_and_mask_subset1( ; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = and i8 %x, 1 %and2 = and i8 %x, 3 @@ -2453,10 +2443,8 @@ define i8 @smin_and_mask_subset1(i8 %x) { define i8 @smax_and_mask_subset1(i8 %x) { ; CHECK-LABEL: @smax_and_mask_subset1( -; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = and i8 %x, 1 %and2 = and i8 %x, 3 @@ -2467,9 +2455,7 @@ define i8 @smax_and_mask_subset1(i8 %x) { define i8 @smin_or_mask_subset1(i8 %x) { ; CHECK-LABEL: @smin_or_mask_subset1( ; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = or i8 %x, 1 %and2 = or i8 %x, 3 @@ -2479,10 +2465,8 @@ define i8 @smin_or_mask_subset1(i8 %x) { define i8 @smax_or_mask_subset1(i8 %x) { ; CHECK-LABEL: @smax_or_mask_subset1( -; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], 1 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], 3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = or i8 %x, 1 %and2 = or i8 %x, 3 @@ -2493,9 +2477,7 @@ define i8 @smax_or_mask_subset1(i8 %x) { define i8 @smin_and_mask_subset2(i8 %x) { ; CHECK-LABEL: @smin_and_mask_subset2( ; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], -4 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], -3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = and i8 %x, -4 %and2 = and i8 %x, -3 @@ -2505,10 +2487,8 @@ define i8 @smin_and_mask_subset2(i8 %x) { define i8 @smax_and_mask_subset2(i8 %x) { ; CHECK-LABEL: @smax_and_mask_subset2( -; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X:%.*]], -4 -; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X]], -3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = and i8 [[X:%.*]], -3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = and i8 %x, -4 %and2 = and i8 %x, -3 @@ -2519,9 +2499,7 @@ define i8 @smax_and_mask_subset2(i8 %x) { define i8 @smin_or_mask_subset2(i8 %x) { ; CHECK-LABEL: @smin_or_mask_subset2( ; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], -4 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], -3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smin.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: ret i8 [[AND1]] ; %and1 = or i8 %x, -4 %and2 = or i8 %x, -3 @@ -2531,10 +2509,8 @@ define i8 @smin_or_mask_subset2(i8 %x) { define i8 @smax_or_mask_subset2(i8 %x) { ; CHECK-LABEL: @smax_or_mask_subset2( -; CHECK-NEXT: [[AND1:%.*]] = or i8 [[X:%.*]], -4 -; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X]], -3 -; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.smax.i8(i8 [[AND1]], i8 [[AND2]]) -; CHECK-NEXT: ret i8 [[VAL]] +; CHECK-NEXT: [[AND2:%.*]] = or i8 [[X:%.*]], -3 +; CHECK-NEXT: ret i8 [[AND2]] ; %and1 = or i8 %x, -4 %and2 = or i8 %x, -3