[llvm] [InstSimplify] Simplify (X - (X urem Y)) u>= 1 via X u>= Y (PR #216072)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 13 07:55:23 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-transforms

Author: Hadong Lee (ChrisLee02)

<details>
<summary>Changes</summary>

This simplifies `(X - (X urem Y)) u>= 1` via `X u>= Y`.

For a defined `urem`, let `Q = X udiv Y` and `R = X urem Y`. Then:

```text
X - R = Q * Y

X - R >= 1
<=> Q != 0
<=> X >= Y
```

This allows dominating conditions involving `X` and `Y` to simplify the original comparison and eliminate `umax(X - (X urem Y), 1)` when `X u>= Y` is known.

Alive2: https://alive2.llvm.org/ce/z/pYsL4L

Fixes #<!-- -->216071

---
Full diff: https://github.com/llvm/llvm-project/pull/216072.diff


2 Files Affected:

- (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+8) 
- (modified) llvm/test/Transforms/InstSimplify/domcondition.ll (+92) 


``````````diff
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 10b159192c4be..ac9f01bc11b75 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3292,6 +3292,14 @@ static Value *simplifyICmpWithBinOpOnLHS(CmpPredicate Pred, BinaryOperator *LBO,
     }
   }
 
+  // (X - (X urem Y)) u>= 1 iff X u>= Y.
+  Value *X, *Divisor;
+  if (MaxRecurse && Pred == ICmpInst::ICMP_UGE && match(RHS, m_One()) &&
+      match(LBO, m_Sub(m_Value(X), m_URem(m_Deferred(X), m_Value(Divisor)))))
+    if (Value *V =
+            simplifyICmpInst(ICmpInst::ICMP_UGE, X, Divisor, Q, MaxRecurse - 1))
+      return V;
+
   // If x is nonzero:
   // x >>u C <u  x --> true  for C != 0.
   // x >>u C !=  x --> true  for C != 0.
diff --git a/llvm/test/Transforms/InstSimplify/domcondition.ll b/llvm/test/Transforms/InstSimplify/domcondition.ll
index 2893bb155bbe7..b3c70070c58e2 100644
--- a/llvm/test/Transforms/InstSimplify/domcondition.ll
+++ b/llvm/test/Transforms/InstSimplify/domcondition.ll
@@ -118,6 +118,98 @@ cond.end:
   ret i32 %cond
 }
 
+define i1 @urem_sub_nonzero_domcondition(i64 %x, i64 %y) {
+; CHECK-LABEL: @urem_sub_nonzero_domcondition(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND:%.*]] = icmp uge i64 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[KNOWN:%.*]], label [[EXIT:%.*]]
+; CHECK:       known:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       exit:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %cond = icmp uge i64 %x, %y
+  br i1 %cond, label %known, label %exit
+
+known:
+  %rem = urem i64 %x, %y
+  %sub = sub i64 %x, %rem
+  %cmp = icmp uge i64 %sub, 1
+  ret i1 %cmp
+
+exit:
+  ret i1 false
+}
+
+declare i64 @llvm.umax.i64(i64, i64)
+
+define i64 @urem_sub_umax_domcondition(i64 %x, i64 %y) {
+; CHECK-LABEL: @urem_sub_umax_domcondition(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND:%.*]] = icmp ult i64 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[BODY:%.*]]
+; CHECK:       body:
+; CHECK-NEXT:    [[REM:%.*]] = urem i64 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[X]], [[REM]]
+; CHECK-NEXT:    ret i64 [[SUB]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i64 0
+;
+entry:
+  %cond = icmp ult i64 %x, %y
+  br i1 %cond, label %exit, label %body
+
+body:
+  %rem = urem i64 %x, %y
+  %sub = sub i64 %x, %rem
+  %max = call i64 @llvm.umax.i64(i64 %sub, i64 1)
+  ret i64 %max
+
+exit:
+  ret i64 0
+}
+
+define i1 @urem_sub_nonzero_no_context(i64 %x, i64 %y) {
+; CHECK-LABEL: @urem_sub_nonzero_no_context(
+; CHECK-NEXT:    [[REM:%.*]] = urem i64 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[X]], [[REM]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i64 [[SUB]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %rem = urem i64 %x, %y
+  %sub = sub i64 %x, %rem
+  %cmp = icmp uge i64 %sub, 1
+  ret i1 %cmp
+}
+
+define i1 @urem_sub_nonzero_different_dividend(i64 %x, i64 %y, i64 %z) {
+; CHECK-LABEL: @urem_sub_nonzero_different_dividend(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND:%.*]] = icmp uge i64 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[KNOWN:%.*]], label [[EXIT:%.*]]
+; CHECK:       known:
+; CHECK-NEXT:    [[REM:%.*]] = urem i64 [[Z:%.*]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[X]], [[REM]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i64 [[SUB]], 1
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %cond = icmp uge i64 %x, %y
+  br i1 %cond, label %known, label %exit
+
+known:
+  %rem = urem i64 %z, %y
+  %sub = sub i64 %x, %rem
+  %cmp = icmp uge i64 %sub, 1
+  ret i1 %cmp
+
+exit:
+  ret i1 false
+}
+
 define i32 @srem_domcondition(i32 %x, i32 %y) {
 ; CHECK-LABEL: @srem_domcondition(
 ; CHECK-NEXT:  entry:

``````````

</details>


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


More information about the llvm-commits mailing list