Skip to content

[ValueTracking] Add subtraction support for setLimitsForBinOp #143618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 15, 2025

Conversation

AZero13
Copy link
Contributor

@AZero13 AZero13 commented Jun 10, 2025

We can determine the range from a subtraction if it has nsw or nuw.

https://alive2.llvm.org/ce/z/tXAKVV

@AZero13 AZero13 requested a review from nikic as a code owner June 10, 2025 22:36
@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Jun 10, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 10, 2025

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: AZero13 (AZero13)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/143618.diff

1 Files Affected:

  • (modified) llvm/lib/Analysis/ValueTracking.cpp (+54)
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);

@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Jun 10, 2025
@AZero13 AZero13 force-pushed the csel branch 2 times, most recently from a859101 to ab86d08 Compare June 11, 2025 00:23
@AZero13 AZero13 force-pushed the csel branch 2 times, most recently from c4d225b to e8e025a Compare June 13, 2025 15:02
@AZero13 AZero13 requested a review from dtcxzyw June 13, 2025 16:44
@AZero13 AZero13 force-pushed the csel branch 3 times, most recently from 2ae5bb4 to 0b9dd31 Compare June 13, 2025 23:16
We can determine the range from a subtraction if it has nsw or nuw.
Alive2: https://alive2.llvm.org/ce/z/tXAKVV
@dtcxzyw
Copy link
Member

dtcxzyw commented Jun 14, 2025

@AZero13 Please avoid rebasing and force-pushing on your branches... If you don't need pre-commit tests from newer commits, just append a new commit for your change.

@dtcxzyw dtcxzyw changed the title Add subtraction support for setLimitsForBinOp [ValueTracking] Add subtraction support for setLimitsForBinOp Jun 14, 2025
AZero13 and others added 2 commits June 14, 2025 08:24
Co-authored-by: Yingwei Zheng <[email protected]>
Co-authored-by: Yingwei Zheng <[email protected]>
Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG

@dtcxzyw dtcxzyw merged commit 30a41a6 into llvm:main Jun 15, 2025
7 checks passed
@AZero13 AZero13 deleted the csel branch June 15, 2025 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants