[llvm] [InstCombine] fold unsigned predicates on srem result (PR #122520)

Jacob Young via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 12 04:39:32 PST 2025


================
@@ -2674,10 +2674,41 @@ Instruction *InstCombinerImpl::foldICmpShrConstant(ICmpInst &Cmp,
 Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
                                                     BinaryOperator *SRem,
                                                     const APInt &C) {
+  const ICmpInst::Predicate Pred = Cmp.getPredicate();
+  if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT) {
+    // Canonicalize unsigned predicates to signed:
+    // (X % DivisorC) ugt C -> (X % DivisorC) slt 0
+    //   iff (C slt 0 ? ~C : C) uge abs(DivisorC)-1
+    // (X % DivisorC) ult C+1 -> (X % DivisorC) sgt -1
+    //   iff (C+1 slt 0 ? ~C : C) uge abs(DivisorC)->
+
+    const APInt *DivisorC;
+    if (!match(SRem->getOperand(1), m_APInt(DivisorC)))
+      return nullptr;
+
+    APInt NormalizedC = C;
+    if (Pred == ICmpInst::ICMP_ULT) {
+      assert(!NormalizedC.isZero() &&
+             "ult X, 0 should have been simplified already.");
+      --NormalizedC;
+    }
+    if (C.isNegative())
+      NormalizedC.flipAllBits();
+    assert(!DivisorC->isZero() &&
+           "srem X, 0 should have been simplified already.");
+    if (!NormalizedC.uge(DivisorC->abs() - 1))
----------------
jacobly0 wrote:

Unfortunately, that's the wrong direction (the equivalent expression is `NormalizedC.ugt(DivisorC->abs() - 2)`), so applying that diff causes the fold to no longer happen in cases where it is still valid.  As much as I tried to make the math look nicer that was already the best I could manage while still having the correct bounds.
```diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c107a12fcf43..8d99b5f1022a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2696,7 +2696,7 @@ Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp,
       NormalizedC.flipAllBits();
     assert(!DivisorC->isZero() &&
            "srem X, 0 should have been simplified already.");
-    if (!NormalizedC.uge(DivisorC->abs() - 1))
+    if (!NormalizedC.ugt(DivisorC->abs()))
       return nullptr;
 
     Type *Ty = SRem->getType();
diff --git a/llvm/test/Transforms/InstCombine/icmp-srem.ll b/llvm/test/Transforms/InstCombine/icmp-srem.ll
index 47429dbad74c..3c9a65e57fd0 100644
--- a/llvm/test/Transforms/InstCombine/icmp-srem.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-srem.ll
@@ -17,7 +17,7 @@ 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:    [[C:%.*]] = icmp ugt i32 [[R]], -5
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %r = srem i32 %x, 5
@@ -53,7 +53,7 @@ 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:    [[C:%.*]] = icmp ugt i32 [[R]], 4
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %r = srem i32 %x, 5
@@ -89,7 +89,7 @@ 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:    [[C:%.*]] = icmp ult i32 [[R]], -4
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %r = srem i32 %x, 5
@@ -125,7 +125,7 @@ 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:    [[C:%.*]] = icmp ult i32 [[R]], 5
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
   %r = srem i32 %x, 5

```
https://alive2.llvm.org/ce/z/naNgve

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


More information about the llvm-commits mailing list