Skip to content

Commit ccb3601

Browse files
committed
Add subtraction support for setLimitsForBinOp
1 parent 07a1d47 commit ccb3601

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
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);

0 commit comments

Comments
 (0)