[llvm] InstSimplify: teach simplifyICmpWithConstant about samesign (PR #125899)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 7 03:09:22 PST 2025


https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/125899

>From 2f07175a2ed055c456a81efdb16e791137924e8e Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Wed, 5 Feb 2025 15:56:35 +0000
Subject: [PATCH 1/3] ValueTracking: pre-commit constrange-samesign tests

---
 .../Analysis/ValueTracking/constant-ranges.ll | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/llvm/test/Analysis/ValueTracking/constant-ranges.ll b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
index c440cfad889d3b4..7a4b9f7ed645a9f 100644
--- a/llvm/test/Analysis/ValueTracking/constant-ranges.ll
+++ b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
@@ -160,6 +160,15 @@ define i1 @srem_posC_okay0(i8 %x) {
   ret i1 %r
 }
 
+define i1 @srem_posC_okay0_samesign(i8 %x) {
+; CHECK-LABEL: @srem_posC_okay0_samesign(
+; CHECK-NEXT:    ret i1 true
+;
+  %val = srem i8 34, %x
+  %r = icmp samesign ule i8 %val, 34
+  ret i1 %r
+}
+
 define i1 @srem_posC_okay1(i8 %x) {
 ; CHECK-LABEL: @srem_posC_okay1(
 ; CHECK-NEXT:    ret i1 true
@@ -169,6 +178,15 @@ define i1 @srem_posC_okay1(i8 %x) {
   ret i1 %r
 }
 
+define i1 @srem_posC_okay1_samesign(i8 %x) {
+; CHECK-LABEL: @srem_posC_okay1_samesign(
+; CHECK-NEXT:    ret i1 false
+;
+  %val = srem i8 34, %x
+  %r = icmp samesign uge i8 %val, -3
+  ret i1 %r
+}
+
 define i1 @srem_negC_okay0(i8 %x) {
 ; CHECK-LABEL: @srem_negC_okay0(
 ; CHECK-NEXT:    ret i1 true
@@ -178,6 +196,17 @@ define i1 @srem_negC_okay0(i8 %x) {
   ret i1 %r
 }
 
+define i1 @srem_negC_okay0_samesign(i8 %x) {
+; CHECK-LABEL: @srem_negC_okay0_samesign(
+; CHECK-NEXT:    [[VAL:%.*]] = srem i8 -34, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp samesign ule i8 [[VAL]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %val = srem i8 -34, %x
+  %r = icmp samesign ule i8 %val, 0
+  ret i1 %r
+}
+
 define i1 @srem_negC_okay1(i8 %x) {
 ; CHECK-LABEL: @srem_negC_okay1(
 ; CHECK-NEXT:    ret i1 true
@@ -187,6 +216,17 @@ define i1 @srem_negC_okay1(i8 %x) {
   ret i1 %r
 }
 
+define i1 @srem_negC_okay1_samesign(i8 %x) {
+; CHECK-LABEL: @srem_negC_okay1_samesign(
+; CHECK-NEXT:    [[VAL:%.*]] = srem i8 -34, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp samesign uge i8 [[VAL]], -34
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %val = srem i8 -34, %x
+  %r = icmp samesign uge i8 %val, -34
+  ret i1 %r
+}
+
 define i1 @srem_posC_fail0(i8 %x) {
 ; CHECK-LABEL: @srem_posC_fail0(
 ; CHECK-NEXT:    [[VAL:%.*]] = srem i8 34, [[X:%.*]]

>From 71b5791b1bd313ca53ae076b7d43df82112aed5f Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Wed, 5 Feb 2025 17:46:48 +0000
Subject: [PATCH 2/3] InstSimplify: teach simplifyICmpWithConstant about
 samesign

We have chosen to change ConstantRange::makeAllowedICmpRegion to respect
samesign information, noting that ConstantRange::makeExactICmpRegion
should not be modified.
---
 llvm/include/llvm/IR/ConstantRange.h          |  5 +-
 llvm/lib/Analysis/InstructionSimplify.cpp     |  2 +-
 llvm/lib/IR/ConstantRange.cpp                 | 94 ++++++++++---------
 .../Analysis/ValueTracking/constant-ranges.ll | 10 +-
 4 files changed, 58 insertions(+), 53 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index d086c25390fd227..a40de0a792ef0aa 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -32,6 +32,7 @@
 #define LLVM_IR_CONSTANTRANGE_H
 
 #include "llvm/ADT/APInt.h"
+#include "llvm/IR/CmpPredicate.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/Support/Compiler.h"
@@ -99,8 +100,10 @@ class [[nodiscard]] ConstantRange {
   /// answer is not representable as a ConstantRange, the return value will be a
   /// proper superset of the above.
   ///
+  /// Note that we respect samesign information on the icmp.
+  ///
   /// Example: Pred = ult and Other = i8 [2, 5) returns Result = [0, 4)
-  static ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred,
+  static ConstantRange makeAllowedICmpRegion(CmpPredicate Pred,
                                              const ConstantRange &Other);
 
   /// Produce the largest range such that all values in the returned range
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 3cbc4107433ef3d..7a5a7a39efb1eb9 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3012,7 +3012,7 @@ static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
   }
 
   // Rule out tautological comparisons (eg., ult 0 or uge 0).
-  ConstantRange RHS_CR = ConstantRange::makeExactICmpRegion(Pred, *C);
+  ConstantRange RHS_CR = ConstantRange::makeAllowedICmpRegion(Pred, *C);
   if (RHS_CR.isEmptySet())
     return ConstantInt::getFalse(ITy);
   if (RHS_CR.isFullSet())
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 35664353989929d..e776ec38b27bfe2 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -95,54 +95,60 @@ KnownBits ConstantRange::toKnownBits() const {
   return Known;
 }
 
-ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
+ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
                                                    const ConstantRange &CR) {
   if (CR.isEmptySet())
     return CR;
 
-  uint32_t W = CR.getBitWidth();
-  switch (Pred) {
-  default:
-    llvm_unreachable("Invalid ICmp predicate to makeAllowedICmpRegion()");
-  case CmpInst::ICMP_EQ:
-    return CR;
-  case CmpInst::ICMP_NE:
-    if (CR.isSingleElement())
-      return ConstantRange(CR.getUpper(), CR.getLower());
-    return getFull(W);
-  case CmpInst::ICMP_ULT: {
-    APInt UMax(CR.getUnsignedMax());
-    if (UMax.isMinValue())
-      return getEmpty(W);
-    return ConstantRange(APInt::getMinValue(W), std::move(UMax));
-  }
-  case CmpInst::ICMP_SLT: {
-    APInt SMax(CR.getSignedMax());
-    if (SMax.isMinSignedValue())
-      return getEmpty(W);
-    return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
-  }
-  case CmpInst::ICMP_ULE:
-    return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
-  case CmpInst::ICMP_SLE:
-    return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
-  case CmpInst::ICMP_UGT: {
-    APInt UMin(CR.getUnsignedMin());
-    if (UMin.isMaxValue())
-      return getEmpty(W);
-    return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
-  }
-  case CmpInst::ICMP_SGT: {
-    APInt SMin(CR.getSignedMin());
-    if (SMin.isMaxSignedValue())
-      return getEmpty(W);
-    return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
-  }
-  case CmpInst::ICMP_UGE:
-    return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
-  case CmpInst::ICMP_SGE:
-    return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
-  }
+  auto CheckPred = [CR](CmpInst::Predicate P) {
+    uint32_t W = CR.getBitWidth();
+    switch (P) {
+    default:
+      llvm_unreachable("Invalid ICmp predicate to makeAllowedICmpRegion()");
+    case CmpInst::ICMP_EQ:
+      return CR;
+    case CmpInst::ICMP_NE:
+      if (CR.isSingleElement())
+        return ConstantRange(CR.getUpper(), CR.getLower());
+      return getFull(W);
+    case CmpInst::ICMP_ULT: {
+      APInt UMax(CR.getUnsignedMax());
+      if (UMax.isMinValue())
+        return getEmpty(W);
+      return ConstantRange(APInt::getMinValue(W), std::move(UMax));
+    }
+    case CmpInst::ICMP_SLT: {
+      APInt SMax(CR.getSignedMax());
+      if (SMax.isMinSignedValue())
+        return getEmpty(W);
+      return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
+    }
+    case CmpInst::ICMP_ULE:
+      return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
+    case CmpInst::ICMP_SLE:
+      return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
+    case CmpInst::ICMP_UGT: {
+      APInt UMin(CR.getUnsignedMin());
+      if (UMin.isMaxValue())
+        return getEmpty(W);
+      return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
+    }
+    case CmpInst::ICMP_SGT: {
+      APInt SMin(CR.getSignedMin());
+      if (SMin.isMaxSignedValue())
+        return getEmpty(W);
+      return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
+    }
+    case CmpInst::ICMP_UGE:
+      return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
+    case CmpInst::ICMP_SGE:
+      return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
+    }
+  };
+  if (Pred.hasSameSign())
+    return CheckPred(Pred).unionWith(
+        CheckPred(ICmpInst::getFlippedSignednessPredicate(Pred)));
+  return CheckPred(Pred);
 }
 
 ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
diff --git a/llvm/test/Analysis/ValueTracking/constant-ranges.ll b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
index 7a4b9f7ed645a9f..2e9731895bff3ce 100644
--- a/llvm/test/Analysis/ValueTracking/constant-ranges.ll
+++ b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
@@ -180,7 +180,7 @@ define i1 @srem_posC_okay1(i8 %x) {
 
 define i1 @srem_posC_okay1_samesign(i8 %x) {
 ; CHECK-LABEL: @srem_posC_okay1_samesign(
-; CHECK-NEXT:    ret i1 false
+; CHECK-NEXT:    ret i1 true
 ;
   %val = srem i8 34, %x
   %r = icmp samesign uge i8 %val, -3
@@ -198,9 +198,7 @@ define i1 @srem_negC_okay0(i8 %x) {
 
 define i1 @srem_negC_okay0_samesign(i8 %x) {
 ; CHECK-LABEL: @srem_negC_okay0_samesign(
-; CHECK-NEXT:    [[VAL:%.*]] = srem i8 -34, [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp samesign ule i8 [[VAL]], 0
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %val = srem i8 -34, %x
   %r = icmp samesign ule i8 %val, 0
@@ -218,9 +216,7 @@ define i1 @srem_negC_okay1(i8 %x) {
 
 define i1 @srem_negC_okay1_samesign(i8 %x) {
 ; CHECK-LABEL: @srem_negC_okay1_samesign(
-; CHECK-NEXT:    [[VAL:%.*]] = srem i8 -34, [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp samesign uge i8 [[VAL]], -34
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %val = srem i8 -34, %x
   %r = icmp samesign uge i8 %val, -34

>From 17a8bff6a2940466a7c66f4420d71365f22b8d4f Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Fri, 7 Feb 2025 10:10:28 +0000
Subject: [PATCH 3/3] CR, IS: address review

---
 llvm/include/llvm/IR/ConstantRange.h      | 10 ++++++----
 llvm/lib/Analysis/InstructionSimplify.cpp |  2 +-
 llvm/lib/IR/ConstantRange.cpp             | 15 ++++++++++-----
 3 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index a40de0a792ef0aa..1d59563dd781142 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -32,10 +32,8 @@
 #define LLVM_IR_CONSTANTRANGE_H
 
 #include "llvm/ADT/APInt.h"
-#include "llvm/IR/CmpPredicate.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
-#include "llvm/Support/Compiler.h"
 #include <cstdint>
 
 namespace llvm {
@@ -43,6 +41,7 @@ namespace llvm {
 class MDNode;
 class raw_ostream;
 struct KnownBits;
+class CmpPredicate;
 
 /// This class represents a range of values.
 class [[nodiscard]] ConstantRange {
@@ -100,12 +99,15 @@ class [[nodiscard]] ConstantRange {
   /// answer is not representable as a ConstantRange, the return value will be a
   /// proper superset of the above.
   ///
-  /// Note that we respect samesign information on the icmp.
-  ///
   /// Example: Pred = ult and Other = i8 [2, 5) returns Result = [0, 4)
   static ConstantRange makeAllowedICmpRegion(CmpPredicate Pred,
                                              const ConstantRange &Other);
 
+  /// Calls makeAllowedICmpRegion with a CmpPredicate, yielding an asymmetric
+  /// range when samesign information is present.
+  static ConstantRange makeAsymmetricICmpRegion(CmpPredicate Pred,
+                                                const ConstantRange &Other);
+
   /// Produce the largest range such that all values in the returned range
   /// satisfy the given predicate with all values contained within Other.
   /// Formally, this returns a subset of
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 7a5a7a39efb1eb9..939df1e4677bf2a 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3012,7 +3012,7 @@ static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
   }
 
   // Rule out tautological comparisons (eg., ult 0 or uge 0).
-  ConstantRange RHS_CR = ConstantRange::makeAllowedICmpRegion(Pred, *C);
+  ConstantRange RHS_CR = ConstantRange::makeAsymmetricICmpRegion(Pred, *C);
   if (RHS_CR.isEmptySet())
     return ConstantInt::getFalse(ITy);
   if (RHS_CR.isFullSet())
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index e776ec38b27bfe2..b5dad4505e21f71 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -100,7 +100,7 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
   if (CR.isEmptySet())
     return CR;
 
-  auto CheckPred = [CR](CmpInst::Predicate P) {
+  auto GetCR = [CR](CmpInst::Predicate P) {
     uint32_t W = CR.getBitWidth();
     switch (P) {
     default:
@@ -145,10 +145,15 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
       return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
     }
   };
-  if (Pred.hasSameSign())
-    return CheckPred(Pred).unionWith(
-        CheckPred(ICmpInst::getFlippedSignednessPredicate(Pred)));
-  return CheckPred(Pred);
+  if (Pred.hasSameSign() && ICmpInst::isRelational(Pred))
+    return GetCR(Pred).unionWith(
+        GetCR(ICmpInst::getFlippedSignednessPredicate(Pred)));
+  return GetCR(Pred);
+}
+
+ConstantRange ConstantRange::makeAsymmetricICmpRegion(CmpPredicate Pred,
+                                                      const ConstantRange &CR) {
+  return makeAllowedICmpRegion(Pred, CR);
 }
 
 ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred,



More information about the llvm-commits mailing list