[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 15:48:35 PDT 2024


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

>From 6393ea91d0e5a1783007486cbeff21e9a40f31b3 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sun, 17 Mar 2024 21:56:02 +0000
Subject: [PATCH 1/2] [InstCombine] Add test cases for folds (X / C) cmp X and
 (X >> C) cmp X

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

diff --git a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
index 8dcb96284685ff..a8c41e61dd39e8 100644
--- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
@@ -375,3 +375,116 @@ define i1 @sdiv_eq_smin_use(i32 %x, i32 %y) {
   %r = icmp eq i32 %d, -2147483648
   ret i1 %r
 }
+
+; Fold (X / C) cmp X into X ~cmp 0 (~cmp is the inverse predicate of cmp), for some C != 1
+; Alternative form of this fold is when division is replaced with logic right shift
+
+define i1 @sdiv_x_by_const_cmp_x(i32 %x) {
+; CHECK-LABEL: @sdiv_x_by_const_cmp_x(
+; CHECK-NEXT:    [[V:%.*]] = udiv i32 [[X:%.*]], 13
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[V]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %v = udiv i32 %x, 13
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+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:    [[V:%.*]] = lshr i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[V]], [[X]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %v = lshr i32 %x, 1
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+define <4 x i1> @lshr_by_const_cmp_sle_value(<4 x i32> %x) {
+; CHECK-LABEL: @lshr_by_const_cmp_sle_value(
+; CHECK-NEXT:    [[V:%.*]] = lshr <4 x i32> [[X:%.*]], <i32 2, i32 3, i32 2, i32 4>
+; CHECK-NEXT:    [[R:%.*]] = icmp sle <4 x i32> [[V]], [[X]]
+; CHECK-NEXT:    ret <4 x i1> [[R]]
+;
+  %v = lshr <4 x i32> %x, <i32 2, i32 3, i32 2, i32 4>
+  %r = icmp sle <4 x i32> %v, %x
+  ret <4 x i1> %r
+}
+
+define i1 @lshr_by_const_cmp_ule_value(i32 %x) {
+; CHECK-LABEL: @lshr_by_const_cmp_ule_value(
+; CHECK-NEXT:    ret i1 true
+;
+  %v = lshr i32 %x, 3
+  %r = icmp ule i32 %v, %x
+  ret i1 %r
+}
+
+; Negative test - constant is 1
+
+define i1 @udiv_by_const_cmp_eq_value_neg(i32 %x) {
+; CHECK-LABEL: @udiv_by_const_cmp_eq_value_neg(
+; CHECK-NEXT:    ret i1 true
+;
+  %v = udiv i32 %x, 1
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+define i1 @sdiv_by_const_cmp_eq_value_neg(i32 %x) {
+; CHECK-LABEL: @sdiv_by_const_cmp_eq_value_neg(
+; CHECK-NEXT:    ret i1 true
+;
+  %v = sdiv i32 %x, 1
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+; Negative test - constant is 0
+
+define i1 @lshr_by_const_cmp_slt_value_neg(i32 %x) {
+; CHECK-LABEL: @lshr_by_const_cmp_slt_value_neg(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = lshr i32 %x, 0
+  %r = icmp slt i32 %v, %x
+  ret i1 %r
+}
+
+; Negative test - unsigned predicate with sdiv
+
+define i1 @sdiv_by_const_cmp_ult_value_neg(i32 %x) {
+; CHECK-LABEL: @sdiv_by_const_cmp_ult_value_neg(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = sdiv i32 %x, 1
+  %r = icmp ult i32 %v, %x
+  ret i1 %r
+}
+
+; Negative case - one of the components of a vector is 1
+
+define <4 x i1> @sdiv_by_const_cmp_sgt_value_neg(<4 x i32> %x) {
+; CHECK-LABEL: @sdiv_by_const_cmp_sgt_value_neg(
+; CHECK-NEXT:    [[V:%.*]] = sdiv <4 x i32> [[X:%.*]], <i32 1, i32 2, i32 3, i32 4>
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt <4 x i32> [[V]], [[X]]
+; CHECK-NEXT:    ret <4 x i1> [[R]]
+;
+  %v = sdiv <4 x i32> %x, <i32 1, i32 2, i32 3, i32 4>
+  %r = icmp sgt <4 x i32> %v, %x
+  ret <4 x i1> %r
+}

>From 65de414a60d3d5fdb4f342f25f991525b8fa8d60 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sun, 17 Mar 2024 22:37:10 +0000
Subject: [PATCH 2/2] [InstCombine] Fold (X / C) cmp X and (X >> C) cmp X into
 X cmp 0

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 0dce0077bf1588..a9f4fa006aaa29 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "InstCombineInternal.h"
+#include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SetVector.h"
@@ -23,6 +24,7 @@
 #include "llvm/Analysis/VectorUtils.h"
 #include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/Support/KnownBits.h"
@@ -7103,6 +7105,34 @@ Instruction *InstCombinerImpl::foldICmpCommutative(ICmpInst::Predicate Pred,
   if (Value *V = foldICmpWithLowBitMaskedVal(Pred, Op0, Op1, Q, *this))
     return replaceInstUsesWith(CxtI, V);
 
+  // Folding (X / Y) < X => X > 0 for some constant Y other than 0 or 1
+  {
+    const APInt *Divisor;
+    Value *Dividend;
+    if (match(Op0, m_UDiv(m_Value(Dividend), m_APInt(Divisor))) &&
+        Op1 == Dividend && Divisor->ugt(1)) {
+      return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Dividend,
+                          Constant::getNullValue(Dividend->getType()));
+    }
+
+    if (match(Op0, m_SDiv(m_Value(Dividend), m_APInt(Divisor))) &&
+        Op1 == Dividend && Divisor->ugt(1) && !ICmpInst::isUnsigned(Pred)) {
+      return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Dividend,
+                          Constant::getNullValue(Dividend->getType()));
+    }
+  }
+
+  // Another case of this fold is (X >> Y) < X => X > 0 if Y != 0
+  {
+    const APInt *Shift;
+    Value *V;
+    if (match(Op0, m_LShr(m_Value(V), m_APInt(Shift))) && Op1 == V &&
+        Shift->ugt(0) && !ICmpInst::isUnsigned(Pred)) {
+      return new ICmpInst(ICmpInst::getInversePredicate(Pred), V,
+                          Constant::getNullValue(V->getType()));
+    }
+  }
+
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
index a8c41e61dd39e8..ad3831cf951094 100644
--- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
@@ -381,8 +381,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:    [[V:%.*]] = udiv i32 [[X:%.*]], 13
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[V]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %v = udiv i32 %x, 13
@@ -392,8 +391,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
@@ -405,8 +403,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:    [[V:%.*]] = lshr i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[V]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %v = lshr i32 %x, 1



More information about the llvm-commits mailing list