[llvm] [InstSimplify] Recognize strict-form variants in icmp simplification (PR #196496)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 8 02:14:59 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Iris Shi (el-ev)
<details>
<summary>Changes</summary>
Extend `simplifyICmpWithBinOp` and `simplifyICmpUsingMonotonicValues` to recognize the strict-form variants.
This PR may not change behaviour but is needed to prevent regression from the canonicalization in #<!-- -->196238.
---
Full diff: https://github.com/llvm/llvm-project/pull/196496.diff
2 Files Affected:
- (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+26-8)
- (modified) llvm/test/Transforms/InstSimplify/compare.ll (+73)
``````````diff
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 2bd0eb269510f..d210ba1941b9d 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3189,9 +3189,18 @@ static void getUnsignedMonotonicValues(SmallPtrSetImpl<Value *> &Res, Value *V,
static Value *simplifyICmpUsingMonotonicValues(CmpPredicate Pred, Value *LHS,
Value *RHS,
const SimplifyQuery &Q) {
- if (Pred != ICmpInst::ICMP_UGE && Pred != ICmpInst::ICMP_ULT)
+ if (Pred != ICmpInst::ICMP_UGE && Pred != ICmpInst::ICMP_ULT &&
+ Pred != ICmpInst::ICMP_UGT && Pred != ICmpInst::ICMP_ULE)
return nullptr;
+ if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE) {
+ const APInt *C;
+ if (!match(RHS, m_APIntAllowPoison(C)) || C->isMaxValue())
+ return nullptr;
+ RHS = ConstantInt::get(RHS->getType(), *C + 1);
+ Pred = Pred == ICmpInst::ICMP_UGT ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT;
+ }
+
// We have LHS uge GreaterValues and LowerValues uge RHS. If any of the
// GreaterValues and LowerValues are the same, it follows that LHS uge RHS.
SmallPtrSet<Value *, 4> GreaterValues;
@@ -3477,13 +3486,22 @@ static Value *simplifyICmpWithBinOp(CmpPredicate Pred, Value *LHS, Value *RHS,
}
// If C is a power-of-2:
- // (C << X) >u 0x8000 --> false
- // (C << X) <=u 0x8000 --> true
- if (match(LHS, m_Shl(m_Power2(), m_Value())) && match(RHS, m_SignMask())) {
- if (Pred == ICmpInst::ICMP_UGT)
- return ConstantInt::getFalse(getCompareTy(RHS));
- if (Pred == ICmpInst::ICMP_ULE)
- return ConstantInt::getTrue(getCompareTy(RHS));
+ // (C << X) >u 0x8000 or >=u 0x8001--> false
+ // (C << X) <=u 0x8000 or <u 0x8001--> true
+ const APInt *RC;
+ if (match(LHS, m_Shl(m_Power2(), m_Value())) &&
+ match(RHS, m_APIntAllowPoison(RC))) {
+ if (RC->isSignMask()) {
+ if (Pred == ICmpInst::ICMP_UGT)
+ return ConstantInt::getFalse(getCompareTy(RHS));
+ if (Pred == ICmpInst::ICMP_ULE)
+ return ConstantInt::getTrue(getCompareTy(RHS));
+ } else if (!RC->isZero() && (*RC - 1).isSignMask()) {
+ if (Pred == ICmpInst::ICMP_UGE)
+ return ConstantInt::getFalse(getCompareTy(RHS));
+ if (Pred == ICmpInst::ICMP_ULT)
+ return ConstantInt::getTrue(getCompareTy(RHS));
+ }
}
if (!MaxRecurse || !LBO || !RBO || LBO->getOpcode() != RBO->getOpcode())
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index ba10ea532a34a..3895dace4209a 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -1902,6 +1902,79 @@ define <2 x i1> @icmp_shl_1_ule_signmask_poison2(<2 x i8> %V) {
ret <2 x i1> %cmp
}
+define i1 @icmp_shl_1_uge_signmask_plus_one(i8 %V) {
+; CHECK-LABEL: @icmp_shl_1_uge_signmask_plus_one(
+; CHECK-NEXT: ret i1 false
+;
+ %shl = shl i8 1, %V
+ %cmp = icmp uge i8 %shl, -127
+ ret i1 %cmp
+}
+
+define i1 @icmp_shl_1_ult_signmask_plus_one(i8 %V) {
+; CHECK-LABEL: @icmp_shl_1_ult_signmask_plus_one(
+; CHECK-NEXT: ret i1 true
+;
+ %shl = shl i8 1, %V
+ %cmp = icmp ult i8 %shl, -127
+ ret i1 %cmp
+}
+
+; (mul nuw X, C) ugt (C - 1) -- strict-form of (mul nuw X, C) uge C, where
+; X is known non-zero. Should fold to true.
+
+define i1 @nuwmul_ugt_const_minus_one(i32 %arg) {
+; CHECK-LABEL: @nuwmul_ugt_const_minus_one(
+; CHECK-NEXT: [[NONZERO:%.*]] = icmp ne i32 [[ARG:%.*]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NONZERO]])
+; CHECK-NEXT: ret i1 true
+;
+ %nonzero = icmp ne i32 %arg, 0
+ call void @llvm.assume(i1 %nonzero)
+ %mul = mul nuw nsw i32 %arg, 24
+ %cmp = icmp ugt i32 %mul, 23
+ ret i1 %cmp
+}
+
+define i1 @nuwmul_uge_const(i32 %arg) {
+; CHECK-LABEL: @nuwmul_uge_const(
+; CHECK-NEXT: [[NONZERO:%.*]] = icmp ne i32 [[ARG:%.*]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NONZERO]])
+; CHECK-NEXT: ret i1 true
+;
+ %nonzero = icmp ne i32 %arg, 0
+ call void @llvm.assume(i1 %nonzero)
+ %mul = mul nuw nsw i32 %arg, 24
+ %cmp = icmp uge i32 %mul, 24
+ ret i1 %cmp
+}
+
+define i1 @shape_ult_const(i32 %arg) {
+; CHECK-LABEL: @shape_ult_const(
+; CHECK-NEXT: [[NONZERO:%.*]] = icmp ne i32 [[ARG:%.*]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NONZERO]])
+; CHECK-NEXT: ret i1 false
+;
+ %nonzero = icmp ne i32 %arg, 0
+ call void @llvm.assume(i1 %nonzero)
+ %mul = mul nuw nsw i32 %arg, 24
+ %cmp = icmp ult i32 %mul, 24
+ ret i1 %cmp
+}
+
+define i1 @shape_ule_const_minus_one(i32 %arg) {
+; CHECK-LABEL: @shape_ule_const_minus_one(
+; CHECK-NEXT: [[NONZERO:%.*]] = icmp ne i32 [[ARG:%.*]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[NONZERO]])
+; CHECK-NEXT: ret i1 false
+;
+ %nonzero = icmp ne i32 %arg, 0
+ call void @llvm.assume(i1 %nonzero)
+ %mul = mul nuw nsw i32 %arg, 24
+ %cmp = icmp ule i32 %mul, 23
+ ret i1 %cmp
+}
+
define i1 @shl_1_cmp_eq_nonpow2(i32 %x) {
; CHECK-LABEL: @shl_1_cmp_eq_nonpow2(
; CHECK-NEXT: ret i1 false
``````````
</details>
https://github.com/llvm/llvm-project/pull/196496
More information about the llvm-commits
mailing list