Skip to content

Commit 30a41a6

Browse files
authored
[ValueTracking] Add subtraction support for setLimitsForBinOp (#143618)
We can determine the range from a subtraction if it has nsw or nuw. https://alive2.llvm.org/ce/z/tXAKVV
1 parent 149cb5c commit 30a41a6

File tree

3 files changed

+36
-11
lines changed

3 files changed

+36
-11
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9580,15 +9580,45 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
95809580
unsigned Width = Lower.getBitWidth();
95819581
const APInt *C;
95829582
switch (BO.getOpcode()) {
9583-
case Instruction::Add:
9584-
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
9583+
case Instruction::Sub:
9584+
if (match(BO.getOperand(0), m_APInt(C))) {
95859585
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
95869586
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
95879587

95889588
// If the caller expects a signed compare, then try to use a signed range.
95899589
// Otherwise if both no-wraps are set, use the unsigned range because it
95909590
// is never larger than the signed range. Example:
9591-
// "add nuw nsw i8 X, -2" is unsigned [254,255] vs. signed [-128, 125].
9591+
// "sub nuw nsw i8 -2, x" is unsigned [0, 254] vs. signed [-128, 126].
9592+
// "sub nuw nsw i8 2, x" is unsigned [0, 2] vs. signed [-125, 127].
9593+
if (PreferSignedRange && HasNSW && HasNUW)
9594+
HasNUW = false;
9595+
9596+
if (HasNUW) {
9597+
// 'sub nuw c, x' produces [0, C].
9598+
Upper = *C + 1;
9599+
} else if (HasNSW) {
9600+
if (C->isNegative()) {
9601+
// 'sub nsw -C, x' produces [SINT_MIN, -C - SINT_MIN].
9602+
Lower = APInt::getSignedMinValue(Width);
9603+
Upper = *C - APInt::getSignedMaxValue(Width);
9604+
} else {
9605+
// Note that sub 0, INT_MIN is not NSW. It techically is a signed wrap
9606+
// 'sub nsw C, x' produces [C - SINT_MAX, SINT_MAX].
9607+
Lower = *C - APInt::getSignedMaxValue(Width);
9608+
Upper = APInt::getSignedMinValue(Width);
9609+
}
9610+
}
9611+
}
9612+
break;
9613+
case Instruction::Add:
9614+
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
9615+
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
9616+
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
9617+
9618+
// If the caller expects a signed compare, then try to use a signed
9619+
// range. Otherwise if both no-wraps are set, use the unsigned range
9620+
// because it is never larger than the signed range. Example: "add nuw
9621+
// nsw i8 X, -2" is unsigned [254,255] vs. signed [-128, 125].
95929622
if (PreferSignedRange && HasNSW && HasNUW)
95939623
HasNUW = false;
95949624

llvm/test/Transforms/InstCombine/div.ll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,7 @@ define <2 x i8> @sdiv_exact_negated_dividend_constant_divisor_vec_splat(<2 x i8>
494494

495495
define i8 @sdiv_negated_dividend_constant_divisor_smin(i8 %x) {
496496
; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_smin(
497-
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
498-
; CHECK-NEXT: [[D:%.*]] = zext i1 [[TMP1]] to i8
499-
; CHECK-NEXT: ret i8 [[D]]
497+
; CHECK-NEXT: ret i8 0
500498
;
501499
%neg = sub nsw i8 0, %x
502500
%d = sdiv i8 %neg, -128
@@ -505,9 +503,7 @@ define i8 @sdiv_negated_dividend_constant_divisor_smin(i8 %x) {
505503

506504
define <2 x i8> @sdiv_negated_dividend_constant_divisor_vec_splat_smin(<2 x i8> %x) {
507505
; CHECK-LABEL: @sdiv_negated_dividend_constant_divisor_vec_splat_smin(
508-
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], splat (i8 -128)
509-
; CHECK-NEXT: [[D:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
510-
; CHECK-NEXT: ret <2 x i8> [[D]]
506+
; CHECK-NEXT: ret <2 x i8> zeroinitializer
511507
;
512508
%neg = sub nsw <2 x i8> zeroinitializer, %x
513509
%d = sdiv <2 x i8> %neg, <i8 -128, i8 -128>

llvm/test/Transforms/InstCombine/icmp-sub.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,7 @@ define i1 @subC_nsw_ne(i32 %x) {
290290
; CHECK-LABEL: @subC_nsw_ne(
291291
; CHECK-NEXT: [[SUBX:%.*]] = sub nsw i32 -2147483647, [[X:%.*]]
292292
; CHECK-NEXT: call void @use(i32 [[SUBX]])
293-
; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[X]], 2147483603
294-
; CHECK-NEXT: ret i1 [[R]]
293+
; CHECK-NEXT: ret i1 true
295294
;
296295
%subx = sub nsw i32 -2147483647, %x
297296
call void @use(i32 %subx)

0 commit comments

Comments
 (0)