diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -1371,7 +1371,8 @@ /// Commuted variants are assumed to be handled by calling this function again /// with the parameters swapped. static Value *simplifyUnsignedRangeCheck(ICmpInst *ZeroICmp, - ICmpInst *UnsignedICmp, bool IsAnd) { + ICmpInst *UnsignedICmp, bool IsAnd, + const DataLayout &DL) { Value *X, *Y; ICmpInst::Predicate EqPred; @@ -1395,6 +1396,18 @@ if (UnsignedPred == ICmpInst::ICMP_ULT && EqPred == ICmpInst::ICMP_NE) return IsAnd ? UnsignedICmp : ZeroICmp; + // X <= Y && Y != 0 --> Y <= X iff X != 0 + // X <= Y || Y != 0 --> Y != 0 iff X != 0 + if (UnsignedPred == ICmpInst::ICMP_ULE && EqPred == ICmpInst::ICMP_NE && + isKnownNonZero(X, DL)) + return IsAnd ? UnsignedICmp : ZeroICmp; + + // X > Y && Y == 0 --> Y == 0 iff X != 0 + // X > Y || Y == 0 --> Y <= X iff X != 0 + if (UnsignedPred == ICmpInst::ICMP_UGT && EqPred == ICmpInst::ICMP_EQ && + isKnownNonZero(X, DL)) + return IsAnd ? ZeroICmp : UnsignedICmp; + // X >= Y || Y != 0 --> true // X >= Y || Y == 0 --> X >= Y if (UnsignedPred == ICmpInst::ICMP_UGE && !IsAnd) { @@ -1587,10 +1600,11 @@ } static Value *simplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1, - const InstrInfoQuery &IIQ) { - if (Value *X = simplifyUnsignedRangeCheck(Op0, Op1, /*IsAnd=*/true)) + const InstrInfoQuery &IIQ, + const DataLayout &DL) { + if (Value *X = simplifyUnsignedRangeCheck(Op0, Op1, /*IsAnd=*/true, DL)) return X; - if (Value *X = simplifyUnsignedRangeCheck(Op1, Op0, /*IsAnd=*/true)) + if (Value *X = simplifyUnsignedRangeCheck(Op1, Op0, /*IsAnd=*/true, DL)) return X; if (Value *X = simplifyAndOfICmpsWithSameOperands(Op0, Op1)) @@ -1660,10 +1674,11 @@ } static Value *simplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1, - const InstrInfoQuery &IIQ) { - if (Value *X = simplifyUnsignedRangeCheck(Op0, Op1, /*IsAnd=*/false)) + const InstrInfoQuery &IIQ, + const DataLayout &DL) { + if (Value *X = simplifyUnsignedRangeCheck(Op0, Op1, /*IsAnd=*/false, DL)) return X; - if (Value *X = simplifyUnsignedRangeCheck(Op1, Op0, /*IsAnd=*/false)) + if (Value *X = simplifyUnsignedRangeCheck(Op1, Op0, /*IsAnd=*/false, DL)) return X; if (Value *X = simplifyOrOfICmpsWithSameOperands(Op0, Op1)) @@ -1738,8 +1753,8 @@ auto *ICmp0 = dyn_cast(Op0); auto *ICmp1 = dyn_cast(Op1); if (ICmp0 && ICmp1) - V = IsAnd ? simplifyAndOfICmps(ICmp0, ICmp1, Q.IIQ) - : simplifyOrOfICmps(ICmp0, ICmp1, Q.IIQ); + V = IsAnd ? simplifyAndOfICmps(ICmp0, ICmp1, Q.IIQ, Q.DL) + : simplifyOrOfICmps(ICmp0, ICmp1, Q.IIQ, Q.DL); auto *FCmp0 = dyn_cast(Op0); auto *FCmp1 = dyn_cast(Op1); diff --git a/llvm/test/Transforms/InstSimplify/redundant-null-check-in-uadd_with_overflow-of-nonnull-ptr.ll b/llvm/test/Transforms/InstSimplify/redundant-null-check-in-uadd_with_overflow-of-nonnull-ptr.ll --- a/llvm/test/Transforms/InstSimplify/redundant-null-check-in-uadd_with_overflow-of-nonnull-ptr.ll +++ b/llvm/test/Transforms/InstSimplify/redundant-null-check-in-uadd_with_overflow-of-nonnull-ptr.ll @@ -11,10 +11,8 @@ ; CHECK-LABEL: @t0( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -27,10 +25,8 @@ ; CHECK-LABEL: @t1( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -43,10 +39,8 @@ ; CHECK-LABEL: @t2( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -59,10 +53,8 @@ ; CHECK-LABEL: @t3( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -72,7 +64,7 @@ ret i1 %res } -; If the joining operator was 'or', i.e. we check that either we produced null +; If the joining operator was 'or', i.e. we check that either we produced non-null ; pointer, or no overflow happened, then the overflow check itself is redundant. define i1 @t4(i8* nonnull %base, i64 %offset) { @@ -80,9 +72,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -96,9 +86,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -112,9 +100,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -128,9 +114,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -148,10 +132,8 @@ ; CHECK-LABEL: @t8( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -164,10 +146,8 @@ ; CHECK-LABEL: @t9( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -180,10 +160,8 @@ ; CHECK-LABEL: @t10( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -196,10 +174,8 @@ ; CHECK-LABEL: @t11( ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] -; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -217,9 +193,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -233,9 +207,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NON_NULL_AFTER_ADJUSTMENT]], [[NO_OVERFLOW_DURING_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -249,9 +221,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset @@ -265,9 +235,7 @@ ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint i8* [[BASE:%.*]] to i64 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]] ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]], [[NON_NULL_AFTER_ADJUSTMENT]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]] ; %base_int = ptrtoint i8* %base to i64 %adjusted = add i64 %base_int, %offset