[llvm] [InstCombine] Fold (X / C) < X and (X >> C) < X into X > 0 (PR #85555)

via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 17 12:21:06 PDT 2024


https://github.com/Poseydon42 updated https://github.com/llvm/llvm-project/pull/85555

>From 6bfc90a80e5f933c8acafadb7352292df8f15dee Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 16 Mar 2024 21:09:41 +0000
Subject: [PATCH 1/2] [IstCombine] Add tests for (X / C) < X and (X >> C) < X
 folds

---
 .../InstCombine/icmp-div-constant.ll          | 79 +++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
index 8dcb96284685ff..5b95144fe633c1 100644
--- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
@@ -375,3 +375,82 @@ define i1 @sdiv_eq_smin_use(i32 %x, i32 %y) {
   %r = icmp eq i32 %d, -2147483648
   ret i1 %r
 }
+
+; Folding (X / C) < X => X > 0 for C != 1
+
+define i1 @sdiv_x_by_const_cmp_x(i32 %x) {
+; CHECK-LABEL: @sdiv_x_by_const_cmp_x(
+; CHECK-NEXT:    [[TMP2:%.*]] = sdiv i32 [[X:%.*]], 123
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[TMP2]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = sdiv i32 %x, 123
+  %2 = icmp slt i32 %1, %x
+  ret i1 %2
+}
+
+define i1 @udiv_x_by_const_cmp_x(i32 %x) {
+; CHECK-LABEL: @udiv_x_by_const_cmp_x(
+; CHECK-NEXT:    [[TMP2:%.*]] = udiv i32 [[X:%.*]], 123
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[TMP2]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = udiv i32 %x, 123
+  %2 = icmp slt i32 %1, %x
+  ret i1 %2
+}
+
+; Same as above but with right shift instead of division (C != 0)
+
+define i1 @lshr_x_by_const_cmp_x(i32 %x) {
+; CHECK-LABEL: @lshr_x_by_const_cmp_x(
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[TMP2]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = lshr i32 %x, 1
+  %2 = icmp slt i32 %1, %x
+  ret i1 %2
+}
+
+; Negative tests for the folds above
+
+define i1 @sdiv_x_by_1_cmp_x_negative(i32 %x) {
+; CHECK-LABEL: @sdiv_x_by_1_cmp_x_negative(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = sdiv i32 %x, 1
+  %2 = icmp slt i32 %1, %x
+  ret i1 %2
+}
+
+define i1 @sdiv_x_by_1_cmp_y(i32 %x, i32 %y) {
+; CHECK-LABEL: @sdiv_x_by_1_cmp_y(
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv i32 [[X:%.*]], 123
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[TMP1]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = sdiv i32 %x, 123
+  %2 = icmp slt i32 %1, %y
+  ret i1 %2
+}
+
+define i1 @lshr_x_by_0_cmp_x(i32 %x) {
+; CHECK-LABEL: @lshr_x_by_0_cmp_x(
+; CHECK-NEXT:    ret i1 false
+;
+  %1 = lshr i32 %x, 0
+  %2 = icmp slt i32 %1, %x
+  ret i1 %2
+}
+
+define i1 @lshr_x_by_const_cmp_y(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_x_by_const_cmp_y(
+; CHECK-NEXT:    [[X:%.*]] = lshr i32 [[X1:%.*]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = lshr i32 %x, 1
+  %2 = icmp slt i32 %1, %y
+  ret i1 %2
+}

>From ba272c141236f63ed26c227d36cd5a0387fa1a2c Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 16 Mar 2024 22:13:15 +0000
Subject: [PATCH 2/2] [InstCombine] Fold (X / C) < X and (X >> C) < X into X >
 0

---
 .../InstCombine/InstCombineCompares.cpp       | 25 +++++++++++++++++++
 .../InstCombine/icmp-div-constant.ll          |  9 +++----
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 0dce0077bf1588..415ea61362776d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7406,6 +7406,31 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   if (Instruction *Res = foldReductionIdiom(I, Builder, DL))
     return Res;
 
+  // Folding (X / Y) < X => X > 0 for some constant Y other than 0 or 1
+  {
+    Constant *Divisor;
+    Value *Dividend;
+    if (match(Op0,
+              m_CombineOr(m_SDiv(m_Value(Dividend), m_ImmConstant(Divisor)),
+                          m_UDiv(m_Value(Dividend), m_ImmConstant(Divisor)))) &&
+        match(Op1, m_Deferred(Dividend)) &&
+        !(Divisor->isZeroValue() || Divisor->isOneValue())) {
+      return new ICmpInst(ICmpInst::ICMP_SGT, Dividend,
+                          Constant::getNullValue(Dividend->getType()));
+    }
+  }
+
+  // Another case of this fold is (X >> Y) < X => X > 0 if Y != 0
+  {
+    Constant *Shift;
+    Value *V;
+    if (match(Op0, m_LShr(m_Value(V), m_ImmConstant(Shift))) &&
+        match(Op1, m_Deferred(V)) && !Shift->isZeroValue()) {
+      return new ICmpInst(ICmpInst::ICMP_SGT, V,
+                          Constant::getNullValue(V->getType()));
+    }
+  }
+
   return Changed ? &I : nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
index 5b95144fe633c1..0bdfa5daa547a5 100644
--- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
@@ -380,8 +380,7 @@ define i1 @sdiv_eq_smin_use(i32 %x, i32 %y) {
 
 define i1 @sdiv_x_by_const_cmp_x(i32 %x) {
 ; CHECK-LABEL: @sdiv_x_by_const_cmp_x(
-; CHECK-NEXT:    [[TMP2:%.*]] = sdiv i32 [[X:%.*]], 123
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[TMP2]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %1 = sdiv i32 %x, 123
@@ -391,8 +390,7 @@ define i1 @sdiv_x_by_const_cmp_x(i32 %x) {
 
 define i1 @udiv_x_by_const_cmp_x(i32 %x) {
 ; CHECK-LABEL: @udiv_x_by_const_cmp_x(
-; CHECK-NEXT:    [[TMP2:%.*]] = udiv i32 [[X:%.*]], 123
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[TMP2]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %1 = udiv i32 %x, 123
@@ -404,8 +402,7 @@ define i1 @udiv_x_by_const_cmp_x(i32 %x) {
 
 define i1 @lshr_x_by_const_cmp_x(i32 %x) {
 ; CHECK-LABEL: @lshr_x_by_const_cmp_x(
-; CHECK-NEXT:    [[TMP2:%.*]] = lshr i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[TMP2]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %1 = lshr i32 %x, 1



More information about the llvm-commits mailing list