[llvm] Add subtraction support for setLimitsForBinOp (PR #143618)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 10 15:36:23 PDT 2025
https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/143618
None
>From ccb3601ecc5bfa932b94cc5efaf59e011e20e8d2 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Tue, 10 Jun 2025 16:44:34 -0400
Subject: [PATCH] Add subtraction support for setLimitsForBinOp
---
llvm/lib/Analysis/ValueTracking.cpp | 54 +++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index d8c1096049dce..88e8ea4878fe1 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9576,6 +9576,60 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
unsigned Width = Lower.getBitWidth();
const APInt *C;
switch (BO.getOpcode()) {
+ case Instruction::Sub:
+ 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:
+ // "sub nuw nsw i8 X, -2" is unsigned [0, 127] vs. signed [-128, 126].
+ if (PreferSignedRange && HasNSW && HasNUW)
+ HasNUW = false;
+
+ if (HasNUW) {
+ // 'sub nuw x, C' produces [0, UINT_MAX - C].
+ Upper = APInt::getAllOnes(Width) - *C + 1;
+ } else if (HasNSW) {
+ if (C->isNegative()) {
+ // 'sub nsw x, -C' produces [SINT_MIN + C, SINT_MAX].
+ Lower = APInt::getSignedMinValue(Width) + *C;
+ Upper = APInt::getSignedMaxValue(Width) + 1;
+ } else {
+ // 'sub nsw x, +C' produces [SINT_MIN, SINT_MAX - C].
+ Lower = APInt::getSignedMinValue(Width);
+ Upper = APInt::getSignedMaxValue(Width) - *C + 1;
+ }
+ }
+ } else 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:
+ // "sub nuw nsw i8 X, -2" is unsigned [0, 127] vs. signed [-128, 126].
+ 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, SINT_MAX - C].
+ Lower = APInt::getSignedMinValue(Width);
+ Upper = APInt::getSignedMaxValue(Width) - *C + 1;
+ } else {
+ // Note that sub 0, INT_MIN is not NSW. It techically is a signed wrap
+ // 'sub nsw C, x' produces [SINT_MIN + 1 + C, SINT_MAX].
+ Lower = APInt::getSignedMinValue(Width) + *C + 1;
+ Upper = APInt::getSignedMaxValue(Width) + 1;
+ }
+ }
+ }
+ break;
case Instruction::Add:
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
More information about the llvm-commits
mailing list