/// 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;
if (UnsignedPred == ICmpInst::ICMP_ULT && EqPred == ICmpInst::ICMP_NE)
return IsAnd ? UnsignedICmp : ZeroICmp;
+ // X <= Y && Y != 0 --> X <= Y 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 --> X > Y 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) {
}
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))
}
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))
auto *ICmp0 = dyn_cast<ICmpInst>(Op0);
auto *ICmp1 = dyn_cast<ICmpInst>(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<FCmpInst>(Op0);
auto *FCmp1 = dyn_cast<FCmpInst>(Op1);
; 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
; 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
; 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
; 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
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) {
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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