Skip to content

Commit 37efa12

Browse files
committed
Add subtraction support for setLimitsForBinOp
1 parent b9329fe commit 37efa12

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9576,6 +9576,60 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
95769576
unsigned Width = Lower.getBitWidth();
95779577
const APInt *C;
95789578
switch (BO.getOpcode()) {
9579+
case Instruction::Sub:
9580+
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
9581+
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
9582+
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
9583+
9584+
// If the caller expects a signed compare, then try to use a signed range.
9585+
// Otherwise if both no-wraps are set, use the unsigned range because it
9586+
// is never larger than the signed range. Example:
9587+
// "sub nuw nsw i8 X, -2" is unsigned [0, 127] vs. signed [-128, 126].
9588+
if (PreferSignedRange && HasNSW && HasNUW)
9589+
HasNUW = false;
9590+
9591+
if (HasNUW) {
9592+
// 'sub nuw x, C' produces [0, UINT_MAX - C].
9593+
Upper = APInt::getAllOnes(Width) - *C + 1;
9594+
} else if (HasNSW) {
9595+
if (C->isNegative()) {
9596+
// 'sub nsw x, -C' produces [SINT_MIN + C, SINT_MAX].
9597+
Lower = APInt::getSignedMinValue(Width) + *C;
9598+
Upper = APInt::getSignedMaxValue(Width) + 1;
9599+
} else {
9600+
// 'sub nsw x, +C' produces [SINT_MIN, SINT_MAX - C].
9601+
Lower = APInt::getSignedMinValue(Width);
9602+
Upper = APInt::getSignedMaxValue(Width) - *C + 1;
9603+
}
9604+
}
9605+
} else if (match(BO.getOperand(0), m_APInt(C))) {
9606+
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
9607+
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
9608+
9609+
// If the caller expects a signed compare, then try to use a signed range.
9610+
// Otherwise if both no-wraps are set, use the unsigned range because it
9611+
// is never larger than the signed range. Example:
9612+
// "sub nuw nsw i8 X, -2" is unsigned [0, 127] vs. signed [-128, 126].
9613+
if (PreferSignedRange && HasNSW && HasNUW)
9614+
HasNUW = false;
9615+
9616+
if (HasNUW) {
9617+
// 'sub nuw c, x' produces [0, C].
9618+
Upper = *C + 1;
9619+
} else if (HasNSW) {
9620+
if (C->isNegative()) {
9621+
// 'sub nsw C, x' produces [SINT_MIN, SINT_MAX - C].
9622+
Lower = APInt::getSignedMinValue(Width);
9623+
Upper = APInt::getSignedMaxValue(Width) - *C + 1;
9624+
} else {
9625+
// Note that sub 0, INT_MIN is not NSW. It techically is a signed wrap
9626+
// 'sub nsw C, x' produces [SINT_MIN + 1 + C, SINT_MAX].
9627+
Lower = APInt::getSignedMinValue(Width) + *C + 1;
9628+
Upper = APInt::getSignedMaxValue(Width) + 1;
9629+
}
9630+
}
9631+
}
9632+
break;
95799633
case Instruction::Add:
95809634
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
95819635
bool HasNSW = IIQ.hasNoSignedWrap(&BO);

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)