diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index d8c1096049dce..b4694b75b8c9a 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -9576,15 +9576,45 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower, unsigned Width = Lower.getBitWidth(); const APInt *C; switch (BO.getOpcode()) { - case Instruction::Add: - if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) { + case Instruction::Sub: + if (match(BO.getOperand(0), m_APInt(C))) { bool HasNSW = IIQ.hasNoSignedWrap(&BO); bool HasNUW = IIQ.hasNoUnsignedWrap(&BO); // If the caller expects a signed compare, then try to use a signed range. // Otherwise if both no-wraps are set, use the unsigned range because it // is never larger than the signed range. Example: - // "add nuw nsw i8 X, -2" is unsigned [254,255] vs. signed [-128, 125]. + // "sub nuw nsw i8 -2, x" is unsigned [0, 254] vs. signed [-128, 126]. + // "sub nuw nsw i8 2, x" is unsigned [0, 2] vs. signed [-125, 127]. + if (PreferSignedRange && HasNSW && HasNUW) + HasNUW = false; + + if (HasNUW) { + // 'sub nuw c, x' produces [0, C]. + Upper = *C + 1; + } else if (HasNSW) { + if (C->isNegative()) { + // 'sub nsw -C, x' produces [SINT_MIN, -C - SINT_MIN]. + Lower = APInt::getSignedMinValue(Width); + Upper = *C - APInt::getSignedMaxValue(Width); + } else { + // Note that sub 0, INT_MIN is not NSW. It techically is a signed wrap + // 'sub nsw C, x' produces [C - SINT_MAX, SINT_MAX]. + Lower = *C - APInt::getSignedMaxValue(Width); + Upper = APInt::getSignedMinValue(Width); + } + } + } + break; + case Instruction::Add: + if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) { + bool HasNSW = IIQ.hasNoSignedWrap(&BO); + bool HasNUW = IIQ.hasNoUnsignedWrap(&BO); + + // If the caller expects a signed compare, then try to use a signed + // range. Otherwise if both no-wraps are set, use the unsigned range + // because it is never larger than the signed range. Example: "add nuw + // nsw i8 X, -2" is unsigned [254,255] vs. signed [-128, 125]. if (PreferSignedRange && HasNSW && HasNUW) HasNUW = false; diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll index 7e93612150e8c..f0fdc5f54366a 100644 --- a/llvm/test/Transforms/InstCombine/div.ll +++ b/llvm/test/Transforms/InstCombine/div.ll @@ -494,9 +494,7 @@ define <2 x i8> @sdiv_exact_negated_dividend_constant_divisor_vec_splat(<2 x i8> define i8 @sdiv_negated_dividend_constant_divisor_smin(i8 %x) { ; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_smin( -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128 -; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i8 -; CHECK-NEXT: ret i8 [[D]] +; CHECK-NEXT: ret i8 0 ; %neg = sub nsw i8 0, %x %d = sdiv i8 %neg, -128 @@ -505,9 +503,7 @@ define i8 @sdiv_negated_dividend_constant_divisor_smin(i8 %x) { define <2 x i8> @sdiv_negated_dividend_constant_divisor_vec_splat_smin(<2 x i8> %x) { ; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec_splat_smin( -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], splat (i8 -128) -; CHECK-NEXT: [[D:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8> -; CHECK-NEXT: ret <2 x i8> [[D]] +; CHECK-NEXT: ret <2 x i8> zeroinitializer ; %neg = sub nsw <2 x i8> zeroinitializer, %x %d = sdiv <2 x i8> %neg, diff --git a/llvm/test/Transforms/InstCombine/icmp-sub.ll b/llvm/test/Transforms/InstCombine/icmp-sub.ll index 4143902bc9c46..13ed7ba0c1703 100644 --- a/llvm/test/Transforms/InstCombine/icmp-sub.ll +++ b/llvm/test/Transforms/InstCombine/icmp-sub.ll @@ -290,8 +290,7 @@ define i1 @subC_nsw_ne(i32 %x) { ; CHECK-LABEL: @subC_nsw_ne( ; CHECK-NEXT: [[SUBX:%.*]] = sub nsw i32 -2147483647, [[X:%.*]] ; CHECK-NEXT: call void @use(i32 [[SUBX]]) -; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[X]], 2147483603 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 true ; %subx = sub nsw i32 -2147483647, %x call void @use(i32 %subx)