[llvm] [InstCombine] canonicalize sign bit checks (PR #122962)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 14 12:29:16 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Jacob Young (jacobly0)

<details>
<summary>Changes</summary>

This is a generalization of #<!-- -->122520 to other instructions with constrained result ranges.

Not sure whether this generalization is desirable, but I thought I would try it out.

---

Patch is 27.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122962.diff


10 Files Affected:

- (modified) llvm/include/llvm/IR/ConstantRange.h (+6) 
- (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+3-7) 
- (modified) llvm/lib/IR/ConstantRange.cpp (+10) 
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+66-1) 
- (modified) llvm/lib/Transforms/InstCombine/InstCombineInternal.h (+8) 
- (modified) llvm/test/Transforms/InstCombine/add.ll (+26) 
- (modified) llvm/test/Transforms/InstCombine/icmp-dom.ll (+3-3) 
- (added) llvm/test/Transforms/InstCombine/icmp-srem.ll (+468) 
- (modified) llvm/test/Transforms/InstCombine/smin-icmp.ll (+6-7) 
- (modified) llvm/unittests/IR/ConstantRangeTest.cpp (+12-1) 


``````````diff
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index d086c25390fd22..92e9341352c177 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -128,6 +128,12 @@ class [[nodiscard]] ConstantRange {
   /// NOTE: false does not mean that inverse predicate holds!
   bool icmp(CmpInst::Predicate Pred, const ConstantRange &Other) const;
 
+  /// Does the predicate \p Pred or its inverse hold between ranges this and \p
+  /// Other? Returns `true` if the predicate always holds, `false` if the
+  /// inverse always holds, or `std::nullopt` otherwise.
+  std::optional<bool> icmpOrInverse(CmpInst::Predicate Pred,
+                                    const ConstantRange &Other) const;
+
   /// Return true iff CR1 ult CR2 is equivalent to CR1 slt CR2.
   /// Does not depend on strictness/direction of the predicate.
   static bool
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index d69747e30f884d..dae4f37908cf2c 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3783,13 +3783,9 @@ static Value *simplifyICmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
   // If both operands have range metadata, use the metadata
   // to simplify the comparison.
   if (std::optional<ConstantRange> RhsCr = getRange(RHS, Q.IIQ))
-    if (std::optional<ConstantRange> LhsCr = getRange(LHS, Q.IIQ)) {
-      if (LhsCr->icmp(Pred, *RhsCr))
-        return ConstantInt::getTrue(ITy);
-
-      if (LhsCr->icmp(CmpInst::getInversePredicate(Pred), *RhsCr))
-        return ConstantInt::getFalse(ITy);
-    }
+    if (std::optional<ConstantRange> LhsCr = getRange(LHS, Q.IIQ))
+      if (auto Res = LhsCr->icmpOrInverse(Pred, *RhsCr))
+        return ConstantInt::getBool(ITy, *Res);
 
   // Compare of cast, for example (zext X) != 0 -> X != 0
   if (isa<CastInst>(LHS) && (isa<Constant>(RHS) || isa<CastInst>(RHS))) {
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 35664353989929..c5380ab2ffeda4 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -274,6 +274,16 @@ bool ConstantRange::icmp(CmpInst::Predicate Pred,
   }
 }
 
+std::optional<bool>
+ConstantRange::icmpOrInverse(CmpInst::Predicate Pred,
+                             const ConstantRange &Other) const {
+  if (icmp(Pred, Other))
+    return true;
+  if (icmp(CmpInst::getInversePredicate(Pred), Other))
+    return false;
+  return std::nullopt;
+}
+
 /// Exact mul nuw region for single element RHS.
 static ConstantRange makeExactMulNUWRegion(const APInt &V) {
   unsigned BitWidth = V.getBitWidth();
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 2e457257599493..f45868ba283a1a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3133,7 +3133,9 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
 
   if (ICmpInst::isUnsigned(Pred) && Add->hasNoSignedWrap() &&
       C.isNonNegative() && (C - *C2).isNonNegative() &&
-      computeConstantRange(X, /*ForSigned=*/true).add(*C2).isAllNonNegative())
+      computeConstantRange(X, Add, /*ForSigned=*/true)
+          .add(*C2)
+          .isAllNonNegative())
     return new ICmpInst(ICmpInst::getSignedPredicate(Pred), X,
                         ConstantInt::get(Ty, C - *C2));
 
@@ -7025,6 +7027,66 @@ static Instruction *canonicalizeICmpBool(ICmpInst &I,
   }
 }
 
+// (icmp X, Y) --> (icmp slt/sgt X, 0/-1) iff Y is outside the signed range of X
+static ICmpInst *canonicalizeSignBitCheck(ICmpInst::Predicate Pred, Value *X,
+                                          const ConstantRange &XRange,
+                                          const ConstantRange &YRange) {
+  if (XRange.isSignWrappedSet())
+    return nullptr;
+  unsigned BitWidth = XRange.getBitWidth();
+  APInt SMin = APInt::getSignedMinValue(BitWidth);
+  APInt Zero = APInt::getZero(BitWidth);
+  auto NegResult =
+      XRange.intersectWith(ConstantRange(SMin, Zero), ConstantRange::Signed)
+          .icmpOrInverse(Pred, YRange);
+  if (!NegResult)
+    return nullptr;
+  auto PosResult =
+      XRange.intersectWith(ConstantRange(Zero, SMin), ConstantRange::Signed)
+          .icmpOrInverse(Pred, YRange);
+  if (!PosResult)
+    return nullptr;
+  assert(NegResult != PosResult &&
+         "Known result should been simplified already.");
+  Type *Ty = X->getType();
+  if (*NegResult)
+    return new ICmpInst(ICmpInst::ICMP_SLT, X, ConstantInt::getNullValue(Ty));
+  return new ICmpInst(ICmpInst::ICMP_SGT, X, ConstantInt::getAllOnesValue(Ty));
+}
+
+// Try to fold an icmp using the constant ranges of its operands.
+Instruction *InstCombinerImpl::foldICmpUsingConstantRanges(ICmpInst &Cmp) {
+  Value *X = Cmp.getOperand(0);
+  if (!X->getType()->isIntOrIntVectorTy())
+    return nullptr;
+  Value *Y = Cmp.getOperand(1);
+  ICmpInst::Predicate Pred = Cmp.getPredicate();
+  ConstantRange XRange =
+      computeConstantRange(X, &Cmp, ICmpInst::isSigned(Pred));
+  if (XRange.isFullSet())
+    return nullptr; // early out if we don't have any information
+  ConstantRange YRange =
+      computeConstantRange(Y, &Cmp, ICmpInst::isSigned(Pred));
+  if (YRange.isFullSet())
+    return nullptr; // early out if we don't have any information
+  if (auto Res = XRange.icmpOrInverse(Pred, YRange))
+    return replaceInstUsesWith(Cmp, ConstantInt::getBool(Cmp.getType(), *Res));
+  if (ICmpInst::isUnsigned(Pred)) {
+    // Check if this icmp is actually a sign bit check.
+    const APInt *C;
+    bool IgnoreTrueIfSigned;
+    if (!match(Y, m_APInt(C)) ||
+        !isSignBitCheck(Pred, *C, IgnoreTrueIfSigned)) {
+      if (ICmpInst *Res = canonicalizeSignBitCheck(Pred, X, XRange, YRange))
+        return Res;
+      if (ICmpInst *Res = canonicalizeSignBitCheck(
+              ICmpInst::getSwappedPredicate(Pred), Y, YRange, XRange))
+        return Res;
+    }
+  }
+  return nullptr;
+}
+
 // Transform pattern like:
 //   (1 << Y) u<= X  or  ~(-1 << Y) u<  X  or  ((1 << Y)+(-1)) u<  X
 //   (1 << Y) u>  X  or  ~(-1 << Y) u>= X  or  ((1 << Y)+(-1)) u>= X
@@ -7397,6 +7459,9 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   if (Instruction *Res = canonicalizeICmpPredicate(I))
     return Res;
 
+  if (Instruction *Res = foldICmpUsingConstantRanges(I))
+    return Res;
+
   if (Instruction *Res = foldICmpWithConstant(I))
     return Res;
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 83e1da98deeda0..9f60dcf59ae467 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -240,6 +240,13 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   convertOrOfShiftsToFunnelShift(Instruction &Or);
 
 private:
+  ConstantRange computeConstantRange(const Value *V, const Instruction *CtxI,
+                                     bool ForSigned, bool UseInstrInfo = true,
+                                     unsigned Depth = 0) {
+    return llvm::computeConstantRange(V, ForSigned, UseInstrInfo, &AC, CtxI,
+                                      &DT, Depth);
+  }
+
   bool annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI);
   bool isDesirableIntType(unsigned BitWidth) const;
   bool shouldChangeType(unsigned FromBitWidth, unsigned ToBitWidth) const;
@@ -668,6 +675,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   Instruction *foldICmpWithCastOp(ICmpInst &ICmp);
   Instruction *foldICmpWithZextOrSext(ICmpInst &ICmp);
 
+  Instruction *foldICmpUsingConstantRanges(ICmpInst &Cmp);
   Instruction *foldICmpUsingKnownBits(ICmpInst &Cmp);
   Instruction *foldICmpWithDominatingICmp(ICmpInst &Cmp);
   Instruction *foldICmpWithConstant(ICmpInst &Cmp);
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 222f87fa3a5f18..495f99824652d6 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -3018,6 +3018,32 @@ define i32 @floor_sdiv_wrong_op(i32 %x, i32 %y) {
   ret i32 %r
 }
 
+define i32 @floor_sdiv_using_srem_by_8(i32 %x) {
+; CHECK-LABEL: @floor_sdiv_using_srem_by_8(
+; CHECK-NEXT:    [[F:%.*]] = ashr i32 [[X:%.*]], 3
+; CHECK-NEXT:    ret i32 [[F]]
+;
+  %d = sdiv i32 %x, 8
+  %r = srem i32 %x, 8
+  %i = icmp ugt i32 %r, -2147483648
+  %s = sext i1 %i to i32
+  %f = add i32 %d, %s
+  ret i32 %f
+}
+
+define i32 @floor_sdiv_using_srem_by_2(i32 %x) {
+; CHECK-LABEL: @floor_sdiv_using_srem_by_2(
+; CHECK-NEXT:    [[F:%.*]] = ashr i32 [[X:%.*]], 1
+; CHECK-NEXT:    ret i32 [[F]]
+;
+  %d = sdiv i32 %x, 2
+  %r = srem i32 %x, 2
+  %i = icmp ugt i32 %r, -2147483648
+  %s = sext i1 %i to i32
+  %f = add i32 %d, %s
+  ret i32 %f
+}
+
 ; (X s>> (BW - 1)) + (zext (X s> 0)) --> (X s>> (BW - 1)) | (zext (X != 0))
 
 define i8 @signum_i8_i8(i8 %x) {
diff --git a/llvm/test/Transforms/InstCombine/icmp-dom.ll b/llvm/test/Transforms/InstCombine/icmp-dom.ll
index 3cf3a7af77041c..66e9e514a9022a 100644
--- a/llvm/test/Transforms/InstCombine/icmp-dom.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-dom.ll
@@ -381,11 +381,11 @@ falselabel:
 
 define i8 @PR48900_alt(i8 %i, ptr %p) {
 ; CHECK-LABEL: @PR48900_alt(
-; CHECK-NEXT:    [[SMAX:%.*]] = call i8 @llvm.smax.i8(i8 [[I:%.*]], i8 -127)
-; CHECK-NEXT:    [[I4:%.*]] = icmp ugt i8 [[SMAX]], -128
+; CHECK-NEXT:    [[I4:%.*]] = icmp slt i8 [[I:%.*]], 0
 ; CHECK-NEXT:    br i1 [[I4]], label [[TRUELABEL:%.*]], label [[FALSELABEL:%.*]]
 ; CHECK:       truelabel:
-; CHECK-NEXT:    [[UMIN:%.*]] = call i8 @llvm.smin.i8(i8 [[SMAX]], i8 -126)
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i8 [[I]], -126
+; CHECK-NEXT:    [[UMIN:%.*]] = select i1 [[TMP1]], i8 -127, i8 -126
 ; CHECK-NEXT:    ret i8 [[UMIN]]
 ; CHECK:       falselabel:
 ; CHECK-NEXT:    ret i8 0
diff --git a/llvm/test/Transforms/InstCombine/icmp-srem.ll b/llvm/test/Transforms/InstCombine/icmp-srem.ll
new file mode 100644
index 00000000000000..9ab92f15ae7d2d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-srem.ll
@@ -0,0 +1,468 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @icmp_ugt_sremsmin_smin(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmin_smin(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X]], -2147483648
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ugt i32 %r, -2147483648
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmin_sminp1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmin_sminp1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[R]], -2147483647
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ugt i32 %r, -2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmin_smaxm1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmin_smaxm1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[R]], 2147483646
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ugt i32 %r, 2147483646
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmin_smax(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmin_smax(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X]], -2147483648
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ugt i32 %r, 2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmin_smin(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_sremsmin_smin(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ult i32 %r, -2147483648
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmin_sminp1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_sremsmin_sminp1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ult i32 %r, -2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmin_sminp2(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_sremsmin_sminp2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[R]], -2147483646
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ult i32 %r, -2147483646
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmin_smax(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_sremsmin_smax(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[R]], 2147483647
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, -2147483648
+  %c = icmp ult i32 %r, 2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_srem5_smin(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_srem5_smin(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ugt i32 %r, -2147483648
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_srem5_m5(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_srem5_m5(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ugt i32 %r, -5
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_srem5_m4(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_srem5_m4(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[R]], -4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ugt i32 %r, -4
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_srem5_3(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_srem5_3(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[R]], 3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ugt i32 %r, 3
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_srem5_4(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_srem5_4(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ugt i32 %r, 4
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_srem5_smaxm1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_srem5_smaxm1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ugt i32 %r, 2147483646
+  ret i1 %c
+}
+
+define i1 @icmp_ult_srem5_sminp1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_srem5_sminp1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ult i32 %r, -2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ult_srem5_m4(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_srem5_m4(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ult i32 %r, -4
+  ret i1 %c
+}
+
+define i1 @icmp_ult_srem5_m3(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_srem5_m3(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[R]], -3
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ult i32 %r, -3
+  ret i1 %c
+}
+
+define i1 @icmp_ult_srem5_4(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_srem5_4(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[R]], 4
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ult i32 %r, 4
+  ret i1 %c
+}
+
+define i1 @icmp_ult_srem5_5(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_srem5_5(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ult i32 %r, 5
+  ret i1 %c
+}
+
+define i1 @icmp_ult_srem5_smax(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_srem5_smax(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 5
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 5
+  %c = icmp ult i32 %r, 2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmax_smin(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_smin(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ugt i32 %r, -2147483648
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmax_sminp1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_sminp1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ugt i32 %r, -2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmax_sminp2(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_sminp2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[R]], -2147483646
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ugt i32 %r, -2147483646
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmax_smaxm2(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_smaxm2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[R]], 2147483645
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ugt i32 %r, 2147483645
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmax_smaxm1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_smaxm1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ugt i32 %r, 2147483646
+  ret i1 %c
+}
+
+define i1 @icmp_ugt_sremsmax_smax(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ugt_sremsmax_smax(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp slt i32 [[R]], 0
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ugt i32 %r, 2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmax_smin(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_sremsmax_smin(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ult i32 %r, -2147483648
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmax_sminp1(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_sremsmax_sminp1(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ult i32 %r, -2147483647
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmax_sminp2(i32 %x) {
+; CHECK-LABEL: define i1 @icmp_ult_sremsmax_sminp2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], 2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[R]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %r = srem i32 %x, 2147483647
+  %c = icmp ult i32 %r, -2147483646
+  ret i1 %c
+}
+
+define i1 @icmp_ult_sremsmax...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/122962


More information about the llvm-commits mailing list