[llvm] [ValueTracking] If overlap in unsigned and signed range is contiguous, return it (PR #144267)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 15 08:25:43 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/144267
>From b8b8a03089d972578ae86672c50288c5bf42f550 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sun, 15 Jun 2025 11:02:22 -0400
Subject: [PATCH] [ValueTracking] If overlap in unsigned and signed range is
contiguous, return it
We have to choose between unsigned and signed if there are two overlaps, aka the range wraps around, meaning [254,255] vs. signed [-128, 125], but [254,255] correspond to [-2 -1] which is in the range [-128, 125].
However, a range that would not work would be one where one has to pick between [0, 129] vs [-127, 127] because 129 is -2 signed.
---
llvm/lib/Analysis/ValueTracking.cpp | 48 +++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index e7a1f07c0270d..58d1d8ef43235 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9585,6 +9585,30 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
+ if (HasNUW && HasNSW) {
+ APInt uLo = APInt::getZero(Width);
+ APInt uHi = *C + 1;
+
+ APInt sLo, sHi;
+ if (C->isNegative()) {
+ sLo = APInt::getSignedMinValue(Width);
+ sHi = APInt::getSignedMaxValue(Width) + *C + 2;
+ } else {
+ sLo = APInt::getSignedMinValue(Width) + *C + 1;
+ sHi = APInt::getSignedMaxValue(Width) + 1;
+ }
+
+ APInt iLo = APIntOps::smax(uLo, sLo);
+ APInt iHi = APIntOps::smin(uHi, sHi);
+
+ if (iLo.ult(iHi) && iLo.sge(APInt::getSignedMinValue(Width)) &&
+ (iHi - 1).sle(APInt::getSignedMaxValue(Width))) {
+ Lower = iLo;
+ Upper = iHi;
+ break;
+ }
+ }
+
// 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:
@@ -9615,6 +9639,30 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
+ if (HasNUW && HasNSW) {
+ APInt uLo = *C;
+ APInt uHi = APInt::getZero(Width);
+
+ APInt sLo, sHi;
+ if (C->isNegative()) {
+ sLo = APInt::getSignedMinValue(Width);
+ sHi = APInt::getSignedMaxValue(Width) + *C + 1;
+ } else {
+ sLo = APInt::getSignedMinValue(Width) + *C;
+ sHi = APInt::getSignedMaxValue(Width) + 1;
+ }
+
+ APInt iLo = APIntOps::smax(uLo, sLo);
+ APInt iHi = APIntOps::smin(uHi, sHi);
+
+ if (iLo.ult(iHi) && iLo.sge(APInt::getSignedMinValue(Width)) &&
+ (iHi - 1).sle(APInt::getSignedMaxValue(Width))) {
+ Lower = iLo;
+ Upper = iHi;
+ break;
+ }
+ }
+
// 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: "add nuw
More information about the llvm-commits
mailing list