[llvm] [InstCombine] canonicalize sign bit checks (PR #122962)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 14 12:29:15 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
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